-
- {transientSingleColumn ? (
-
- ) : (
-
- )}
+ {!banner &&
}
+ {banner &&
+
+ {banner}
+
+ }
+
{signedIn && (
<>
-
+
} text={intl.formatMessage(messages.notifications)} />
>
)}
{trendsEnabled ? (
-
+
) : (
-
+
)}
{(signedIn || timelinePreview) && (
-
+
)}
{!signedIn && (
@@ -98,22 +114,22 @@ class NavigationPanel extends Component {
{signedIn && (
<>
-
-
-
-
+
+
+
+
-
+
>
)}
-
+
diff --git a/app/javascript/mastodon/features/ui/components/notifications_counter_icon.js b/app/javascript/mastodon/features/ui/components/notifications_counter_icon.js
index 7a9032b98473e1..b3e9950e93ffbd 100644
--- a/app/javascript/mastodon/features/ui/components/notifications_counter_icon.js
+++ b/app/javascript/mastodon/features/ui/components/notifications_counter_icon.js
@@ -1,10 +1,14 @@
import { connect } from 'react-redux';
+import { ReactComponent as NotificationsIcon } from '@material-symbols/svg-600/outlined/notifications-fill.svg';
+
import { IconWithBadge } from 'mastodon/components/icon_with_badge';
+
const mapStateToProps = state => ({
count: state.getIn(['notifications', 'unread']),
id: 'bell',
+ icon: NotificationsIcon,
});
export default connect(mapStateToProps)(IconWithBadge);
diff --git a/app/javascript/mastodon/features/ui/components/report_modal.jsx b/app/javascript/mastodon/features/ui/components/report_modal.jsx
index fef1ced824e8f2..2b6f04207ebdd1 100644
--- a/app/javascript/mastodon/features/ui/components/report_modal.jsx
+++ b/app/javascript/mastodon/features/ui/components/report_modal.jsx
@@ -7,6 +7,8 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
+import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
+
import { submitReport } from 'mastodon/actions/reports';
import { fetchServer } from 'mastodon/actions/server';
import { expandAccountTimeline } from 'mastodon/actions/timelines';
@@ -209,7 +211,7 @@ class ReportModal extends ImmutablePureComponent {
return (
-
+
{account.get('acct')} }} />
diff --git a/app/javascript/mastodon/features/ui/components/sign_in_banner.jsx b/app/javascript/mastodon/features/ui/components/sign_in_banner.jsx
index d5f0c00dca70df..4216f3da3827bc 100644
--- a/app/javascript/mastodon/features/ui/components/sign_in_banner.jsx
+++ b/app/javascript/mastodon/features/ui/components/sign_in_banner.jsx
@@ -25,7 +25,7 @@ const SignInBanner = () => {
- )
+ );
}
if (registrationsOpen) {
diff --git a/app/javascript/mastodon/features/ui/components/zoomable_image.jsx b/app/javascript/mastodon/features/ui/components/zoomable_image.jsx
index f2cada3f6a584f..5e71da9d9687be 100644
--- a/app/javascript/mastodon/features/ui/components/zoomable_image.jsx
+++ b/app/javascript/mastodon/features/ui/components/zoomable_image.jsx
@@ -3,6 +3,9 @@ import { PureComponent } from 'react';
import { defineMessages, injectIntl } from 'react-intl';
+import { ReactComponent as FullscreenExitIcon } from '@material-symbols/svg-600/outlined/fullscreen_exit.svg';
+import { ReactComponent as RectangleIcon } from '@material-symbols/svg-600/outlined/rectangle.svg';
+
import { IconButton } from 'mastodon/components/icon_button';
const messages = defineMessages({
@@ -418,6 +421,7 @@ class ZoomableImage extends PureComponent {
className={`media-modal__zoom-button ${zoomButtonShouldHide}`}
title={zoomButtonTitle}
icon={this.state.zoomState}
+ iconComponent={this.state.zoomState === 'compress' ? FullscreenExitIcon : RectangleIcon}
onClick={this.handleZoomClick}
size={40}
style={{
diff --git a/app/javascript/mastodon/features/ui/index.jsx b/app/javascript/mastodon/features/ui/index.jsx
index ac5e2d9361f140..f836dace7f398d 100644
--- a/app/javascript/mastodon/features/ui/index.jsx
+++ b/app/javascript/mastodon/features/ui/index.jsx
@@ -16,6 +16,7 @@ import { synchronouslySubmitMarkers, submitMarkers, fetchMarkers } from 'mastodo
import { INTRODUCTION_VERSION } from 'mastodon/actions/onboarding';
import PictureInPicture from 'mastodon/features/picture_in_picture';
import { layoutFromWindow } from 'mastodon/is_mobile';
+import { WithRouterPropTypes } from 'mastodon/utils/react_router';
import { uploadCompose, resetCompose, changeComposeSpoilerness } from '../../actions/compose';
import { clearHeight } from '../../actions/height_cache';
@@ -184,7 +185,9 @@ class SwitchingColumnsArea extends PureComponent {
{singleColumn ?
: null}
{singleColumn && pathName.startsWith('/deck/') ?
: null}
+ {/* Redirect old bookmarks (without /deck) with home-like routes to the advanced interface */}
{!singleColumn && pathName === '/getting-started' ?
: null}
+ {!singleColumn && pathName === '/home' ?
: null}
@@ -246,7 +249,6 @@ class SwitchingColumnsArea extends PureComponent {
class UI extends PureComponent {
static contextTypes = {
- router: PropTypes.object.isRequired,
identity: PropTypes.object.isRequired,
};
@@ -257,12 +259,12 @@ class UI extends PureComponent {
hasComposingText: PropTypes.bool,
hasMediaAttachments: PropTypes.bool,
canUploadMore: PropTypes.bool,
- location: PropTypes.object,
intl: PropTypes.object.isRequired,
dropdownMenuIsOpen: PropTypes.bool,
layout: PropTypes.string.isRequired,
firstLaunch: PropTypes.bool,
username: PropTypes.string,
+ ...WithRouterPropTypes,
};
state = {
@@ -359,7 +361,7 @@ class UI extends PureComponent {
handleServiceWorkerPostMessage = ({ data }) => {
if (data.type === 'navigate') {
- this.context.router.history.push(data.path);
+ this.props.history.push(data.path);
} else {
console.warn('Unknown message type:', data.type);
}
@@ -480,12 +482,12 @@ class UI extends PureComponent {
};
handleHotkeyBack = () => {
- const { router } = this.context;
+ const { history } = this.props;
- if (router.history.location?.state?.fromMastodon) {
- router.history.goBack();
+ if (history.location?.state?.fromMastodon) {
+ history.goBack();
} else {
- router.history.push('/');
+ history.push('/');
}
};
@@ -495,58 +497,58 @@ class UI extends PureComponent {
handleHotkeyToggleHelp = () => {
if (this.props.location.pathname === '/keyboard-shortcuts') {
- this.context.router.history.goBack();
+ this.props.history.goBack();
} else {
- this.context.router.history.push('/keyboard-shortcuts');
+ this.props.history.push('/keyboard-shortcuts');
}
};
handleHotkeyGoToHome = () => {
- this.context.router.history.push('/home');
+ this.props.history.push('/home');
};
handleHotkeyGoToNotifications = () => {
- this.context.router.history.push('/notifications');
+ this.props.history.push('/notifications');
};
handleHotkeyGoToLocal = () => {
- this.context.router.history.push('/public/local');
+ this.props.history.push('/public/local');
};
handleHotkeyGoToFederated = () => {
- this.context.router.history.push('/public');
+ this.props.history.push('/public');
};
handleHotkeyGoToDirect = () => {
- this.context.router.history.push('/conversations');
+ this.props.history.push('/conversations');
};
handleHotkeyGoToStart = () => {
- this.context.router.history.push('/getting-started');
+ this.props.history.push('/getting-started');
};
handleHotkeyGoToFavourites = () => {
- this.context.router.history.push('/favourites');
+ this.props.history.push('/favourites');
};
handleHotkeyGoToPinned = () => {
- this.context.router.history.push('/pinned');
+ this.props.history.push('/pinned');
};
handleHotkeyGoToProfile = () => {
- this.context.router.history.push(`/@${this.props.username}`);
+ this.props.history.push(`/@${this.props.username}`);
};
handleHotkeyGoToBlocked = () => {
- this.context.router.history.push('/blocks');
+ this.props.history.push('/blocks');
};
handleHotkeyGoToMuted = () => {
- this.context.router.history.push('/mutes');
+ this.props.history.push('/mutes');
};
handleHotkeyGoToRequests = () => {
- this.context.router.history.push('/follow_requests');
+ this.props.history.push('/follow_requests');
};
render () {
diff --git a/app/javascript/mastodon/features/ui/util/react_router_helpers.jsx b/app/javascript/mastodon/features/ui/util/react_router_helpers.jsx
index 99277268573cc5..ec68b5a4a72491 100644
--- a/app/javascript/mastodon/features/ui/util/react_router_helpers.jsx
+++ b/app/javascript/mastodon/features/ui/util/react_router_helpers.jsx
@@ -1,36 +1,29 @@
import PropTypes from 'prop-types';
-import { Component, PureComponent, cloneElement, Children } from 'react';
+import { Component, cloneElement, Children } from 'react';
-import { Switch, Route } from 'react-router-dom';
+import { Switch, Route, useLocation } from 'react-router-dom';
import StackTrace from 'stacktrace-js';
import BundleColumnError from '../components/bundle_column_error';
-import ColumnLoading from '../components/column_loading';
+import { ColumnLoading } from '../components/column_loading';
import BundleContainer from '../containers/bundle_container';
// Small wrapper to pass multiColumn to the route components
-export class WrappedSwitch extends PureComponent {
- static contextTypes = {
- router: PropTypes.object,
- };
-
- render () {
- const { multiColumn, children } = this.props;
- const { location } = this.context.router.route;
-
- const decklessLocation = multiColumn && location.pathname.startsWith('/deck')
- ? {...location, pathname: location.pathname.slice(5)}
- : location;
-
- return (
-
- {Children.map(children, child => child ? cloneElement(child, { multiColumn }) : null)}
-
- );
- }
+export const WrappedSwitch = ({ multiColumn, children }) => {
+ const location = useLocation();
+
+ const decklessLocation = multiColumn && location.pathname.startsWith('/deck')
+ ? {...location, pathname: location.pathname.slice(5)}
+ : location;
+
+ return (
+
+ {Children.map(children, child => child ? cloneElement(child, { multiColumn }) : null)}
+
+ );
+};
-}
WrappedSwitch.propTypes = {
multiColumn: PropTypes.bool,
diff --git a/app/javascript/mastodon/features/video/index.jsx b/app/javascript/mastodon/features/video/index.jsx
index ec0e7a9095c067..c04d9e3d4b9085 100644
--- a/app/javascript/mastodon/features/video/index.jsx
+++ b/app/javascript/mastodon/features/video/index.jsx
@@ -7,6 +7,14 @@ import classNames from 'classnames';
import { is } from 'immutable';
+import { ReactComponent as FullscreenIcon } from '@material-symbols/svg-600/outlined/fullscreen.svg';
+import { ReactComponent as FullscreenExitIcon } from '@material-symbols/svg-600/outlined/fullscreen_exit.svg';
+import { ReactComponent as PauseIcon } from '@material-symbols/svg-600/outlined/pause.svg';
+import { ReactComponent as PlayArrowIcon } from '@material-symbols/svg-600/outlined/play_arrow.svg';
+import { ReactComponent as RectangleIcon } from '@material-symbols/svg-600/outlined/rectangle.svg';
+import { ReactComponent as VisibilityOffIcon } from '@material-symbols/svg-600/outlined/visibility_off.svg';
+import { ReactComponent as VolumeOffIcon } from '@material-symbols/svg-600/outlined/volume_off.svg';
+import { ReactComponent as VolumeUpIcon } from '@material-symbols/svg-600/outlined/volume_up.svg';
import { throttle } from 'lodash';
import { Blurhash } from 'mastodon/components/blurhash';
@@ -592,8 +600,8 @@ class Video extends PureComponent {
-
-
+
+
@@ -615,10 +623,10 @@ class Video extends PureComponent {
- {(!onCloseVideo && !editable && !fullscreen && !this.props.alwaysVisible) && }
- {(!fullscreen && onOpenVideo) && }
- {onCloseVideo && }
-
+ {(!onCloseVideo && !editable && !fullscreen && !this.props.alwaysVisible) && }
+ {(!fullscreen && onOpenVideo) && }
+ {onCloseVideo && }
+
diff --git a/app/javascript/mastodon/initial_state.js b/app/javascript/mastodon/initial_state.js
index 34fd5439db3f2d..598e7337480d65 100644
--- a/app/javascript/mastodon/initial_state.js
+++ b/app/javascript/mastodon/initial_state.js
@@ -101,6 +101,7 @@ const initialPath = document.querySelector("head meta[name=initialPath]")?.getAt
/** @type {boolean} */
export const hasMultiColumnPath = initialPath === '/'
|| initialPath === '/getting-started'
+ || initialPath === '/home'
|| initialPath.startsWith('/deck');
/**
diff --git a/app/javascript/mastodon/locales/bn.json b/app/javascript/mastodon/locales/bn.json
index 4b055f53a410f4..85d6f2474a04e5 100644
--- a/app/javascript/mastodon/locales/bn.json
+++ b/app/javascript/mastodon/locales/bn.json
@@ -190,6 +190,7 @@
"conversation.open": "কথপোকথন দেখান",
"conversation.with": "{names} এর সঙ্গে",
"copypaste.copied": "অনুলিপিকৃত",
+ "copypaste.copy_to_clipboard": "ক্লিপবোর্ডে কপি করুন",
"directory.federated": "পরিচিত ফেডিভারসের থেকে",
"directory.local": "শুধু {domain} থেকে",
"directory.new_arrivals": "নতুন আগত",
diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json
index 94d62a4889dc05..33c7c31d9c17d9 100644
--- a/app/javascript/mastodon/locales/cs.json
+++ b/app/javascript/mastodon/locales/cs.json
@@ -534,6 +534,7 @@
"reply_indicator.cancel": "Zrušit",
"report.block": "Blokovat",
"report.block_explanation": "Neuvidíte příspěvky tohoto uživatele. On neuvidí vaše příspěvky, ani vás nebude moci sledovat. Pozná, že je blokován.",
+ "report.categories.legal": "Právní ustanovení",
"report.categories.other": "Ostatní",
"report.categories.spam": "Spam",
"report.categories.violation": "Obsah porušuje jedno nebo více pravidel serveru",
@@ -590,6 +591,7 @@
"search_popout.options": "Možnosti hledání",
"search_popout.quick_actions": "Rychlé akce",
"search_popout.recent": "Nedávná vyhledávání",
+ "search_popout.specific_date": "konkrétní datum",
"search_popout.user": "uživatel",
"search_results.accounts": "Profily",
"search_results.all": "Vše",
diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json
index acd53c28a77fb5..76b37ef44b06df 100644
--- a/app/javascript/mastodon/locales/de.json
+++ b/app/javascript/mastodon/locales/de.json
@@ -383,7 +383,7 @@
"lists.new.create": "Neue Liste erstellen",
"lists.new.title_placeholder": "Titel der neuen Liste",
"lists.replies_policy.followed": "Alle folgenden Profile",
- "lists.replies_policy.list": "Mitglieder*innen der Liste",
+ "lists.replies_policy.list": "Mitglieder der Liste",
"lists.replies_policy.none": "Niemanden",
"lists.replies_policy.title": "Antworten anzeigen für:",
"lists.search": "Suche nach Leuten, denen du folgst",
diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json
index b674f90c84acd0..5b4fef59c0fca2 100644
--- a/app/javascript/mastodon/locales/eu.json
+++ b/app/javascript/mastodon/locales/eu.json
@@ -613,7 +613,7 @@
"sign_in_banner.create_account": "Sortu kontua",
"sign_in_banner.sign_in": "Hasi saioa",
"sign_in_banner.sso_redirect": "Hasi saioa edo izena eman",
- "sign_in_banner.text": "Hasi saioa profilak edo traolak jarraitzeko, bidalketak gogokoetara gehitzeko, partekatzeko edo erantzuteko. Zure kontutik ere komunika zaitezke beste zerbitzari ezberdin vatean.",
+ "sign_in_banner.text": "Hasi saioa profilak edo traolak jarraitzeko, bidalketak gogokoetara gehitzeko, partekatzeko edo erantzuteko. Zure kontutik ere komunika zaitezke beste zerbitzari ezberdin batean.",
"status.admin_account": "Ireki @{name} erabiltzailearen moderazio interfazea",
"status.admin_domain": "{domain}-(r)en moderazio-interfazea ireki",
"status.admin_status": "Ireki bidalketa hau moderazio interfazean",
diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json
index c1b067cff89536..f4a2e09e73412a 100644
--- a/app/javascript/mastodon/locales/fa.json
+++ b/app/javascript/mastodon/locales/fa.json
@@ -338,7 +338,7 @@
"keyboard_shortcuts.column": "برای تمرکز روی یک فرسته در یکی از ستونها",
"keyboard_shortcuts.compose": "تمرکز روی محیط نوشتن",
"keyboard_shortcuts.description": "توضیح",
- "keyboard_shortcuts.direct": "باز کردن ستون اشارههای خصوصی",
+ "keyboard_shortcuts.direct": "برای گشودن ستون اشارههای خصوصی",
"keyboard_shortcuts.down": "پایین بردن در سیاهه",
"keyboard_shortcuts.enter": "گشودن فرسته",
"keyboard_shortcuts.favourite": "پسندیدن فرسته",
diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json
index 2454bdf980fa06..aac4256ffdbf96 100644
--- a/app/javascript/mastodon/locales/fi.json
+++ b/app/javascript/mastodon/locales/fi.json
@@ -1,9 +1,9 @@
{
- "about.blocks": "Moderoidut palvelimet",
- "about.contact": "Yhteystiedot:",
+ "about.blocks": "Valvotut palvelimet",
+ "about.contact": "Ota yhteyttä:",
"about.disclaimer": "Mastodon on vapaa avoimen lähdekoodin ohjelmisto ja Mastodon gGmbH:n tavaramerkki.",
"about.domain_blocks.no_reason_available": "Syytä ei ole ilmoitettu",
- "about.domain_blocks.preamble": "Yleisesti Mastodonin avulla voidaan tarkastella minkä tahansa muun fediverse-palvelinten sisältöä ja vuorovaikuttaa eri palvelinten käyttäjien kanssa. Nämä ovat tälle palvelimelle määritetyt poikkeukset.",
+ "about.domain_blocks.preamble": "Mastodonin avulla voidaan yleensä tarkastella minkä tahansa fediversumiin kuuluvan palvelimen sisältöä ja vuorovaikuttaa eri palvelinten käyttäjien kanssa. Nämä ovat tälle palvelimelle määritetyt poikkeukset.",
"about.domain_blocks.silenced.explanation": "Et yleensä näe tämän palvelimen profiileja ja sisältöä, jollet erityisesti etsi juuri sitä tai liity siihen seuraamalla.",
"about.domain_blocks.silenced.title": "Rajoitettu",
"about.domain_blocks.suspended.explanation": "Mitään tämän palvelimen tietoja ei käsitellä, tallenneta tai vaihdeta, mikä tekee vuorovaikutuksesta ja viestinnästä sen käyttäjien kanssa mahdotonta.",
@@ -16,7 +16,7 @@
"account.badges.bot": "Botti",
"account.badges.group": "Ryhmä",
"account.block": "Estä @{name}",
- "account.block_domain": "Estä palvelu {domain}",
+ "account.block_domain": "Estä verkkotunnus {domain}",
"account.block_short": "Estä",
"account.blocked": "Estetty",
"account.browse_more_on_origin_server": "Selaile lisää alkuperäisellä palvelimella",
@@ -25,16 +25,16 @@
"account.disable_notifications": "Lopeta ilmoittamasta minulle, kun @{name} julkaisee",
"account.domain_blocked": "Verkkotunnus estetty",
"account.edit_profile": "Muokkaa profiilia",
- "account.enable_notifications": "Ilmoita kun käyttäjä @{name} julkaisee viestin",
- "account.endorse": "Suosittele profiilissasi",
- "account.featured_tags.last_status_at": "Viimeisin viesti {date}",
- "account.featured_tags.last_status_never": "Ei viestejä",
- "account.featured_tags.title": "Käyttäjän {name} esillä olevat aihetunnisteet",
+ "account.enable_notifications": "Ilmoita minulle, kun @{name} julkaisee",
+ "account.endorse": "Pidä esillä profiilissa",
+ "account.featured_tags.last_status_at": "Viimeisin julkaisu {date}",
+ "account.featured_tags.last_status_never": "Ei julkaisuja",
+ "account.featured_tags.title": "Käyttäjän {name} esillä pidettävät aihetunnisteet",
"account.follow": "Seuraa",
- "account.followers": "seuraaja(t)",
+ "account.followers": "Seuraajat",
"account.followers.empty": "Kukaan ei seuraa tätä käyttäjää vielä.",
"account.followers_counter": "{count, plural, one {{counter} seuraaja} other {{counter} seuraajaa}}",
- "account.following": "Seurataan",
+ "account.following": "Seuratut",
"account.following_counter": "{count, plural, one {{counter} seurattu} other {{counter} seurattua}}",
"account.follows.empty": "Tämä käyttäjä ei vielä seuraa ketään.",
"account.follows_you": "Seuraa sinua",
@@ -54,28 +54,28 @@
"account.muted": "Mykistetty",
"account.no_bio": "Kuvausta ei ole annettu.",
"account.open_original_page": "Avaa alkuperäinen sivu",
- "account.posts": "viesti(t)",
- "account.posts_with_replies": "Viestit ja vastaukset",
+ "account.posts": "Julkaisut",
+ "account.posts_with_replies": "Julkaisut ja vastaukset",
"account.report": "Raportoi @{name}",
- "account.requested": "Odottaa hyväksyntää. Peruuta seuraamispyyntö klikkaamalla",
+ "account.requested": "Odottaa hyväksyntää. Peruuta seuraamispyyntö napsauttamalla",
"account.requested_follow": "{name} on pyytänyt lupaa seurata sinua",
"account.share": "Jaa käyttäjän @{name} profiili",
- "account.show_reblogs": "Näytä tehostukset käyttäjältä @{name}",
- "account.statuses_counter": "{count, plural, one {{counter} viesti} other {{counter} viestiä}}",
- "account.unblock": "Poista esto: @{name}",
- "account.unblock_domain": "Salli palvelu {domain}",
+ "account.show_reblogs": "Näytä käyttäjän @{name} tehostukset",
+ "account.statuses_counter": "{count, plural, one {{counter} julkaisu} other {{counter} julkaisua}}",
+ "account.unblock": "Poista käyttäjän @{name} esto",
+ "account.unblock_domain": "Poista verkkotunnuksen {domain} esto",
"account.unblock_short": "Poista esto",
- "account.unendorse": "Poista suosittelu profiilistasi",
+ "account.unendorse": "Älä pidä esillä profiilissa",
"account.unfollow": "Lopeta seuraaminen",
"account.unmute": "Poista käyttäjän @{name} mykistys",
- "account.unmute_notifications_short": "Kumoa ilmoitusten mykistys",
+ "account.unmute_notifications_short": "Poista ilmoitusten mykistys",
"account.unmute_short": "Poista mykistys",
"account_note.placeholder": "Lisää muistiinpano napsauttamalla",
- "admin.dashboard.daily_retention": "Käyttäjän säilyminen rekisteröitymisen jälkeiseen päivään mennessä",
- "admin.dashboard.monthly_retention": "Käyttäjän säilyminen rekisteröitymisen jälkeiseen kuukauteen mennessä",
+ "admin.dashboard.daily_retention": "Käyttäjien pysyvyys rekisteröitymisen jälkeen päivittäin",
+ "admin.dashboard.monthly_retention": "Käyttäjien pysyvyys rekisteröitymisen jälkeen kuukausittain",
"admin.dashboard.retention.average": "Keskimäärin",
- "admin.dashboard.retention.cohort": "Kirjautumiset",
- "admin.dashboard.retention.cohort_size": "Uudet käyttäjät",
+ "admin.dashboard.retention.cohort": "Rekisteröitymis-kk.",
+ "admin.dashboard.retention.cohort_size": "Uusia käyttäjiä",
"admin.impact_report.instance_accounts": "Tilien profiilit, jotka tämä poistaisi",
"admin.impact_report.instance_followers": "Seuraajat, jotka käyttäjämme menettäisivät",
"admin.impact_report.instance_follows": "Seuraajat, jotka heidän käyttäjänsä menettäisivät",
@@ -101,7 +101,7 @@
"bundle_modal_error.close": "Sulje",
"bundle_modal_error.message": "Jotain meni pieleen komponenttia ladattaessa.",
"bundle_modal_error.retry": "Yritä uudelleen",
- "closed_registrations.other_server_instructions": "Koska Mastodon on hajautettu, voit luoda tilin toiselle palvelimelle ja silti olla vuorovaikutuksessa tämän kanssa.",
+ "closed_registrations.other_server_instructions": "Koska Mastodon on hajautettu, voit luoda tilin toiselle palvelimelle ja olla silti vuorovaikutuksessa tämän kanssa.",
"closed_registrations_modal.description": "Tilin luonti palveluun {domain} ei tällä hetkellä ole mahdollista, mutta huomioi, ettei Mastodonin käyttö edellytä juuri kyseisen palvelun tiliä.",
"closed_registrations_modal.find_another_server": "Etsi toinen palvelin",
"closed_registrations_modal.preamble": "Mastodon on hajautettu, joten riippumatta siitä, missä luot tilisi, voit seurata ja olla vuorovaikutuksessa kenen tahansa kanssa tällä palvelimella. Voit jopa isännöidä palvelinta!",
@@ -112,15 +112,15 @@
"column.community": "Paikallinen aikajana",
"column.direct": "Yksityiset maininnat",
"column.directory": "Selaa profiileja",
- "column.domain_blocks": "Estetyt palvelut",
+ "column.domain_blocks": "Estetyt verkkotunnukset",
"column.favourites": "Suosikit",
- "column.firehose": "Live-syötteet",
+ "column.firehose": "Livesyötteet",
"column.follow_requests": "Seuraamispyynnöt",
"column.home": "Koti",
"column.lists": "Listat",
"column.mutes": "Mykistetyt käyttäjät",
"column.notifications": "Ilmoitukset",
- "column.pins": "Kiinnitetyt viestit",
+ "column.pins": "Kiinnitetyt julkaisut",
"column.public": "Yleinen aikajana",
"column_back_button.label": "Takaisin",
"column_header.hide_settings": "Piilota asetukset",
@@ -128,22 +128,22 @@
"column_header.moveRight_settings": "Siirrä saraketta oikealle",
"column_header.pin": "Kiinnitä",
"column_header.show_settings": "Näytä asetukset",
- "column_header.unpin": "Poista kiinnitys",
+ "column_header.unpin": "Irrota",
"column_subheading.settings": "Asetukset",
"community.column_settings.local_only": "Vain paikalliset",
"community.column_settings.media_only": "Vain media",
"community.column_settings.remote_only": "Vain etätilit",
"compose.language.change": "Vaihda kieli",
"compose.language.search": "Hae kieliä...",
- "compose.published.body": "Julkaisusi julkaistiin.",
+ "compose.published.body": "Julkaisu lähetetty.",
"compose.published.open": "Avaa",
- "compose.saved.body": "Viesti tallennettu.",
+ "compose.saved.body": "Julkaisu tallennettu.",
"compose_form.direct_message_warning_learn_more": "Lisätietoja",
- "compose_form.encryption_warning": "Mastodonin viestit eivät ole päästä päähän salattuja. Älä jaa arkaluonteisia tietoja Mastodonissa.",
+ "compose_form.encryption_warning": "Mastodonin julkaisut eivät ole päästä päähän salattuja. Älä jaa arkaluonteisia tietoja Mastodonissa.",
"compose_form.hashtag_warning": "Tätä julkaisua ei voi liittää aihetunnisteisiin, koska se ei ole julkinen. Vain näkyvyydeltään julkisiksi määritettyjä julkaisuja voidaan hakea aihetunnisteiden avulla.",
"compose_form.lock_disclaimer": "Tilisi ei ole {locked}. Kuka tahansa voi seurata tiliäsi ja nähdä vain seuraajille rajaamasi julkaisut.",
"compose_form.lock_disclaimer.lock": "lukittu",
- "compose_form.placeholder": "Mitä sinulla on mielessäsi?",
+ "compose_form.placeholder": "Mitä mietit?",
"compose_form.poll.add_option": "Lisää valinta",
"compose_form.poll.duration": "Äänestyksen kesto",
"compose_form.poll.option_placeholder": "Valinta {number}",
@@ -154,9 +154,9 @@
"compose_form.publish_form": "Uusi julkaisu",
"compose_form.publish_loud": "{publish}!",
"compose_form.save_changes": "Tallenna muutokset",
- "compose_form.sensitive.hide": "{count, plural, one {Merkitse media arkaluontoiseksi} other {Merkitse mediat arkaluontoiseksi}}",
- "compose_form.sensitive.marked": "{count, plural, one {Media on merkitty arkaluontoiseksi} other {Mediat on merkitty arkaluontoiseksi}}",
- "compose_form.sensitive.unmarked": "{count, plural, one {Mediaa ei ole merkitty arkaluontoiseksi} other {Medioja ei ole merkitty arkaluontoiseksi}}",
+ "compose_form.sensitive.hide": "{count, plural, one {Merkitse media arkaluonteiseksi} other {Merkitse mediat arkaluonteisiksi}}",
+ "compose_form.sensitive.marked": "{count, plural, one {Media on merkitty arkaluonteiseksi} other {Mediat on merkitty arkaluonteisiksi}}",
+ "compose_form.sensitive.unmarked": "{count, plural, one {Mediaa ei ole merkitty arkaluonteiseksi} other {Medioita ei ole merkitty arkaluonteisiksi}}",
"compose_form.spoiler.marked": "Poista sisältövaroitus",
"compose_form.spoiler.unmarked": "Lisää sisältövaroitus",
"compose_form.spoiler_placeholder": "Kirjoita varoituksesi tähän",
@@ -167,24 +167,24 @@
"confirmations.cancel_follow_request.confirm": "Peruuta pyyntö",
"confirmations.cancel_follow_request.message": "Haluatko varmasti peruuttaa pyyntösi seurata profiilia {name}?",
"confirmations.delete.confirm": "Poista",
- "confirmations.delete.message": "Haluatko varmasti poistaa tämän viestin?",
+ "confirmations.delete.message": "Haluatko varmasti poistaa tämän julkaisun?",
"confirmations.delete_list.confirm": "Poista",
- "confirmations.delete_list.message": "Haluatko varmasti poistaa tämän listan kokonaan?",
+ "confirmations.delete_list.message": "Haluatko varmasti poistaa tämän listan pysyvästi?",
"confirmations.discard_edit_media.confirm": "Hylkää",
"confirmations.discard_edit_media.message": "Sinulla on tallentamattomia muutoksia median kuvaukseen tai esikatseluun, hylätäänkö ne silti?",
"confirmations.domain_block.confirm": "Estä koko verkkotunnus",
- "confirmations.domain_block.message": "Haluatko aivan varmasti estää palvelun {domain} täysin? Useimmiten muutama kohdistettu esto tai mykistys on riittävä ja suositeltava toimenpide. Et näe kyseisen sisältöä kyseiseltä verkkoalueelta missään julkisissa aikajanoissa tai ilmoituksissa. Tälle verkkoalueelle kuuluvat seuraajasi poistetaan.",
+ "confirmations.domain_block.message": "Haluatko aivan varmasti estää koko verkkotunnuksen {domain}? Useimmiten muutama kohdistettu esto tai mykistys on riittävä ja suositeltava toimi. Et näe sisältöä tästä verkkotunnuksesta millään julkisilla aikajanoilla tai ilmoituksissa. Tähän verkkotunnukseen kuuluvat seuraajasi poistetaan.",
"confirmations.edit.confirm": "Muokkaa",
- "confirmations.edit.message": "Muokkaaminen nyt korvaa viestin, jota paraikaa työstät. Haluatko varmasti jatkaa?",
+ "confirmations.edit.message": "Jos muokkaat viestiä nyt, se korvaa parhaillaan työstämäsi viestin. Haluatko varmasti jatkaa?",
"confirmations.logout.confirm": "Kirjaudu ulos",
"confirmations.logout.message": "Haluatko varmasti kirjautua ulos?",
"confirmations.mute.confirm": "Mykistä",
"confirmations.mute.explanation": "Tämä toiminto piilottaa heidän julkaisunsa sinulta – mukaan lukien ne, joissa heidät mainitaan – sallien heidän yhä nähdä julkaisusi ja seurata sinua.",
- "confirmations.mute.message": "Haluatko varmasti mykistää profiilin {name}?",
+ "confirmations.mute.message": "Haluatko varmasti mykistää käyttäjän {name}?",
"confirmations.redraft.confirm": "Poista & palauta muokattavaksi",
- "confirmations.redraft.message": "Haluatko varmasti poistaa viestin ja tehdä siitä luonnoksen? Suosikiksi lisäykset sekä tehostukset menetään, ja vastaukset alkuperäisviestiisi jäävät orvoiksi.",
+ "confirmations.redraft.message": "Haluatko varmasti poistaa julkaisun ja tehdä siitä luonnoksen? Suosikit ja tehostukset menetetään, ja alkuperäisen julkaisun vastaukset jäävät orvoiksi.",
"confirmations.reply.confirm": "Vastaa",
- "confirmations.reply.message": "Jos vastaat nyt, vastaus korvaa tällä hetkellä työstämäsi viestin. Oletko varma, että haluat jatkaa?",
+ "confirmations.reply.message": "Jos vastaat nyt, vastaus korvaa parhaillaan työstämäsi viestin. Haluatko varmasti jatkaa?",
"confirmations.unfollow.confirm": "Lopeta seuraaminen",
"confirmations.unfollow.message": "Haluatko varmasti lakata seuraamasta profiilia {name}?",
"conversation.delete": "Poista keskustelu",
@@ -193,20 +193,20 @@
"conversation.with": "{names} kanssa",
"copypaste.copied": "Kopioitu",
"copypaste.copy_to_clipboard": "Kopioi leikepöydälle",
- "directory.federated": "Koko tunnettu fediverse",
- "directory.local": "Vain palvelusta {domain}",
+ "directory.federated": "Koko tunnettu fediversumi",
+ "directory.local": "Vain palvelimelta {domain}",
"directory.new_arrivals": "Äskettäin saapuneet",
"directory.recently_active": "Hiljattain aktiiviset",
"disabled_account_banner.account_settings": "Tilin asetukset",
"disabled_account_banner.text": "Tilisi {disabledAccount} on tällä hetkellä poissa käytöstä.",
- "dismissable_banner.community_timeline": "Nämä ovat uusimmat julkiset julkaisut käyttäjiltä, joiden tilejä isännöi {domain}.",
+ "dismissable_banner.community_timeline": "Nämä ovat viimeisimpiä julkaisuja käyttäjiltä, joiden tili sijaitsee palvelimella {domain}.",
"dismissable_banner.dismiss": "Hylkää",
- "dismissable_banner.explore_links": "Näistä uutisista puhutaan juuri nyt tällä ja muilla hajautetun verkon palvelimilla.",
- "dismissable_banner.explore_statuses": "Nämä ovat tänään huomiota keräävimpiä sosiaalisen verkon julkaisuja. Tuoreimmat, tehostetuimmat sekä suosikeiksi merkityimmät sijoitetaan listauksessa korkeammalle.",
- "dismissable_banner.explore_tags": "Nämä aihetunnisteet saavat juuri nyt vetovoimaa tällä ja muilla hajautetun verkon palvelimilla olevien ihmisten keskuudessa.",
- "dismissable_banner.public_timeline": "Nämä ovat viimeisimpiä julkaisuja sosiaalisen verkon käyttäjiltä, joita seurataan palvelussa {domain}.",
+ "dismissable_banner.explore_links": "Näitä uutisia jaetaan tänään sosiaalisessa verkossa eniten. Uusimmat ja eri käyttäjien eniten lähettämät uutiset nousevat listauksessa korkeimmalle.",
+ "dismissable_banner.explore_statuses": "Nämä sosiaalisen verkon julkaisut keräävät tänään eniten huomiota. Uusimmat, tehostetuimmat ja suosikiksi lisätyimmät nousevat listauksessa korkeimmalle.",
+ "dismissable_banner.explore_tags": "Nämä sosiaalisen verkon aihetunnisteet keräävät tänään eniten huomiota. Useimman käyttäjän käyttämät aihetunnisteet nousevat listauksessa korkeimmalle.",
+ "dismissable_banner.public_timeline": "Nämä ovat viimeisimpiä julkaisuja sosiaalisen verkon käyttäjiltä, joita seurataan palvelimella {domain}.",
"embed.instructions": "Upota julkaisu verkkosivullesi kopioimalla alla oleva koodi.",
- "embed.preview": "Se tulee näyttämään tältä:",
+ "embed.preview": "Tältä se näyttää:",
"emoji_button.activity": "Aktiviteetit",
"emoji_button.clear": "Tyhjennä",
"emoji_button.custom": "Mukautetut",
@@ -218,33 +218,33 @@
"emoji_button.objects": "Esineet",
"emoji_button.people": "Ihmiset",
"emoji_button.recent": "Usein käytetyt",
- "emoji_button.search": "Etsi...",
+ "emoji_button.search": "Hae...",
"emoji_button.search_results": "Hakutulokset",
"emoji_button.symbols": "Symbolit",
"emoji_button.travel": "Matkailu ja paikat",
"empty_column.account_suspended": "Tili jäädytetty",
"empty_column.account_timeline": "Ei viestejä täällä.",
"empty_column.account_unavailable": "Profiilia ei löydy",
- "empty_column.blocks": "Et ole estänyt käyttäjiä.",
- "empty_column.bookmarked_statuses": "Et ole vielä lisännyt viestejä kirjanmerkkeihisi. Kun lisäät yhden, se näkyy tässä.",
+ "empty_column.blocks": "Et ole vielä estänyt käyttäjiä.",
+ "empty_column.bookmarked_statuses": "Et ole vielä lisännyt julkaisuja kirjanmerkkeihisi. Kun lisäät yhden, se näkyy tässä.",
"empty_column.community": "Paikallinen aikajana on tyhjä. Kirjoita jotain julkista, niin homma lähtee käyntiin!",
"empty_column.direct": "Yksityisiä mainintoja ei vielä ole. Jos lähetät tai sinulle lähetetään sellaisia, näet ne täällä.",
- "empty_column.domain_blocks": "Palveluita ei ole vielä estetty.",
- "empty_column.explore_statuses": "Mikään ei trendaa nyt. Tarkista myöhemmin uudelleen!",
- "empty_column.favourited_statuses": "Sinulla ei ole vielä yhtään suosikkiviestiä. Kun lisäät yhden, näkyy se tässä.",
- "empty_column.favourites": "Kukaan ei ole vielä merkinnyt tätä viestiä suosikiksi. Kun joku tekee niin, näkyy asia täällä.",
- "empty_column.follow_requests": "Et ole vielä vastaanottanut seurauspyyntöjä. Saamasi pyynnöt näytetään täällä.",
- "empty_column.followed_tags": "Et ole vielä ottanut yhtään aihetunnistetta seurattavaksesi. Jos tai kun sitten teet niin, ne listautuvat tänne.",
+ "empty_column.domain_blocks": "Verkkotunnuksia ei ole vielä estetty.",
+ "empty_column.explore_statuses": "Mikään ei ole nyt suosittua. Tarkista myöhemmin uudelleen!",
+ "empty_column.favourited_statuses": "Sinulla ei ole vielä yhtään suosikkijulkaisua. Kun lisäät sellaisen, näkyy se tässä.",
+ "empty_column.favourites": "Kukaan ei ole vielä lisännyt tätä julkaisua suosikkeihinsa. Kun joku tekee niin, tulee hän tähän näkyviin.",
+ "empty_column.follow_requests": "Et ole vielä vastaanottanut seuraamispyyntöjä. Saamasi pyynnöt näkyvät täällä.",
+ "empty_column.followed_tags": "Et seuraa vielä yhtäkään aihetunnistetta. Kun alat seurata, ne tulevat tähän näkyviin.",
"empty_column.hashtag": "Tällä aihetunnisteella ei ole vielä mitään.",
"empty_column.home": "Kotiaikajanasi on tyhjä! Seuraa useampia henkilöjä, niin näet enemmän sisältöä.",
- "empty_column.list": "Tässä luettelossa ei ole vielä mitään. Kun tämän luettelon jäsenet julkaisevat uusia viestejä, ne näkyvät täällä.",
+ "empty_column.list": "Tällä listalla ei ole vielä mitään. Kun tämän listan jäsenet lähettävät uusia julkaisuja, ne näkyvät tässä.",
"empty_column.lists": "Sinulla ei ole vielä yhtään listaa. Kun luot sellaisen, näkyy se tässä.",
"empty_column.mutes": "Et ole mykistänyt vielä yhtään käyttäjää.",
"empty_column.notifications": "Sinulla ei ole vielä ilmoituksia. Kun keskustelet muille, näet sen täällä.",
"empty_column.public": "Täällä ei ole mitään! Kirjoita jotain julkisesti. Voit myös seurata muiden palvelimien käyttäjiä",
"error.unexpected_crash.explanation": "Sivua ei voi näyttää oikein, johtuen bugista tai ongelmasta selaimen yhteensopivuudessa.",
"error.unexpected_crash.explanation_addons": "Sivua ei voitu näyttää oikein. Tämä virhe johtuu todennäköisesti selaimen lisäosasta tai automaattisista käännöstyökaluista.",
- "error.unexpected_crash.next_steps": "Kokeile sivun päivitystä. Jos se ei auta, voi Mastodonin käyttö silti olla mahdollista eri selaimella tai natiivilla sovelluksella.",
+ "error.unexpected_crash.next_steps": "Kokeile päivittää sivu. Jos se ei auta, voi Mastodonin käyttö ehkä onnistua eri selaimella tai natiivisovelluksella.",
"error.unexpected_crash.next_steps_addons": "Yritä poistaa ne käytöstä ja päivittää sivu. Jos se ei auta, voit silti käyttää Mastodonia eri selaimen tai sovelluksen kautta.",
"errors.unexpected_crash.copy_stacktrace": "Kopioi pinon jäljitys leikepöydälle",
"errors.unexpected_crash.report_issue": "Ilmoita ongelmasta",
@@ -254,28 +254,28 @@
"explore.trending_links": "Uutiset",
"explore.trending_statuses": "Julkaisut",
"explore.trending_tags": "Aihetunnisteet",
- "filter_modal.added.context_mismatch_explanation": "Tämä suodatinluokka ei koske asiayhteyttä, jossa olet käyttänyt tätä viestiä. Jos haluat, että viesti suodatetaan myös tässä yhteydessä, sinun on muokattava suodatinta.",
- "filter_modal.added.context_mismatch_title": "Asiayhteys ei täsmää!",
- "filter_modal.added.expired_explanation": "Tämä suodatinluokka on vanhentunut ja sinun on muutettava viimeistä voimassaolon päivää, jotta sitä voidaan käyttää.",
+ "filter_modal.added.context_mismatch_explanation": "Tämä suodatinluokka ei koske kontekstia, jossa olet tarkastellut tätä julkaisua. Jos haluat, että julkaisu suodatetaan myös tässä kontekstissa, sinun pitää muokata suodatinta.",
+ "filter_modal.added.context_mismatch_title": "Konteksti ei täsmää!",
+ "filter_modal.added.expired_explanation": "Tämä suodatinluokka on vanhentunut, joten sinun on muutettava viimeistä voimassaolopäivää, jotta suodatin on voimassa.",
"filter_modal.added.expired_title": "Vanhentunut suodatin!",
- "filter_modal.added.review_and_configure": "Voit tarkastella tätä suodatinluokkaa ja määrittää sen tarkemmin siirtymällä {settings_link}.",
+ "filter_modal.added.review_and_configure": "Voit tarkastella tätä suodatinluokkaa ja määrittää sen tarkemmin kohdassa {settings_link}.",
"filter_modal.added.review_and_configure_title": "Suodattimen asetukset",
"filter_modal.added.settings_link": "asetukset-sivulle",
- "filter_modal.added.short_explanation": "Tämä viesti on lisätty seuraavaan suodatinluokkaan: {title}.",
+ "filter_modal.added.short_explanation": "Tämä julkaisu on lisätty seuraavaan suodatinluokkaan: {title}.",
"filter_modal.added.title": "Suodatin lisätty!",
- "filter_modal.select_filter.context_mismatch": "ei sovellu tähän asiayhteyteen",
+ "filter_modal.select_filter.context_mismatch": "ei sovellu tähän kontekstiin",
"filter_modal.select_filter.expired": "vanhentunut",
"filter_modal.select_filter.prompt_new": "Uusi luokka: {name}",
- "filter_modal.select_filter.search": "Etsi tai luo",
- "filter_modal.select_filter.subtitle": "Käytä olemassa olevaa luokkaa tai luo uusi luokka",
- "filter_modal.select_filter.title": "Suodata tämä viesti",
- "filter_modal.title.status": "Suodata viesti",
+ "filter_modal.select_filter.search": "Hae tai luo",
+ "filter_modal.select_filter.subtitle": "Käytä olemassa olevaa luokkaa tai luo uusi",
+ "filter_modal.select_filter.title": "Suodata tämä julkaisu",
+ "filter_modal.title.status": "Suodata julkaisu",
"firehose.all": "Kaikki",
"firehose.local": "Tämä palvelin",
"firehose.remote": "Muut palvelimet",
"follow_request.authorize": "Valtuuta",
"follow_request.reject": "Hylkää",
- "follow_requests.unlocked_explanation": "Vaikkei tiliäsi ole lukittu, on palvelun {domain} ylläpito arvioinut, että saatat olla halukas tarkistamaan nämä seurauspyynnöt erikseen.",
+ "follow_requests.unlocked_explanation": "Vaikkei tiliäsi ole lukittu, palvelimen {domain} ylläpito on arvioinut, että saatat olla halukas tarkistamaan nämä seuraamispyynnöt erikseen.",
"followed_tags": "Seuratut aihetunnisteet",
"footer.about": "Tietoja",
"footer.directory": "Profiilihakemisto",
@@ -307,63 +307,63 @@
"home.column_settings.basic": "Perusasetukset",
"home.column_settings.show_reblogs": "Näytä tehostukset",
"home.column_settings.show_replies": "Näytä vastaukset",
- "home.explore_prompt.body": "Kotisyötteesi on sekoitus seuraamistasi aihetunnisteista ja käyttäjistä sekä heidän tehostamistaan viesteistä. Jos se näyttää tällä hetkellä turhan hiljaiselta, saatat haluta:",
+ "home.explore_prompt.body": "Kotisyötteesi on sekoitus seuraamiasi aihetunnisteita ja käyttäjiä sekä heidän tehostamiaan julkaisuja. Jos se tuntuu liian hiljaiselta, saatat haluta:",
"home.explore_prompt.title": "Tämä on tukikohtasi Mastodonissa.",
- "home.hide_announcements": "Piilota ilmoitukset",
+ "home.hide_announcements": "Piilota tiedotteet",
"home.pending_critical_update.body": "Päivitäthän Mastodon-palvelimen mahdollisimman pian!",
"home.pending_critical_update.link": "Tutustu päivityssisältöihin",
"home.pending_critical_update.title": "Kriittinen tietoturvapäivitys saatavilla!",
- "home.show_announcements": "Näytä ilmoitukset",
- "interaction_modal.description.favourite": "Mastodon-tilisi myötä voit merkitä julkaisuja suosikeiksi, jolloin osoitat julkaisijoille arvostavasi sisältöä, ja tallennat sitä myös helpommin saatavillesi jatkossa.",
- "interaction_modal.description.follow": "Kun sinulla on Mastodon-tili, voit seurata käyttäjää {name} nähdäksesi hänen viestinsä kotisyötteessäsi.",
- "interaction_modal.description.reblog": "Kun sinulla on tili Mastodonissa, voit tehostaa viestiä ja jakaa sen omien seuraajiesi kanssa.",
- "interaction_modal.description.reply": "Kun sinulla on tili Mastodonissa, voit vastata tähän viestiin.",
- "interaction_modal.login.action": "Palaa aloitussivulle",
- "interaction_modal.login.prompt": "Kotipalvelimesi verkkotunnus (kuten mastodon.social)",
+ "home.show_announcements": "Näytä tiedotteet",
+ "interaction_modal.description.favourite": "Mastodon-tilillä voit lisätä tämän julkaisun suosikkeihisi osoittaaksesi kirjoittajalle arvostavasi sitä ja tallentaaksesi sen tulevaa käyttöä varten.",
+ "interaction_modal.description.follow": "Mastodon-tilillä voit seurata käyttäjää {name} saadaksesi hänen julkaisunsa kotisyötteeseesi.",
+ "interaction_modal.description.reblog": "Mastodon-tilillä voit tehostaa tätä julkaisua jakaaksesi sen seuraajiesi kanssa.",
+ "interaction_modal.description.reply": "Mastodon-tilillä voit vastata tähän julkaisuun.",
+ "interaction_modal.login.action": "Siirry kotiin",
+ "interaction_modal.login.prompt": "Kotipalvelimesi verkkotunnus, kuten mastodon.social",
"interaction_modal.no_account_yet": "Etkö ole vielä Mastodonissa?",
"interaction_modal.on_another_server": "Toisella palvelimella",
"interaction_modal.on_this_server": "Tällä palvelimella",
"interaction_modal.sign_in": "Et ole kirjautunut tälle palvelimelle. Millä palvelimella tilisi sijaitsee?",
- "interaction_modal.sign_in_hint": "Vihje: Se on sama verkkosivusto, jolla loit tilisi. Jos et muista, etsi tervetuliaissähköpostia saapuneista viesteistäsi. Voit myös syöttää koko käyttäjätunnuksesi! (Esimerkki: @Mastodon@mastodon.social)",
+ "interaction_modal.sign_in_hint": "Vihje: Se on sama verkkosivusto, jolle rekisteröidyit. Jos et muista, etsi tervetulosähköposti saapuneista viesteistäsi. Voit myös syöttää koko käyttäjätunnuksesi! (Esimerkki: @Mastodon@Mastodon.social)",
"interaction_modal.title.favourite": "Lisää käyttäjän {name} julkaisu suosikkeihin",
- "interaction_modal.title.follow": "Seuraa {name}",
- "interaction_modal.title.reblog": "Tehosta käyttäjän {name} viestiä",
- "interaction_modal.title.reply": "Vastaa käyttäjän {name} viestiin",
+ "interaction_modal.title.follow": "Seuraa käyttäjää {name}",
+ "interaction_modal.title.reblog": "Tehosta käyttäjän {name} julkaisua",
+ "interaction_modal.title.reply": "Vastaa käyttäjän {name} julkaisuun",
"intervals.full.days": "{number, plural, one {# päivä} other {# päivää}}",
"intervals.full.hours": "{number, plural, one {# tunti} other {# tuntia}}",
"intervals.full.minutes": "{number, plural, one {# minuutti} other {# minuuttia}}",
"keyboard_shortcuts.back": "Siirry takaisin",
"keyboard_shortcuts.blocked": "Avaa estettyjen käyttäjien luettelo",
- "keyboard_shortcuts.boost": "Tehosta viestiä",
+ "keyboard_shortcuts.boost": "Tehosta julkaisua",
"keyboard_shortcuts.column": "Kohdista sarakkeeseen",
- "keyboard_shortcuts.compose": "siirry tekstinsyöttöön",
+ "keyboard_shortcuts.compose": "Kohdista kirjoituskenttään",
"keyboard_shortcuts.description": "Kuvaus",
- "keyboard_shortcuts.direct": "avataksesi yksityisten mainintojen sarakkeen",
+ "keyboard_shortcuts.direct": "Avaa yksityisten mainintojen sarake",
"keyboard_shortcuts.down": "Siirry listassa alaspäin",
"keyboard_shortcuts.enter": "Avaa julkaisu",
"keyboard_shortcuts.favourite": "Lisää julkaisu suosikkeihin",
- "keyboard_shortcuts.favourites": "Avaa suosikkilista",
+ "keyboard_shortcuts.favourites": "Avaa suosikkiluettelo",
"keyboard_shortcuts.federated": "Avaa yleinen aikajana",
"keyboard_shortcuts.heading": "Pikanäppäimet",
"keyboard_shortcuts.home": "Avaa kotiaikajana",
"keyboard_shortcuts.hotkey": "Pikanäppäin",
- "keyboard_shortcuts.legend": "Näytä tämä selite",
+ "keyboard_shortcuts.legend": "Näytä tämä ohje",
"keyboard_shortcuts.local": "Avaa paikallinen aikajana",
- "keyboard_shortcuts.mention": "Mainitse julkaisija",
- "keyboard_shortcuts.muted": "Avaa lista mykistetyistä käyttäjistä",
+ "keyboard_shortcuts.mention": "Mainitse kirjoittaja",
+ "keyboard_shortcuts.muted": "Avaa mykistettyjen käyttäjien luettelo",
"keyboard_shortcuts.my_profile": "Avaa profiilisi",
- "keyboard_shortcuts.notifications": "Avaa ilmoitukset-valikko",
+ "keyboard_shortcuts.notifications": "Avaa ilmoitussarake",
"keyboard_shortcuts.open_media": "Avaa media",
- "keyboard_shortcuts.pinned": "Avaa lista kiinnitetyistä viesteistä",
+ "keyboard_shortcuts.pinned": "Avaa kiinnitettyjen julkaisujen luettelo",
"keyboard_shortcuts.profile": "Avaa kirjoittajan profiili",
- "keyboard_shortcuts.reply": "Vastaa viestiin",
- "keyboard_shortcuts.requests": "Avaa lista seurauspyynnöistä",
- "keyboard_shortcuts.search": "siirry hakukenttään",
+ "keyboard_shortcuts.reply": "Vastaa julkaisuun",
+ "keyboard_shortcuts.requests": "Avaa seuraamispyyntöjen luettelo",
+ "keyboard_shortcuts.search": "Kohdista hakukenttään",
"keyboard_shortcuts.spoilers": "Näytä/piilota sisältövaroituskenttä",
- "keyboard_shortcuts.start": "avaa \"Aloitus\"",
- "keyboard_shortcuts.toggle_hidden": "näytä/piilota sisältövaroituksella merkitty teksti",
- "keyboard_shortcuts.toggle_sensitivity": "näytä/piilota media",
- "keyboard_shortcuts.toot": "Luo uusi viesti",
+ "keyboard_shortcuts.start": "Avaa Näin pääset alkuun -sarake",
+ "keyboard_shortcuts.toggle_hidden": "Näytä/piilota sisältövaroituksella merkitty teksti",
+ "keyboard_shortcuts.toggle_sensitivity": "Näytä/piilota media",
+ "keyboard_shortcuts.toot": "Luo uusi julkaisu",
"keyboard_shortcuts.unfocus": "Poistu teksti-/hakukentästä",
"keyboard_shortcuts.up": "Siirry listassa ylöspäin",
"lightbox.close": "Sulje",
@@ -372,19 +372,19 @@
"lightbox.next": "Seuraava",
"lightbox.previous": "Edellinen",
"limited_account_hint.action": "Näytä profiili joka tapauksessa",
- "limited_account_hint.title": "Palvelun {domain} ylläpito on piilottanut tämän profiilin.",
+ "limited_account_hint.title": "Palvelun {domain} valvojat ovat piilottaneet tämän profiilin.",
"link_preview.author": "Julkaissut {name}",
- "lists.account.add": "Lisää listaan",
- "lists.account.remove": "Poista listasta",
+ "lists.account.add": "Lisää listalle",
+ "lists.account.remove": "Poista listalta",
"lists.delete": "Poista lista",
"lists.edit": "Muokkaa listaa",
- "lists.edit.submit": "Vaihda otsikko",
- "lists.exclusive": "Piilota nämä julkaisut kotiaikajanaltasi",
+ "lists.edit.submit": "Vaihda nimi",
+ "lists.exclusive": "Piilota nämä julkaisut kotisyötteestä",
"lists.new.create": "Lisää lista",
"lists.new.title_placeholder": "Uuden listan nimi",
- "lists.replies_policy.followed": "Jokainen seurattu käyttäjä",
- "lists.replies_policy.list": "Listan jäsenet",
- "lists.replies_policy.none": "Ei kukaan",
+ "lists.replies_policy.followed": "Jokaiselle seuratulle käyttäjälle",
+ "lists.replies_policy.list": "Listan jäsenille",
+ "lists.replies_policy.none": "Ei kellekään",
"lists.replies_policy.title": "Näytä vastaukset:",
"lists.search": "Etsi seuraamistasi henkilöistä",
"lists.subheading": "Omat listasi",
@@ -400,26 +400,26 @@
"navigation_bar.blocks": "Estetyt käyttäjät",
"navigation_bar.bookmarks": "Kirjanmerkit",
"navigation_bar.community_timeline": "Paikallinen aikajana",
- "navigation_bar.compose": "Julkaise",
+ "navigation_bar.compose": "Kirjoita uusi julkaisu",
"navigation_bar.direct": "Yksityiset maininnat",
"navigation_bar.discover": "Löydä uutta",
- "navigation_bar.domain_blocks": "Estetyt palvelut",
+ "navigation_bar.domain_blocks": "Estetyt verkkotunnukset",
"navigation_bar.edit_profile": "Muokkaa profiilia",
"navigation_bar.explore": "Selaa",
"navigation_bar.favourites": "Suosikit",
"navigation_bar.filters": "Mykistetyt sanat",
"navigation_bar.follow_requests": "Seuraamispyynnöt",
"navigation_bar.followed_tags": "Seuratut aihetunnisteet",
- "navigation_bar.follows_and_followers": "Seurattavat ja seuraajat",
+ "navigation_bar.follows_and_followers": "Seuratut ja seuraajat",
"navigation_bar.lists": "Listat",
"navigation_bar.logout": "Kirjaudu ulos",
"navigation_bar.mutes": "Mykistetyt käyttäjät",
- "navigation_bar.opened_in_classic_interface": "Julkaisut, profiilit sekä tietyt muut sivut avataan oletuksena perinteisessä käyttöliittymässä.",
+ "navigation_bar.opened_in_classic_interface": "Julkaisut, profiilit ja tietyt muut sivut avautuvat oletuksena perinteiseen selainkäyttöliittymään.",
"navigation_bar.personal": "Henkilökohtainen",
- "navigation_bar.pins": "Kiinnitetyt viestit",
+ "navigation_bar.pins": "Kiinnitetyt julkaisut",
"navigation_bar.preferences": "Asetukset",
"navigation_bar.public_timeline": "Yleinen aikajana",
- "navigation_bar.search": "Haku",
+ "navigation_bar.search": "Hae",
"navigation_bar.security": "Turvallisuus",
"not_signed_in_indicator.not_signed_in": "Sinun on kirjauduttava sisään käyttääksesi resurssia.",
"notification.admin.report": "{name} teki ilmoituksen käytäjästä {target}",
@@ -430,23 +430,23 @@
"notification.mention": "{name} mainitsi sinut",
"notification.own_poll": "Äänestyksesi on päättynyt",
"notification.poll": "Äänestys, johon osallistuit, on päättynyt",
- "notification.reblog": "{name} tehosti viestiäsi",
- "notification.status": "{name} julkaisi juuri viestin",
- "notification.update": "{name} muokkasi viestiä",
+ "notification.reblog": "{name} tehosti julkaisuasi",
+ "notification.status": "{name} julkaisi juuri",
+ "notification.update": "{name} muokkasi julkaisua",
"notifications.clear": "Tyhjennä ilmoitukset",
"notifications.clear_confirmation": "Haluatko varmasti poistaa kaikki ilmoitukset pysyvästi?",
"notifications.column_settings.admin.report": "Uudet ilmoitukset:",
- "notifications.column_settings.admin.sign_up": "Uudet kirjautumiset:",
+ "notifications.column_settings.admin.sign_up": "Uudet rekisteröitymiset:",
"notifications.column_settings.alert": "Työpöytäilmoitukset",
"notifications.column_settings.favourite": "Suosikit:",
- "notifications.column_settings.filter_bar.advanced": "Näytä kaikki kategoriat",
+ "notifications.column_settings.filter_bar.advanced": "Näytä kaikki luokat",
"notifications.column_settings.filter_bar.category": "Pikasuodatuspalkki",
"notifications.column_settings.filter_bar.show_bar": "Näytä suodatinpalkki",
"notifications.column_settings.follow": "Uudet seuraajat:",
"notifications.column_settings.follow_request": "Uudet seuraamispyynnöt:",
"notifications.column_settings.mention": "Maininnat:",
"notifications.column_settings.poll": "Äänestyksen tulokset:",
- "notifications.column_settings.push": "Push-ilmoitukset",
+ "notifications.column_settings.push": "Puskuilmoitukset",
"notifications.column_settings.reblog": "Tehostukset:",
"notifications.column_settings.show": "Näytä sarakkeessa",
"notifications.column_settings.sound": "Äänimerkki",
@@ -472,14 +472,14 @@
"notifications_permission_banner.title": "Älä anna minkään mennä ohi",
"onboarding.action.back": "Palaa takaisin",
"onboarding.actions.back": "Palaa takaisin",
- "onboarding.actions.go_to_explore": "Siirry suosituimpien aiheiden syötteeseen",
- "onboarding.actions.go_to_home": "Siirry kotisyötteeseen",
+ "onboarding.actions.go_to_explore": "Siirry suosittujen aiheiden syötteeseen",
+ "onboarding.actions.go_to_home": "Siirry kotisyötteeseeni",
"onboarding.compose.template": "Tervehdys #Mastodon!",
- "onboarding.follows.empty": "Valitettavasti tuloksia ei voida näyttää juuri nyt. Voit kokeilla hakua tai selata tutustumissivua löytääksesi seurattavaa, tai yrittää myöhemmin uudelleen.",
+ "onboarding.follows.empty": "Valitettavasti tuloksia ei voida näyttää juuri nyt. Voit kokeilla hakua tai selata tutustumissivua löytääksesi seurattavaa tai yrittää myöhemmin uudelleen.",
"onboarding.follows.lead": "Kokoat oman kotisyötteesi itse. Mitä enemmän ihmisiä seuraat, sitä aktiivisempi ja kiinnostavampi syöte on. Nämä profiilit voivat olla alkuun hyvä lähtökohta — voit aina lopettaa niiden seuraamisen myöhemmin!",
- "onboarding.follows.title": "Suosittua Mastodonissa",
+ "onboarding.follows.title": "Mukauta kotisyötettäsi",
"onboarding.share.lead": "Kerro ihmisille, kuinka he voivat löytää sinut Mastodonista!",
- "onboarding.share.message": "Olen {username} #Mastodon'issa! Seuraa minua osoitteessa {url}",
+ "onboarding.share.message": "Olen {username} #Mastodonissa! Seuraa minua osoitteessa {url}",
"onboarding.share.next_steps": "Mahdolliset seuraavat vaiheet:",
"onboarding.share.title": "Jaa profiilisi",
"onboarding.start.lead": "Uusi Mastodon-tilisi on nyt valmiina käyttöön. Kyseessä on ainutlaatuinen, hajautettu sosiaalisen median alusta, jolla sinä itse – algoritmin sijaan – määrität käyttökokemuksesi. Näin hyödyt Mastodonista eniten:",
@@ -493,10 +493,10 @@
"onboarding.steps.setup_profile.title": "Mukauta profiiliasi",
"onboarding.steps.share_profile.body": "Kerro kavereillesi, kuinka sinut löytää Mastodonista",
"onboarding.steps.share_profile.title": "Jaa Mastodon-profiilisi",
- "onboarding.tips.2fa": "
Tiesitkö? Voit lisäsuojata tiliäsi ottamalla kaksivaiheisen todennuksen käyttöön palvelun tiliasetuksista. Ominaisuus toimii haluamasi TOTP-todennussovelluksen avulla, eikä käyttö edellytä puhelinnumeron antamista!",
- "onboarding.tips.accounts_from_other_servers": "
Tiesitkö? Koska Mastodon kuuluu hajautettuun verkkoon, osa kohtaamistasi profiileista sijaitsee muilla palvelimilla kuin sinun. Voit silti viestiä saumattomasti heidän kanssaan! Heidän palvelimensa ilmaistaan käyttäjänimen perässä!",
+ "onboarding.tips.2fa": "
Tiesitkö? Voit suojata tilisi ottamalla kaksivaiheisen todennuksen käyttöön tilisi asetuksista. Se toimii millä tahansa TOTP-sovelluksella, eikä sen käyttö edellytä puhelinnumeroa!",
+ "onboarding.tips.accounts_from_other_servers": "
Tiesitkö? Koska Mastodon on hajautettu, osa kohtaamistasi profiileista sijaitsee muilla kuin sinun palvelimellasi. Voit silti viestiä saumattomasti heidän kanssaan! Heidän palvelimensa mainitaan käyttäjänimen jälkiosassa!",
"onboarding.tips.migration": "
Tiesitkö? Jos koet, ettei {domain} ole jatkossa itsellesi hyvä palvelinvalinta, voit siirtyä toiselle Mastodon-palvelimelle menettämättä seuraajiasi. Voit jopa isännöidä omaa palvelintasi!",
- "onboarding.tips.verification": "
Tiesitkö? Voit vahvistaa tilisi lisäämällä omalle verkkosivustollesi linkin Mastodon-profiiliisi, ja lisäämällä sitten verkkosivustosi osoitteen Mastodon-profiilisi tietoihin. Tämä ei maksa mitään, eikä sinun tarvitse lähetellä mitään asiakirjoja!",
+ "onboarding.tips.verification": "
Tiesitkö? Voit vahvistaa tilisi lisäämällä omalle verkkosivustollesi linkin Mastodon-profiiliisi ja lisäämällä sitten verkkosivustosi osoitteen Mastodon-profiilisi lisäkenttään. Tämä ei maksa mitään, eikä sinun tarvitse lähetellä asiakirjoja!",
"password_confirmation.exceeds_maxlength": "Salasanan vahvistus ylittää salasanan enimmäispituuden",
"password_confirmation.mismatching": "Salasanan vahvistus ei täsmää",
"picture_in_picture.restore": "Laita se takaisin",
@@ -510,15 +510,15 @@
"poll.votes": "{votes, plural, one {# ääni} other {# ääntä}}",
"poll_button.add_poll": "Lisää äänestys",
"poll_button.remove_poll": "Poista äänestys",
- "privacy.change": "Muuta viestin näkyvyyttä",
- "privacy.direct.long": "Näkyvissä vain mainituille käyttäjille",
- "privacy.direct.short": "Vain mainitut henkilöt",
- "privacy.private.long": "Näkyvissä vain seuraajille",
+ "privacy.change": "Muuta julkaisun näkyvyyttä",
+ "privacy.direct.long": "Näkyy vain mainituille käyttäjille",
+ "privacy.direct.short": "Vain mainitut käyttäjät",
+ "privacy.private.long": "Näkyy vain seuraajille",
"privacy.private.short": "Vain seuraajat",
- "privacy.public.long": "Näkyvissä kaikille",
+ "privacy.public.long": "Näkyy kaikille",
"privacy.public.short": "Julkinen",
- "privacy.unlisted.long": "Näkyvissä kaikille, mutta jättäen pois hakemisen mahdollisuus",
- "privacy.unlisted.short": "Listaamaton julkinen",
+ "privacy.unlisted.long": "Näkyy kaikille mutta jää pois löytämisominaisuuksista",
+ "privacy.unlisted.short": "Listaamaton",
"privacy_policy.last_updated": "Viimeksi päivitetty {date}",
"privacy_policy.title": "Tietosuojakäytäntö",
"refresh": "Päivitä",
@@ -537,13 +537,13 @@
"relative_time.today": "tänään",
"reply_indicator.cancel": "Peruuta",
"report.block": "Estä",
- "report.block_explanation": "Et näe hänen viestejään, eikä hän voi nähdä viestejäsi tai seurata sinua. Hän näkevät, että olet estänyt hänet.",
+ "report.block_explanation": "Et näe hänen viestejään, eikä hän voi nähdä viestejäsi tai seurata sinua. Hän näkee, että olet estänyt hänet.",
"report.categories.legal": "Lakiasiat",
- "report.categories.other": "muu",
+ "report.categories.other": "Muu",
"report.categories.spam": "Roskaposti",
"report.categories.violation": "Sisältö rikkoo yhtä tai useampaa palvelimen sääntöä",
- "report.category.subtitle": "Valitse se, mikä sopii parhaiten",
- "report.category.title": "Kerro meille miksi tämä {type} pitää raportoida",
+ "report.category.subtitle": "Valitse sopivin",
+ "report.category.title": "Kerro meille, miksi tämä {type} pitää raportoida",
"report.category.title_account": "profiili",
"report.category.title_status": "julkaisu",
"report.close": "Valmis",
@@ -551,7 +551,7 @@
"report.forward": "Välitä kohteeseen {target}",
"report.forward_hint": "Tämä tili on toisella palvelimella. Haluatko lähettää nimettömän raportin myös sinne?",
"report.mute": "Mykistä",
- "report.mute_explanation": "Et näe hänen viestejään. Hän voi silti seurata sinua ja nähdä viestisi. Hän ei tiedä, että on mykistetty.",
+ "report.mute_explanation": "Et näe hänen julkaisujaan. Hän voi silti seurata sinua ja nähdä julkaisusi. Hän ei tiedä, että hänet on mykistetty.",
"report.next": "Seuraava",
"report.placeholder": "Lisäkommentit",
"report.reasons.dislike": "En pidä siitä",
@@ -564,10 +564,10 @@
"report.reasons.spam_description": "Haitalliset linkit, väärennetyt sitoutumiset tai toistuvat vastaukset",
"report.reasons.violation": "Se rikkoo palvelimen sääntöjä",
"report.reasons.violation_description": "Tiedät, että se rikkoo tiettyjä sääntöjä",
- "report.rules.subtitle": "Valitse kaikki jotka sopivat",
+ "report.rules.subtitle": "Valitse kaikki sopivat",
"report.rules.title": "Mitä sääntöjä rikotaan?",
"report.statuses.subtitle": "Valitse kaikki sopivat",
- "report.statuses.title": "Onko olemassa yhtään viestiä, jotka tukevat tätä raporttia?",
+ "report.statuses.title": "Onko julkaisuja, jotka tukevat tätä raporttia?",
"report.submit": "Lähetä",
"report.target": "Raportoidaan {target}",
"report.thanks.take_action": "Tässä on vaihtoehtosi hallita näkemääsi Mastodonissa:",
@@ -576,7 +576,7 @@
"report.thanks.title_actionable": "Kiitos raportista, tutkimme asiaa.",
"report.unfollow": "Lopeta käyttäjän @{name} seuraaminen",
"report.unfollow_explanation": "Seuraat tätä tiliä. Estääksesi tilin viestejä näykymästä kotisyötteessäsi, lopeta sen seuraaminen.",
- "report_notification.attached_statuses": "{count, plural, one {{count} viesti} other {{count} viestiä}} liitteenä",
+ "report_notification.attached_statuses": "{count, plural, one {{count} julkaisu} other {{count} julkaisua}} liitteenä",
"report_notification.categories.legal": "Laillinen",
"report_notification.categories.other": "Muu",
"report_notification.categories.spam": "Roskaposti",
@@ -584,26 +584,26 @@
"report_notification.open": "Avaa raportti",
"search.no_recent_searches": "Ei viimeaikaisia hakuja",
"search.placeholder": "Hae",
- "search.quick_action.account_search": "Profiilit, jotka vastaavat hakua {x}",
- "search.quick_action.go_to_account": "Avaa profiili {x}",
+ "search.quick_action.account_search": "Profiilit haulla {x}",
+ "search.quick_action.go_to_account": "Siirry profiiliin {x}",
"search.quick_action.go_to_hashtag": "Siirry aihetunnisteeseen {x}",
"search.quick_action.open_url": "Avaa URL-osoite Mastodonissa",
- "search.quick_action.status_search": "Julkaisut, jotka vastaavat hakua {x}",
- "search.search_or_paste": "Etsi tai kirjoita URL-osoite",
+ "search.quick_action.status_search": "Julkaisut haulla {x}",
+ "search.search_or_paste": "Hae tai liitä URL-osoite",
"search_popout.full_text_search_disabled_message": "Ei saatavilla palvelimella {domain}.",
"search_popout.language_code": "ISO-kielikoodi",
- "search_popout.options": "Haun asetukset",
+ "search_popout.options": "Hakuvalinnat",
"search_popout.quick_actions": "Pikatoiminnot",
- "search_popout.recent": "Viime haut",
- "search_popout.specific_date": "tietty päivämäärä",
+ "search_popout.recent": "Viimeaikaiset haut",
+ "search_popout.specific_date": "tarkka päiväys",
"search_popout.user": "käyttäjä",
"search_results.accounts": "Profiilit",
"search_results.all": "Kaikki",
"search_results.hashtags": "Aihetunnisteet",
"search_results.nothing_found": "Näille hakusanoille ei löytynyt mitään",
"search_results.see_all": "Näytä kaikki",
- "search_results.statuses": "Viestit",
- "search_results.title": "Etsi {q}",
+ "search_results.statuses": "Julkaisut",
+ "search_results.title": "Hae {q}",
"server_banner.about_active_users": "Palvelinta käyttäneet ihmiset viimeisen 30 päivän aikana (kuukauden aktiiviset käyttäjät)",
"server_banner.active_users": "aktiivista käyttäjää",
"server_banner.administered_by": "Ylläpitäjä:",
@@ -613,15 +613,15 @@
"sign_in_banner.create_account": "Luo tili",
"sign_in_banner.sign_in": "Kirjaudu",
"sign_in_banner.sso_redirect": "Kirjaudu tai rekisteröidy",
- "sign_in_banner.text": "Kirjaudu sisään seurataksesi profiileja tai aihetunnisteita, merkitäksesi julkaisuja suosikeiksi, julkaistaksesi sekä vastataksesi julkaisuihin. Voit vuorovaikuttaa myös eri palvelimella sijaitsevalta tililtäsi.",
- "status.admin_account": "Avaa moderaattorinäkymä tilistä @{name}",
- "status.admin_domain": "Avaa palvelimen {domain} moderointitoiminnot",
- "status.admin_status": "Avaa viesti moderointinäkymässä",
+ "sign_in_banner.text": "Kirjaudu sisään, niin voit seurata profiileja tai aihetunnisteita, lisätä julkaisuja suosikkeihin, jakaa julkaisuja ja vastata niihin. Voit olla vuorovaikutuksessa myös eri palvelimella olevalta tililtäsi.",
+ "status.admin_account": "Avaa tilin @{name} valvontanäkymä",
+ "status.admin_domain": "Avaa palvelimen {domain} valvontanäkymä",
+ "status.admin_status": "Avaa julkaisu valvontanäkymässä",
"status.block": "Estä @{name}",
- "status.bookmark": "Tallenna kirjanmerkki",
+ "status.bookmark": "Lisää kirjanmerkki",
"status.cancel_reblog_private": "Peru tehostus",
- "status.cannot_reblog": "Tätä viestiä ei voi tehostaa",
- "status.copy": "Kopioi linkki viestiin",
+ "status.cannot_reblog": "Tätä julkaisua ei voi tehostaa",
+ "status.copy": "Kopioi julkaisun linkki",
"status.delete": "Poista",
"status.detailed_status": "Yksityiskohtainen keskustelunäkymä",
"status.direct": "Mainitse @{name} yksityisesti",
@@ -630,41 +630,41 @@
"status.edited": "Muokattu {date}",
"status.edited_x_times": "Muokattu {count, plural, one {{count} kerran} other {{count} kertaa}}",
"status.embed": "Upota",
- "status.favourite": "Merkitse suosikiksi",
- "status.filter": "Suodata tämä viesti",
+ "status.favourite": "Suosikki",
+ "status.filter": "Suodata tämä julkaisu",
"status.filtered": "Suodatettu",
"status.hide": "Piilota julkaisu",
"status.history.created": "{name} luotu {date}",
"status.history.edited": "{name} muokkasi {date}",
"status.load_more": "Lataa lisää",
- "status.media.open": "Napsauta avataksesi",
+ "status.media.open": "Avaa napsauttamalla",
"status.media.show": "Napsauta näyttääksesi",
"status.media_hidden": "Media piilotettu",
"status.mention": "Mainitse @{name}",
"status.more": "Lisää",
"status.mute": "Mykistä @{name}",
"status.mute_conversation": "Mykistä keskustelu",
- "status.open": "Laajenna viesti",
+ "status.open": "Laajenna julkaisu",
"status.pin": "Kiinnitä profiiliin",
"status.pinned": "Kiinnitetty julkaisu",
"status.read_more": "Näytä enemmän",
"status.reblog": "Tehosta",
"status.reblog_private": "Tehosta alkuperäiselle yleisölle",
"status.reblogged_by": "{name} tehosti",
- "status.reblogs.empty": "Kukaan ei ole vielä tehostanut tätä viestiä. Kun joku tekee niin, näkyy kyseinen henkilö tässä.",
+ "status.reblogs.empty": "Kukaan ei ole vielä tehostanut tätä julkaisua. Kun joku tekee niin, tulee hän tähän näkyviin.",
"status.redraft": "Poista ja palauta muokattavaksi",
"status.remove_bookmark": "Poista kirjanmerkki",
- "status.replied_to": "Vastattu {name}",
+ "status.replied_to": "Vastaus käyttäjälle {name}",
"status.reply": "Vastaa",
"status.replyAll": "Vastaa ketjuun",
"status.report": "Raportoi @{name}",
- "status.sensitive_warning": "Arkaluontoista sisältöä",
+ "status.sensitive_warning": "Arkaluonteista sisältöä",
"status.share": "Jaa",
"status.show_filter_reason": "Näytä joka tapauksessa",
"status.show_less": "Näytä vähemmän",
- "status.show_less_all": "Näytä vähemmän kaikista",
+ "status.show_less_all": "Näytä kaikista vähemmän",
"status.show_more": "Näytä lisää",
- "status.show_more_all": "Näytä lisää kaikista",
+ "status.show_more_all": "Näytä kaikista enemmän",
"status.show_original": "Näytä alkuperäinen",
"status.title.with_attachments": "{user} liitti {attachmentCount, plural, one {{attachmentCount} tiedoston} other {{attachmentCount} tiedostoa}}",
"status.translate": "Käännä",
@@ -672,7 +672,7 @@
"status.uncached_media_warning": "Esikatselu ei ole käytettävissä",
"status.unmute_conversation": "Poista keskustelun mykistys",
"status.unpin": "Irrota profiilista",
- "subscribed_languages.lead": "Vain valituilla kielillä julkaistut viestit näkyvät etusivullasi ja aikajanalla muutoksen jälkeen. Valitse ei mitään, jos haluat vastaanottaa viestejä kaikilla kielillä.",
+ "subscribed_languages.lead": "Vain valituilla kielillä kirjoitetut julkaisut näkyvät koti- ja lista-aikajanoillasi muutoksen jälkeen. Älä valitse mitään, jos haluat nähdä julkaisuja kaikilla kielillä.",
"subscribed_languages.save": "Tallenna muutokset",
"subscribed_languages.target": "Vaihda tilatut kielet {target}",
"tabs_bar.home": "Koti",
@@ -685,8 +685,8 @@
"timeline_hint.remote_resource_not_displayed": "{resource} muilta palvelimilta ei näytetä.",
"timeline_hint.resources.followers": "Seuraajat",
"timeline_hint.resources.follows": "seurattua",
- "timeline_hint.resources.statuses": "Vanhemmat viestit",
- "trends.counter_by_accounts": "{count, plural, one {{counter} henkilö} other {{counter} henkilöä}} viimeisten {days, plural, one {päivän} other {{days} päivän}}",
+ "timeline_hint.resources.statuses": "Vanhemmat julkaisut",
+ "trends.counter_by_accounts": "{count, plural, one {{counter} henkilö} other {{counter} henkilöä}} {days, plural, one {viime päivänä} other {viimeisenä {days} päivänä}}",
"trends.trending_now": "Suosittua nyt",
"ui.beforeunload": "Luonnos häviää, jos poistut Mastodonista.",
"units.short.billion": "{count} mrd.",
@@ -694,7 +694,7 @@
"units.short.thousand": "{count} t.",
"upload_area.title": "Lataa raahaamalla ja pudottamalla tähän",
"upload_button.label": "Lisää kuvia, video tai äänitiedosto",
- "upload_error.limit": "Tiedostolatauksien raja ylitetty.",
+ "upload_error.limit": "Tiedostolatauksien rajoitus ylitetty.",
"upload_error.poll": "Tiedoston lataaminen ei ole sallittua äänestyksissä.",
"upload_form.audio_description": "Kuvaile sisältöä kuuroille ja kuulorajoitteisille",
"upload_form.description": "Kuvaile sisältöä sokeille ja näkörajoitteisille",
@@ -711,11 +711,11 @@
"upload_modal.detect_text": "Tunnista teksti kuvasta",
"upload_modal.edit_media": "Muokkaa mediaa",
"upload_modal.hint": "Klikkaa tai vedä ympyrä esikatselussa valitaksesi keskipiste, joka näkyy aina pienoiskuvissa.",
- "upload_modal.preparing_ocr": "Valmistellaan OCR…",
+ "upload_modal.preparing_ocr": "Valmistellaan tekstintunnistusta…",
"upload_modal.preview_label": "Esikatselu ({ratio})",
"upload_progress.label": "Ladataan...",
"upload_progress.processing": "Käsitellään…",
- "username.taken": "Kyseinen käyttäjätunnus on jo käytössä. Kokeile eri tunnusta",
+ "username.taken": "Käyttäjänimi on jo varattu. Kokeile toista",
"video.close": "Sulje video",
"video.download": "Lataa tiedosto",
"video.exit_fullscreen": "Poistu koko näytön tilasta",
@@ -725,5 +725,5 @@
"video.mute": "Mykistä ääni",
"video.pause": "Keskeytä",
"video.play": "Toista",
- "video.unmute": "Poista äänen mykistys"
+ "video.unmute": "Palauta ääni"
}
diff --git a/app/javascript/mastodon/locales/fr-QC.json b/app/javascript/mastodon/locales/fr-QC.json
index 4da7477dca399c..16a18048b49043 100644
--- a/app/javascript/mastodon/locales/fr-QC.json
+++ b/app/javascript/mastodon/locales/fr-QC.json
@@ -308,7 +308,7 @@
"home.column_settings.show_reblogs": "Afficher boosts",
"home.column_settings.show_replies": "Afficher réponses",
"home.explore_prompt.body": "Votre fil d'actualité aura un mélange de messages depuis les hashtags que vous avez choisi de suivre, les personnes que vous avez choisi de suivre, et les messages qu'ils boostent. Si ça vous semble trop calme à votre goût, n’hésitez pas à :",
- "home.explore_prompt.title": "C'est chez vous dans Mastadon.",
+ "home.explore_prompt.title": "C'est votre page d'accueil dans Mastodon.",
"home.hide_announcements": "Masquer les annonces",
"home.pending_critical_update.body": "Veuillez mettre à jour votre serveur Mastodon dès que possible !",
"home.pending_critical_update.link": "Voir les mises à jour",
diff --git a/app/javascript/mastodon/locales/fy.json b/app/javascript/mastodon/locales/fy.json
index dbd0a3f3a2ff23..12365c879d76fe 100644
--- a/app/javascript/mastodon/locales/fy.json
+++ b/app/javascript/mastodon/locales/fy.json
@@ -163,13 +163,13 @@
"confirmation_modal.cancel": "Annulearje",
"confirmations.block.block_and_report": "Blokkearje en rapportearje",
"confirmations.block.confirm": "Blokkearje",
- "confirmations.block.message": "Bisto wis datsto {name} blokkearje wolst?",
+ "confirmations.block.message": "Binne jo wis dat jo {name} blokkearje wolle?",
"confirmations.cancel_follow_request.confirm": "Fersyk annulearje",
"confirmations.cancel_follow_request.message": "Binne jo wis dat jo jo fersyk om {name} te folgjen annulearje wolle?",
"confirmations.delete.confirm": "Fuortsmite",
"confirmations.delete.message": "Binne jo wis dat jo dit berjocht fuortsmite wolle?",
"confirmations.delete_list.confirm": "Fuortsmite",
- "confirmations.delete_list.message": "Bisto wis datsto dizze list foar permanint fuortsmite wolst?",
+ "confirmations.delete_list.message": "Binne jo wis dat jo dizze list foar permanint fuortsmite wolle?",
"confirmations.discard_edit_media.confirm": "Fuortsmite",
"confirmations.discard_edit_media.message": "Jo hawwe net-bewarre wizigingen yn de mediabeskriuwing of foarfertoaning, wolle jo dizze dochs fuortsmite?",
"confirmations.domain_block.confirm": "Alles fan dit domein blokkearje",
@@ -177,16 +177,16 @@
"confirmations.edit.confirm": "Bewurkje",
"confirmations.edit.message": "Troch no te bewurkjen sil it berjocht dat jo no oan it skriuwen binne oerskreaun wurde. Wolle jo trochgean?",
"confirmations.logout.confirm": "Ofmelde",
- "confirmations.logout.message": "Bisto wis datsto ôfmelde wolst?",
+ "confirmations.logout.message": "Binne jo wis dat jo ôfmelde wolle?",
"confirmations.mute.confirm": "Negearje",
- "confirmations.mute.explanation": "Dit sil berjochten fan harren en berjochten dêr’t se yn fermeld wurde ûnsichtber meitsje, mar se sille berjochten noch hieltyd sjen kinne en jo folgje kinne.",
+ "confirmations.mute.explanation": "Dit sil berjochten fan harren en berjochten dêr’t se yn fermeld wurde ûnsichtber meitsje, mar se sille jo berjochten noch hieltyd sjen kinne en jo folgje kinne.",
"confirmations.mute.message": "Binne jo wis dat jo {name} negearje wolle?",
"confirmations.redraft.confirm": "Fuortsmite en opnij opstelle",
"confirmations.redraft.message": "Binne jo wis dat jo dit berjocht fuortsmite en opnij opstelle wolle? Favoriten en boosts geane dan ferlern en reaksjes op it oarspronklike berjocht reitsje jo kwyt.",
"confirmations.reply.confirm": "Reagearje",
"confirmations.reply.message": "Troch no te reagearjen sil it berjocht dat jo no oan it skriuwen binne oerskreaun wurde. Wolle jo trochgean?",
"confirmations.unfollow.confirm": "Net mear folgje",
- "confirmations.unfollow.message": "Bisto wis datsto {name} net mear folgje wolst?",
+ "confirmations.unfollow.message": "Binne jo wis dat jo {name} net mear folgje wolle?",
"conversation.delete": "Petear fuortsmite",
"conversation.mark_as_read": "As lêzen markearje",
"conversation.open": "Petear toane",
@@ -351,7 +351,7 @@
"keyboard_shortcuts.local": "to open local timeline",
"keyboard_shortcuts.mention": "Skriuwer fermelde",
"keyboard_shortcuts.muted": "to open muted users list",
- "keyboard_shortcuts.my_profile": "Dyn profyl iepenje",
+ "keyboard_shortcuts.my_profile": "Jo profyl iepenje",
"keyboard_shortcuts.notifications": "Meldingen toane",
"keyboard_shortcuts.open_media": "Media iepenje",
"keyboard_shortcuts.pinned": "Fêstsette berjochten toane",
@@ -421,20 +421,20 @@
"navigation_bar.public_timeline": "Globale tiidline",
"navigation_bar.search": "Sykje",
"navigation_bar.security": "Befeiliging",
- "not_signed_in_indicator.not_signed_in": "Do moatst oanmelde om tagong ta dizze ynformaasje te krijen.",
+ "not_signed_in_indicator.not_signed_in": "Jo moatte oanmelde om tagong ta dizze ynformaasje te krijen.",
"notification.admin.report": "{name} hat {target} rapportearre",
"notification.admin.sign_up": "{name} hat harren registrearre",
"notification.favourite": "{name} hat jo berjocht as favoryt markearre",
"notification.follow": "{name} folget dy",
"notification.follow_request": "{name} hat dy in folchfersyk stjoerd",
"notification.mention": "{name} hat dy fermeld",
- "notification.own_poll": "Dyn poll is beëinige",
+ "notification.own_poll": "Jo poll is beëinige",
"notification.poll": "In enkête dêr’t jo yn stimd hawwe is beëinige",
"notification.reblog": "{name} hat jo berjocht boost",
"notification.status": "{name} hat in berjocht pleatst",
"notification.update": "{name} hat in berjocht bewurke",
"notifications.clear": "Meldingen wiskje",
- "notifications.clear_confirmation": "Bisto wis datsto al dyn meldingen permanint fuortsmite wolst?",
+ "notifications.clear_confirmation": "Binne jo wis dat jo al jo meldingen permanint fuortsmite wolle?",
"notifications.column_settings.admin.report": "Nije rapportaazjes:",
"notifications.column_settings.admin.sign_up": "Nije registraasjes:",
"notifications.column_settings.alert": "Desktopmeldingen",
diff --git a/app/javascript/mastodon/locales/gd.json b/app/javascript/mastodon/locales/gd.json
index ea1ce59e84833f..4f485cfc55d76d 100644
--- a/app/javascript/mastodon/locales/gd.json
+++ b/app/javascript/mastodon/locales/gd.json
@@ -7,7 +7,7 @@
"about.domain_blocks.silenced.explanation": "San fharsaingeachd, chan fhaic thu pròifilean agus susbaint an fhrithealaiche seo ach ma nì thu lorg no ma tha thu ga leantainn.",
"about.domain_blocks.silenced.title": "Cuingichte",
"about.domain_blocks.suspended.explanation": "Cha dèid dàta sam bith on fhrithealaiche seo a phròiseasadh, a stòradh no iomlaid agus chan urrainn do na cleachdaichean on fhrithealaiche sin conaltradh no eadar-ghnìomh a ghabhail an-seo.",
- "about.domain_blocks.suspended.title": "’Na dhàil",
+ "about.domain_blocks.suspended.title": "À rèim",
"about.not_available": "Cha deach am fiosrachadh seo a sholar air an fhrithealaiche seo.",
"about.powered_by": "Lìonra sòisealta sgaoilte le cumhachd {mastodon}",
"about.rules": "Riaghailtean an fhrithealaiche",
diff --git a/app/javascript/mastodon/locales/hy.json b/app/javascript/mastodon/locales/hy.json
index e61aa773dc5c1b..776991b014d0b1 100644
--- a/app/javascript/mastodon/locales/hy.json
+++ b/app/javascript/mastodon/locales/hy.json
@@ -17,6 +17,7 @@
"account.blocked": "Արգելափակուած է",
"account.browse_more_on_origin_server": "Դիտել աւելին իրական պրոֆիլում",
"account.cancel_follow_request": "Withdraw follow request",
+ "account.direct": "Մասնաւոր յիշատակում @{name}",
"account.disable_notifications": "Ծանուցումները անջատել @{name} գրառումների համար",
"account.domain_blocked": "Տիրոյթը արգելափակուած է",
"account.edit_profile": "Խմբագրել հաշիւը",
@@ -85,9 +86,11 @@
"column.blocks": "Արգելափակուած օգտատէրեր",
"column.bookmarks": "Էջանիշեր",
"column.community": "Տեղական հոսք",
+ "column.direct": "Մասնաւոր յիշատակումներ",
"column.directory": "Զննել անձնական էջերը",
"column.domain_blocks": "Թաքցուած տիրոյթները",
"column.favourites": "Հաւանածներ",
+ "column.firehose": "Հոսքեր",
"column.follow_requests": "Հետեւելու հայցեր",
"column.home": "Հիմնական",
"column.lists": "Ցանկեր",
@@ -135,6 +138,7 @@
"confirmations.block.block_and_report": "Արգելափակել եւ բողոքել",
"confirmations.block.confirm": "Արգելափակել",
"confirmations.block.message": "Վստա՞հ ես, որ ուզում ես արգելափակել {name}֊ին։",
+ "confirmations.cancel_follow_request.confirm": "Կասեցնել հայցը",
"confirmations.delete.confirm": "Ջնջել",
"confirmations.delete.message": "Վստա՞հ ես, որ ուզում ես ջնջել այս գրառումը։",
"confirmations.delete_list.confirm": "Ջնջել",
@@ -216,6 +220,8 @@
"filter_modal.select_filter.search": "Որոնել կամ ստեղծել",
"filter_modal.select_filter.title": "Զտել այս գրառումը",
"firehose.all": "Բոլորը",
+ "firehose.local": "Այս հանգոյցը",
+ "firehose.remote": "Այլ հանգոյցներ",
"follow_request.authorize": "Վաւերացնել",
"follow_request.reject": "Մերժել",
"follow_requests.unlocked_explanation": "Այս հարցումը ուղարկուած է հաշուից, որի համար {domain}-ի անձնակազմը միացրել է ձեռքով ստուգում։",
@@ -246,6 +252,8 @@
"home.column_settings.show_replies": "Ցուցադրել պատասխանները",
"home.hide_announcements": "Թաքցնել յայտարարութիւնները",
"home.show_announcements": "Ցուցադրել յայտարարութիւնները",
+ "interaction_modal.on_another_server": "Այլ հանգոյցում",
+ "interaction_modal.on_this_server": "Այս հանգոյցում",
"interaction_modal.title.favourite": "Հաւանել {name}-ի գրառումը",
"interaction_modal.title.follow": "Հետեւել {name}-ին",
"interaction_modal.title.reblog": "Տարածել {name}-ի գրառումը",
@@ -316,6 +324,7 @@
"navigation_bar.bookmarks": "Էջանիշեր",
"navigation_bar.community_timeline": "Տեղական հոսք",
"navigation_bar.compose": "Ստեղծել նոր գրառում",
+ "navigation_bar.direct": "Մասնաւոր յիշատակումներ",
"navigation_bar.discover": "Բացայայտել",
"navigation_bar.domain_blocks": "Թաքցուած տիրոյթներ",
"navigation_bar.edit_profile": "Խմբագրել հաշիւը",
@@ -451,11 +460,15 @@
"report_notification.attached_statuses": "{count, plural, one {# post} other {# posts}} attached",
"report_notification.categories.other": "Այլ",
"report_notification.categories.spam": "Սպամ",
+ "search.no_recent_searches": "Որոնման պատմութիւն չկայ",
"search.placeholder": "Փնտրել",
"search.search_or_paste": "Որոնել կամ դնել URL",
+ "search_popout.options": "Որոնման տեսակները",
+ "search_popout.recent": "Վերջին որոնումները",
"search_results.accounts": "Հաշիւներ",
"search_results.all": "Բոլորը",
"search_results.hashtags": "Պիտակներ",
+ "search_results.see_all": "Տեսնել բոլորը",
"search_results.statuses": "Գրառումներ",
"search_results.title": "Որոնել {q}-ն",
"server_banner.active_users": "ակտիւ մարդիկ",
@@ -475,6 +488,8 @@
"status.copy": "Պատճէնել գրառման յղումը",
"status.delete": "Ջնջել",
"status.detailed_status": "Շղթայի ընդլայնուած դիտում",
+ "status.direct": "Մասնաւոր յիշատակում @{name}",
+ "status.direct_indicator": "Մասնաւոր յիշատակում",
"status.edit": "Խմբագրել",
"status.edited": "Խմբագրուել է՝ {date}",
"status.edited_x_times": "Edited {count, plural, one {# time} other {# times}}",
diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json
index cfba6db93f87f7..a01354463f7f91 100644
--- a/app/javascript/mastodon/locales/ja.json
+++ b/app/javascript/mastodon/locales/ja.json
@@ -1,13 +1,13 @@
{
"about.blocks": "制限中のサーバー",
"about.contact": "連絡先",
- "about.disclaimer": "Mastodonは自由なオープンソースソフトウェアでMastodon gGmbHの商標です。",
- "about.domain_blocks.no_reason_available": "制限理由",
- "about.domain_blocks.preamble": "Mastodonでは連合先のどのようなサーバーのユーザーとも交流できます。ただし次のサーバーには例外が設定されています。",
+ "about.disclaimer": "Mastodonは自由なオープンソースソフトウェアであり、Mastodon gGmbHの商標です。",
+ "about.domain_blocks.no_reason_available": "理由未記載",
+ "about.domain_blocks.preamble": "Mastodonでは原則的にあらゆるサーバー同士で交流したり、互いの投稿を読んだりできますが、当サーバーでは例外的に次のような制限を設けています。",
"about.domain_blocks.silenced.explanation": "このサーバーのプロフィールやコンテンツは、明示的に検索したり、フォローでオプトインしない限り、通常は表示されません。",
"about.domain_blocks.silenced.title": "制限",
"about.domain_blocks.suspended.explanation": "これらのサーバーからのデータは処理されず、保存や変換もされません。該当するユーザーとの交流もできません。",
- "about.domain_blocks.suspended.title": "停止済み",
+ "about.domain_blocks.suspended.title": "停止中",
"about.not_available": "この情報はこのサーバーでは利用できません。",
"about.powered_by": "{mastodon}による分散型ソーシャルメディア",
"about.rules": "サーバーのルール",
@@ -47,7 +47,7 @@
"account.locked_info": "このアカウントは承認制アカウントです。相手が承認するまでフォローは完了しません。",
"account.media": "メディア",
"account.mention": "@{name}さんにメンション",
- "account.moved_to": "{name}さんがアカウントを引っ越しました:",
+ "account.moved_to": "{name}さんはこちらのアカウントに引っ越しました:",
"account.mute": "@{name}さんをミュート",
"account.mute_notifications_short": "通知をオフにする",
"account.mute_short": "ミュート",
@@ -137,7 +137,7 @@
"compose.language.search": "言語を検索...",
"compose.published.body": "投稿されました!",
"compose.published.open": "開く",
- "compose.saved.body": "投稿が保存されました",
+ "compose.saved.body": "変更を保存しました。",
"compose_form.direct_message_warning_learn_more": "もっと詳しく",
"compose_form.encryption_warning": "Mastodonの投稿はエンドツーエンド暗号化に対応していません。安全に送受信されるべき情報をMastodonで共有しないでください。",
"compose_form.hashtag_warning": "この投稿は公開設定ではないのでハッシュタグの一覧に表示されません。公開投稿だけがハッシュタグで検索できます。",
@@ -250,7 +250,7 @@
"errors.unexpected_crash.report_issue": "問題を報告",
"explore.search_results": "検索結果",
"explore.suggested_follows": "ユーザー",
- "explore.title": "エクスプローラー",
+ "explore.title": "探索する",
"explore.trending_links": "ニュース",
"explore.trending_statuses": "投稿",
"explore.trending_tags": "ハッシュタグ",
@@ -301,7 +301,7 @@
"hashtag.counter_by_uses_today": "今日{count, plural, other {{counter}件}}",
"hashtag.follow": "ハッシュタグをフォローする",
"hashtag.unfollow": "ハッシュタグのフォローを解除",
- "hashtags.and_other": "+{count, plural, other {#件}}",
+ "hashtags.and_other": "ほか{count, plural, other {#個}}",
"home.actions.go_to_explore": "話題をさがす",
"home.actions.go_to_suggestions": "フォローするユーザーを検索",
"home.column_settings.basic": "基本設定",
@@ -405,7 +405,7 @@
"navigation_bar.discover": "見つける",
"navigation_bar.domain_blocks": "ブロックしたドメイン",
"navigation_bar.edit_profile": "プロフィールを編集",
- "navigation_bar.explore": "エクスプローラー",
+ "navigation_bar.explore": "探索する",
"navigation_bar.favourites": "お気に入り",
"navigation_bar.filters": "フィルター設定",
"navigation_bar.follow_requests": "フォローリクエスト",
@@ -424,7 +424,7 @@
"not_signed_in_indicator.not_signed_in": "この機能を使うにはログインする必要があります。",
"notification.admin.report": "{name}さんが{target}さんを通報しました",
"notification.admin.sign_up": "{name}さんがサインアップしました",
- "notification.favourite": "{name}さんがあなたの投稿をお気に入りに追加しました。",
+ "notification.favourite": "{name}さんがお気に入りしました",
"notification.follow": "{name}さんにフォローされました",
"notification.follow_request": "{name}さんがあなたにフォローリクエストしました",
"notification.mention": "{name}さんがあなたに返信しました",
@@ -518,7 +518,7 @@
"privacy.public.long": "誰でも閲覧可",
"privacy.public.short": "公開",
"privacy.unlisted.long": "誰でも閲覧可、サイレント",
- "privacy.unlisted.short": "未収載",
+ "privacy.unlisted.short": "非収載",
"privacy_policy.last_updated": "{date}に更新",
"privacy_policy.title": "プライバシーポリシー",
"refresh": "更新",
diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json
index 5b37324f7dd7b7..ccd783e8092208 100644
--- a/app/javascript/mastodon/locales/ko.json
+++ b/app/javascript/mastodon/locales/ko.json
@@ -102,7 +102,7 @@
"bundle_modal_error.message": "컴포넌트를 불러오는 중 문제가 발생했습니다.",
"bundle_modal_error.retry": "다시 시도",
"closed_registrations.other_server_instructions": "마스토돈은 분산화 되어 있기 때문에, 다른 서버에서 계정을 만들더라도 이 서버와 상호작용 할 수 있습니다.",
- "closed_registrations_modal.description": "{domain}은 현재 가입이 막혀있는 상태입니다, 만약 마스토돈을 이용하기 위해 꼭 {domain}을 사용할 필요는 없다는 사실을 인지해 두세요.",
+ "closed_registrations_modal.description": "{domain}은 현재 가입이 막혀있는 상태입니다, 마스토돈을 이용하기 위해 꼭 {domain}을 사용할 필요는 없다는 사실을 인지해 두세요.",
"closed_registrations_modal.find_another_server": "다른 서버 찾기",
"closed_registrations_modal.preamble": "마스토돈은 분산화 되어 있습니다, 그렇기 때문에 어디에서 계정을 생성하든, 이 서버에 있는 누구와도 팔로우와 상호작용을 할 수 있습니다. 심지어는 스스로 서버를 만드는 것도 가능합니다!",
"closed_registrations_modal.title": "마스토돈에서 가입",
@@ -204,7 +204,7 @@
"dismissable_banner.explore_links": "이 소식들은 오늘 소셜 웹에서 가장 많이 공유된 내용들입니다. 새 소식을 더 많은 사람들이 공유할수록 높은 순위가 됩니다.",
"dismissable_banner.explore_statuses": "이 게시물들은 오늘 소셜 웹에서 호응을 얻고 있는 게시물들입니다. 부스트와 관심을 받는 새로운 글들이 높은 순위가 됩니다.",
"dismissable_banner.explore_tags": "이 해시태그들은 이 서버와 분산화된 네트워크의 다른 서버에서 사람들의 인기를 끌고 있는 것들입니다.",
- "dismissable_banner.public_timeline": "이것들은 {domain}에 있는 사람들이 팔로우한 사람들의 최신 게시물들입니다.",
+ "dismissable_banner.public_timeline": "{domain} 사람들이 팔로우하는 소셜 웹 사람들의 최신 공개 게시물입니다.",
"embed.instructions": "아래의 코드를 복사하여 대화를 원하는 곳으로 공유하세요.",
"embed.preview": "이렇게 표시됩니다:",
"emoji_button.activity": "활동",
@@ -590,7 +590,7 @@
"search.quick_action.open_url": "마스토돈에서 URL 열기",
"search.quick_action.status_search": "{x}에 맞는 게시물",
"search.search_or_paste": "검색하거나 URL 붙여넣기",
- "search_popout.full_text_search_disabled_message": "{domain}에서는 쓸 수 없습니다.",
+ "search_popout.full_text_search_disabled_message": "{domain}에서는 사용할 수 없습니다.",
"search_popout.language_code": "ISO 언어코드",
"search_popout.options": "검색 옵션",
"search_popout.quick_actions": "빠른 작업",
diff --git a/app/javascript/mastodon/locales/lv.json b/app/javascript/mastodon/locales/lv.json
index 2480f879caaa67..7f71d9318b5ccf 100644
--- a/app/javascript/mastodon/locales/lv.json
+++ b/app/javascript/mastodon/locales/lv.json
@@ -13,7 +13,7 @@
"about.rules": "Servera noteikumi",
"account.account_note_header": "Piezīme",
"account.add_or_remove_from_list": "Pievienot vai Noņemt no sarakstiem",
- "account.badges.bot": "Robots",
+ "account.badges.bot": "Automatizēts",
"account.badges.group": "Grupa",
"account.block": "Bloķēt @{name}",
"account.block_domain": "Bloķēt domēnu {domain}",
@@ -26,7 +26,7 @@
"account.domain_blocked": "Domēns ir bloķēts",
"account.edit_profile": "Rediģēt profilu",
"account.enable_notifications": "Paziņot man, kad @{name} publicē ierakstu",
- "account.endorse": "Izcelt profilā",
+ "account.endorse": "Izcelts profilā",
"account.featured_tags.last_status_at": "Beidzamā ziņa {date}",
"account.featured_tags.last_status_never": "Ierakstu nav",
"account.featured_tags.title": "{name} izceltie tēmturi",
@@ -102,7 +102,7 @@
"bundle_modal_error.message": "Kaut kas nogāja greizi, ielādējot šo komponenti.",
"bundle_modal_error.retry": "Mēģināt vēlreiz",
"closed_registrations.other_server_instructions": "Tā kā Mastodon ir decentralizēts, tu vari izveidot kontu citā serverī un joprojām mijiedarboties ar šo.",
- "closed_registrations_modal.description": "Pašlaik nav iespējams izveidot kontu domēnā {domain}, taču ņem vērā, ka tev nav nepieciešams konts tieši domēnā {domain}, lai izmantotu Mastodon.",
+ "closed_registrations_modal.description": "Pašlaik nav iespējams izveidot kontu domēnā {domain}, taču ņem vērā, ka tev nav nepieciešams konts tieši {domain}, lai lietotu Mastodon.",
"closed_registrations_modal.find_another_server": "Atrast citu serveri",
"closed_registrations_modal.preamble": "Mastodon ir decentralizēts, tāpēc neatkarīgi no tā, kur tu izveido savu kontu, varēsi sekot līdzi un sazināties ar ikvienu šajā serverī. Tu pat vari vadīt to pats!",
"closed_registrations_modal.title": "Reģistrēšanās Mastodon",
@@ -113,7 +113,7 @@
"column.direct": "Privāti pieminēti",
"column.directory": "Pārlūkot profilus",
"column.domain_blocks": "Bloķētie domēni",
- "column.favourites": "Iecienīti",
+ "column.favourites": "Iecienītie",
"column.firehose": "Tiešraides plūsmas",
"column.follow_requests": "Sekošanas pieprasījumi",
"column.home": "Sākums",
@@ -151,7 +151,7 @@
"compose_form.poll.switch_to_multiple": "Mainīt aptaujas veidu, lai atļautu vairākas izvēles",
"compose_form.poll.switch_to_single": "Mainīt aptaujas veidu, lai atļautu vienu izvēli",
"compose_form.publish": "Publicēt",
- "compose_form.publish_form": "Publicēt",
+ "compose_form.publish_form": "Jauns ieraksts",
"compose_form.publish_loud": "{publish}!",
"compose_form.save_changes": "Saglabāt izmaiņas",
"compose_form.sensitive.hide": "{count, plural, one {Atzīmēt multividi kā sensitīvu} other {Atzīmēt multivides kā sensitīvas}}",
@@ -161,13 +161,13 @@
"compose_form.spoiler.unmarked": "Pievienot satura brīdinājumu",
"compose_form.spoiler_placeholder": "Ieraksti savu brīdinājumu šeit",
"confirmation_modal.cancel": "Atcelt",
- "confirmations.block.block_and_report": "Bloķēt un sūdzēties",
+ "confirmations.block.block_and_report": "Bloķēt un ziņot",
"confirmations.block.confirm": "Bloķēt",
"confirmations.block.message": "Vai tiešām vēlies bloķēt {name}?",
"confirmations.cancel_follow_request.confirm": "Atsaukt pieprasījumu",
"confirmations.cancel_follow_request.message": "Vai tiešām vēlies atsaukt pieprasījumu sekot {name}?",
"confirmations.delete.confirm": "Dzēst",
- "confirmations.delete.message": "Vai tiešām vēlies dzēst šo ziņu?",
+ "confirmations.delete.message": "Vai tiešām vēlies dzēst šo ierakstu?",
"confirmations.delete_list.confirm": "Dzēst",
"confirmations.delete_list.message": "Vai tiešam vēlies neatgriezeniski dzēst šo sarakstu?",
"confirmations.discard_edit_media.confirm": "Atmest",
@@ -202,7 +202,7 @@
"dismissable_banner.community_timeline": "Šīs ir jaunākās publiskās ziņas no personām, kuru kontus mitina {domain}.",
"dismissable_banner.dismiss": "Atcelt",
"dismissable_banner.explore_links": "Par šiem jaunumiem šobrīd runā cilvēki šajā un citos decentralizētā tīkla serveros.",
- "dismissable_banner.explore_statuses": "Šīs ir ziņas no visa sociālā tīkla, kas šodien kļūst arvien populārākas. Jaunākas ziņas ar vairāk uzlabojumiem un iecienītākajām ziņām tiek novērtētas augstāk.",
+ "dismissable_banner.explore_statuses": "Ieraksti, kas šobrīd gūst arvien lielāku ievērību visā sociālajā tīklā. Augstāk tiek kārtoti neseni ieraksti, kas pastiprināti un pievienoti izlasēm.",
"dismissable_banner.explore_tags": "Šie tēmturi šobrīd kļūst arvien populārāki cilvēku vidū šajā un citos decentralizētā tīkla serveros.",
"dismissable_banner.public_timeline": "Šīs ir jaunākās publiskās ziņas no lietotājiem sociālajā tīmeklī, kurām seko lietotāji domēnā {domain}.",
"embed.instructions": "Iestrādā šo ziņu savā mājaslapā, kopējot zemāk redzamo kodu.",
@@ -236,7 +236,7 @@
"empty_column.follow_requests": "Šobrīd tev nav sekošanas pieprasījumu. Kad kāds pieteiksies tev sekot, pieprasījums parādīsies šeit.",
"empty_column.followed_tags": "Tu vēl neesi sekojis nevienam tēmturim. Kad to izdarīsi, tie tiks parādīti šeit.",
"empty_column.hashtag": "Ar šo tēmturi nekas nav atrodams.",
- "empty_column.home": "Tava mājas laika līnija ir tukša! Lai to aizpildītu, pieseko vairāk cilvēkiem. {suggestions}",
+ "empty_column.home": "Tava mājas laikrinda ir tukša! Lai to aizpildītu, pieseko vairāk cilvēkiem.",
"empty_column.list": "Šis saraksts pašreiz ir tukšs. Kad šī saraksta dalībnieki publicēs jaunas ziņas, tās parādīsies šeit.",
"empty_column.lists": "Pašreiz tev nav neviena saraksta. Kad tādu izveidosi, tas parādīsies šeit.",
"empty_column.mutes": "Neviens lietotājs vēl nav apklusināts.",
@@ -309,11 +309,11 @@
"home.column_settings.show_replies": "Rādīt atbildes",
"home.explore_prompt.body": "Tavā mājas plūsmā būs dažādu ziņu sajaukums no atsaucēm, kurām esi izvēlējies sekot, personām, kurām esi izvēlējies sekot, un ziņām, kuras tās izceļ. Ja tas šķiet pārāk kluss, iespējams, vēlēsies:",
"home.explore_prompt.title": "Šī ir tava Mastodon mājvieta.",
- "home.hide_announcements": "Slēpt anonsus",
+ "home.hide_announcements": "Slēpt paziņojumus",
"home.pending_critical_update.body": "Lūdzu, pēc iespējas ātrāk atjaunini savu Mastodon serveri!",
"home.pending_critical_update.link": "Skatīt jauninājumus",
"home.pending_critical_update.title": "Pieejams kritisks drošības jauninājums!",
- "home.show_announcements": "Rādīt anonsus",
+ "home.show_announcements": "Rādīt paziņojumus",
"interaction_modal.description.favourite": "Ar Mastodon kontu tu vari pievienot šo ziņu izlasei, lai informētu autoru, ka to novērtē, un saglabātu to vēlākai lasīšanai.",
"interaction_modal.description.follow": "Ar Mastodon kontu tu vari sekot {name}, lai saņemtu viņu ziņas savā mājas plūsmā.",
"interaction_modal.description.reblog": "Izmantojot kontu Mastodon, tu vari izcelt šo ziņu, lai kopīgotu to ar saviem sekotājiem.",
@@ -369,7 +369,7 @@
"lightbox.close": "Aizvērt",
"lightbox.compress": "Saspiest attēla skata lodziņu",
"lightbox.expand": "Izvērst attēla skata lodziņu",
- "lightbox.next": "Nākamais",
+ "lightbox.next": "Tālāk",
"lightbox.previous": "Iepriekšējais",
"limited_account_hint.action": "Tik un tā rādīt profilu",
"limited_account_hint.title": "{domain} moderatori ir paslēpuši šo profilu.",
@@ -422,8 +422,8 @@
"navigation_bar.search": "Meklēt",
"navigation_bar.security": "Drošība",
"not_signed_in_indicator.not_signed_in": "Lai piekļūtu šim resursam, tev ir jāpierakstās.",
- "notification.admin.report": "{name} sūdzējās par {target}",
- "notification.admin.sign_up": "{name} pierakstījās",
+ "notification.admin.report": "{name} ziņoja par {target}",
+ "notification.admin.sign_up": "{name} ir pierakstījies",
"notification.favourite": "{name} pievienoja tavu ziņu izlasei",
"notification.follow": "{name} uzsāka tev sekot",
"notification.follow_request": "{name} nosūtīja tev sekošanas pieprasījumu",
@@ -435,7 +435,7 @@
"notification.update": "{name} rediģēja ierakstu",
"notifications.clear": "Notīrīt paziņojumus",
"notifications.clear_confirmation": "Vai tiešām vēlies neatgriezeniski notīrīt visus savus paziņojumus?",
- "notifications.column_settings.admin.report": "Jaunas sūdzības:",
+ "notifications.column_settings.admin.report": "Jauni ziņojumi:",
"notifications.column_settings.admin.sign_up": "Jaunas pierakstīšanās:",
"notifications.column_settings.alert": "Darbvirsmas paziņojumi",
"notifications.column_settings.favourite": "Izlase:",
@@ -445,7 +445,7 @@
"notifications.column_settings.follow": "Jauni sekotāji:",
"notifications.column_settings.follow_request": "Jauni sekošanas pieprasījumi:",
"notifications.column_settings.mention": "Pieminējumi:",
- "notifications.column_settings.poll": "Aptauju rezultāti:",
+ "notifications.column_settings.poll": "Aptaujas rezultāti:",
"notifications.column_settings.push": "Uznirstošie paziņojumi",
"notifications.column_settings.reblog": "Pastiprinātie ieraksti:",
"notifications.column_settings.show": "Rādīt kolonnā",
@@ -457,13 +457,13 @@
"notifications.filter.all": "Visi",
"notifications.filter.boosts": "Pastiprinātie ieraksti",
"notifications.filter.favourites": "Izlases",
- "notifications.filter.follows": "Sekošana",
+ "notifications.filter.follows": "Seko",
"notifications.filter.mentions": "Pieminējumi",
- "notifications.filter.polls": "Aptauju rezultāti",
+ "notifications.filter.polls": "Aptaujas rezultāti",
"notifications.filter.statuses": "Jaunumi no cilvēkiem, kuriem tu seko",
"notifications.grant_permission": "Piešķirt atļauju.",
"notifications.group": "{count} paziņojumi",
- "notifications.mark_as_read": "Atzīmēt visus paziņojumus kā izlasītus",
+ "notifications.mark_as_read": "Atzīmēt katru paziņojumu kā izlasītu",
"notifications.permission_denied": "Darbvirsmas paziņojumi nav pieejami, jo iepriekš tika noraidīts pārlūka atļauju pieprasījums",
"notifications.permission_denied_alert": "Darbvirsmas paziņojumus nevar iespējot, jo pārlūkprogrammai atļauja tika iepriekš atteikta",
"notifications.permission_required": "Darbvirsmas paziņojumi nav pieejami, jo nav piešķirta nepieciešamā atļauja.",
@@ -476,23 +476,23 @@
"onboarding.actions.go_to_home": "Dodieties uz manu mājas plūsmu",
"onboarding.compose.template": "Sveiki, #Mastodon!",
"onboarding.follows.empty": "Diemžēl pašlaik nevar parādīt rezultātus. Vari mēģināt izmantot meklēšanu vai pārlūkot izpētes lapu, lai atrastu personas, kurām sekot, vai mēģināt vēlreiz vēlāk.",
- "onboarding.follows.lead": "Savu mājas plūsmu veido tu pats. Jo vairāk cilvēkiem tu sekosi, jo aktīvāk un interesantāk viss būs. Šie profili var būt labs sākumpunkts — vēlāk vienmēr varēsi pārstāt sekot!",
+ "onboarding.follows.lead": "Tava mājas plūsma ir galvenais veids, kā izbaudīt Mastodon. Jo vairāk cilvēku sekosi, jo aktīvāk un interesantāk tas būs. Lai sāktu, šeit ir daži ieteikumi:",
"onboarding.follows.title": "Populārs Mastodon",
"onboarding.share.lead": "Paziņo citiem, kā viņi tevi var atrast Mastodon!",
"onboarding.share.message": "Es esmu {username} #Mastodon! Nāc sekot man uz {url}",
"onboarding.share.next_steps": "Iespējamie nākamie soļi:",
"onboarding.share.title": "Kopīgo savu profilu",
- "onboarding.start.lead": "Tavs jaunais Mastodon konts ir gatavs lietošanai. Lūk, kā tu vari to pilnīgāk izmantot:",
- "onboarding.start.skip": "Vai vēlies izlaist tieši uz priekšu?",
+ "onboarding.start.lead": "Tagad tu esat daļa no Mastodon — unikālas, decentralizētas sociālo mediju platformas, kurā tu, nevis algoritms, veido savu pieredzi. Sāksim darbu šajā jaunajā sociālajā jomā:",
+ "onboarding.start.skip": "Nav nepieciešama palīdzība darba sākšanai?",
"onboarding.start.title": "Tev tas izdevās!",
"onboarding.steps.follow_people.body": "Tu pats veido savu plūsmu. Piepildīsim to ar interesantiem cilvēkiem.",
"onboarding.steps.follow_people.title": "Sekot {count, plural, one {one person} other {# cilvēkiem}}",
- "onboarding.steps.publish_status.body": "Sveicini pasauli.",
+ "onboarding.steps.publish_status.body": "Sveicini pasauli ar tekstu, fotoattēliem, video, vai aptaujām {emoji}",
"onboarding.steps.publish_status.title": "Izveido savu pirmo ziņu",
"onboarding.steps.setup_profile.body": "Citi, visticamāk, sazināsies ar tevi, izmantojot aizpildītu profilu.",
"onboarding.steps.setup_profile.title": "Pielāgo savu profilu",
"onboarding.steps.share_profile.body": "Paziņo saviem draugiem, kā tevi atrast Mastodon!",
- "onboarding.steps.share_profile.title": "Kopīgo savu profilu",
+ "onboarding.steps.share_profile.title": "Kopīgo savu Mastodon profilu",
"onboarding.tips.2fa": "
Vai zināji? Tu vari aizsargāt savu kontu, konta iestatījumos iestatot divu faktoru autentifikāciju. Tas darbojas ar jebkuru tevis izvēlētu TOTP lietotni, nav nepieciešams tālruņa numurs!",
"onboarding.tips.accounts_from_other_servers": "
Vai zināji? Tā kā Mastodon ir decentralizēts, daži profili, ar kuriem saskaraties, tiks mitināti citos, nevis tavos serveros. Un tomēr tu varat sazināties ar viņiem nevainojami! Viņu serveris atrodas viņu lietotājvārda otrajā pusē!",
"onboarding.tips.migration": "
Vai zināji? Ja uzskati, ka {domain} nākotnē nav lieliska servera izvēle, vari pāriet uz citu Mastodon serveri, nezaudējot savus sekotājus. Tu pat vari mitināt savu personīgo serveri!",
@@ -518,7 +518,7 @@
"privacy.public.long": "Redzams visiem",
"privacy.public.short": "Publiska",
"privacy.unlisted.long": "Redzams visiem, bet izslēgts no satura atklāšanas funkcijām",
- "privacy.unlisted.short": "Nerindota",
+ "privacy.unlisted.short": "Neiekļautie",
"privacy_policy.last_updated": "Pēdējo reizi atjaunināta {date}",
"privacy_policy.title": "Privātuma politika",
"refresh": "Atsvaidzināt",
@@ -563,25 +563,25 @@
"report.reasons.spam": "Tas ir spams",
"report.reasons.spam_description": "Ļaunprātīgas saites, viltus iesaistīšana vai atkārtotas atbildes",
"report.reasons.violation": "Tas pārkāpj servera noteikumus",
- "report.reasons.violation_description": "Tu zini, ka tas pārkāpj konkrētus noteikumus",
+ "report.reasons.violation_description": "Tu zini, ka tas pārkāpj īpašus noteikumus",
"report.rules.subtitle": "Atlasi visus atbilstošos",
"report.rules.title": "Kuri noteikumi tiek pārkāpti?",
"report.statuses.subtitle": "Atlasi visus atbilstošos",
"report.statuses.title": "Vai ir kādi ieraksti, kas atbalsta šo sūdzību?",
"report.submit": "Iesniegt",
- "report.target": "Sūdzība par {target}",
- "report.thanks.take_action": "Vari veikt šīs darbības, lai kontrolētu Mastodon redzamo saturu:",
+ "report.target": "Ziņošana par: {target}",
+ "report.thanks.take_action": "Tālāk ir norādītas iespējas, kā kontrolēt Mastodon redzamo saturu:",
"report.thanks.take_action_actionable": "Kamēr mēs to izskatām, tu vari veikt darbības pret @{name}:",
"report.thanks.title": "Vai nevēlies to redzēt?",
"report.thanks.title_actionable": "Paldies, ka ziņoji, mēs to izskatīsim.",
"report.unfollow": "Pārtraukt sekot @{name}",
"report.unfollow_explanation": "Tu seko šim kontam. Lai vairs neredzētu viņu ziņas savā mājas plūsmā, pārtrauc viņiem sekot.",
- "report_notification.attached_statuses": "{count, plural, one {Pievienots {count} ieraksts} other {Pievienoti {count} ieraksti}}",
+ "report_notification.attached_statuses": "Pievienoti {count, plural,one {{count} sūtījums} other {{count} sūtījumi}}",
"report_notification.categories.legal": "Tiesisks",
"report_notification.categories.other": "Cita",
"report_notification.categories.spam": "Spams",
"report_notification.categories.violation": "Noteikumu pārkāpums",
- "report_notification.open": "Atvērt sūdzību",
+ "report_notification.open": "Atvērt ziņojumu",
"search.no_recent_searches": "Nav nesen veiktu meklējumu",
"search.placeholder": "Meklēšana",
"search.quick_action.account_search": "Profili atbilst {x}",
@@ -628,7 +628,7 @@
"status.direct_indicator": "Pieminēts privāti",
"status.edit": "Rediģēt",
"status.edited": "Rediģēts {date}",
- "status.edited_x_times": "Rediģēts {count, plural, one {{count} reizi} other {{count} reizes}}",
+ "status.edited_x_times": "Rediģēts {count, plural, one {{count} reize} other {{count} reizes}}",
"status.embed": "Iestrādāt",
"status.favourite": "Iecienīts",
"status.filter": "Filtrē šo ziņu",
@@ -656,8 +656,8 @@
"status.remove_bookmark": "Noņemt grāmatzīmi",
"status.replied_to": "Atbildēja {name}",
"status.reply": "Atbildēt",
- "status.replyAll": "Atbildēt uz pavedienu",
- "status.report": "Sūdzēties par @{name}",
+ "status.replyAll": "Atbildēt uz tematu",
+ "status.report": "Ziņot par @{name}",
"status.sensitive_warning": "Sensitīvs saturs",
"status.share": "Kopīgot",
"status.show_filter_reason": "Tomēr rādīt",
@@ -668,7 +668,7 @@
"status.show_original": "Rādīt oriģinālu",
"status.title.with_attachments": "{user} publicējis {attachmentCount, plural, one {pielikumu} other {{attachmentCount} pielikumus}}",
"status.translate": "Tulkot",
- "status.translated_from_with": "Tulkots no {lang}, izmantojot {provider}",
+ "status.translated_from_with": "Tulkots no {lang} izmantojot {provider}",
"status.uncached_media_warning": "Priekšskatījums nav pieejams",
"status.unmute_conversation": "Noņemt sarunas apklusinājumu",
"status.unpin": "Noņemt profila piespraudumu",
@@ -681,16 +681,16 @@
"time_remaining.hours": "{number, plural, one {Atlikusi # stunda} other {Atlikušas # stundas}}",
"time_remaining.minutes": "{number, plural, one {Atlikusi # minūte} other {Atlikušas # minūtes}}",
"time_remaining.moments": "Atlikuši daži mirkļi",
- "time_remaining.seconds": "{number, plural, one {Atlikusi # sekunde} other {Atlikušas # sekundes}}",
+ "time_remaining.seconds": "Atlikušas {number, plural, one {# sekunde} other {# sekundes}}",
"timeline_hint.remote_resource_not_displayed": "{resource} no citiem serveriem nav parādīti.",
"timeline_hint.resources.followers": "Sekotāji",
- "timeline_hint.resources.follows": "Sekojošie",
+ "timeline_hint.resources.follows": "Seko",
"timeline_hint.resources.statuses": "Vecāki ieraksti",
"trends.counter_by_accounts": "{count, plural, one {{counter} persona} other {{counter} cilvēki}} par {days, plural, one {# dienu} other {{days} dienām}}",
"trends.trending_now": "Aktuālās tendences",
- "ui.beforeunload": "Ja pametīsiet Mastodon, jūsu melnraksts tiks zaudēts.",
+ "ui.beforeunload": "Ja pametīsit Mastodonu, jūsu melnraksts tiks zaudēts.",
"units.short.billion": "{count}Mjd",
- "units.short.million": "{count}Mjn",
+ "units.short.million": "{count}M",
"units.short.thousand": "{count}Tk",
"upload_area.title": "Velc un nomet, lai augšupielādētu",
"upload_button.label": "Pievienot bildi, video vai audio datni",
@@ -707,7 +707,7 @@
"upload_modal.apply": "Pielietot",
"upload_modal.applying": "Pielieto…",
"upload_modal.choose_image": "Izvēlēties attēlu",
- "upload_modal.description_placeholder": "Raibais runcis Rīgā ratu rumbā rūc",
+ "upload_modal.description_placeholder": "Raibais runcis rīgā ratu rumbā rūc",
"upload_modal.detect_text": "Noteikt tekstu no attēla",
"upload_modal.edit_media": "Rediģēt multividi",
"upload_modal.hint": "Noklikšķini vai velc apli priekšskatījumā, lai izvēlētos fokusa punktu, kas vienmēr būs redzams visos sīktēlos.",
diff --git a/app/javascript/mastodon/locales/ms.json b/app/javascript/mastodon/locales/ms.json
index c6993c809c4c46..3814e691516c01 100644
--- a/app/javascript/mastodon/locales/ms.json
+++ b/app/javascript/mastodon/locales/ms.json
@@ -593,6 +593,7 @@
"search_results.all": "Semua",
"search_results.hashtags": "Tanda pagar",
"search_results.nothing_found": "Tidak dapat menemui apa-apa untuk istilah carian tersebut",
+ "search_results.see_all": "Lihat semua",
"search_results.statuses": "Hantaran",
"search_results.title": "Mencari {q}",
"server_banner.about_active_users": "Pengguna pelayan ini sepanjang 30 hari yang lalu (Pengguna Aktif Bulanan)",
diff --git a/app/javascript/mastodon/locales/my.json b/app/javascript/mastodon/locales/my.json
index 8e0b7ab41e85dd..103f4e0f8d657e 100644
--- a/app/javascript/mastodon/locales/my.json
+++ b/app/javascript/mastodon/locales/my.json
@@ -312,6 +312,7 @@
"home.hide_announcements": "ကြေညာချက်များကို ဖျောက်ပါ",
"home.pending_critical_update.body": "သင့် Mastodon ဆာဗာ အမြန်ဆုံး အပ်ဒိတ်လုပ်ပါ။",
"home.pending_critical_update.link": "အပ်ဒိတ်များကြည့်ရန်",
+ "home.pending_critical_update.title": "အရေးကြီးသည့် လုံခြုံရေးအပ်ဒိတ် ရနိုင်ပါမည်။",
"home.show_announcements": "ကြေညာချက်များကို ပြပါ",
"interaction_modal.description.favourite": "Mastodon အကောင့်ဖြင့် ဤပို့စ်ကို သင် favorite ပြုလုပ်ကြောင်း စာရေးသူအား အသိပေးပြီး နောက်ပိုင်းတွင် သိမ်းဆည်းနိုင်သည်။",
"interaction_modal.description.follow": "Mastodon အကောင့်ဖြင့် သင်၏ ပင်မစာမျက်နှာတွင် ၎င်းတို့၏ ပို့စ်များကို ရရှိရန်အတွက် {name} ကို စောင့်ကြည့်နိုင်ပါသည်။",
@@ -594,6 +595,7 @@
"search_popout.options": "ရွေးချယ်ထားသည်များ ရှာဖွေရန်",
"search_popout.quick_actions": "အမြန်လုပ်ဆောင်မှုများ",
"search_popout.recent": "လတ်တလော ရှာဖွေမှုများ",
+ "search_popout.specific_date": "သီးခြားရက်စွဲ",
"search_popout.user": "အသုံးပြုသူ",
"search_results.accounts": "စာမျက်နှာ",
"search_results.all": "အားလုံး",
diff --git a/app/javascript/mastodon/locales/nn.json b/app/javascript/mastodon/locales/nn.json
index 0a14ea93a39f87..8ff390aabb8ed1 100644
--- a/app/javascript/mastodon/locales/nn.json
+++ b/app/javascript/mastodon/locales/nn.json
@@ -153,7 +153,7 @@
"compose_form.publish": "Legg ut",
"compose_form.publish_form": "Legg ut",
"compose_form.publish_loud": "{publish}!",
- "compose_form.save_changes": "Gøym",
+ "compose_form.save_changes": "Lagre endringar",
"compose_form.sensitive.hide": "{count, plural, one {Marker mediet som ømtolig} other {Marker media som ømtolige}}",
"compose_form.sensitive.marked": "{count, plural, one {Mediet er markert som ømtolig} other {Media er markerte som ømtolige}}",
"compose_form.sensitive.unmarked": "{count, plural, one {Mediet er ikkje markert som ømtolig} other {Media er ikkje markerte som ømtolige}}",
@@ -171,7 +171,7 @@
"confirmations.delete_list.confirm": "Slett",
"confirmations.delete_list.message": "Er du sikker på at du vil sletta denne lista for alltid?",
"confirmations.discard_edit_media.confirm": "Forkast",
- "confirmations.discard_edit_media.message": "Du har ulagra endringar i mediaskildringa eller førehandsvisinga. Vil du forkaste dei likevel?",
+ "confirmations.discard_edit_media.message": "Du har ulagra endringar i mediaskildringa eller førehandsvisinga. Vil du forkasta dei likevel?",
"confirmations.domain_block.confirm": "Skjul alt frå domenet",
"confirmations.domain_block.message": "Er du heilt, heilt sikker på at du vil skjula heile {domain}? I dei fleste tilfelle er det godt nok og føretrekt med nokre få målretta blokkeringar eller målbindingar. Du kjem ikkje til å sjå innhald frå domenet i fødererte tidsliner eller i varsla dine. Fylgjarane dine frå domenet vert fjerna.",
"confirmations.edit.confirm": "Rediger",
@@ -285,7 +285,7 @@
"footer.privacy_policy": "Personvernsreglar",
"footer.source_code": "Vis kjeldekode",
"footer.status": "Status",
- "generic.saved": "Gøymt",
+ "generic.saved": "Lagra",
"getting_started.heading": "Kom i gang",
"hashtag.column_header.tag_mode.all": "og {additional}",
"hashtag.column_header.tag_mode.any": "eller {additional}",
@@ -314,7 +314,7 @@
"home.pending_critical_update.link": "Sjå oppdateringar",
"home.pending_critical_update.title": "Kritisk sikkerheitsoppdatering er tilgjengeleg!",
"home.show_announcements": "Vis kunngjeringar",
- "interaction_modal.description.favourite": "Med ein konto på Mastodon kan du favorittmerkja dette innlegget for å visa forfattaren at du set pris på det, og for å lagra det til seinare.",
+ "interaction_modal.description.favourite": "Med ein konto på Mastodon kan du favorittmerka dette innlegget for å visa forfattaren at du set pris på det, og for å lagra det til seinare.",
"interaction_modal.description.follow": "Med ein konto på Mastodon kan du fylgja {name} for å sjå innlegga deira i din heimestraum.",
"interaction_modal.description.reblog": "Med ein konto på Mastodon kan du framheva dette innlegget for å dela det med dine eigne fylgjarar.",
"interaction_modal.description.reply": "Med ein konto på Mastodon kan du svara på dette innlegget.",
@@ -673,7 +673,7 @@
"status.unmute_conversation": "Opphev målbinding av samtalen",
"status.unpin": "Løys frå profil",
"subscribed_languages.lead": "Kun innlegg på valde språk vil bli dukke opp i heimestraumen din og i listene dine etter denne endringa. For å motta innlegg på alle språk, la vere å velje nokon.",
- "subscribed_languages.save": "Gøym",
+ "subscribed_languages.save": "Lagre endringar",
"subscribed_languages.target": "Endre abonnerte språk for {target}",
"tabs_bar.home": "Heim",
"tabs_bar.notifications": "Varsel",
diff --git a/app/javascript/mastodon/locales/oc.json b/app/javascript/mastodon/locales/oc.json
index 1a221945546421..6b82654500fdd4 100644
--- a/app/javascript/mastodon/locales/oc.json
+++ b/app/javascript/mastodon/locales/oc.json
@@ -65,6 +65,7 @@
"account.unendorse": "Mostrar pas pel perfil",
"account.unfollow": "Quitar de sègre",
"account.unmute": "Quitar de rescondre @{name}",
+ "account.unmute_notifications_short": "Restablir las notificacions",
"account.unmute_short": "Tornar afichar",
"account_note.placeholder": "Clicar per ajustar una nòta",
"admin.dashboard.retention.average": "Mejana",
@@ -97,6 +98,8 @@
"column.direct": "Mencions privadas",
"column.directory": "Percórrer los perfils",
"column.domain_blocks": "Domenis resconduts",
+ "column.favourites": "Favorits",
+ "column.firehose": "Tuts en dirèct",
"column.follow_requests": "Demandas d’abonament",
"column.home": "Acuèlh",
"column.lists": "Listas",
@@ -117,6 +120,7 @@
"community.column_settings.remote_only": "Sonque alonhat",
"compose.language.change": "Cambiar de lenga",
"compose.language.search": "Recercar de lengas...",
+ "compose.published.body": "Tut publicat.",
"compose.published.open": "Dobrir",
"compose.saved.body": "Publicacion enregistrada.",
"compose_form.direct_message_warning_learn_more": "Ne saber mai",
@@ -170,6 +174,7 @@
"conversation.open": "Veire la conversacion",
"conversation.with": "Amb {names}",
"copypaste.copied": "Copiat",
+ "copypaste.copy_to_clipboard": "Copiar al quichapapièr",
"directory.federated": "Del fediverse conegut",
"directory.local": "Solament de {domain}",
"directory.new_arrivals": "Nòus-venguts",
@@ -220,6 +225,7 @@
"errors.unexpected_crash.copy_stacktrace": "Copiar las traças al quichapapièrs",
"errors.unexpected_crash.report_issue": "Senhalar un problèma",
"explore.search_results": "Resultats de recèrca",
+ "explore.suggested_follows": "Personas",
"explore.title": "Explorar",
"explore.trending_links": "Novèlas",
"explore.trending_statuses": "Publicacions",
@@ -234,6 +240,7 @@
"filter_modal.select_filter.search": "Cercar o crear",
"filter_modal.select_filter.title": "Filtrar aquesta publicacion",
"filter_modal.title.status": "Filtrar una publicacion",
+ "firehose.local": "Aqueste servidor",
"follow_request.authorize": "Acceptar",
"follow_request.reject": "Regetar",
"follow_requests.unlocked_explanation": "Encara que vòstre compte siasque pas verrolhat, la còla de {domain} pensèt que volriatz benlèu repassar las demandas d’abonament d’aquestes comptes.",
@@ -257,12 +264,19 @@
"hashtag.column_settings.tag_mode.any": "Un d’aquestes",
"hashtag.column_settings.tag_mode.none": "Cap d’aquestes",
"hashtag.column_settings.tag_toggle": "Inclure las etiquetas suplementàrias dins aquesta colomna",
+ "hashtag.counter_by_accounts": "{count, plural, one {{counter} participant} other {{counter} participants}}",
+ "hashtag.counter_by_uses": "{count, plural, one {{counter} tut} other {{counter} tuts}}",
+ "hashtag.counter_by_uses_today": "{count, plural, one {{counter} tut} other {{counter} tuts}} uèi",
"hashtag.follow": "Sègre l’etiqueta",
"hashtag.unfollow": "Quitar de sègre l’etiqueta",
+ "hashtags.and_other": "…e {count, plural, one {}other {# de mai}}",
+ "home.actions.go_to_explore": "Agachatz las tendéncias",
+ "home.actions.go_to_suggestions": "Trobatz de monde de sègre",
"home.column_settings.basic": "Basic",
"home.column_settings.show_reblogs": "Mostrar los partatges",
"home.column_settings.show_replies": "Mostrar las responsas",
"home.hide_announcements": "Rescondre las anóncias",
+ "home.pending_critical_update.link": "Veire las mesas a jorn",
"home.show_announcements": "Mostrar las anóncias",
"interaction_modal.on_another_server": "Sus un autre servidor",
"interaction_modal.on_this_server": "Sus aqueste servidor",
@@ -332,14 +346,17 @@
"mute_modal.hide_notifications": "Rescondre las notificacions d’aquesta persona ?",
"mute_modal.indefinite": "Cap de data de fin",
"navigation_bar.about": "A prepaus",
+ "navigation_bar.advanced_interface": "Dobrir l’interfàcia web avançada",
"navigation_bar.blocks": "Personas blocadas",
"navigation_bar.bookmarks": "Marcadors",
"navigation_bar.community_timeline": "Flux public local",
"navigation_bar.compose": "Escriure un nòu tut",
+ "navigation_bar.direct": "Mencions privadas",
"navigation_bar.discover": "Trobar",
"navigation_bar.domain_blocks": "Domenis resconduts",
"navigation_bar.edit_profile": "Modificar lo perfil",
"navigation_bar.explore": "Explorar",
+ "navigation_bar.favourites": "Favorits",
"navigation_bar.filters": "Mots ignorats",
"navigation_bar.follow_requests": "Demandas d’abonament",
"navigation_bar.followed_tags": "Etiquetas seguidas",
@@ -369,6 +386,7 @@
"notifications.column_settings.admin.report": "Senhalaments novèls :",
"notifications.column_settings.admin.sign_up": "Nòus inscrits :",
"notifications.column_settings.alert": "Notificacions localas",
+ "notifications.column_settings.favourite": "Favorits :",
"notifications.column_settings.filter_bar.advanced": "Mostrar totas las categorias",
"notifications.column_settings.filter_bar.category": "Barra de recèrca rapida",
"notifications.column_settings.filter_bar.show_bar": "Afichar la barra de filtres",
@@ -386,6 +404,7 @@
"notifications.column_settings.update": "Modificacions :",
"notifications.filter.all": "Totas",
"notifications.filter.boosts": "Partages",
+ "notifications.filter.favourites": "Favorits",
"notifications.filter.follows": "Seguiments",
"notifications.filter.mentions": "Mencions",
"notifications.filter.polls": "Resultats del sondatge",
@@ -399,15 +418,21 @@
"notifications_permission_banner.enable": "Activar las notificacions burèu",
"notifications_permission_banner.how_to_control": "Per recebre las notificacions de Mastodon quand es pas dobèrt, activatz las notificacions de burèu. Podètz precisar quin tipe de notificacion generarà una notificacion de burèu via lo boton {icon} dessús un còp activadas.",
"notifications_permission_banner.title": "Manquetz pas jamai res",
+ "onboarding.action.back": "Tornar en rèire",
+ "onboarding.actions.back": "Tornar en rèire",
"onboarding.actions.go_to_explore": "See what's trending",
"onboarding.actions.go_to_home": "Go to your home feed",
+ "onboarding.compose.template": "Adiu #Mastodon !",
"onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!",
"onboarding.follows.title": "Popular on Mastodon",
+ "onboarding.share.title": "Partejar vòstre perfil",
"onboarding.start.lead": "Your new Mastodon account is ready to go. Here's how you can make the most of it:",
"onboarding.start.skip": "Want to skip right ahead?",
+ "onboarding.start.title": "Tot es prèst !",
"onboarding.steps.follow_people.body": "You curate your own feed. Lets fill it with interesting people.",
"onboarding.steps.follow_people.title": "Follow {count, plural, one {one person} other {# people}}",
"onboarding.steps.publish_status.body": "Say hello to the world.",
+ "onboarding.steps.publish_status.title": "Escrivètz vòstre primièr tut",
"onboarding.steps.setup_profile.body": "Others are more likely to interact with you with a filled out profile.",
"onboarding.steps.setup_profile.title": "Customize your profile",
"onboarding.steps.share_profile.body": "Let your friends know how to find you on Mastodon!",
@@ -415,6 +440,7 @@
"picture_in_picture.restore": "Lo tornar",
"poll.closed": "Tampat",
"poll.refresh": "Actualizar",
+ "poll.reveal": "Veire los resultats",
"poll.total_people": "{count, plural, one {# persona} other {# personas}}",
"poll.total_votes": "{count, plural, one {# vòte} other {# vòtes}}",
"poll.vote": "Votar",
@@ -482,11 +508,17 @@
"report_notification.open": "Dobrir lo senhalament",
"search.placeholder": "Recercar",
"search.search_or_paste": "Recercar o picar una URL",
+ "search_popout.language_code": "Còdi ISO de lenga",
+ "search_popout.options": "Opcions de recèrca",
+ "search_popout.quick_actions": "Accions rapidas",
+ "search_popout.recent": "Recèrcas recentas",
+ "search_popout.specific_date": "data especifica",
"search_popout.user": "utilizaire",
"search_results.accounts": "Perfils",
"search_results.all": "Tot",
"search_results.hashtags": "Etiquetas",
"search_results.nothing_found": "Cap de resultat per aquestes tèrmes de recèrca",
+ "search_results.see_all": "O veire tot",
"search_results.statuses": "Tuts",
"search_results.title": "Recèrca : {q}",
"server_banner.active_users": "utilizaires actius",
@@ -506,16 +538,20 @@
"status.copy": "Copiar lo ligam de l’estatut",
"status.delete": "Escafar",
"status.detailed_status": "Vista detalhada de la convèrsa",
+ "status.direct_indicator": "Mencion privada",
"status.edit": "Modificar",
"status.edited": "Modificat {date}",
"status.edited_x_times": "Modificat {count, plural, un {{count} còp} other {{count} còps}}",
"status.embed": "Embarcar",
+ "status.favourite": "Apondre als favorits",
"status.filter": "Filtrar aquesta publicacion",
"status.filtered": "Filtrat",
"status.hide": "Amagar la publicacion",
"status.history.created": "{name} o creèt lo {date}",
"status.history.edited": "{name} o modifiquèt lo {date}",
"status.load_more": "Cargar mai",
+ "status.media.open": "Clicar per dobrir",
+ "status.media.show": "Clicar per mostar",
"status.media_hidden": "Mèdia rescondut",
"status.mention": "Mencionar",
"status.more": "Mai",
@@ -546,6 +582,7 @@
"status.title.with_attachments": "{user} posted {attachmentCount, plural, one {an attachment} other {# attachments}}",
"status.translate": "Traduire",
"status.translated_from_with": "Traduch del {lang} amb {provider}",
+ "status.uncached_media_warning": "Apercebut indisponible",
"status.unmute_conversation": "Tornar mostrar la conversacion",
"status.unpin": "Tirar del perfil",
"subscribed_languages.lead": "Sonque las publicacions dins las lengas seleccionadas apreissaràn dins vòstre acuèlh e linha cronologica aprèp aqueste cambiament. Seleccionatz pas res per recebre las publicacions en quina lenga que siá.",
diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json
index ae9cef593849bc..69db89dc86f0b3 100644
--- a/app/javascript/mastodon/locales/ru.json
+++ b/app/javascript/mastodon/locales/ru.json
@@ -537,7 +537,7 @@
"relative_time.today": "сегодня",
"reply_indicator.cancel": "Отмена",
"report.block": "Заблокировать",
- "report.block_explanation": "В перестаните видеть посты этого пользователя, а он(а) больше не сможет подписаться на вас и читать ваши посты. Он(а) сможет понять что вы заблокировали его/её.",
+ "report.block_explanation": "Вы перестанете видеть посты этого пользователя, и он(а) больше не сможет подписаться на вас и читать ваши посты. Он(а) сможет понять, что вы заблокировали его/её.",
"report.categories.legal": "Правовая информация",
"report.categories.other": "Другое",
"report.categories.spam": "Спам",
diff --git a/app/javascript/mastodon/locales/si.json b/app/javascript/mastodon/locales/si.json
index 27c19adf8e27a2..7b26a9b4884755 100644
--- a/app/javascript/mastodon/locales/si.json
+++ b/app/javascript/mastodon/locales/si.json
@@ -1,79 +1,88 @@
{
+ "about.blocks": "මැදිහත්කරණ සේවාදායක",
+ "about.contact": "සබඳතාව:",
+ "about.disclaimer": "මාස්ටඩන් යනු නිදහස් විවෘත මූලාශ්ර මෘදුකාංගයකි. එය මාස්ටඩන් gGmbH හි වෙළඳ නාමයකි.",
+ "about.domain_blocks.suspended.title": "අත්හිටුවා ඇත",
+ "about.rules": "සේවාදායකයේ නීති",
"account.account_note_header": "සටහන",
"account.add_or_remove_from_list": "ලැයිස්තු වලින් එකතු හෝ ඉවත් කරන්න",
- "account.badges.bot": "ස්වයං ක්රමලේඛය",
+ "account.badges.bot": "ස්වයංක්රියයි",
"account.badges.group": "සමූහය",
"account.block": "@{name} අවහිර කරන්න",
"account.block_domain": "{domain} වසම අවහිර කරන්න",
+ "account.block_short": "අවහිර",
"account.blocked": "අවහිර කර ඇත",
"account.browse_more_on_origin_server": "මුල් පැතිකඩෙහි තවත් පිරික්සන්න",
- "account.cancel_follow_request": "Withdraw follow request",
"account.disable_notifications": "@{name} පළ කරන විට මට දැනුම් නොදෙන්න",
"account.domain_blocked": "වසම අවහිර කර ඇත",
"account.edit_profile": "පැතිකඩ සංස්කරණය",
"account.enable_notifications": "@{name} පළ කරන විට මට දැනුම් දෙන්න",
"account.endorse": "පැතිකඩෙහි විශේෂාංගය",
+ "account.featured_tags.last_status_never": "ලිපි නැත",
"account.follow": "අනුගමනය",
"account.followers": "අනුගාමිකයින්",
"account.followers.empty": "කිසිවෙක් අනුගමනය කර නැත.",
- "account.followers_counter": "{count, plural, one {{counter} අනුගාමිකයෙක්} other {{counter} අනුගාමිකයින්}}",
- "account.following": "අනුගමනය",
- "account.following_counter": "{count, plural, one {අනුගාමිකයින් {counter}} other {අනුගාමිකයින් {counter}}}",
+ "account.followers_counter": "{count, plural, one {අනුගාමිකයින් {counter}} other {අනුගාමිකයින් {counter}}}",
+ "account.following": "අනුගමන",
+ "account.following_counter": "{count, plural, one {අනුගමන {counter}} other {අනුගමන {counter}}}",
"account.follows.empty": "තවමත් කිසිවෙක් අනුගමනය නොකරයි.",
"account.follows_you": "ඔබව අනුගමනය කරයි",
- "account.hide_reblogs": "@{name}සිට බූස්ට් සඟවන්න",
+ "account.go_to_profile": "පැතිකඩට යන්න",
+ "account.joined_short": "එක් වූ දිනය",
"account.link_verified_on": "මෙම සබැඳියේ අයිතිය {date} දී පරීක්ෂා කෙරිණි",
- "account.locked_info": "මෙම ගිණුමේ රහස්යතා තත්ත්වය අගුලු දමා ඇත. හිමිකරු ඔවුන් අනුගමනය කළ හැක්කේ කාටදැයි හස්තීයව සමාලෝචනය කරයි.",
- "account.media": "මාධ්යය",
- "account.mention": "@{name} සැඳහුම",
+ "account.media": "මාධ්ය",
+ "account.mention": "@{name} සඳහන් කරන්ක",
"account.mute": "@{name} නිහඬ කරන්න",
+ "account.mute_short": "නිහඬ",
"account.muted": "නිහඬ කළා",
"account.posts": "ලිපි",
- "account.posts_with_replies": "ටූට්ස් සහ පිළිතුරු",
+ "account.posts_with_replies": "ලිපි සහ පිළිතුරු",
"account.report": "@{name} වාර්තා කරන්න",
- "account.requested": "අනුමැතිය බලාපොරොත්තුවෙන්",
"account.share": "@{name} ගේ පැතිකඩ බෙදාගන්න",
- "account.show_reblogs": "@{name}සිට බූස්ට් පෙන්වන්න",
- "account.statuses_counter": "{count, plural, one {{counter} ටූට්} other {{counter} ටූට්ස්}}",
+ "account.statuses_counter": "{count, plural, one {ලිපි {counter}} other {ලිපි {counter}}}",
"account.unblock": "@{name} අනවහිර කරන්න",
"account.unblock_domain": "{domain} වසම අනවහිර කරන්න",
"account.unblock_short": "අනවහිර",
"account.unendorse": "පැතිකඩෙහි විශේෂාංග නොකරන්න",
- "account.unfollow": "අනුගමනය නොකරන්න",
- "account.unmute": "@{name}නිහඬ නොකරන්න",
"account.unmute_short": "නොනිහඬ",
"account_note.placeholder": "සටහන යෙදීමට ඔබන්න",
- "admin.dashboard.daily_retention": "ලියාපදිංචි වීමෙන් පසු දිනකට පරිශීලක රඳවා ගැනීමේ අනුපාතය",
- "admin.dashboard.monthly_retention": "ලියාපදිංචි වීමෙන් පසු මාසය අනුව පරිශීලක රඳවා ගැනීමේ අනුපාතය",
- "admin.dashboard.retention.average": "සාමාන්යය",
- "admin.dashboard.retention.cohort": "ලියාපදිංචි වීමේ මාසය",
+ "admin.dashboard.retention.cohort": "ලියාපදිංචි මාසය",
"admin.dashboard.retention.cohort_size": "නව පරිශ්රීලකයින්",
"alert.rate_limited.message": "{retry_time, time, medium} කට පසුව උත්සාහ කරන්න.",
- "alert.rate_limited.title": "මිල සීමා සහිතයි",
- "alert.unexpected.message": "අනපේක්ෂිත දෝෂයක් ඇතිවුනා.",
+ "alert.rate_limited.title": "අනුපාතනය වී ඇත",
+ "alert.unexpected.message": "අනපේක්ෂිත දෝෂයක් සිදු විය.",
"alert.unexpected.title": "අපොයි!",
"announcement.announcement": "නිවේදනය",
- "attachments_list.unprocessed": "(සැකසුම් නොකළ)",
"audio.hide": "හඬපටය සඟවන්න",
"autosuggest_hashtag.per_week": "සතියකට {count}",
- "boost_modal.combo": "ඊළඟ වතාවේ මෙය මඟ හැරීමට ඔබට {combo} එබිය හැක",
+ "boost_modal.combo": "ඊළඟ වතාවේ මෙය මඟ හැරීමට {combo} එබීමට හැකිය",
+ "bundle_column_error.copy_stacktrace": "දෝෂ වාර්තාවේ පිටපතක්",
+ "bundle_column_error.error.title": "අපොයි!",
+ "bundle_column_error.network.title": "ජාලයේ දෝෂයකි",
"bundle_column_error.retry": "නැවත උත්සාහ කරන්න",
+ "bundle_column_error.return": "ආපසු මුලට යන්න",
+ "bundle_column_error.routing.title": "404",
"bundle_modal_error.close": "වසන්න",
- "bundle_modal_error.message": "මෙම සංරචකය පූරණය කිරීමේදී යම් දෙයක් වැරදී ඇත.",
+ "bundle_modal_error.message": "මෙම සංරචකය පූරණයේ දී යම් දෙයක් වැරදී ඇත.",
"bundle_modal_error.retry": "නැවත උත්සාහ කරන්න",
+ "closed_registrations_modal.find_another_server": "වෙනත් සේවාදායක",
+ "closed_registrations_modal.title": "මාස්ටඩන් හි ලියාපදිංචි වන්න",
"column.about": "පිලිබඳව",
"column.blocks": "අවහිර කළ අය",
- "column.bookmarks": "පොත් යොමු",
- "column.community": "දේශීය කාලරේඛාව",
+ "column.bookmarks": "පොත්යොමු",
+ "column.community": "ස්ථානීය කාලරේඛාව",
+ "column.direct": "පෞද්ගලික සැඳහුම්",
"column.directory": "පැතිකඩ පිරික්සන්න",
"column.domain_blocks": "අවහිර කළ වසම්",
+ "column.favourites": "ප්රියතමයන්",
+ "column.firehose": "සජීව සංග්රහ",
"column.follow_requests": "අනුගමන ඉල්ලීම්",
"column.home": "මුල් පිටුව",
- "column.lists": "ලේඛන",
+ "column.lists": "ලැයිස්තු",
"column.mutes": "නිහඬ කළ අය",
"column.notifications": "දැනුම්දීම්",
"column.pins": "ඇමිණූ ලිපි",
- "column.public": "ෆෙඩරේටඩ් කාලරේඛාව",
+ "column.public": "ඒකාබද්ධ කාලරේඛාව",
"column_back_button.label": "ආපසු",
"column_header.hide_settings": "සැකසුම් සඟවන්න",
"column_header.moveLeft_settings": "තීරුව වමට ගෙනයන්න",
@@ -87,70 +96,62 @@
"community.column_settings.remote_only": "දුරස්ථව පමණයි",
"compose.language.change": "භාෂාව සංශෝධනය",
"compose.language.search": "භාෂා සොයන්න...",
+ "compose.published.body": "ලිපිය පළ විය.",
+ "compose.published.open": "අරින්න",
+ "compose.saved.body": "ලිපිය සුරැකිණි.",
"compose_form.direct_message_warning_learn_more": "තව දැනගන්න",
- "compose_form.encryption_warning": "Mastodon හි පළ කිරීම් අන්තයේ සිට අවසානය දක්වා සංකේතනය කර නොමැත. Mastodon හරහා කිසිදු සංවේදී තොරතුරක් බෙදා නොගන්න.",
- "compose_form.hashtag_warning": "This post won't be listed under any hashtag as it is unlisted. Only public posts can be searched by hashtag.",
- "compose_form.lock_disclaimer": "ඔබගේ ගිණුම {locked}නොවේ. ඔබගේ අනුගාමිකයින්ට පමණක් පළ කිරීම් බැලීමට ඕනෑම කෙනෙකුට ඔබව අනුගමනය කළ හැක.",
+ "compose_form.encryption_warning": "මාස්ටඩන් වෙත පළ කරන දෑ අන්ත සංකේතනයෙන් ආරක්ෂා නොවේ. මාස්ටඩන් හරහා කිසිදු සංවේදී තොරතුරක් බෙදා නොගන්න.",
"compose_form.lock_disclaimer.lock": "අගුළු දමා ඇත",
"compose_form.placeholder": "ඔබගේ සිතුවිලි මොනවාද?",
"compose_form.poll.add_option": "තේරීමක් යොදන්න",
"compose_form.poll.duration": "මත විමසීමේ කාලය",
"compose_form.poll.option_placeholder": "තේරීම {number}",
"compose_form.poll.remove_option": "මෙම ඉවත් කරන්න",
- "compose_form.poll.switch_to_multiple": "තේරීම් කිහිපයක් ඉඩ දීම සඳහා මත විමසුම වෙනස් කරන්න",
- "compose_form.poll.switch_to_single": "තනි තේරීමකට ඉඩ දීම සඳහා මත විමසුම වෙනස් කරන්න",
+ "compose_form.poll.switch_to_multiple": "තේරීම් කිහිපයකට මත විමසුම වෙනස් කරන්න",
+ "compose_form.poll.switch_to_single": "තනි තේරීමකට මත විමසුම වෙනස් කරන්න",
"compose_form.publish": "ප්රකාශනය",
- "compose_form.publish_form": "Publish",
+ "compose_form.publish_form": "නව ලිපිය",
"compose_form.publish_loud": "{publish}!",
"compose_form.save_changes": "වෙනස්කම් සුරකින්න",
- "compose_form.sensitive.hide": "{count, plural, one {මාධ්ය සංවේදී ලෙස සලකුණු කරන්න} other {මාධ්ය සංවේදී ලෙස සලකුණු කරන්න}}",
- "compose_form.sensitive.marked": "{count, plural, one {මාධ්ය සංවේදී ලෙස සලකුණු කර ඇත} other {මාධ්ය සංවේදී ලෙස සලකුණු කර ඇත}}",
- "compose_form.sensitive.unmarked": "{count, plural, one {මාධ්ය සංවේදී ලෙස සලකුණු කර නැත} other {මාධ්ය සංවේදී ලෙස සලකුණු කර නැත}}",
- "compose_form.spoiler.marked": "අනතුරු ඇඟවීම පිටුපස පෙළ සඟවා ඇත",
- "compose_form.spoiler.unmarked": "ප්රයෝජනය සඟවා නැත",
+ "compose_form.spoiler.marked": "අන්තර්ගත අවවාදය ඉවත් කරන්න",
+ "compose_form.spoiler.unmarked": "අන්තර්ගත අවවාදයක් එක් කරන්න",
"compose_form.spoiler_placeholder": "අවවාදය මෙහි ලියන්න",
"confirmation_modal.cancel": "අවලංගු",
"confirmations.block.block_and_report": "අවහිර කර වාර්තා කරන්න",
"confirmations.block.confirm": "අවහිර",
"confirmations.block.message": "ඔබට {name} අවහිර කිරීමට වුවමනා ද?",
"confirmations.delete.confirm": "මකන්න",
- "confirmations.delete.message": "ඔබට මෙම තත්ත්වය මැකීමට අවශ්ය බව විශ්වාසද?",
+ "confirmations.delete.message": "ඔබට මෙම ලිපිය මැකීමට වුවමනා ද?",
"confirmations.delete_list.confirm": "මකන්න",
- "confirmations.delete_list.message": "ඔබට මෙම ලැයිස්තුව ස්ථිරවම මැකීමට අවශ්ය බව විශ්වාසද?",
+ "confirmations.delete_list.message": "ඔබට මෙම ලැයිස්තුව සදහටම මැකීමට වුවමනා ද?",
"confirmations.discard_edit_media.confirm": "ඉවත ලන්න",
"confirmations.discard_edit_media.message": "ඔබට මාධ්ය විස්තරයට හෝ පෙරදසුනට නොසුරකින ලද වෙනස්කම් තිබේ, කෙසේ වෙතත් ඒවා ඉවත දමන්නද?",
"confirmations.domain_block.confirm": "සම්පූර්ණ වසම අවහිර කරන්න",
- "confirmations.domain_block.message": "ඔබට සම්පූර්ණ {domain}අවහිර කිරීමට අවශ්ය බව ඔබට සැබවින්ම විශ්වාසද? බොහෝ අවස්ථාවලදී ඉලක්කගත බ්ලොක් හෝ නිශ්ශබ්ද කිරීම් කිහිපයක් ප්රමාණවත් වන අතර වඩාත් යෝග්ය වේ. ඔබ කිසිදු පොදු කාලරාමුවක හෝ ඔබගේ දැනුම්දීම් වල එම වසමේ අන්තර්ගතය නොදකිනු ඇත. එම වසමෙන් ඔබගේ අනුගාමිකයින් ඉවත් කරනු ලැබේ.",
+ "confirmations.edit.confirm": "සංස්කරණය",
"confirmations.logout.confirm": "නික්මෙන්න",
"confirmations.logout.message": "ඔබට නික්මෙන්න අවශ්ය බව විශ්වාසද?",
"confirmations.mute.confirm": "නිශ්ශබ්ද",
- "confirmations.mute.explanation": "මෙය ඔවුන්ගෙන් පළ කිරීම් සහ ඒවා සඳහන් කරන පළ කිරීම් සඟවයි, නමුත් එය ඔවුන්ට ඔබේ පළ කිරීම් බැලීමට සහ ඔබව අනුගමනය කිරීමට තවමත් ඉඩ ලබා දේ.",
- "confirmations.mute.message": "ඔබට {name} නිශ්ශබ්ද කිරීමට අවශ්ය බව විශ්වාසද?",
- "confirmations.redraft.confirm": "මකන්න සහ නැවත කෙටුම්පත් කරන්න",
+ "confirmations.mute.message": "{name} නිහඬ කිරීමට වුවමනා ද?",
"confirmations.reply.confirm": "පිළිතුර",
- "confirmations.reply.message": "දැන් පිළිතුරු දීම ඔබ දැනට රචනා කරන පණිවිඩය උඩින් ලියයි. ඔබට ඉදිරියට යාමට අවශ්ය බව විශ්වාසද?",
- "confirmations.unfollow.confirm": "අනුගමනය නොකරන්න",
- "confirmations.unfollow.message": "ඔබට {name}අනුගමනය නොකිරීමට අවශ්ය බව විශ්වාසද?",
"conversation.delete": "සංවාදය මකන්න",
"conversation.mark_as_read": "කියවූ බව යොදන්න",
"conversation.open": "සංවාදය බලන්න",
"conversation.with": "{names} සමඟ",
"copypaste.copied": "පිටපත් විය",
- "directory.federated": "දන්නා fediverse වලින්",
+ "copypaste.copy_to_clipboard": "පසුරුපුවරුවට පිටපතක්",
+ "directory.federated": "දන්නා ෆෙඩිවර්ස් වෙතින්",
"directory.local": "{domain} වෙතින් පමණි",
"directory.new_arrivals": "නව පැමිණීම්",
"directory.recently_active": "මෑත දී සක්රියයි",
- "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.",
- "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.",
- "embed.instructions": "පහත කේතය පිටපත් කිරීමෙන් මෙම තත්ත්වය ඔබේ වෙබ් අඩවියට ඇතුළත් කරන්න.",
- "embed.preview": "එය පෙනෙන්නේ කෙසේද යන්න මෙන්න:",
+ "disabled_account_banner.account_settings": "ගිණුමේ සැකසුම්",
+ "embed.instructions": "පහත කේතය පිටපත් කිරීමෙන් මෙම ලිපිය ඔබගේ අඩවියට කාවද්දන්න.",
+ "embed.preview": "මෙන්න එය පෙනෙන අන්දම:",
"emoji_button.activity": "ක්රියාකාරකම",
"emoji_button.clear": "මකන්න",
"emoji_button.custom": "අභිරුචි",
- "emoji_button.flags": "කොඩි",
"emoji_button.food": "ආහාර සහ පාන",
"emoji_button.label": "ඉමොජි යොදන්න",
- "emoji_button.nature": "ස්වභාවික",
+ "emoji_button.nature": "සොබාදහම",
"emoji_button.not_found": "ගැළපෙන ඉමෝජි හමු නොවිණි",
"emoji_button.objects": "වස්තූන්",
"emoji_button.people": "මිනිසුන්",
@@ -160,158 +161,152 @@
"emoji_button.symbols": "සංකේත",
"emoji_button.travel": "චාරිකා සහ ස්ථාන",
"empty_column.account_suspended": "ගිණුම අත්හිටුවා ඇත",
- "empty_column.account_timeline": "මෙහි දත් නැත!",
+ "empty_column.account_timeline": "මෙහි ලිපි නැත!",
"empty_column.account_unavailable": "පැතිකඩ නොතිබේ",
"empty_column.blocks": "කිසිදු පරිශීලකයෙකු අවහිර කර නැත.",
- "empty_column.bookmarked_statuses": "ඔබට තවමත් පිටු සලකුණු කළ මෙවලම් කිසිවක් නොමැත. ඔබ එකක් පිටු සලකුණු කළ විට, එය මෙහි පෙන්වනු ඇත.",
- "empty_column.community": "දේශීය කාලරේඛාව හිස් ය. පන්දුව පෙරළීමට ප්රසිද්ධියේ යමක් ලියන්න!",
+ "empty_column.bookmarked_statuses": "ඔබ සතුව පොත්යොමු තබන ලද ලිපි කිසිවක් නැත. ඔබ පොත්යොමුවක් තබන විට, එය මෙහි දිස්වනු ඇත.",
"empty_column.domain_blocks": "අවහිර කරන ලද වසම් නැත.",
"empty_column.explore_statuses": "දැන් කිසිවක් නැඹුරු නොවේ. පසුව නැවත පරීක්ෂා කරන්න!",
- "empty_column.follow_requests": "ඔබට තවමත් අනුගමනය කිරීමේ ඉල්ලීම් කිසිවක් නොමැත. ඔබට එකක් ලැබුණු විට, එය මෙහි පෙන්වනු ඇත.",
- "empty_column.hashtag": "මෙම හැෂ් ටැග් එකේ තවම කිසිවක් නොමැත.",
- "empty_column.home": "ඔබගේ නිවසේ කාලරේඛාව හිස්ය! එය පිරවීම සඳහා තවත් පුද්ගලයින් අනුගමනය කරන්න. {suggestions}",
- "empty_column.list": "මෙම ලැයිස්තුවේ තවමත් කිසිවක් නොමැත. මෙම ලැයිස්තුවේ සාමාජිකයන් නව තත්ව පළ කරන විට, ඔවුන් මෙහි දිස් වනු ඇත.",
+ "empty_column.follow_requests": "ඔබට තවමත් අනුගමන ඉල්ලීම් ලැබී නැත. ඉල්ලීමක් ලැබුණු විට, එය මෙහි පෙන්වනු ඇත.",
+ "empty_column.home": "මුල් පිටුව හිස් ය! මෙය පිරවීමට බොහෝ පුද්ගලයින් අනුගමනය කරන්න.",
"empty_column.lists": "ඔබට තවමත් ලැයිස්තු කිසිවක් නැත. ඔබ එකක් සාදන විට, එය මෙහි පෙන්වනු ඇත.",
"empty_column.mutes": "ඔබ තවමත් කිසිදු පරිශීලකයෙකු නිහඬ කර නැත.",
- "empty_column.notifications": "ඔබට තවම දැනුම්දීම් කිසිවක් නැත. වෙනත් පුද්ගලයින් ඔබ සමඟ අන්තර් ක්රියා කරන විට, ඔබ එය මෙහි දකිනු ඇත.",
- "empty_column.public": "මෙහි කිසිවක් නැත! යමක් ප්රසිද්ධියේ ලියන්න, නැතහොත් එය පිරවීම සඳහා වෙනත් සේවාදායකයන්ගෙන් පරිශීලකයන් හස්තීයව අනුගමනය කරන්න",
+ "empty_column.notifications": "ඔබට දැනුම්දීම් ලැබී නැත. අන් අය සහ ඔබ අතර අන්යෝන්ය බලපවත්වන දෑ මෙහි දිස්වනු ඇත.",
"error.unexpected_crash.explanation": "අපගේ කේතයේ දෝෂයක් හෝ බ්රවුසර ගැළපුම් ගැටලුවක් හේතුවෙන්, මෙම පිටුව නිවැරදිව ප්රදර්ශනය කළ නොහැක.",
"error.unexpected_crash.explanation_addons": "මෙම පිටුව නිවැරදිව ප්රදර්ශනය කළ නොහැක. මෙම දෝෂය බ්රවුසර ඇඩෝනයක් හෝ ස්වයංක්රීය පරිවර්තන මෙවලම් නිසා ඇති විය හැක.",
- "error.unexpected_crash.next_steps": "පිටුව නැවුම් කිරීමට උත්සාහ කරන්න. එය උදව් නොකළහොත්, ඔබට තවමත් වෙනත් බ්රවුසරයක් හෝ ස්වදේශීය යෙදුමක් හරහා Mastodon භාවිත කිරීමට හැකි වේ.",
- "error.unexpected_crash.next_steps_addons": "ඒවා අක්රිය කර පිටුව නැවුම් කිරීමට උත්සාහ කරන්න. එය උදව් නොකළහොත්, ඔබට තවමත් වෙනත් බ්රවුසරයක් හෝ ස්වදේශීය යෙදුමක් හරහා Mastodon භාවිත කිරීමට හැකි වේ.",
- "errors.unexpected_crash.copy_stacktrace": "ස්ටැක්ට්රේස් පසුරු පුවරුවට පිටපත් කරන්න",
+ "error.unexpected_crash.next_steps": "පිටුව නැවුම් කර බලන්න. එයින් ඵලක් නොවේ නම්, වෙනත් අතිරික්සුවක් හෝ නිසග යෙදුමක් හරහා මාස්ටඩන් භාවිතා කරන්න.",
+ "error.unexpected_crash.next_steps_addons": "ඒවා අබල කර පිටුව නැවුම් කරන්න. එයින් ඵලක් නොවේ නම්, වෙනත් අතිරික්සුවක් හෝ නිසග යෙදුමක් හරහා මාස්ටඩන් භාවිතා කරන්න.",
"errors.unexpected_crash.report_issue": "ගැටළුව වාර්තාව",
"explore.search_results": "සෙවුම් ප්රතිඵල",
- "explore.title": "ගවේශණය",
+ "explore.suggested_follows": "පුද්ගලයින්",
+ "explore.title": "ගවේශනය",
+ "explore.trending_links": "පුවත්",
+ "explore.trending_statuses": "ලිපි",
"filter_modal.added.expired_title": "පෙරහන ඉකුත්ය!",
"filter_modal.added.review_and_configure_title": "පෙරහන් සැකසුම්",
"filter_modal.added.settings_link": "සැකසුම් පිටුව",
+ "filter_modal.added.title": "පෙරහන එක් කළා!",
"filter_modal.select_filter.expired": "ඉකුත්ය",
"filter_modal.select_filter.prompt_new": "නව ප්රවර්ගය: {name}",
"filter_modal.select_filter.search": "සොයන්න හෝ සාදන්න",
- "follow_request.authorize": "අවසරලත්",
+ "filter_modal.select_filter.title": "මෙම ලිපිය පෙරන්න",
+ "filter_modal.title.status": "ලිපියක් පෙරන්න",
+ "firehose.local": "මෙම සේවාදායකය",
+ "firehose.remote": "වෙනත් සේවාදායක",
"follow_request.reject": "ප්රතික්ෂේප",
- "follow_requests.unlocked_explanation": "ඔබගේ ගිණුම අගුලු දමා නොතිබුණද, {domain} කාර්ය මණ්ඩලය සිතුවේ ඔබට මෙම ගිණුම් වලින් ලැබෙන ඉල්ලීම් හස්තීයව සමාලෝචනය කිරීමට අවශ්ය විය හැකි බවයි.",
+ "footer.about": "පිළිබඳව",
+ "footer.directory": "පැතිකඩ නාමාවලිය",
+ "footer.get_app": "යෙදුම ගන්න",
+ "footer.invite": "ආරාධනා කරන්න",
+ "footer.keyboard_shortcuts": "යතුරුපුවරුවේ කෙටිමං",
+ "footer.privacy_policy": "රහස්යතා ප්රතිපත්තිය",
+ "footer.source_code": "මූලාශ්ර කේතය බලන්න",
+ "footer.status": "තත්වය",
"generic.saved": "සුරැකිණි",
"getting_started.heading": "පටන් ගන්න",
"hashtag.column_header.tag_mode.all": "සහ {additional}",
"hashtag.column_header.tag_mode.any": "හෝ {additional}",
- "hashtag.column_header.tag_mode.none": "{additional}නොමැතිව",
"hashtag.column_settings.select.no_options_message": "යෝජනා හමු නොවිණි",
- "hashtag.column_settings.select.placeholder": "හැෂ් ටැග්…ඇතුලත් කරන්න",
"hashtag.column_settings.tag_mode.all": "මේ සියල්ලම",
- "hashtag.column_settings.tag_mode.any": "ඇතුළත් එකක්",
"hashtag.column_settings.tag_mode.none": "මේ කිසිවක් නැත",
"hashtag.column_settings.tag_toggle": "මෙම තීරුවේ අමතර ටැග් ඇතුළත් කරන්න",
+ "home.actions.go_to_explore": "නැගී එන දෑ බලන්න",
+ "home.actions.go_to_suggestions": "පුද්ගලයින් සොයන්න",
"home.column_settings.basic": "මූලික",
- "home.column_settings.show_reblogs": "බූස්ට් පෙන්වන්න",
"home.column_settings.show_replies": "පිළිතුරු පෙන්වන්න",
+ "home.explore_prompt.title": "මෙය ඔබගේ මාස්ටඩන් මුල් පිටුවයි.",
"home.hide_announcements": "නිවේදන සඟවන්න",
+ "home.pending_critical_update.link": "යාවත්කාල බලන්න",
"home.show_announcements": "නිවේදන පෙන්වන්න",
- "intervals.full.days": "{number, plural, one {# දින} other {# දින}}",
- "intervals.full.hours": "{number, plural, one {# පැය} other {# පැය}}",
- "intervals.full.minutes": "{number, plural, one {විනාඩි #} other {# මිනිත්තු}}",
+ "interaction_modal.login.action": "මුලට ගෙනයන්න",
+ "interaction_modal.on_this_server": "මෙම සේවාදායකයෙහි",
+ "interaction_modal.title.favourite": "{name}ගේ ලිපිය ප්රිය කරන්න",
+ "interaction_modal.title.follow": "{name} අනුගමනය",
+ "intervals.full.days": "{number, plural, one {දවස් #} other {දවස් #}}",
+ "intervals.full.hours": "{number, plural, one {පැය #} other {පැය #}}",
+ "intervals.full.minutes": "{number, plural, one {විනාඩි #} other {විනාඩි #}}",
"keyboard_shortcuts.back": "ආපසු යාත්රණය",
- "keyboard_shortcuts.blocked": "අවහිර කළ පරිශීලක ලැයිස්තුව විවෘත කිරීමට",
- "keyboard_shortcuts.boost": "වැඩි කිරීමට",
- "keyboard_shortcuts.column": "එක් තීරුවක තත්ත්වය නාභිගත කිරීමට",
- "keyboard_shortcuts.compose": "රචනා පාඨ ප්රදේශය නාභිගත කිරීමට",
"keyboard_shortcuts.description": "සවිස්තරය",
- "keyboard_shortcuts.direct": "to open direct messages column",
- "keyboard_shortcuts.down": "ලැයිස්තුවේ පහළට ගමන් කිරීමට",
+ "keyboard_shortcuts.down": "ලැයිස්තුවේ පහළට ගෙනයන්න",
"keyboard_shortcuts.enter": "ලිපිය අරින්න",
+ "keyboard_shortcuts.favourites": "ප්රියතමයන් ලැයිස්තුව අරින්න",
"keyboard_shortcuts.federated": "ෆෙඩරේටඩ් කාලරාමුව විවෘත කිරීමට",
"keyboard_shortcuts.heading": "යතුරුපුවරු කෙටිමං",
- "keyboard_shortcuts.home": "නිවසේ කාලරේඛාව විවෘත කිරීමට",
"keyboard_shortcuts.hotkey": "උණු යතුර",
- "keyboard_shortcuts.legend": "මෙම පුරාවෘත්තය ප්රදර්ශනය කිරීමට",
"keyboard_shortcuts.local": "දේශීය කාලරේඛාව විවෘත කිරීමට",
"keyboard_shortcuts.mention": "කතුවරයා සඳහන් කිරීමට",
- "keyboard_shortcuts.muted": "නිශ්ශබ්ද පරිශීලක ලැයිස්තුව විවෘත කිරීමට",
+ "keyboard_shortcuts.muted": "නිහඬ කළ අය පෙන්වන්න",
"keyboard_shortcuts.my_profile": "ඔබගේ පැතිකඩ අරින්න",
"keyboard_shortcuts.notifications": "දැනුම්දීම් තීරුව විවෘත කිරීමට",
"keyboard_shortcuts.open_media": "මාධ්ය අරින්න",
- "keyboard_shortcuts.pinned": "ඇමිණූ ලිපි ලේඛනය අරින්න",
+ "keyboard_shortcuts.pinned": "ඇමිණූ ලිපි ලැයිස්තුව අරින්න",
"keyboard_shortcuts.profile": "කතෘගේ පැතිකඩ අරින්න",
"keyboard_shortcuts.reply": "පිළිතුරු දීමට",
- "keyboard_shortcuts.requests": "පහත ඉල්ලීම් ලැයිස්තුව විවෘත කිරීමට",
- "keyboard_shortcuts.search": "සෙවුම් අවධානය යොමු කිරීමට",
- "keyboard_shortcuts.spoilers": "CW ක්ෂේත්රය පෙන්වීමට/සැඟවීමට",
+ "keyboard_shortcuts.spoilers": "CW ක්ෂේත්රය පෙන්වන්න/සඟවන්න",
"keyboard_shortcuts.start": "\"පටන් ගන්න\" තීරුව අරින්න",
- "keyboard_shortcuts.toggle_hidden": "CW පිටුපස පෙළ පෙන්වීමට/සැඟවීමට",
"keyboard_shortcuts.toggle_sensitivity": "මාධ්ය පෙන්වන්න/සඟවන්න",
- "keyboard_shortcuts.toot": "අලුත්ම ටූට් එකක් පටන් ගන්න",
- "keyboard_shortcuts.unfocus": "අවධානය යොමු නොකිරීමට textarea/search රචනා කරන්න",
- "keyboard_shortcuts.up": "ලැයිස්තුවේ ඉහළට යාමට",
+ "keyboard_shortcuts.toot": "නව ලිපියක් අරඹන්න",
+ "keyboard_shortcuts.up": "ලැයිස්තුවේ ඉහළට ගෙනයන්න",
"lightbox.close": "වසන්න",
- "lightbox.compress": "රූප බැලීමේ කොටුව සම්පීඩනය කරන්න",
- "lightbox.expand": "රූප දර්ශන පෙට්ටිය දිග හරින්න",
"lightbox.next": "ඊළඟ",
"lightbox.previous": "පෙර",
"limited_account_hint.action": "කෙසේ හෝ පැතිකඩ පෙන්වන්න",
- "lists.account.add": "ලේඛනයට දමන්න",
- "lists.account.remove": "ලේඛනයෙන් ඉවතලන්න",
- "lists.delete": "ලේඛනය මකන්න",
- "lists.edit": "ලේඛනය සංස්කරණය",
- "lists.edit.submit": "මාතෘකාව වෙනස් කරන්න",
- "lists.new.create": "ලැයිස්තුව එකතු කරන්න",
- "lists.new.title_placeholder": "නව ලැයිස්තු මාතෘකාව",
- "lists.replies_policy.followed": "අනුගමනය කරන ඕනෑම පරිශීලකයෙක්",
- "lists.replies_policy.list": "ලැයිස්තුවේ සාමාජිකයන්",
+ "lists.account.add": "ලැයිස්තුවට දමන්න",
+ "lists.account.remove": "ලැයිස්තුවෙන් ඉවතලන්න",
+ "lists.delete": "ලැයිස්තුව මකන්න",
+ "lists.edit": "ලැයිස්තුව සංස්කරණය",
+ "lists.edit.submit": "සිරැසිය සංශෝධනය",
+ "lists.new.title_placeholder": "නව ලැයිස්තුවේ සිරැසිය",
+ "lists.replies_policy.list": "ලැයිස්තුවේ සාමාජිකයින්",
"lists.replies_policy.none": "කිසිවෙක් නැත",
"lists.replies_policy.title": "පිළිතුරු පෙන්වන්න:",
- "lists.search": "ඔබ අනුගමනය කරන පුද්ගලයින් අතර සොයන්න",
- "lists.subheading": "ඔබගේ ලේඛන",
- "load_pending": "{count, plural, one {# නව අයිතමයක්} other {නව අයිතම #ක්}}",
+ "lists.subheading": "ඔබගේ ලැයිස්තු",
"loading_indicator.label": "පූරණය වෙමින්...",
- "media_gallery.toggle_visible": "{number, plural, one {රූපය සඟවන්න} other {පින්තූර සඟවන්න}}",
"mute_modal.duration": "පරාසය",
- "mute_modal.hide_notifications": "මෙම පරිශීලකයාගෙන් දැනුම්දීම් සඟවන්නද?",
- "mute_modal.indefinite": "අවිනිශ්චිත",
+ "mute_modal.hide_notifications": "මෙම පුද්ගලයාගේ දැනුම්දීම් සඟවන්නද?",
+ "navigation_bar.about": "පිළිබඳව",
"navigation_bar.blocks": "අවහිර කළ අය",
"navigation_bar.bookmarks": "පොත්යොමු",
- "navigation_bar.community_timeline": "දේශීය කාලරේඛාව",
- "navigation_bar.compose": "නව ටූට් සාදන්න",
- "navigation_bar.discover": "සොයා ගන්න",
+ "navigation_bar.community_timeline": "ස්ථානීය කාලරේඛාව",
+ "navigation_bar.compose": "නව ලිපියක් ලියන්න",
+ "navigation_bar.direct": "පෞද්ගලික සැඳහුම්",
"navigation_bar.domain_blocks": "අවහිර කළ වසම්",
"navigation_bar.edit_profile": "පැතිකඩ සංස්කරණය",
- "navigation_bar.explore": "ගවේෂණය කරන්න",
+ "navigation_bar.explore": "ගවේශනය",
+ "navigation_bar.favourites": "ප්රියතමයන්",
"navigation_bar.filters": "නිහඬ කළ වචන",
"navigation_bar.follow_requests": "අනුගමන ඉල්ලීම්",
- "navigation_bar.follows_and_followers": "අනුගමනය හා අනුගාමිකයින්",
- "navigation_bar.lists": "ලේඛන",
+ "navigation_bar.follows_and_followers": "අනුගමන හා අනුගාමික",
+ "navigation_bar.lists": "ලැයිස්තු",
"navigation_bar.logout": "නික්මෙන්න",
"navigation_bar.mutes": "නිහඬ කළ අය",
"navigation_bar.personal": "පුද්ගලික",
"navigation_bar.pins": "ඇමිණූ ලිපි",
"navigation_bar.preferences": "අභිප්රේත",
- "navigation_bar.public_timeline": "ෆෙඩරේටඩ් කාලරේඛාව",
+ "navigation_bar.public_timeline": "ඒකාබද්ධ කාලරේඛාව",
+ "navigation_bar.search": "සොයන්න",
"navigation_bar.security": "ආරක්ෂාව",
"not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.",
- "notification.admin.report": "{name} වාර්තා {target}",
- "notification.admin.sign_up": "{name} අත්සන් කර ඇත",
"notification.follow": "{name} ඔබව අනුගමනය කළා",
- "notification.follow_request": "{name} ඔබව අනුගමනය කිරීමට ඉල්ලා ඇත",
"notification.mention": "{name} ඔබව සඳහන් කර ඇත",
"notification.own_poll": "ඔබගේ මත විමසුම නිමයි",
"notification.poll": "ඔබ ඡන්දය දුන් මත විමසුමක් නිමයි",
- "notification.reblog": "{name} ඔබේ තත්ත්වය ඉහළ නැංවීය",
"notification.status": "{name} දැන් පළ කළා",
- "notification.update": "{name} පළ කිරීමක් සංස්කරණය කළා",
+ "notification.update": "{name} ලිපියක් සංස්කරණය කළා",
"notifications.clear": "දැනුම්දීම් මකන්න",
- "notifications.clear_confirmation": "ඔබට ඔබගේ සියලු දැනුම්දීම් ස්ථිරවම හිස් කිරීමට අවශ්ය බව විශ්වාසද?",
+ "notifications.clear_confirmation": "දැනුම්දීම් සියල්ල හිස් කිරීමට වුවමනා ද?",
"notifications.column_settings.admin.report": "නව වාර්තා:",
"notifications.column_settings.admin.sign_up": "නව ලියාපදිංචි:",
"notifications.column_settings.alert": "වැඩතල දැනුම්දීම්",
+ "notifications.column_settings.favourite": "ප්රියතමයන්:",
"notifications.column_settings.filter_bar.advanced": "සියළු ප්රවර්ග පෙන්වන්න",
"notifications.column_settings.filter_bar.category": "ඉක්මන් පෙරහන් තීරුව",
"notifications.column_settings.filter_bar.show_bar": "පෙරහන් තීරුව පෙන්වන්න",
"notifications.column_settings.follow": "නව අනුගාමිකයින්:",
"notifications.column_settings.follow_request": "නව අනුගමන ඉල්ලීම්:",
"notifications.column_settings.mention": "සැඳහුම්:",
- "notifications.column_settings.poll": "ඡන්ද ප්රතිඵල:",
+ "notifications.column_settings.poll": "මත විමසුමේ ප්රතිඵල:",
"notifications.column_settings.push": "තල්ලු දැනුම්දීම්",
- "notifications.column_settings.reblog": "තල්ලු කිරීම්:",
"notifications.column_settings.show": "තීරුවෙහි පෙන්වන්න",
"notifications.column_settings.sound": "ශබ්දය වාදනය",
"notifications.column_settings.status": "නව ලිපි:",
@@ -319,42 +314,27 @@
"notifications.column_settings.unread_notifications.highlight": "නොකියවූ දැනුම්දීම් ඉස්මතු කරන්න",
"notifications.column_settings.update": "සංශෝධන:",
"notifications.filter.all": "සියල්ල",
- "notifications.filter.boosts": "බූස්ට් කරයි",
+ "notifications.filter.favourites": "ප්රියතමයන්",
"notifications.filter.follows": "අනුගමනය",
"notifications.filter.mentions": "සැඳහුම්",
- "notifications.filter.polls": "ඡන්ද ප්රතිඵල",
- "notifications.filter.statuses": "ඔබ අනුගමනය කරන පුද්ගලයින්ගෙන් යාවත්කාලීන",
- "notifications.grant_permission": "අවසර දෙන්න.",
+ "notifications.filter.polls": "මත විමසුමේ ප්රතිඵල",
"notifications.group": "දැනුම්දීම් {count}",
"notifications.mark_as_read": "සියළු දැනුම්දීම් කියවූ බව යොදන්න",
- "notifications.permission_denied": "කලින් ප්රතික්ෂේප කළ බ්රවුසර අවසර ඉල්ලීම හේතුවෙන් ඩෙස්ක්ටොප් දැනුම්දීම් නොමැත",
- "notifications.permission_denied_alert": "බ්රවුසර අවසරය පෙර ප්රතික්ෂේප කර ඇති බැවින්, ඩෙස්ක්ටොප් දැනුම්දීම් සබල කළ නොහැක",
- "notifications.permission_required": "අවශ්ය අවසරය ලබා දී නොමැති නිසා ඩෙස්ක්ටොප් දැනුම්දීම් නොමැත.",
"notifications_permission_banner.enable": "වැඩතල දැනුම්දීම් සබල කරන්න",
- "notifications_permission_banner.how_to_control": "Mastodon විවෘතව නොමැති විට දැනුම්දීම් ලබා ගැනීමට, ඩෙස්ක්ටොප් දැනුම්දීම් සබල කරන්න. ඔබට ඒවා සක්රිය කළ පසු ඉහත {icon} බොත්තම හරහා ඩෙස්ක්ටොප් දැනුම්දීම් ජනනය කරන්නේ කුමන ආකාරයේ අන්තර්ක්රියාද යන්න නිවැරදිව පාලනය කළ හැක.",
- "notifications_permission_banner.title": "කිසිම දෙයක් අතපසු කරන්න එපා",
- "onboarding.actions.go_to_explore": "See what's trending",
- "onboarding.actions.go_to_home": "Go to your home feed",
- "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!",
- "onboarding.follows.title": "Popular on Mastodon",
- "onboarding.start.lead": "Your new Mastodon account is ready to go. Here's how you can make the most of it:",
- "onboarding.start.skip": "Want to skip right ahead?",
- "onboarding.steps.follow_people.body": "You curate your own feed. Lets fill it with interesting people.",
- "onboarding.steps.follow_people.title": "Follow {count, plural, one {one person} other {# people}}",
- "onboarding.steps.publish_status.body": "Say hello to the world.",
- "onboarding.steps.setup_profile.body": "Others are more likely to interact with you with a filled out profile.",
- "onboarding.steps.setup_profile.title": "Customize your profile",
- "onboarding.steps.share_profile.body": "Let your friends know how to find you on Mastodon!",
- "onboarding.steps.share_profile.title": "Share your profile",
- "picture_in_picture.restore": "ආපහු දාන්න",
+ "notifications_permission_banner.title": "කිසිවක් අතපසු නොකරන්න",
+ "onboarding.actions.go_to_explore": "නැගී එන දෑ වෙත ගෙනයන්න",
+ "onboarding.compose.template": "ආයුබෝ #මාස්ටඩන්!",
+ "onboarding.share.title": "ඔබගේ පැතිකඩ බෙදාගන්න",
+ "onboarding.steps.publish_status.title": "පළමු ලිපිය පළ කරන්න",
+ "onboarding.steps.setup_profile.title": "ඔබගේ පැතිකඩ අභිරුචිකරණය",
+ "onboarding.steps.share_profile.body": "මාස්ටඩන් හි ඔබව සොයා ගන්නේ කෙසේදැයි යහළුවන්ට දන්වන්න",
+ "onboarding.steps.share_profile.title": "ඔබගේ පැතිකඩ බෙදාගන්න",
"poll.closed": "වසා ඇත",
"poll.refresh": "නැවුම් කරන්න",
- "poll.total_people": "{count, plural, one {# පුද්ගලයා} other {# මහජන}}",
- "poll.total_votes": "{count, plural, one {# ඡන්දය} other {ඡන්ද #}}",
+ "poll.reveal": "ප්රතිඵල බලන්න",
"poll.vote": "ඡන්දය",
- "poll.voted": "ඔබ මෙම පිළිතුරට ඡන්දය දුන්නා",
- "poll.votes": "{votes, plural, one {# ඡන්දය} other {ඡන්ද #}}",
- "poll_button.add_poll": "මත විමසුමක් යොදන්න",
+ "poll.voted": "ඔබ මෙම උත්තරයට ඡන්දය දී ඇත",
+ "poll_button.add_poll": "මත විමසුමක් අරඹන්න",
"poll_button.remove_poll": "මත විමසුම ඉවතලන්න",
"privacy.change": "ලිපියේ රහස්යතාව සංශෝධනය",
"privacy.direct.long": "සඳහන් කළ අයට දිස්වෙයි",
@@ -363,13 +343,11 @@
"privacy.private.short": "අනුගාමිකයින් පමණි",
"privacy.public.long": "සැමට දිස්වෙයි",
"privacy.public.short": "ප්රසිද්ධ",
- "privacy.unlisted.long": "සැමට දෘශ්යමාන, නමුත් සොයාගැනීමේ විශේෂාංග වලින් ඉවත් විය",
- "privacy.unlisted.short": "ලැයිස්තුගත නොකළ",
+ "privacy_policy.title": "රහස්යතා ප්රතිපත්තිය",
"refresh": "නැවුම් කරන්න",
"regeneration_indicator.label": "පූරණය වෙමින්…",
- "regeneration_indicator.sublabel": "ඔබේ නිවසේ පෝෂණය සූදානම් වෙමින් පවතී!",
"relative_time.days": "ද. {number}",
- "relative_time.full.days": "{number, plural, one {# දින} other {# දින}} පෙර",
+ "relative_time.full.days": "{number, plural, one {දවස් #} other {දවස් #}} කට පෙර",
"relative_time.full.hours": "{number, plural, one {පැය #} other {පැය #}} කට පෙර",
"relative_time.full.just_now": "මේ දැන්",
"relative_time.full.minutes": "{number, plural, one {විනාඩි #} other {විනාඩි #}} කට පෙර",
@@ -381,25 +359,24 @@
"relative_time.today": "අද",
"reply_indicator.cancel": "අවලංගු කරන්න",
"report.block": "අවහිර",
- "report.block_explanation": "ඔබට ඔවුන්ගේ පෝස්ට් නොපෙනේ. ඔවුන්ට ඔබේ පළ කිරීම් බැලීමට හෝ ඔබව අනුගමනය කිරීමට නොහැකි වනු ඇත. ඔවුන් අවහිර කර ඇති බව ඔවුන්ට පැවසිය හැකිය.",
"report.categories.other": "වෙනත්",
"report.categories.spam": "ආයාචිත",
- "report.categories.violation": "අන්තර්ගතය සේවාදායක නීති එකක් හෝ කිහිපයක් උල්ලංඝනය කරයි",
+ "report.categories.violation": "අන්තර්ගතය නිසා සේවාදායකයේ නීතියක් හෝ කිහිපයක් කඩ වේ",
"report.category.subtitle": "හොඳම ගැලපීම තෝරන්න",
"report.category.title": "මෙම {type}සමඟ සිදුවන්නේ කුමක්දැයි අපට කියන්න",
"report.category.title_account": "පැතිකඩ",
- "report.category.title_status": "තැපැල්",
+ "report.category.title_status": "ලිපිය",
"report.close": "අහවරයි",
"report.comment.title": "අප දැනගත යුතු යැයි ඔබ සිතන තවත් යමක් තිබේද?",
"report.forward": "{target} වෙත හරවන්න",
"report.forward_hint": "ගිණුම වෙනත් සේවාදායකයකින්. වාර්තාවේ නිර්නාමික පිටපතක් එතනටත් එවන්න?",
"report.mute": "නිහඬ",
- "report.mute_explanation": "ඔබට ඔවුන්ගේ පෝස්ට් නොපෙනේ. ඔවුන්ට තවමත් ඔබව අනුගමනය කිරීමට සහ ඔබේ පළ කිරීම් දැකීමට හැකි අතර ඒවා නිශ්ශබ්ද කර ඇති බව නොදැනේ.",
+ "report.mute_explanation": "ඔබ ඔවුන්ගේ ලිපි නොදකිනු ඇත. ඔවුන්ට තවමත් ඔබව අනුගමනයට සහ ඔබගේ ලිපි දැකීමට හැකි අතර ඔවුන්ව නිහඬ කර ඇති බව දැන ගැනීමට නොහැකිය.",
"report.next": "ඊළඟ",
"report.placeholder": "අමතර අදහස්",
"report.reasons.dislike": "මම එයට අකැමතියි",
"report.reasons.dislike_description": "ඒක බලන්න ඕන දෙයක් නෙවෙයි",
- "report.reasons.other": "ඒක වෙන දෙයක්",
+ "report.reasons.other": "එය වෙනත් දෙයක්",
"report.reasons.other_description": "ගැටළුව වෙනත් වර්ග වලට නොගැලපේ",
"report.reasons.spam": "එය අයාචිතයි",
"report.reasons.spam_description": "අනිෂ්ට සබැඳි, ව්යාජ නියැලීම, හෝ පුනරාවර්තන පිළිතුරු",
@@ -408,44 +385,59 @@
"report.rules.subtitle": "අදාළ සියල්ල තෝරන්න",
"report.rules.title": "කුමන නීති උල්ලංඝනය කරන්නේද?",
"report.statuses.subtitle": "අදාළ සියල්ල තෝරන්න",
- "report.statuses.title": "මෙම වාර්තාව උපස්ථ කරන පෝස්ට් තිබේද?",
+ "report.statuses.title": "මෙම වාර්තාව උපස්ථ කළ ලිපි තිබේ ද?",
"report.submit": "යොමන්න",
- "report.target": "වාර්තාව {target}",
- "report.thanks.take_action": "Mastodon හි ඔබ දකින දේ පාලනය කිරීම සඳහා ඔබේ විකල්ප මෙන්න:",
+ "report.target": "{target} වාර්තා කිරීම",
+ "report.thanks.take_action": "මාස්ටඩන් හි ඔබ දකින දෑ පාලනයට තිබෙන විකල්ප:",
"report.thanks.take_action_actionable": "අපි මෙය සමාලෝචනය කරන අතරතුර, ඔබට @{name}ට එරෙහිව පියවර ගත හැක:",
"report.thanks.title": "මෙය නොපෙන්විය යුතුද?",
"report.thanks.title_actionable": "වාර්තා කිරීමට ස්තූතියි, අපි මේ ගැන සොයා බලමු.",
"report.unfollow": "@{name}අනුගමනය නොකරන්න",
- "report.unfollow_explanation": "ඔබ මෙම ගිණුම අනුගමනය කරයි. ඔබේ නිවසේ සංග්රහයේ ඔවුන්ගේ පළ කිරීම් තවදුරටත් නොදැකීමට, ඒවා අනුගමනය නොකරන්න.",
+ "report.unfollow_explanation": "ඔබ මෙම ගිණුම අනුගමනය කරයි. ඔබගේ මුල් පිටුවේ ඔවුන්ගේ ලිපි නොදැකීමට, ඔවුන්ව තවදුරටත් අනුගමනය නොකරන්න.",
"report_notification.attached_statuses": "{count, plural, one {ලිපි {count}} other {ලිපි {count} ක්}} අමුණා ඇත",
"report_notification.categories.other": "වෙනත්",
"report_notification.categories.spam": "ආයාචිත",
"report_notification.categories.violation": "නීතිය කඩ කිරීම",
"report_notification.open": "විවෘත වාර්තාව",
+ "search.no_recent_searches": "මෑත සෙවීම් නැත",
"search.placeholder": "සොයන්න",
+ "search.quick_action.account_search": "ගැළපෙන පැතිකඩ {x}",
+ "search.quick_action.go_to_account": "{x} පැතිකඩ වෙත යන්න",
+ "search.quick_action.open_url": "ලිපිනය මාස්ටඩන්හි අරින්න",
+ "search.quick_action.status_search": "ගැළපෙන ලිපි {x}",
+ "search.search_or_paste": "සොයන්න හෝ ඒ.ස.නි. අලවන්න",
+ "search_popout.options": "සෙවුම් විකල්ප",
+ "search_popout.quick_actions": "ඉක්මන් ක්රියාමාර්ග",
+ "search_popout.recent": "මෑත සෙවීම්",
+ "search_popout.specific_date": "නිශ්චිත දිනයකට",
+ "search_popout.user": "පරිශ්රීලකයා",
+ "search_results.accounts": "පැතිකඩ",
"search_results.all": "සියල්ල",
- "search_results.hashtags": "හැෂ් ටැග්",
"search_results.nothing_found": "මෙම සෙවුම් පද සඳහා කිසිවක් සොයාගත නොහැකි විය",
+ "search_results.see_all": "සියල්ල බලන්න",
"search_results.statuses": "ලිපි",
- "sign_in_banner.sign_in": "Sign in",
- "status.admin_account": "@{name}සඳහා මධ්යස්ථ අතුරුමුහුණත විවෘත කරන්න",
- "status.admin_status": "මධ්යස්ථ අතුරුමුහුණතෙහි මෙම තත්ත්වය විවෘත කරන්න",
+ "search_results.title": "{q} සොයන්න",
+ "server_banner.active_users": "සක්රිය පරිශ්රීලකයින්",
+ "server_banner.learn_more": "තව දැනගන්න",
+ "sign_in_banner.create_account": "ගිණුමක් සාදන්න",
+ "sign_in_banner.sign_in": "පිවිසෙන්න",
+ "status.admin_status": "මෙම ලිපිය මැදිහත්කරණ අතුරුමුහුණතෙහි අරින්න",
"status.block": "@{name} අවහිර",
"status.bookmark": "පොත්යොමුවක්",
- "status.cannot_reblog": "මෙම තනතුර වැඩි කළ නොහැක",
- "status.copy": "තත්වයට සබැඳිය පිටපත් කරන්න",
"status.delete": "මකන්න",
"status.detailed_status": "විස්තරාත්මක සංවාද දැක්ම",
"status.edit": "සංස්කරණය",
"status.edited": "සංශෝධිතයි {date}",
"status.edited_x_times": "සංශෝධිතයි {count, plural, one {වාර {count}} other {වාර {count}}}",
"status.embed": "කාවැද්දූ",
+ "status.filter": "මෙම ලිපිය පෙරන්න",
"status.filtered": "පෙරන ලද",
+ "status.hide": "ලිපිය සඟවන්න",
"status.history.created": "{name} නිර්මාණය {date}",
"status.history.edited": "{name} සංස්කරණය {date}",
"status.load_more": "තව පූරණය",
"status.media_hidden": "මාධ්ය සඟවා ඇත",
- "status.mention": "@{name} සැඳහුම",
+ "status.mention": "@{name} සඳහන් කරන්ක",
"status.more": "තව",
"status.mute": "@{name} නිහඬව",
"status.mute_conversation": "සංවාදය නිහඬව",
@@ -453,15 +445,10 @@
"status.pin": "පැතිකඩට අමුණන්න",
"status.pinned": "ඇමිණූ ලිපියකි",
"status.read_more": "තව කියවන්න",
- "status.reblog": "බූස්ට් කරන්න",
- "status.reblog_private": "මුල් දෘශ්යතාව සමඟ වැඩි කරන්න",
- "status.reblogged_by": "{name} වැඩි කරන ලදී",
- "status.reblogs.empty": "තාම කවුරුත් මේ toot එක boost කරලා නැහැ. යමෙකු එසේ කළ විට, ඔවුන් මෙහි පෙන්වනු ඇත.",
- "status.redraft": "මකන්න සහ නැවත කෙටුම්පත",
"status.remove_bookmark": "පොත්යොමුව ඉවතලන්න",
"status.reply": "පිළිතුරු",
- "status.replyAll": "ත්රෙඩ් එකට පිළිතුරු දෙන්න",
- "status.report": "@{name} වාර්තාව",
+ "status.replyAll": "නූලට පිළිතුරු දෙන්න",
+ "status.report": "@{name} වාර්තා කරන්න",
"status.sensitive_warning": "සංවේදී අන්තර්ගතයකි",
"status.share": "බෙදාගන්න",
"status.show_filter_reason": "කෙසේ වුවද පෙන්වන්න",
@@ -469,29 +456,29 @@
"status.show_less_all": "සියල්ල අඩුවෙන් පෙන්වන්න",
"status.show_more": "තවත් පෙන්වන්න",
"status.show_more_all": "සියල්ල වැඩියෙන් පෙන්වන්න",
- "status.title.with_attachments": "{user} posted {attachmentCount, plural, one {an attachment} other {# attachments}}",
+ "status.translate": "පරිවර්තනය",
+ "status.translated_from_with": "{provider} මගින් {lang} භාෂාවෙන් පරිවර්තනය කර ඇත",
+ "status.uncached_media_warning": "පෙරදසුන නැත",
"status.unmute_conversation": "සංවාදය නොනිහඬ",
"status.unpin": "පැතිකඩෙන් ගළවන්න",
"subscribed_languages.save": "වෙනස්කම් සුරකින්න",
"tabs_bar.home": "මුල් පිටුව",
"tabs_bar.notifications": "දැනුම්දීම්",
- "time_remaining.days": "{number, plural, one {# දින} other {# දින}} අත්හැරියා",
- "time_remaining.hours": "{number, plural, one {# පැය} other {# පැය}} අත්හැරියා",
- "time_remaining.minutes": "{number, plural, one {විනාඩි #} other {# මිනිත්තු}} අත්හැරියා",
- "time_remaining.moments": "ඉතිරිව ඇති මොහොත",
- "time_remaining.seconds": "{number, plural, one {# දෙවැනි} other {# තත්පර}} අත්හැරියා",
+ "time_remaining.days": "{number, plural, one {දවස් #} other {දවස් #}} ක් ඉතිරිය",
+ "time_remaining.hours": "{number, plural, one {පැය #} other {පැය #}} ක් ඉතිරිය",
+ "time_remaining.minutes": "{number, plural, one {විනාඩි #} other {විනාඩි #}} ක් ඉතිරිය",
+ "time_remaining.seconds": "{number, plural, one {තත්පර #} other {තත්පර #}} ක් ඉතිරිය",
"timeline_hint.remote_resource_not_displayed": "වෙනත් සේවාදායකයන්ගෙන් {resource} දර්ශනය නොවේ.",
"timeline_hint.resources.followers": "අනුගාමිකයින්",
- "timeline_hint.resources.follows": "අනුගමනය",
+ "timeline_hint.resources.follows": "අනුගමන",
"timeline_hint.resources.statuses": "පරණ ලිපි",
- "trends.counter_by_accounts": "{count, plural, one {{counter} person} other {{counter} people}} in the past {days, plural, one {day} other {# days}}",
- "trends.trending_now": "දැන් ප්රවණතාවය",
+ "trends.trending_now": "දැන් නැගී එන",
"ui.beforeunload": "ඔබ මාස්ටඩන් හැර ගියහොත් කටුපිටපත අහිමි වේ.",
"units.short.billion": "{count}බී",
"units.short.million": "ද.ල. {count}",
"units.short.thousand": "{count}කි",
"upload_area.title": "උඩුගතයට ඇද දමන්න",
- "upload_button.label": "රූප, දෘශ්යක හෝ හඬපට යොදන්න",
+ "upload_button.label": "රූප, දෘශ්යක හෝ හඬපට අමුණන්න",
"upload_error.limit": "සීමාව ඉක්මවා ඇත.",
"upload_error.poll": "මත විමසුම් සමඟ ගොනු යෙදීමට ඉඩ නොදේ.",
"upload_form.audio_description": "නොඇසෙන අය සඳහා විස්තර කරන්න",
@@ -508,10 +495,11 @@
"upload_modal.description_placeholder": "කඩිසර දුඹුරු හිවලෙක් කම්මැලි බල්ලා මතින් පනී",
"upload_modal.detect_text": "රූපයෙහි පෙළ අනාවරණය",
"upload_modal.edit_media": "මාධ්ය සංස්කරණය",
- "upload_modal.hint": "සියලුම සිඟිති රූ මත සැම විටම දර්ශනය වන නාභි ලක්ෂ්යය තේරීමට පෙරදසුනෙහි රවුම ක්ලික් කරන්න හෝ අදින්න.",
- "upload_modal.preparing_ocr": "OCR…සූදානම් කරමින්",
+ "upload_modal.preparing_ocr": "OCR සඳහා සැරසෙමින්…",
"upload_modal.preview_label": "පෙරදසුන ({ratio})",
"upload_progress.label": "උඩුගත වෙමින්...",
+ "upload_progress.processing": "සැකසෙමින්…",
+ "username.taken": "නම දැනටමත් අරගෙන ඇත",
"video.close": "දෘශ්යකය වසන්න",
"video.download": "ගොනුව බාගන්න",
"video.exit_fullscreen": "පූර්ණ තිරයෙන් පිටවන්න",
diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json
index bd1252b47fe42b..60760607f27522 100644
--- a/app/javascript/mastodon/locales/sk.json
+++ b/app/javascript/mastodon/locales/sk.json
@@ -12,56 +12,56 @@
"about.powered_by": "Decentralizované sociálne médiá poháňané technológiou {mastodon}",
"about.rules": "Pravidlá servera",
"account.account_note_header": "Poznámka",
- "account.add_or_remove_from_list": "Pridaj do, alebo odober zo zoznamov",
+ "account.add_or_remove_from_list": "Pridaj alebo odober zo zoznamov",
"account.badges.bot": "Bot",
"account.badges.group": "Skupina",
"account.block": "Blokuj @{name}",
- "account.block_domain": "Ukry všetko z {domain}",
+ "account.block_domain": "Skry všetko z {domain}",
"account.block_short": "Blokuj",
"account.blocked": "Blokovaný/á",
"account.browse_more_on_origin_server": "Prehľadávaj viac na pôvodnom profile",
- "account.cancel_follow_request": "Stiahni žiadosť o nasledovanie",
- "account.direct": "Spomeň @{name} v súkromí",
- "account.disable_notifications": "Prestaň ma oboznamovať, keď má @{name} príspevky",
- "account.domain_blocked": "Doména ukrytá",
+ "account.cancel_follow_request": "Zruš žiadosť o sledovanie",
+ "account.direct": "Spomeň @{name} súkromne",
+ "account.disable_notifications": "Prestaň mi oznamovať, keď má @{name} príspevky",
+ "account.domain_blocked": "Doména skrytá",
"account.edit_profile": "Uprav profil",
- "account.enable_notifications": "Oboznamuj ma, keď má @{name} príspevky",
+ "account.enable_notifications": "Oznamuj mi, keď má @{name} príspevky",
"account.endorse": "Zobrazuj na profile",
"account.featured_tags.last_status_at": "Posledný príspevok dňa {date}",
"account.featured_tags.last_status_never": "Žiadne príspevky",
"account.featured_tags.title": "Odporúčané hashtagy používateľa {name}",
- "account.follow": "Nasleduj",
- "account.followers": "Nasledovatelia",
+ "account.follow": "Sleduj",
+ "account.followers": "Sledovatelia",
"account.followers.empty": "Tohto používateľa ešte nikto nenasleduje.",
- "account.followers_counter": "{count, plural, one {{counter} Sledujúci} few {{counter} Sledujúci} many {{counter} Sledujúci} other {{counter} Sledujúci}}",
- "account.following": "Nasledujem",
+ "account.followers_counter": "{count, plural, one {{counter} Sledujúci} few {{counter} Sledujúci} many {{counter} Sledujúcich} other {{counter} Sledujúcich}}",
+ "account.following": "Sledujem",
"account.following_counter": "{count, plural, one {{counter} Sledovaných} other {{counter} Sledujúcich}}",
- "account.follows.empty": "Tento používateľ ešte nikoho nenasleduje.",
- "account.follows_you": "Nasleduje ťa",
+ "account.follows.empty": "Tento používateľ ešte nikoho nesleduje.",
+ "account.follows_you": "Sleduje ťa",
"account.go_to_profile": "Prejdi na profil",
- "account.hide_reblogs": "Skry vyzdvihnutia od @{name}",
+ "account.hide_reblogs": "Skry zdieľania od @{name}",
"account.in_memoriam": "In Memoriam.",
"account.joined_short": "Pridal/a sa",
"account.languages": "Zmeniť odoberané jazyky",
"account.link_verified_on": "Vlastníctvo tohto odkazu bolo skontrolované {date}",
- "account.locked_info": "Stav súkromia pre tento účet je nastavený na zamknutý. Jeho vlastník sám prehodnocuje, kto ho môže sledovať.",
+ "account.locked_info": "Stav súkromia pre tento účet je nastavený na zamknutý. Jeho vlastník sa sám rozhoduje, kto ho môže sledovať.",
"account.media": "Médiá",
"account.mention": "Spomeň @{name}",
"account.moved_to": "{name} uvádza, že jeho/jej nový účet je teraz:",
- "account.mute": "Nevšímaj si @{name}",
- "account.mute_notifications_short": "Stíš oboznámenia",
- "account.mute_short": "Nevšímaj si",
- "account.muted": "Nevšímaný/á",
- "account.no_bio": "Nieje uvedený žiadny popis.",
+ "account.mute": "Stíš @{name}",
+ "account.mute_notifications_short": "Stíš oznámenia",
+ "account.mute_short": "Stíš",
+ "account.muted": "Stíšený",
+ "account.no_bio": "Nie je uvedený žiadny popis.",
"account.open_original_page": "Otvor pôvodnú stránku",
"account.posts": "Príspevky",
"account.posts_with_replies": "Príspevky a odpovede",
"account.report": "Nahlás @{name}",
"account.requested": "Čaká na schválenie. Klikni pre zrušenie žiadosti",
- "account.requested_follow": "{name} ťa žiada nasledovať",
+ "account.requested_follow": "{name} ti poslal žiadosť na sledovanie",
"account.share": "Zdieľaj @{name} profil",
"account.show_reblogs": "Ukáž vyzdvihnutia od @{name}",
- "account.statuses_counter": "{count, plural, one {{counter} Toot} other {{counter} Toots}}",
+ "account.statuses_counter": "{count, plural, one {{counter} príspevok} other {{counter} príspevkov}}",
"account.unblock": "Odblokuj @{name}",
"account.unblock_domain": "Prestaň skrývať {domain}",
"account.unblock_short": "Odblokuj",
@@ -84,7 +84,7 @@
"alert.rate_limited.title": "Tempo obmedzené",
"alert.unexpected.message": "Vyskytla sa nečakaná chyba.",
"alert.unexpected.title": "Ups!",
- "announcement.announcement": "Oboznámenie",
+ "announcement.announcement": "Oznámenie",
"attachments_list.unprocessed": "(nespracované)",
"audio.hide": "Skry zvuk",
"autosuggest_hashtag.per_week": "{count} týždenne",
@@ -119,7 +119,7 @@
"column.home": "Domov",
"column.lists": "Zoznamy",
"column.mutes": "Nevšímaní užívatelia",
- "column.notifications": "Oboznámenia",
+ "column.notifications": "Oznámenia",
"column.pins": "Pripnuté príspevky",
"column.public": "Federovaná časová os",
"column_back_button.label": "Späť",
@@ -185,7 +185,7 @@
"confirmations.redraft.message": "Ste si istý, že chcete premazať a prepísať tento príspevok? Jeho nadobudnuté vyzdvihnutia a obľúbenia, ale i odpovede na pôvodný príspevok budú odlúčené.",
"confirmations.reply.confirm": "Odpovedz",
"confirmations.reply.message": "Odpovedaním akurát teraz prepíšeš správu, ktorú máš práve rozpísanú. Si si istý/á, že chceš pokračovať?",
- "confirmations.unfollow.confirm": "Nesleduj",
+ "confirmations.unfollow.confirm": "Prestaň sledovať",
"confirmations.unfollow.message": "Naozaj chceš prestať sledovať {name}?",
"conversation.delete": "Vymaž konverzáciu",
"conversation.mark_as_read": "Označ za prečítané",
@@ -223,7 +223,7 @@
"emoji_button.symbols": "Symboly",
"emoji_button.travel": "Cestovanie a miesta",
"empty_column.account_suspended": "Účet bol vylúčený",
- "empty_column.account_timeline": "Niesu tu žiadne príspevky!",
+ "empty_column.account_timeline": "Nie sú tu žiadne príspevky!",
"empty_column.account_unavailable": "Profil nedostupný",
"empty_column.blocks": "Ešte si nikoho nezablokoval/a.",
"empty_column.bookmarked_statuses": "Ešte nemáš žiadné záložky. Keď si pridáš príspevok k záložkám, zobrazí sa tu.",
@@ -296,19 +296,24 @@
"hashtag.column_settings.tag_mode.any": "Hociktorý z týchto",
"hashtag.column_settings.tag_mode.none": "Žiaden z týchto",
"hashtag.column_settings.tag_toggle": "Vlož dodatočné haštagy pre tento stĺpec",
- "hashtag.follow": "Nasleduj haštag",
+ "hashtag.counter_by_accounts": "{count, plural, one {{counter} sledujúci} few {{counter} sledujúci} many {{counter} sledujúcich} other {{counter} sledujúcich}}",
+ "hashtag.counter_by_uses": "{count, plural, one {{counter} príspevok} few {{counter} príspevky} many {{counter} príspevkov} other {{counter} príspevkov}}",
+ "hashtag.counter_by_uses_today": "{count, plural, one {{counter} príspevok} few {{counter} príspevky} many {{counter} príspevkov} other {{counter} príspevkov}} dnes",
+ "hashtag.follow": "Sleduj haštag",
"hashtag.unfollow": "Nesleduj haštag",
+ "hashtags.and_other": "…a {count, plural, one {} few {# ďalšie} many {# ďalších}other {# ďalších}}",
"home.actions.go_to_explore": "Pozrieť, čo je trendy",
"home.actions.go_to_suggestions": "Nájdi ľudí na sledovanie",
"home.column_settings.basic": "Základné",
"home.column_settings.show_reblogs": "Ukáž vyzdvihnuté",
"home.column_settings.show_replies": "Ukáž odpovede",
+ "home.explore_prompt.body": "Váš domovský informačný kanál bude obsahovať mix príspevkov z mriežok, ktoré ste sa rozhodli sledovať, ľudí, ktorých ste sa rozhodli sledovať, a príspevkov, ktoré preferujú. Ak sa vám to zdá príliš málo, možno budete chcieť:",
"home.explore_prompt.title": "Toto je tvoja domovina v rámci Mastodonu.",
- "home.hide_announcements": "Skry oboznámenia",
+ "home.hide_announcements": "Skry oznámenia",
"home.pending_critical_update.body": "Prosím aktualizuj si svoj Mastodon server, ako náhle to bude možné!",
"home.pending_critical_update.link": "Pozri aktualizácie",
"home.pending_critical_update.title": "Je dostupná kritická bezpečnostná aktualizácia!",
- "home.show_announcements": "Ukáž oboznámenia",
+ "home.show_announcements": "Ukáž oznámenia",
"interaction_modal.description.favourite": "S účtom na Mastodone si môžeš tento príspevok obľúbiť, aby si dal/a autorovi vedieť, že ho oceňuješ, a uložiť si ho na neskôr.",
"interaction_modal.description.follow": "Ak máte konto na Mastodone, môžete sledovať {name} a dostávať príspevky do svojho domovského kanála.",
"interaction_modal.description.reblog": "Ak máte účet na Mastodone, môžete tento príspevok posilniť a zdieľať ho s vlastnými sledovateľmi.",
@@ -319,6 +324,7 @@
"interaction_modal.on_another_server": "Na inom serveri",
"interaction_modal.on_this_server": "Na tomto serveri",
"interaction_modal.sign_in": "Nie si prihláseý/á na tomto serveri. Kde je tvoj účet hostovaný?",
+ "interaction_modal.sign_in_hint": "Tip: Toto je webová stránka, na ktorej ste sa zaregistrovali. Ak si nepamätáte, pohľadajte uvítací e-mail vo svojej schránke. Môžete tiež zadať svoje celé používateľské meno! (napr. @Mastodon@mastodon.social)",
"interaction_modal.title.favourite": "Obľúb si {name} ov/in príspevok",
"interaction_modal.title.follow": "Nasleduj {name}",
"interaction_modal.title.reblog": "Vyzdvihni {name}ov/in príspevok",
@@ -346,7 +352,7 @@
"keyboard_shortcuts.mention": "spomeň autora",
"keyboard_shortcuts.muted": "otvor zoznam stíšených užívateľov",
"keyboard_shortcuts.my_profile": "otvor svoj profil",
- "keyboard_shortcuts.notifications": "otvor panel oboznámení",
+ "keyboard_shortcuts.notifications": "Otvor panel oznámení",
"keyboard_shortcuts.open_media": "na otvorenie médií",
"keyboard_shortcuts.pinned": "otvor zoznam pripnutých príspevkov",
"keyboard_shortcuts.profile": "otvor autorov profil",
@@ -373,6 +379,7 @@
"lists.delete": "Vymaž list",
"lists.edit": "Uprav zoznam",
"lists.edit.submit": "Zmeň názov",
+ "lists.exclusive": "Skryť tieto príspevky z domovskej stránky",
"lists.new.create": "Pridaj zoznam",
"lists.new.title_placeholder": "Názov nového zoznamu",
"lists.replies_policy.followed": "Akýkoľvek nasledovaný užívateľ",
@@ -426,11 +433,11 @@
"notification.reblog": "{name} zdieľal/a tvoj príspevok",
"notification.status": "{name} práve uverejnil/a",
"notification.update": "{name} upravil/a príspevok",
- "notifications.clear": "Vyčisti oboznámenia",
- "notifications.clear_confirmation": "Naozaj chceš nenávratne prečistiť všetky tvoje oboznámenia?",
+ "notifications.clear": "Vyčisti oznámenia",
+ "notifications.clear_confirmation": "Naozaj chceš nenávratne odstrániť všetky tvoje oznámenia?",
"notifications.column_settings.admin.report": "Nové hlásenia:",
"notifications.column_settings.admin.sign_up": "Nové registrácie:",
- "notifications.column_settings.alert": "Oboznámenia na ploche",
+ "notifications.column_settings.alert": "Oznámenia na ploche",
"notifications.column_settings.favourite": "Obľúbené:",
"notifications.column_settings.filter_bar.advanced": "Zobraz všetky kategórie",
"notifications.column_settings.filter_bar.category": "Rýchle triedenie",
@@ -444,8 +451,8 @@
"notifications.column_settings.show": "Ukáž v stĺpci",
"notifications.column_settings.sound": "Prehraj zvuk",
"notifications.column_settings.status": "Nové príspevky:",
- "notifications.column_settings.unread_notifications.category": "Neprečítané oboznámenia",
- "notifications.column_settings.unread_notifications.highlight": "Zdôrazni neprečítané oboznámenia",
+ "notifications.column_settings.unread_notifications.category": "Neprečítané oznámenia",
+ "notifications.column_settings.unread_notifications.highlight": "Zdôrazni neprečítané oznámenia",
"notifications.column_settings.update": "Úpravy:",
"notifications.filter.all": "Všetky",
"notifications.filter.boosts": "Vyzdvihnutia",
@@ -455,12 +462,12 @@
"notifications.filter.polls": "Výsledky ankiet",
"notifications.filter.statuses": "Aktualizácie od ľudí, ktorých nasleduješ",
"notifications.grant_permission": "Udeľ povolenie.",
- "notifications.group": "{count} oboznámení",
- "notifications.mark_as_read": "Označ každé oboznámenie za prečítané",
- "notifications.permission_denied": "Oboznámenia na plochu sú nedostupné, kvôli predtým zamietnutej požiadavke prehliadača",
- "notifications.permission_denied_alert": "Oboznámenia na ploche nemôžu byť zapnuté, pretože požiadavka prehliadača o to, bola už skôr zamietnutá",
- "notifications.permission_required": "Oboznámenia na ploche sú nedostupné, pretože potrebné povolenia neboli udelené.",
- "notifications_permission_banner.enable": "Povoliť oboznámenia na plochu",
+ "notifications.group": "{count} Oznámení",
+ "notifications.mark_as_read": "Označ každé oznámenie za prečítané",
+ "notifications.permission_denied": "Oznámenia na ploche sú nedostupné, kvôli predtým zamietnutej požiadavke prehliadača",
+ "notifications.permission_denied_alert": "Oznámenia na ploche nemôžu byť zapnuté, pretože požiadavka prehliadača bola už skôr zamietnutá",
+ "notifications.permission_required": "Oznámenia na ploche sú nedostupné, pretože potrebné povolenia neboli udelené.",
+ "notifications_permission_banner.enable": "Povoliť oznámenia na ploche",
"notifications_permission_banner.how_to_control": "Ak chcete dostávať upozornenia, keď Mastodon nie je otvorený, povoľte upozornenia na ploche. Po ich zapnutí môžete presne kontrolovať, ktoré typy interakcií generujú upozornenia na ploche, a to prostredníctvom tlačidla {icon} vyššie.",
"notifications_permission_banner.title": "Nikdy nezmeškaj jedinú vec",
"onboarding.action.back": "Vziať ma späť",
@@ -468,6 +475,7 @@
"onboarding.actions.go_to_explore": "See what's trending",
"onboarding.actions.go_to_home": "Go to your home feed",
"onboarding.compose.template": "Nazdar #Mastodon!",
+ "onboarding.follows.empty": "Žiaľ, momentálne sa nedajú zobraziť žiadne výsledky. Môžete skúsiť použiť vyhľadávanie alebo navštíviť stránku objavovania a nájsť ľudí, ktorých chcete sledovať, alebo to skúste znova neskôr.",
"onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!",
"onboarding.follows.title": "Popular on Mastodon",
"onboarding.share.lead": "Daj ľudom vedieť, ako ťa môžu na Mastodone nájsť!",
@@ -476,6 +484,7 @@
"onboarding.share.title": "Zdieľaj svoj profil",
"onboarding.start.lead": "Your new Mastodon account is ready to go. Here's how you can make the most of it:",
"onboarding.start.skip": "Want to skip right ahead?",
+ "onboarding.start.title": "Zvládli ste to!",
"onboarding.steps.follow_people.body": "You curate your own feed. Lets fill it with interesting people.",
"onboarding.steps.follow_people.title": "Follow {count, plural, one {one person} other {# people}}",
"onboarding.steps.publish_status.body": "Say hello to the world.",
@@ -484,6 +493,12 @@
"onboarding.steps.setup_profile.title": "Customize your profile",
"onboarding.steps.share_profile.body": "Let your friends know how to find you on Mastodon!",
"onboarding.steps.share_profile.title": "Share your profile",
+ "onboarding.tips.2fa": "
Vedeli ste? Svoj účet môžete zabezpečiť nastavením dvojfaktorového overenia v nastaveniach účtu. Funguje to s akoukoľvek aplikáciou TOTP podľa vášho výberu, nie je potrebné žiadne telefónne číslo!",
+ "onboarding.tips.accounts_from_other_servers": "
Vedeli ste? Keďže Mastodon je decentralizovaný, niektoré profily, s ktorými sa stretnete, budú na iných serveroch, ako je váš. Aj napriek tomu s nimi môžete bezproblémovo komunikovať! Ich server je v druhej časti ich používateľského mena!",
+ "onboarding.tips.migration": "
Vedeli ste? Ak máte pocit, že doména {domain} pre vás v budúcnosti nebude skvelou voľbou, môžete prejsť na iný server Mastodon bez straty svojich sledovateľov. Môžete dokonca hostovať svoj vlastný server!",
+ "onboarding.tips.verification": "
Vedeli ste? Svoj účet môžete overiť umiestnením odkazu na svoj profil Mastodon na svoju vlastnú webovú lokalitu a pridaním webovej lokality do svojho profilu. Nie sú potrebné žiadne poplatky ani doklady!",
+ "password_confirmation.exceeds_maxlength": "Potvrdené heslo presahuje maximálnu dĺžku hesla",
+ "password_confirmation.mismatching": "Zadané heslá sa nezhodujú",
"picture_in_picture.restore": "Vrátiť späť",
"poll.closed": "Uzatvorená",
"poll.refresh": "Obnoviť",
@@ -542,6 +557,7 @@
"report.reasons.dislike": "Nepáči sa mi",
"report.reasons.dislike_description": "Nieje to niečo, čo chceš vidieť",
"report.reasons.legal": "Je to nelegálne",
+ "report.reasons.legal_description": "Domnievate sa, že porušuje zákony vašej krajiny alebo krajiny servera",
"report.reasons.other": "Je to niečo iné",
"report.reasons.other_description": "Tento problém nepatrí do iných kategórií",
"report.reasons.spam": "Je to spam",
@@ -559,6 +575,7 @@
"report.thanks.title": "Nechceš to vidieť?",
"report.thanks.title_actionable": "Vďaka za nahlásenie, pozrieme sa na to.",
"report.unfollow": "Nesleduj @{name}",
+ "report.unfollow_explanation": "Tento účet sledujete. Ak už nechcete vidieť jeho príspevky vo svojom domovskom kanáli, zrušte jeho sledovanie.",
"report_notification.attached_statuses": "{count, plural, one {# post} other {# posts}} attached",
"report_notification.categories.legal": "Právne ujednania",
"report_notification.categories.other": "Ostatné",
@@ -573,6 +590,8 @@
"search.quick_action.open_url": "Otvor URL v rámci Mastodonu",
"search.quick_action.status_search": "Príspevky zodpovedajúce {x}",
"search.search_or_paste": "Hľadaj, alebo vlož URL adresu",
+ "search_popout.full_text_search_disabled_message": "Nie je k dispozícii v doméne {domain}.",
+ "search_popout.language_code": "ISO kód jazyka",
"search_popout.options": "Možnosti vyhľadávania",
"search_popout.quick_actions": "Rýchle akcie",
"search_popout.recent": "Nedávne vyhľadávania",
@@ -585,14 +604,18 @@
"search_results.see_all": "Ukáž všetky",
"search_results.statuses": "Príspevky",
"search_results.title": "Hľadaj {q}",
+ "server_banner.about_active_users": "Ľudia používajúci tento server za posledných 30 dní (Aktívni používatelia za mesiac)",
"server_banner.active_users": "aktívni užívatelia",
"server_banner.administered_by": "Správcom je:",
+ "server_banner.introduction": "{domain} je súčasťou decentralizovanej sociálnej siete využívajúcej technológiu {mastodon}.",
"server_banner.learn_more": "Zisti viac",
"server_banner.server_stats": "Serverové štatistiky:",
"sign_in_banner.create_account": "Vytvor účet",
"sign_in_banner.sign_in": "Prihlás sa",
"sign_in_banner.sso_redirect": "Prihlás sa, alebo zaregistruj",
+ "sign_in_banner.text": "Prihláste sa, aby ste mohli sledovať profily alebo haštagy, obľúbené veci, zdieľať ich a odpovedať na príspevky. Môžete tiež komunikovať zo svojho účtu na inom serveri.",
"status.admin_account": "Otvor moderovacie rozhranie užívateľa @{name}",
+ "status.admin_domain": "Otvor rozhranie na moderovanie domény {domain}",
"status.admin_status": "Otvor tento príspevok v moderovacom rozhraní",
"status.block": "Blokuj @{name}",
"status.bookmark": "Záložka",
@@ -649,9 +672,11 @@
"status.uncached_media_warning": "Náhľad nie je k dispozícii",
"status.unmute_conversation": "Prestaň si nevšímať konverzáciu",
"status.unpin": "Odopni z profilu",
+ "subscribed_languages.lead": "Po zmene sa na vašej domovskej stránke a časovej osi zoznamu zobrazia iba príspevky vo vybraných jazykoch. Ak chcete dostávať príspevky vo všetkých jazykoch, vyberte možnosť žiadne.",
"subscribed_languages.save": "Ulož zmeny",
+ "subscribed_languages.target": "Zmeniť prihlásené jazyky pre {target}",
"tabs_bar.home": "Domov",
- "tabs_bar.notifications": "Oboznámenia",
+ "tabs_bar.notifications": "Oznámenia",
"time_remaining.days": "Ostáva {number, plural, one {# deň} few {# dní} many {# dní} other {# dní}}",
"time_remaining.hours": "Ostáva {number, plural, one {# hodina} few {# hodín} many {# hodín} other {# hodiny}}",
"time_remaining.minutes": "Ostáva {number, plural, one {# minúta} few {# minút} many {# minút} other {# minúty}}",
@@ -680,6 +705,7 @@
"upload_form.video_description": "Popíš, pre ľudí so stratou sluchu, alebo očným znevýhodnením",
"upload_modal.analyzing_picture": "Analyzujem obrázok…",
"upload_modal.apply": "Použi",
+ "upload_modal.applying": "Nastavovanie…",
"upload_modal.choose_image": "Vyber obrázok",
"upload_modal.description_placeholder": "Rýchla hnedá líška skáče ponad lenivého psa",
"upload_modal.detect_text": "Rozpoznaj text z obrázka",
@@ -689,6 +715,7 @@
"upload_modal.preview_label": "Náhľad ({ratio})",
"upload_progress.label": "Nahráva sa...",
"upload_progress.processing": "Spracovávanie…",
+ "username.taken": "Používateľské meno je obsadené. Skúste iné",
"video.close": "Zavri video",
"video.download": "Stiahni súbor",
"video.exit_fullscreen": "Vypni zobrazenie na celú obrazovku",
diff --git a/app/javascript/mastodon/locales/sr-Latn.json b/app/javascript/mastodon/locales/sr-Latn.json
index 9750784bbc12dc..f64952f7b54dfc 100644
--- a/app/javascript/mastodon/locales/sr-Latn.json
+++ b/app/javascript/mastodon/locales/sr-Latn.json
@@ -514,7 +514,7 @@
"privacy.direct.long": "Vidljivo samo pomenutim korisnicima",
"privacy.direct.short": "Samo pomenute osobe",
"privacy.private.long": "Vidljivo samo pratiocima",
- "privacy.private.short": "Samo pratiocima",
+ "privacy.private.short": "Samo pratioci",
"privacy.public.long": "Vidljivo za sve",
"privacy.public.short": "Javno",
"privacy.unlisted.long": "Vidljivo svima, ali isključeno iz funkcija otkrivanja",
diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json
index bb4739cbcc37fc..ec2c76e8f942e1 100644
--- a/app/javascript/mastodon/locales/sr.json
+++ b/app/javascript/mastodon/locales/sr.json
@@ -303,7 +303,7 @@
"hashtag.unfollow": "Отпрати хеш ознаку",
"hashtags.and_other": "…и {count, plural, one {још #} few {још #}other {још #}}",
"home.actions.go_to_explore": "Погледате шта је у тренду",
- "home.actions.go_to_suggestions": "Пронађeте људе које бисте пратили",
+ "home.actions.go_to_suggestions": "Пронађете људе које бисте пратили",
"home.column_settings.basic": "Основна",
"home.column_settings.show_reblogs": "Прикажи подржавања",
"home.column_settings.show_replies": "Прикажи одговоре",
@@ -514,7 +514,7 @@
"privacy.direct.long": "Видљиво само поменутим корисницима",
"privacy.direct.short": "Само поменуте особе",
"privacy.private.long": "Видљиво само пратиоцима",
- "privacy.private.short": "Само пратиоцима",
+ "privacy.private.short": "Само пратиоци",
"privacy.public.long": "Видљиво за све",
"privacy.public.short": "Јавно",
"privacy.unlisted.long": "Видљиво свима, али искључено из функција откривања",
diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json
index 48e76141d88949..aa17e125454558 100644
--- a/app/javascript/mastodon/locales/uk.json
+++ b/app/javascript/mastodon/locales/uk.json
@@ -79,16 +79,16 @@
"admin.impact_report.instance_accounts": "Профілі облікових записів буде видалено",
"admin.impact_report.instance_followers": "Підписники, яких можуть втратити наші користувачі",
"admin.impact_report.instance_follows": "Підписники, яких можуть втратити їхні користувачі",
- "admin.impact_report.title": "Наслідки",
- "alert.rate_limited.message": "Спробуйте ще раз через {retry_time, time, medium}.",
+ "admin.impact_report.title": "Підсумки впливу",
+ "alert.rate_limited.message": "Спробуйте ще раз за {retry_time, time, medium}.",
"alert.rate_limited.title": "Швидкість обмежена",
"alert.unexpected.message": "Сталася неочікувана помилка.",
"alert.unexpected.title": "Ой!",
"announcement.announcement": "Оголошення",
"attachments_list.unprocessed": "(не оброблено)",
"audio.hide": "Сховати аудіо",
- "autosuggest_hashtag.per_week": "{count} в тиждень",
- "boost_modal.combo": "Ви можете натиснути {combo}, щоб пропустити це наступного разу",
+ "autosuggest_hashtag.per_week": "{count} на тиждень",
+ "boost_modal.combo": "Ви можете натиснути {combo}, щоби пропустити це наступного разу",
"bundle_column_error.copy_stacktrace": "Копіювати звіт про помилку",
"bundle_column_error.error.body": "Неможливо показати запитану сторінку. Це може бути спричинено помилкою у нашому коді, або через проблему сумісності з браузером.",
"bundle_column_error.error.title": "О, ні!",
@@ -140,7 +140,7 @@
"compose.saved.body": "Допис збережено.",
"compose_form.direct_message_warning_learn_more": "Дізнатися більше",
"compose_form.encryption_warning": "Дописи на Mastodon не захищені шифруванням. Не поширюйте жодну делікатну інформацію.",
- "compose_form.hashtag_warning": "Цей допис не буде зображений у жодній стрічці гештеґу, оскільки він прихований. Тільки публічні дописи можуть бути знайдені за гештеґом.",
+ "compose_form.hashtag_warning": "Цього допису не буде під жодним гештеґом, оскільки він не є загальнодоступним. За гештеґом можна шукати лише публічні дописи.",
"compose_form.lock_disclaimer": "Ваш обліковий запис не {locked}. Будь-який користувач може підписатися на вас та переглядати ваші дописи для підписників.",
"compose_form.lock_disclaimer.lock": "приватний",
"compose_form.placeholder": "Що у вас на думці?",
@@ -151,7 +151,7 @@
"compose_form.poll.switch_to_multiple": "Дозволити вибір декількох відповідей",
"compose_form.poll.switch_to_single": "Перемкнути у режим вибору однієї відповіді",
"compose_form.publish": "Опублікувати",
- "compose_form.publish_form": "Опублікувати",
+ "compose_form.publish_form": "Новий допис",
"compose_form.publish_loud": "{publish}!",
"compose_form.save_changes": "Зберегти зміни",
"compose_form.sensitive.hide": "{count, plural, one {Позначити медіа делікатним} other {Позначити медіа делікатними}}",
@@ -206,7 +206,7 @@
"dismissable_banner.explore_tags": "Ці хештеги зараз набирають популярності серед людей на цьому та інших серверах децентралізованої мережі. Хештеги, які використовуються більшою кількістю людей, мають вищий рейтинг.",
"dismissable_banner.public_timeline": "Це найновіші загальнодоступні дописи від людей в соціальній мережі, на які підписані люди в {domain}.",
"embed.instructions": "Вбудуйте цей допис до вашого вебсайту, скопіювавши код нижче.",
- "embed.preview": "Ось як він виглядатиме:",
+ "embed.preview": "Ось який вигляд це матиме:",
"emoji_button.activity": "Діяльність",
"emoji_button.clear": "Очистити",
"emoji_button.custom": "Власні",
@@ -227,7 +227,7 @@
"empty_column.account_unavailable": "Профіль недоступний",
"empty_column.blocks": "Ви ще не заблокували жодного користувача.",
"empty_column.bookmarked_statuses": "У вас ще немає дописів у закладках. Коли ви щось додасте до закладок, воно з'явиться тут.",
- "empty_column.community": "Локальна стрічка пуста. Напишіть щось, щоб розігріти народ!",
+ "empty_column.community": "Локальна стрічка порожня. Напишіть щось, щоб розігріти народ!",
"empty_column.direct": "У вас ще немає жодних особистих згадок. Коли ви надсилаєте чи отримуєте повідомлення, воно з'явиться тут.",
"empty_column.domain_blocks": "Тут поки немає прихованих доменів.",
"empty_column.explore_statuses": "Нема нічого популярного. Подивіться пізніше!",
@@ -240,10 +240,10 @@
"empty_column.list": "Цей список порожній. Коли його учасники додадуть нові дописи, вони з'являться тут.",
"empty_column.lists": "У вас ще немає списків. Коли ви їх створите, вони з'являться тут.",
"empty_column.mutes": "Ви ще не приховали жодного користувача.",
- "empty_column.notifications": "У вас ще немає сповіщень. Переписуйтесь з іншими користувачами, щоб почати розмову.",
+ "empty_column.notifications": "У вас ще немає сповіщень. Коли інші люди почнуть взаємодіяти з вами, ви побачите їх тут.",
"empty_column.public": "Тут поки нічого немає! Опублікуйте щось, або вручну підпишіться на користувачів інших серверів, щоб заповнити стрічку",
"error.unexpected_crash.explanation": "Через помилку у нашому коді або несумісність браузера, ця сторінка не може бути зображена коректно.",
- "error.unexpected_crash.explanation_addons": "Неможливо правильно показати цю сторінку. Ймовірно, цю помилку викликано додатком браузера або автоматичним засобом перекладу.",
+ "error.unexpected_crash.explanation_addons": "Неможливо правильно показати цю сторінку. Ймовірно, цю помилку спричинило розширення браузера або автоматичний засіб перекладу.",
"error.unexpected_crash.next_steps": "Спробуйте перезавантажити сторінку. Якщо це не допоможе, ви все ще зможете використовувати Mastodon через інший браузер або рідний застосунок.",
"error.unexpected_crash.next_steps_addons": "Спробуйте їх вимкнути та оновити сторінку. Якщо це не допомагає, ви можете використовувати Mastodon через інший браузер або окремий застосунок.",
"errors.unexpected_crash.copy_stacktrace": "Скопіювати трасування стека у буфер обміну",
@@ -394,7 +394,7 @@
"moved_to_account_banner.text": "Ваш обліковий запис {disabledAccount} наразі вимкнений, оскільки вас перенесено до {movedToAccount}.",
"mute_modal.duration": "Тривалість",
"mute_modal.hide_notifications": "Сховати сповіщення цього користувача?",
- "mute_modal.indefinite": "Назавжди",
+ "mute_modal.indefinite": "Невизначений строк",
"navigation_bar.about": "Про застосунок",
"navigation_bar.advanced_interface": "Відкрити в розширеному вебінтерфейсі",
"navigation_bar.blocks": "Заблоковані користувачі",
@@ -428,7 +428,7 @@
"notification.follow": "{name} підписалися на вас",
"notification.follow_request": "{name} відправили запит на підписку",
"notification.mention": "{name} згадали вас",
- "notification.own_poll": "Ваше опитування завершено",
+ "notification.own_poll": "Ваше опитування завершилося",
"notification.poll": "Опитування, у якому ви голосували, скінчилося",
"notification.reblog": "{name} поширює ваш допис",
"notification.status": "{name} щойно дописує",
@@ -480,7 +480,7 @@
"onboarding.follows.title": "Персоналізуйте домашню стрічку",
"onboarding.share.lead": "Розкажіть людям про те, як вони можуть знайти вас на Mastodon!",
"onboarding.share.message": "Я {username} на #Mastodon! Стежте за мною на {url}",
- "onboarding.share.next_steps": "Можливі наступні кроки:",
+ "onboarding.share.next_steps": "Можливі такі кроки:",
"onboarding.share.title": "Поділитися своїм профілем",
"onboarding.start.lead": "Тепер ви — частина Mastodon, унікальної децентралізованої платформи соціальних медіа, де ви, а не алгоритми керують вашими вподобаннями. Розпочнімо роботу:",
"onboarding.start.skip": "Хочете пропустити?",
@@ -694,7 +694,7 @@
"units.short.thousand": "{count} тис",
"upload_area.title": "Перетягніть сюди, щоб завантажити",
"upload_button.label": "Додати зображення, відео або аудіо",
- "upload_error.limit": "Ліміт завантаження файлів перевищено.",
+ "upload_error.limit": "Ви перевищили ліміт завантаження файлів.",
"upload_error.poll": "Не можна завантажувати файли до опитувань.",
"upload_form.audio_description": "Опишіть для людей із вадами слуху",
"upload_form.description": "Опишіть для людей з вадами зору",
@@ -713,7 +713,7 @@
"upload_modal.hint": "Клацніть або перетягніть коло на превʼю, щоб обрати точку, яку буде завжди видно на мініатюрах.",
"upload_modal.preparing_ocr": "Підготовка OCR…",
"upload_modal.preview_label": "Переглянути ({ratio})",
- "upload_progress.label": "Завантаження...",
+ "upload_progress.label": "Вивантаження...",
"upload_progress.processing": "Обробка…",
"username.taken": "Це ім'я користувача вже зайнято. Спробуйте інше",
"video.close": "Закрити відео",
diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json
index e5de8daa9d5d5e..47880f711259b4 100644
--- a/app/javascript/mastodon/locales/zh-HK.json
+++ b/app/javascript/mastodon/locales/zh-HK.json
@@ -590,6 +590,7 @@
"search.quick_action.open_url": "在 Mastodon 中打開網址",
"search.quick_action.status_search": "符合的帖文 {x}",
"search.search_or_paste": "搜尋或貼上網址",
+ "search_popout.full_text_search_disabled_message": "在 {domain} 上無法使用。",
"search_popout.language_code": "ISO 語言代碼",
"search_popout.options": "搜尋選項",
"search_popout.quick_actions": "快速動作",
diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json
index a6694b21df03a9..dab8a721913e89 100644
--- a/app/javascript/mastodon/locales/zh-TW.json
+++ b/app/javascript/mastodon/locales/zh-TW.json
@@ -204,7 +204,7 @@
"dismissable_banner.explore_links": "這些新聞故事正在被此伺服器以及去中心化網路上的人們熱烈討論著。越多不同人所嘟出的新聞排名更高。",
"dismissable_banner.explore_statuses": "這些於此伺服器以及去中心化網路中其他伺服器發出的嘟文正在被此伺服器上的人們熱烈討論著。越多不同人轉嘟及最愛排名更高。",
"dismissable_banner.explore_tags": "這些主題標籤正在被此伺服器以及去中心化網路上的人們熱烈討論著。越多不同人所嘟出的主題標籤排名更高。",
- "dismissable_banner.public_timeline": "這些是來自 {domain} 上人們於社群網站中跟隨者所發表之最近公開嘟文。",
+ "dismissable_banner.public_timeline": "這些是來自 {domain} 使用者們跟隨中帳號所發表之最新公開嘟文。",
"embed.instructions": "要在您的網站嵌入此嘟文,請複製以下程式碼。",
"embed.preview": "它將顯示成這樣:",
"emoji_button.activity": "活動",
@@ -271,8 +271,8 @@
"filter_modal.select_filter.title": "過濾此嘟文",
"filter_modal.title.status": "過濾一則嘟文",
"firehose.all": "全部",
- "firehose.local": "此伺服器",
- "firehose.remote": "其他伺服器",
+ "firehose.local": "本站",
+ "firehose.remote": "聯邦宇宙",
"follow_request.authorize": "授權",
"follow_request.reject": "拒絕",
"follow_requests.unlocked_explanation": "即便您的帳號未被鎖定,{domain} 的管理員認為您可能想要自己審核這些帳號的跟隨請求。",
@@ -373,7 +373,7 @@
"lightbox.previous": "上一步",
"limited_account_hint.action": "一律顯示個人檔案",
"limited_account_hint.title": "此個人檔案已被 {domain} 的管理員隱藏。",
- "link_preview.author": "按照 {name}",
+ "link_preview.author": "由 {name} 提供",
"lists.account.add": "新增至列表",
"lists.account.remove": "從列表中移除",
"lists.delete": "刪除列表",
@@ -409,7 +409,7 @@
"navigation_bar.favourites": "最愛",
"navigation_bar.filters": "已靜音的關鍵字",
"navigation_bar.follow_requests": "跟隨請求",
- "navigation_bar.followed_tags": "已跟隨的主題標籤",
+ "navigation_bar.followed_tags": "已跟隨主題標籤",
"navigation_bar.follows_and_followers": "跟隨中與跟隨者",
"navigation_bar.lists": "列表",
"navigation_bar.logout": "登出",
@@ -629,7 +629,7 @@
"status.edit": "編輯",
"status.edited": "編輯於 {date}",
"status.edited_x_times": "已編輯 {count, plural, one {{count} 次} other {{count} 次}}",
- "status.embed": "內嵌",
+ "status.embed": "內嵌嘟文",
"status.favourite": "最愛",
"status.filter": "過濾此嘟文",
"status.filtered": "已過濾",
@@ -662,9 +662,9 @@
"status.share": "分享",
"status.show_filter_reason": "仍要顯示",
"status.show_less": "減少顯示",
- "status.show_less_all": "減少顯示這類嘟文",
+ "status.show_less_all": "隱藏所有內容警告與額外標籤",
"status.show_more": "顯示更多",
- "status.show_more_all": "顯示更多這類嘟文",
+ "status.show_more_all": "顯示所有內容警告與額外標籤",
"status.show_original": "顯示原文",
"status.title.with_attachments": "{user} 嘟了 {attachmentCount, plural, other {{attachmentCount} 個附加檔案}}",
"status.translate": "翻譯",
diff --git a/app/javascript/mastodon/reducers/compose.js b/app/javascript/mastodon/reducers/compose.js
index 49c3e566a865e5..d12e4e7628a30c 100644
--- a/app/javascript/mastodon/reducers/compose.js
+++ b/app/javascript/mastodon/reducers/compose.js
@@ -226,7 +226,7 @@ const startLaTeX = (state, position, latex_style) => {
const latex_styles = {
'inline': {open: '\\(', close: '\\)'},
'display': {open: '\\[', close: '\\]'}
- }
+ };
const { open, close } = latex_styles[latex_style];
return state.merge({
diff --git a/app/javascript/mastodon/utils/react_router.jsx b/app/javascript/mastodon/utils/react_router.jsx
new file mode 100644
index 00000000000000..fa8f0db2b5cbd6
--- /dev/null
+++ b/app/javascript/mastodon/utils/react_router.jsx
@@ -0,0 +1,61 @@
+import PropTypes from "prop-types";
+
+import { __RouterContext } from "react-router";
+
+import hoistStatics from "hoist-non-react-statics";
+
+export const WithRouterPropTypes = {
+ match: PropTypes.object.isRequired,
+ location: PropTypes.object.isRequired,
+ history: PropTypes.object.isRequired,
+};
+
+export const WithOptionalRouterPropTypes = {
+ match: PropTypes.object,
+ location: PropTypes.object,
+ history: PropTypes.object,
+};
+
+// This is copied from https://github.com/remix-run/react-router/blob/v5.3.4/packages/react-router/modules/withRouter.js
+// but does not fail if called outside of a React Router context
+export function withOptionalRouter(Component) {
+ const displayName = `withRouter(${Component.displayName || Component.name})`;
+ const C = props => {
+ const { wrappedComponentRef, ...remainingProps } = props;
+
+ return (
+ <__RouterContext.Consumer>
+ {context => {
+ if(context)
+ return (
+
+ );
+ else
+ return (
+
+ );
+ }}
+
+ );
+ };
+
+ C.displayName = displayName;
+ C.WrappedComponent = Component;
+ C.propTypes = {
+ ...Component.propTypes,
+ wrappedComponentRef: PropTypes.oneOfType([
+ PropTypes.string,
+ PropTypes.func,
+ PropTypes.object
+ ])
+ };
+
+ return hoistStatics(C, Component);
+}
diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js
index f26321c41aae99..d13388b4791620 100644
--- a/app/javascript/packs/application.js
+++ b/app/javascript/packs/application.js
@@ -1,5 +1,5 @@
import './public-path';
-import main from "mastodon/main"
+import main from "mastodon/main";
import { start } from '../mastodon/common';
import { loadLocale } from '../mastodon/locales';
diff --git a/app/javascript/packs/public.jsx b/app/javascript/packs/public.jsx
index 4bfbf7e25a6218..62ab7b42821a5f 100644
--- a/app/javascript/packs/public.jsx
+++ b/app/javascript/packs/public.jsx
@@ -5,7 +5,7 @@ import { createRoot } from 'react-dom/client';
import { IntlMessageFormat } from 'intl-messageformat';
import { defineMessages } from 'react-intl';
-import { delegate } from '@rails/ujs';
+import delegate from '@rails/ujs';
import axios from 'axios';
import { throttle } from 'lodash';
diff --git a/app/javascript/styles/application.scss b/app/javascript/styles/application.scss
index 1b2969c2348fd4..0dd573da9ba736 100644
--- a/app/javascript/styles/application.scss
+++ b/app/javascript/styles/application.scss
@@ -12,7 +12,6 @@
@import 'mastodon/forms';
@import 'mastodon/accounts';
@import 'mastodon/statuses';
-@import 'mastodon/boost';
@import 'mastodon/components';
@import 'mastodon/polls';
@import 'mastodon/modal';
diff --git a/app/javascript/styles/mastodon/boost.scss b/app/javascript/styles/mastodon/boost.scss
deleted file mode 100644
index 2969958e227261..00000000000000
--- a/app/javascript/styles/mastodon/boost.scss
+++ /dev/null
@@ -1,44 +0,0 @@
-button.icon-button {
- i.fa-retweet {
- background-image: url("data:image/svg+xml;utf8,
");
- }
-
- &:hover i.fa-retweet {
- background-image: url("data:image/svg+xml;utf8,
");
- }
-
- &.reblogPrivate {
- i.fa-retweet {
- background-image: url("data:image/svg+xml;utf8,
");
- }
-
- &:hover i.fa-retweet {
- background-image: url("data:image/svg+xml;utf8,
");
- }
- }
-
- &.disabled {
- i.fa-retweet,
- &:hover i.fa-retweet {
- background-image: url("data:image/svg+xml;utf8,
");
- }
- }
-
- .media-modal__overlay .picture-in-picture__footer & {
- i.fa-retweet {
- background-image: url("data:image/svg+xml;utf8,
");
- }
-
- &.reblogPrivate {
- i.fa-retweet {
- background-image: url("data:image/svg+xml;utf8,
");
- }
- }
-
- &.disabled {
- i.fa-retweet {
- background-image: url("data:image/svg+xml;utf8,
");
- }
- }
- }
-}
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index 9a183b88d8a39b..6e7f725e5511e5 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -53,7 +53,10 @@
box-sizing: border-box;
color: $ui-button-color;
cursor: pointer;
- display: inline-block;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ gap: 6px;
font-family: inherit;
font-size: 15px;
font-weight: 500;
@@ -167,9 +170,13 @@
}
&.button--block {
- display: block;
width: 100%;
}
+
+ .icon {
+ width: 18px;
+ height: 18px;
+ }
}
.column__wrapper {
@@ -178,15 +185,30 @@
position: relative;
}
+.icon {
+ flex: 0 0 auto;
+ width: 20px;
+ height: 20px;
+ aspect-ratio: 1;
+
+ path {
+ fill: currentColor;
+ }
+}
+
.icon-button {
- display: inline-block;
- padding: 0;
+ display: inline-flex;
color: $action-button-color;
border: 0;
+ padding: 2px;
border-radius: 4px;
background: transparent;
cursor: pointer;
+ align-items: center;
+ justify-content: center;
text-decoration: none;
+ gap: 4px;
+ flex: 0 0 auto;
a {
color: inherit;
@@ -258,17 +280,9 @@
}
}
- &--with-counter {
- display: inline-flex;
- align-items: center;
- width: auto !important;
- padding: 0 4px 0 2px;
- }
-
&__counter {
- display: inline-block;
+ display: block;
width: auto;
- margin-inline-start: 4px;
font-size: 12px;
font-weight: 500;
}
@@ -628,6 +642,11 @@ body > [data-popper-placement] {
padding: 10px;
font-family: inherit;
+ .icon {
+ width: 15px;
+ height: 15px;
+ }
+
&:hover,
&:focus,
&:active {
@@ -673,6 +692,11 @@ body > [data-popper-placement] {
.compose-form__buttons {
display: flex;
+ gap: 2px;
+
+ .icon-button {
+ height: 100%;
+ }
.compose-form__upload-button-icon {
line-height: 27px;
@@ -747,10 +771,6 @@ body > [data-popper-placement] {
&:hover {
text-decoration: underline;
-
- .fa {
- color: lighten($dark-text-color, 7%);
- }
}
}
}
@@ -863,10 +883,6 @@ body > [data-popper-placement] {
&:hover {
text-decoration: underline;
-
- .fa {
- color: lighten($dark-text-color, 7%);
- }
}
&.mention {
@@ -878,10 +894,6 @@ body > [data-popper-placement] {
}
}
}
-
- .fa {
- color: $dark-text-color;
- }
}
a.unhandled-link {
@@ -966,7 +978,8 @@ body > [data-popper-placement] {
.status__content__read-more-button,
.status__content__translate-button {
- display: block;
+ display: flex;
+ align-items: center;
font-size: 15px;
line-height: 22px;
color: $highlight-text-color;
@@ -980,6 +993,11 @@ body > [data-popper-placement] {
&:active {
text-decoration: underline;
}
+
+ .icon {
+ width: 15px;
+ height: 15px;
+ }
}
.translate-button {
@@ -1191,6 +1209,12 @@ body > [data-popper-placement] {
.status__visibility-icon {
padding: 0 4px;
+
+ .icon {
+ width: 1em;
+ height: 1em;
+ margin-bottom: -2px;
+ }
}
.status__display-name {
@@ -1369,6 +1393,13 @@ body > [data-popper-placement] {
color: $dark-text-color;
font-size: 14px;
line-height: 18px;
+
+ .icon {
+ width: 15px;
+ height: 15px;
+ position: relative;
+ top: 0.145em;
+ }
}
.detailed-status__action-bar {
@@ -1407,18 +1438,24 @@ body > [data-popper-placement] {
}
.detailed-status__link {
+ display: inline-flex;
+ align-items: center;
color: inherit;
text-decoration: none;
- white-space: nowrap;
+ gap: 6px;
+ position: relative;
+ top: 0.145em;
+
+ .icon {
+ top: 0;
+ }
}
.detailed-status__favorites,
.detailed-status__reblogs {
- display: inline-block;
font-weight: 500;
font-size: 12px;
- line-height: 17px;
- margin-inline-start: 6px;
+ line-height: 18px;
}
.reply-indicator__content {
@@ -1759,10 +1796,17 @@ a.account__display-name {
line-height: 22px;
font-weight: 500;
display: flex;
+ align-items: center;
gap: 10px;
- .fa {
+ .icon {
color: $highlight-text-color;
+ width: 18px;
+ height: 18px;
+ }
+
+ .icon-star {
+ color: $gold-star;
}
> span {
@@ -1772,12 +1816,6 @@ a.account__display-name {
}
}
-.notification__favourite-icon-wrapper {
- .star-icon {
- color: $gold-star;
- }
-}
-
.icon-button.star-icon.active {
color: $gold-star;
}
@@ -1788,13 +1826,13 @@ a.account__display-name {
.no-reduce-motion .icon-button.star-icon {
&.activate {
- & > .fa-star {
+ & > .icon {
animation: spring-rotate-in 1s linear;
}
}
&.deactivate {
- & > .fa-star {
+ & > .icon {
animation: spring-rotate-out 1s linear;
}
}
@@ -1919,6 +1957,11 @@ a.account__display-name {
pointer-events: auto;
transform: scale(1, 1) translate(0, 0);
opacity: 1;
+
+ .icon {
+ width: 24px;
+ height: 24px;
+ }
}
}
}
@@ -1985,7 +2028,8 @@ a.account__display-name {
z-index: 9999;
&__text-button {
- display: inline;
+ display: inline-flex;
+ align-items: center;
color: inherit;
background: transparent;
border: 0;
@@ -1998,6 +2042,11 @@ a.account__display-name {
&:focus-visible {
outline: 1px dotted;
}
+
+ .icon {
+ width: 15px;
+ height: 15px;
+ }
}
&__container {
@@ -2201,6 +2250,11 @@ $ui-header-height: 55px;
.button-tertiary {
flex-shrink: 1;
}
+
+ .icon {
+ width: 22px;
+ height: 22px;
+ }
}
}
@@ -2215,14 +2269,6 @@ $ui-header-height: 55px;
padding-top: 10px;
top: 0;
}
-
- .tabs-bar {
- margin-bottom: 0;
-
- @media screen and (min-width: $no-gap-breakpoint) {
- margin-bottom: 10px;
- }
- }
}
.react-swipeable-view-container {
@@ -2272,13 +2318,15 @@ $ui-header-height: 55px;
}
.drawer__tab {
- display: block;
+ display: flex;
flex: 1 1 auto;
padding: 15px 5px 13px;
color: $darker-text-color;
text-decoration: none;
text-align: center;
font-size: 16px;
+ align-items: center;
+ justify-content: center;
border-bottom: 2px solid transparent;
}
@@ -2318,61 +2366,6 @@ $ui-header-height: 55px;
}
}
-.tabs-bar {
- box-sizing: border-box;
- display: flex;
- background: lighten($ui-base-color, 8%);
- flex: 0 0 auto;
- overflow-y: auto;
-}
-
-.tabs-bar__link {
- display: block;
- flex: 1 1 auto;
- padding: 15px 10px;
- padding-bottom: 13px;
- color: $primary-text-color;
- text-decoration: none;
- text-align: center;
- font-size: 14px;
- font-weight: 500;
- border-bottom: 2px solid lighten($ui-base-color, 8%);
- transition: all 50ms linear;
- transition-property: border-bottom, background, color;
-
- .fa {
- font-weight: 400;
- font-size: 16px;
- }
-
- &:hover,
- &:focus,
- &:active {
- @media screen and (width >= 631px) {
- background: lighten($ui-base-color, 14%);
- border-bottom-color: lighten($ui-base-color, 14%);
- }
- }
-
- &.active {
- border-bottom: 2px solid $highlight-text-color;
- color: $highlight-text-color;
- }
-
- span {
- margin-inline-start: 5px;
- display: none;
- }
-}
-
-@media screen and (width >= 600px) {
- .tabs-bar__link {
- span {
- display: inline;
- }
- }
-}
-
.columns-area--mobile {
flex-direction: column;
width: 100%;
@@ -2425,10 +2418,6 @@ $ui-header-height: 55px;
}
@media screen and (min-width: $no-gap-breakpoint) {
- .tabs-bar {
- width: 100%;
- }
-
.react-swipeable-view-container .columns-area--mobile {
height: calc(100% - 10px) !important;
}
@@ -2437,10 +2426,6 @@ $ui-header-height: 55px;
margin-bottom: 10px;
}
- .tabs-bar__link.optional {
- display: none;
- }
-
.search-page .search {
display: none;
}
@@ -2477,6 +2462,7 @@ $ui-header-height: 55px;
.navigation-panel__sign-in-banner,
.navigation-panel__logo,
+ .navigation-panel__banner,
.getting-started__trends {
display: none;
}
@@ -2539,6 +2525,7 @@ $ui-header-height: 55px;
}
.icon-with-badge {
+ display: inline-flex;
position: relative;
&__badge {
@@ -3004,13 +2991,14 @@ $ui-header-height: 55px;
position: relative;
overflow: hidden;
display: flex;
+ border-radius: 4px;
}
.drawer__inner {
position: absolute;
top: 0;
inset-inline-start: 0;
- background: lighten($ui-base-color, 13%);
+ background: $ui-base-color;
box-sizing: border-box;
padding: 0;
display: flex;
@@ -3026,7 +3014,7 @@ $ui-header-height: 55px;
}
.drawer__inner__mastodon {
- background: lighten($ui-base-color, 13%)
+ background: $ui-base-color
url('data:image/svg+xml;utf8,
')
no-repeat bottom / 100% auto;
flex: 1;
@@ -3057,20 +3045,15 @@ $ui-header-height: 55px;
.drawer__header {
flex: 0 0 auto;
font-size: 16px;
- background: lighten($ui-base-color, 8%);
+ background: $ui-base-color;
margin-bottom: 10px;
display: flex;
flex-direction: row;
border-radius: 4px;
overflow: hidden;
- a {
- transition: background 100ms ease-in;
-
- &:hover {
- background: lighten($ui-base-color, 3%);
- transition: background 200ms ease-out;
- }
+ a:hover {
+ background: lighten($ui-base-color, 3%);
}
}
@@ -3129,6 +3112,8 @@ $ui-header-height: 55px;
margin: 0;
z-index: 3;
outline: 0;
+ display: flex;
+ align-items: center;
&:hover {
text-decoration: underline;
@@ -3136,6 +3121,8 @@ $ui-header-height: 55px;
}
.column-header__back-button {
+ display: flex;
+ align-items: center;
background: $ui-base-color;
border: 0;
font-family: inherit;
@@ -3301,7 +3288,9 @@ $ui-header-height: 55px;
.column-link {
background: lighten($ui-base-color, 8%);
color: $primary-text-color;
- display: block;
+ display: flex;
+ align-items: center;
+ gap: 5px;
font-size: 16px;
padding: 15px;
text-decoration: none;
@@ -3353,11 +3342,6 @@ $ui-header-height: 55px;
}
}
-.column-link__icon {
- display: inline-block;
- margin-inline-end: 5px;
-}
-
.column-link__badge {
display: inline-block;
border-radius: 4px;
@@ -3517,29 +3501,6 @@ $ui-header-height: 55px;
}
}
-button.icon-button i.fa-retweet {
- background-position: 0 0;
- height: 19px;
- transition: background-position 0.9s steps(10);
- transition-duration: 0s;
- vertical-align: middle;
- width: 22px;
-
- &::before {
- display: none !important;
- }
-}
-
-button.icon-button.active i.fa-retweet {
- transition-duration: 0.9s;
- background-position: 0 100%;
-}
-
-.reduce-motion button.icon-button i.fa-retweet,
-.reduce-motion button.icon-button.active i.fa-retweet {
- transition: none;
-}
-
.status-card {
display: flex;
align-items: center;
@@ -3716,8 +3677,9 @@ a.status-card {
background: lighten($ui-base-color, 8%);
position: relative;
- & > .fa {
- font-size: 21px;
+ & > .icon {
+ width: 18px;
+ height: 18px;
position: absolute;
transform-origin: 50% 50%;
top: 50%;
@@ -3924,6 +3886,9 @@ a.status-card {
outline: 0;
& > button {
+ display: flex;
+ align-items: center;
+ gap: 5px;
margin: 0;
border: 0;
padding: 15px;
@@ -3973,6 +3938,9 @@ a.status-card {
}
.column-header__button {
+ display: flex;
+ justify-content: center;
+ align-items: center;
background: $ui-base-color;
border: 0;
color: $darker-text-color;
@@ -4079,7 +4047,9 @@ a.status-card {
}
.text-btn {
- display: inline-block;
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
padding: 0;
font-family: inherit;
font-size: inherit;
@@ -4087,6 +4057,11 @@ a.status-card {
border: 0;
background: transparent;
cursor: pointer;
+
+ .icon {
+ width: 13px;
+ height: 13px;
+ }
}
.column-header__issue-btn {
@@ -4098,11 +4073,6 @@ a.status-card {
}
}
-.column-header__icon {
- display: inline-block;
- margin-inline-end: 5px;
-}
-
.loading-indicator {
color: $dark-text-color;
font-size: 12px;
@@ -4761,10 +4731,11 @@ a.status-card {
color: $lighter-text-color;
overflow: hidden;
display: flex;
+ gap: 10px;
- .fa {
- font-size: 34px;
- margin-inline-end: 10px;
+ .icon {
+ width: 24px;
+ height: 24px;
}
span {
@@ -4947,22 +4918,6 @@ a.status-card {
}
}
-.privacy-dropdown.active {
- .privacy-dropdown__value {
- background: $simple-background-color;
- border-radius: 4px 4px 0 0;
- }
-
- &.top .privacy-dropdown__value {
- border-radius: 0 0 4px 4px;
- }
-
- .privacy-dropdown__dropdown {
- display: block;
- box-shadow: var(--dropdown-shadow);
- }
-}
-
.latex-dropdown__dropdown {
position: absolute;
background: $simple-background-color;
@@ -5108,6 +5063,9 @@ a.status-card {
font-weight: 500;
padding: 10px;
border-radius: 4px;
+ display: flex;
+ gap: 6px;
+ align-items: center;
&:focus,
&:active,
@@ -5163,6 +5121,15 @@ a.status-card {
margin-bottom: 10px;
}
+ .icon-button {
+ padding: 0;
+ }
+
+ .icon {
+ width: 18px;
+ height: 18px;
+ }
+
&__menu {
margin-bottom: 20px;
@@ -5271,17 +5238,16 @@ a.status-card {
outline: 0 !important;
}
- .fa {
+ .icon {
position: absolute;
- top: 16px;
+ top: 13px;
inset-inline-end: 10px;
display: inline-block;
opacity: 0;
transition: all 100ms linear;
transition-property: transform, opacity;
- font-size: 18px;
- width: 18px;
- height: 18px;
+ width: 24px;
+ height: 24px;
color: $secondary-text-color;
cursor: default;
pointer-events: none;
@@ -5292,7 +5258,7 @@ a.status-card {
}
}
- .fa-search {
+ .icon-search {
transform: rotate(90deg);
&.active {
@@ -5301,8 +5267,7 @@ a.status-card {
}
}
- .fa-times-circle {
- top: 17px;
+ .icon-times-circle {
transform: rotate(0deg);
color: $action-button-color;
cursor: pointer;
@@ -5325,11 +5290,9 @@ a.status-card {
font-weight: 500;
font-size: 16px;
cursor: default;
-
- .fa {
- display: inline-block;
- margin-inline-end: 5px;
- }
+ display: flex;
+ align-items: center;
+ gap: 5px;
}
.search-results__section {
@@ -5349,8 +5312,10 @@ a.status-card {
display: flex;
justify-content: space-between;
- h3 .fa {
- margin-inline-end: 5px;
+ h3 {
+ display: flex;
+ align-items: center;
+ gap: 5px;
}
button {
@@ -5777,19 +5742,6 @@ a.status-card {
flex-direction: column;
}
-.actions-modal {
- .status {
- background: $white;
- border-bottom-color: $ui-secondary-color;
- padding-top: 10px;
- padding-bottom: 10px;
- }
-
- .dropdown-menu__separator {
- border-bottom-color: $ui-secondary-color;
- }
-}
-
.boost-modal__container {
overflow-x: scroll;
padding: 10px;
@@ -6160,11 +6112,6 @@ a.status-card {
max-height: 80vh;
max-width: 80vw;
- .status {
- overflow-y: auto;
- max-height: 300px;
- }
-
.actions-modal__item-label {
font-weight: 500;
}
@@ -6371,7 +6318,9 @@ a.status-card {
}
.media-gallery__gifv__label {
- display: block;
+ display: flex;
+ align-items: center;
+ justify-content: center;
color: $white;
background: rgba($black, 0.65);
backdrop-filter: blur(10px) saturate(180%) contrast(75%) brightness(70%);
@@ -6382,6 +6331,11 @@ a.status-card {
z-index: 1;
pointer-events: none;
line-height: 18px;
+
+ .icon {
+ width: 15px;
+ height: 15px;
+ }
}
.attachment-list {
@@ -6403,10 +6357,6 @@ a.status-card {
align-items: center;
justify-content: center;
font-size: 26px;
-
- .fa {
- display: block;
- }
}
&__list {
@@ -6441,7 +6391,7 @@ a.status-card {
display: block;
}
- .fa {
+ .icon {
color: $dark-text-color;
}
}
@@ -6736,18 +6686,17 @@ a.status-card {
flex: 0 1 auto;
min-width: 30px;
align-items: center;
- font-size: 16px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
+ gap: 5px;
.player-button {
display: inline-block;
outline: 0;
+ padding: 5px;
flex: 0 0 auto;
background: transparent;
- padding: 5px;
- font-size: 16px;
border: 0;
color: rgba($white, 0.75);
@@ -7138,7 +7087,6 @@ noscript {
$duration: 400ms;
$delay: 100ms;
- .tabs-bar,
.search {
will-change: margin-top;
transition: margin-top $duration $delay;
@@ -7181,7 +7129,6 @@ noscript {
}
.is-composing {
- .tabs-bar,
.search {
margin-top: -50px;
}
@@ -7847,24 +7794,14 @@ noscript {
font-weight: 500;
text-decoration: none;
}
-}
-
-.trends {
- &__header {
- color: $dark-text-color;
- background: lighten($ui-base-color, 2%);
- border-bottom: 1px solid darken($ui-base-color, 4%);
- font-weight: 500;
- padding: 15px;
- font-size: 16px;
- cursor: default;
- .fa {
- display: inline-block;
- margin-inline-end: 5px;
- }
+ .icon {
+ width: 16px;
+ height: 16px;
}
+}
+.trends {
&__item {
display: flex;
align-items: center;
@@ -8355,10 +8292,9 @@ noscript {
color: $darker-text-color;
aspect-ratio: 16 / 9;
- i {
- display: block;
- font-size: 24px;
- font-weight: 400;
+ .icon {
+ width: 24px;
+ height: 24px;
margin-bottom: 10px;
}
@@ -8419,21 +8355,20 @@ noscript {
border: 1px solid lighten($ui-base-color, 8%);
}
- .search .fa {
- top: 10px;
+ .search .icon {
+ top: 9px;
inset-inline-end: 10px;
color: $dark-text-color;
}
-
- .search .fa-times-circle {
- top: 12px;
- }
}
.explore__search-results {
flex: 1 1 auto;
display: flex;
flex-direction: column;
+ background: $ui-base-color;
+ border-bottom-left-radius: 4px;
+ border-bottom-right-radius: 4px;
}
.story {
@@ -9164,6 +9099,10 @@ noscript {
color: $dark-text-color;
margin-bottom: 20px;
+ .version {
+ white-space: nowrap;
+ }
+
strong {
font-weight: 500;
}
@@ -9345,6 +9284,9 @@ noscript {
margin-bottom: 10px;
&__title {
+ display: flex;
+ align-items: center;
+ gap: 6px;
font-size: 17px;
font-weight: 600;
line-height: 22px;
@@ -9439,14 +9381,17 @@ noscript {
0 10px 15px -3px rgba($base-shadow-color, 0.25),
0 4px 6px -4px rgba($base-shadow-color, 0.25);
cursor: default;
- transition: 0.5s cubic-bezier(0.89, 0.01, 0.5, 1.1);
- transform: translateZ(0);
font-size: 15px;
line-height: 21px;
&.notification-bar-active {
inset-inline-start: 1rem;
}
+
+ .no-reduce-motion & {
+ transition: 0.5s cubic-bezier(0.89, 0.01, 0.5, 1.1);
+ transform: translateZ(0);
+ }
}
.notification-bar-title {
diff --git a/app/javascript/types/image.d.ts b/app/javascript/types/image.d.ts
index 15f0007af5dff9..07d19295556b47 100644
--- a/app/javascript/types/image.d.ts
+++ b/app/javascript/types/image.d.ts
@@ -20,6 +20,14 @@ declare module '*.png' {
}
declare module '*.svg' {
+ import type React from 'react';
+
+ interface SVGPropsWithTitle extends React.SVGProps
{
+ title?: string;
+ }
+
+ export const ReactComponent: React.FC;
+
const path: string;
export default path;
}
diff --git a/app/lib/account_statuses_filter.rb b/app/lib/account_statuses_filter.rb
index e3d73067b0cdf6..44385290443070 100644
--- a/app/lib/account_statuses_filter.rb
+++ b/app/lib/account_statuses_filter.rb
@@ -60,8 +60,12 @@ def filtered_reblogs_scope
.where(reblog_of_id: nil)
.or(
scope
+ # This is basically `Status.not_domain_blocked_by_account(current_account)`
+ # and `Status.not_excluded_by_account(current_account)` but on the
+ # `reblog` association. Unfortunately, there seem to be no clean way
+ # to re-use those scopes in our case.
+ .where(reblog: { accounts: { domain: nil } }).or(scope.where.not(reblog: { accounts: { domain: current_account.excluded_from_timeline_domains } }))
.where.not(reblog: { account_id: current_account.excluded_from_timeline_account_ids })
- .where.not(reblog: { accounts: { domain: current_account.excluded_from_timeline_domains } })
)
end
diff --git a/app/lib/activitypub/case_transform.rb b/app/lib/activitypub/case_transform.rb
index da2c5eb8b05774..bf5de722103a88 100644
--- a/app/lib/activitypub/case_transform.rb
+++ b/app/lib/activitypub/case_transform.rb
@@ -14,6 +14,8 @@ def camel_lower(value)
when String
camel_lower_cache[value] ||= if value.start_with?('_:')
"_:#{value.delete_prefix('_:').underscore.camelize(:lower)}"
+ elsif LanguagesHelper::ISO_639_1_REGIONAL.key?(value.to_sym)
+ value
else
value.underscore.camelize(:lower)
end
diff --git a/app/lib/activitypub/linked_data_signature.rb b/app/lib/activitypub/linked_data_signature.rb
index ea59879f3b7eed..faea63e8f12c6e 100644
--- a/app/lib/activitypub/linked_data_signature.rb
+++ b/app/lib/activitypub/linked_data_signature.rb
@@ -18,8 +18,8 @@ def verify_actor!
return unless type == 'RsaSignature2017'
- creator = ActivityPub::TagManager.instance.uri_to_actor(creator_uri)
- creator ||= ActivityPub::FetchRemoteKeyService.new.call(creator_uri, id: false)
+ creator = ActivityPub::TagManager.instance.uri_to_actor(creator_uri)
+ creator = ActivityPub::FetchRemoteKeyService.new.call(creator_uri, id: false) if creator&.public_key.blank?
return if creator.nil?
@@ -28,6 +28,8 @@ def verify_actor!
to_be_verified = options_hash + document_hash
creator if creator.keypair.public_key.verify(OpenSSL::Digest.new('SHA256'), Base64.decode64(signature), to_be_verified)
+ rescue OpenSSL::PKey::RSAError
+ false
end
def sign!(creator, sign_with: nil)
diff --git a/app/lib/admin/metrics/dimension/software_versions_dimension.rb b/app/lib/admin/metrics/dimension/software_versions_dimension.rb
index 72a98a88ab78c4..ccf556eae0864a 100644
--- a/app/lib/admin/metrics/dimension/software_versions_dimension.rb
+++ b/app/lib/admin/metrics/dimension/software_versions_dimension.rb
@@ -25,7 +25,8 @@ def mastodon_version
end
def ruby_version
- value = "#{RUBY_VERSION}p#{RUBY_PATCHLEVEL}"
+ yjit = defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled?
+ value = "#{RUBY_VERSION}p#{RUBY_PATCHLEVEL}#{yjit ? ' +YJIT' : ''}"
{
key: 'ruby',
diff --git a/app/lib/admin/metrics/dimension/space_usage_dimension.rb b/app/lib/admin/metrics/dimension/space_usage_dimension.rb
index cc856089047b40..f1b6dba0403008 100644
--- a/app/lib/admin/metrics/dimension/space_usage_dimension.rb
+++ b/app/lib/admin/metrics/dimension/space_usage_dimension.rb
@@ -11,7 +11,7 @@ def key
protected
def perform_query
- [postgresql_size, redis_size, media_size]
+ [postgresql_size, redis_size, media_size, search_size].compact
end
def postgresql_size
@@ -65,4 +65,22 @@ def redis_info
redis.info
end
end
+
+ def search_size
+ return unless Chewy.enabled?
+
+ client_info = Chewy.client.info
+
+ value = Chewy.client.indices.stats['indices'].values.sum { |index_data| index_data['primaries']['store']['size_in_bytes'] }
+
+ {
+ key: 'search',
+ human_key: client_info.dig('version', 'distribution') == 'opensearch' ? 'OpenSearch' : 'Elasticsearch',
+ value: value.to_s,
+ unit: 'bytes',
+ human_value: number_to_human_size(value),
+ }
+ rescue Faraday::ConnectionFailed, Elasticsearch::Transport::Transport::Error
+ nil
+ end
end
diff --git a/app/lib/admin/system_check/elasticsearch_check.rb b/app/lib/admin/system_check/elasticsearch_check.rb
index 406bb5bcb9a61e..ea35807f301f2d 100644
--- a/app/lib/admin/system_check/elasticsearch_check.rb
+++ b/app/lib/admin/system_check/elasticsearch_check.rb
@@ -76,14 +76,35 @@ def required_version
end
def compatible_version?
- return false if running_version.nil?
-
- Gem::Version.new(running_version) >= Gem::Version.new(required_version) ||
- Gem::Version.new(compatible_wire_version) >= Gem::Version.new(required_version)
+ running_version_ok? || compatible_wire_version_ok?
rescue ArgumentError
false
end
+ def running_version_ok?
+ return false if running_version.blank?
+
+ gem_version_running >= gem_version_required
+ end
+
+ def compatible_wire_version_ok?
+ return false if compatible_wire_version.blank?
+
+ gem_version_compatible_wire >= gem_version_required
+ end
+
+ def gem_version_running
+ Gem::Version.new(running_version)
+ end
+
+ def gem_version_required
+ Gem::Version.new(required_version)
+ end
+
+ def gem_version_compatible_wire
+ Gem::Version.new(compatible_wire_version)
+ end
+
def mismatched_indexes
@mismatched_indexes ||= INDEXES.filter_map do |klass|
klass.base_name if Chewy.client.indices.get_mapping[klass.index_name]&.deep_symbolize_keys != klass.mappings_hash
diff --git a/app/lib/attachment_batch.rb b/app/lib/attachment_batch.rb
index b75938bdd76215..78bd5931603535 100644
--- a/app/lib/attachment_batch.rb
+++ b/app/lib/attachment_batch.rb
@@ -75,7 +75,7 @@ def remove_files
end
when :fog
logger.debug { "Deleting #{attachment.path(style)}" }
- attachment.directory.files.new(key: attachment.path(style)).destroy
+ attachment.send(:directory).files.new(key: attachment.path(style)).destroy
when :azure
logger.debug { "Deleting #{attachment.path(style)}" }
attachment.destroy
diff --git a/app/lib/cache_buster.rb b/app/lib/cache_buster.rb
index c54b0da1a11fbc..554f2ba95d7307 100644
--- a/app/lib/cache_buster.rb
+++ b/app/lib/cache_buster.rb
@@ -2,7 +2,7 @@
class CacheBuster
def initialize(options = {})
- ActiveSupport::Deprecation.warn('Default values for the cache buster secret header name and values will be removed in Mastodon 4.3. Please set them explicitely if you rely on those.') unless options[:http_method] || (options[:secret] && options[:secret_header])
+ Rails.application.deprecators[:mastodon].warn('Default values for the cache buster secret header name and values will be removed in Mastodon 4.3. Please set them explicitely if you rely on those.') unless options[:http_method] || (options[:secret] && options[:secret_header])
@secret_header = options[:secret_header] ||
(options[:http_method] ? nil : 'Secret-Header')
diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb
index 4650d64cdb2e88..0bcf332b1d28f0 100644
--- a/app/lib/feed_manager.rb
+++ b/app/lib/feed_manager.rb
@@ -217,6 +217,7 @@ def unmerge_tag_from_home(from_tag, into_account)
# also tagged with another followed hashtag or from a followed user
scope = from_tag.statuses
.where(id: timeline_status_ids)
+ .where.not(account: into_account)
.where.not(account: into_account.following)
.tagged_with_none(TagFollow.where(account: into_account).pluck(:tag_id))
diff --git a/app/lib/importer/base_importer.rb b/app/lib/importer/base_importer.rb
index a21557d303a480..7688426b48cbf6 100644
--- a/app/lib/importer/base_importer.rb
+++ b/app/lib/importer/base_importer.rb
@@ -34,7 +34,9 @@ def optimize_for_search!
# Estimate the amount of documents that would be indexed. Not exact!
# @returns [Integer]
def estimate!
- ActiveRecord::Base.connection_pool.with_connection { |connection| connection.select_one("SELECT reltuples AS estimate FROM pg_class WHERE relname = '#{index.adapter.target.table_name}'")['estimate'].to_i }
+ reltuples = ActiveRecord::Base.connection_pool.with_connection { |connection| connection.select_one("SELECT reltuples FROM pg_class WHERE relname = '#{index.adapter.target.table_name}'")['reltuples'].to_i }
+ # If the table has never yet been vacuumed or analyzed, reltuples contains -1
+ [reltuples, 0].max
end
# Import data from the database into the index
diff --git a/app/lib/link_details_extractor.rb b/app/lib/link_details_extractor.rb
index b95ec805190848..a96612cab0d131 100644
--- a/app/lib/link_details_extractor.rb
+++ b/app/lib/link_details_extractor.rb
@@ -36,7 +36,8 @@ def description
end
def language
- json['inLanguage']
+ lang = json['inLanguage']
+ lang.is_a?(Hash) ? (lang['alternateName'] || lang['name']) : lang
end
def type
diff --git a/app/lib/search_query_transformer.rb b/app/lib/search_query_transformer.rb
index a45ae3d09bc1a7..927495eace9795 100644
--- a/app/lib/search_query_transformer.rb
+++ b/app/lib/search_query_transformer.rb
@@ -58,6 +58,8 @@ def indexes
case @flags['in']
when 'library'
[StatusesIndex]
+ when 'public'
+ [PublicStatusesIndex]
else
[PublicStatusesIndex, StatusesIndex]
end
diff --git a/app/models/account.rb b/app/models/account.rb
index d670767dab92a1..e15606368a92f7 100644
--- a/app/models/account.rb
+++ b/app/models/account.rb
@@ -66,7 +66,7 @@ class Account < ApplicationRecord
BACKGROUND_REFRESH_INTERVAL = 1.week.freeze
USERNAME_RE = /[a-z0-9_]+([a-z0-9_.-]+[a-z0-9_]+)?/i
- MENTION_RE = %r{(?<=^|[^/[:word:]])@((#{USERNAME_RE})(?:@[[:word:].-]+[[:word:]]+)?)}i
+ MENTION_RE = %r{(? { without_unapproved.without_suspended.where(moved_to_account_id: nil) }
scope :discoverable, -> { searchable.without_silenced.where(discoverable: true).joins(:account_stat) }
scope :followable_by, ->(account) { joins(arel_table.join(Follow.arel_table, Arel::Nodes::OuterJoin).on(arel_table[:id].eq(Follow.arel_table[:target_account_id]).and(Follow.arel_table[:account_id].eq(account.id))).join_sources).where(Follow.arel_table[:id].eq(nil)).joins(arel_table.join(FollowRequest.arel_table, Arel::Nodes::OuterJoin).on(arel_table[:id].eq(FollowRequest.arel_table[:target_account_id]).and(FollowRequest.arel_table[:account_id].eq(account.id))).join_sources).where(FollowRequest.arel_table[:id].eq(nil)) }
- scope :by_recent_status, -> { order(Arel.sql('account_stats.last_status_at DESC NULLS LAST')) }
+ scope :by_recent_status, -> { includes(:account_stat).merge(AccountStat.order('last_status_at DESC NULLS LAST')).references(:account_stat) }
scope :by_recent_sign_in, -> { order(Arel.sql('users.current_sign_in_at DESC NULLS LAST')) }
scope :popular, -> { order('account_stats.followers_count desc') }
scope :by_domain_and_subdomains, ->(domain) { where(domain: Instance.by_domain_and_subdomains(domain).select(:domain)) }
diff --git a/app/models/account_alias.rb b/app/models/account_alias.rb
index f859344fa2560a..3b75919afe2969 100644
--- a/app/models/account_alias.rb
+++ b/app/models/account_alias.rb
@@ -23,10 +23,7 @@ class AccountAlias < ApplicationRecord
after_create :add_to_account
after_destroy :remove_from_account
- def acct=(val)
- val = val.to_s.strip
- super(val.start_with?('@') ? val[1..] : val)
- end
+ normalizes :acct, with: ->(acct) { acct.strip.delete_prefix('@') }
def pretty_acct
username, domain = acct.split('@', 2)
diff --git a/app/models/account_migration.rb b/app/models/account_migration.rb
index b9da596172b5e1..dc22e329421df6 100644
--- a/app/models/account_migration.rb
+++ b/app/models/account_migration.rb
@@ -25,6 +25,8 @@ class AccountMigration < ApplicationRecord
before_validation :set_target_account
before_validation :set_followers_count
+ normalizes :acct, with: ->(acct) { acct.strip.delete_prefix('@') }
+
validates :acct, presence: true, domain: { acct: true }
validate :validate_migration_cooldown
validate :validate_target_account
@@ -51,10 +53,6 @@ def cooldown_at
created_at + COOLDOWN_PERIOD
end
- def acct=(val)
- super(val.to_s.strip.gsub(/\A@/, ''))
- end
-
private
def set_target_account
diff --git a/app/models/account_warning.rb b/app/models/account_warning.rb
index 4f8cc5320095b1..9286577f516e65 100644
--- a/app/models/account_warning.rb
+++ b/app/models/account_warning.rb
@@ -27,7 +27,7 @@ class AccountWarning < ApplicationRecord
suspend: 4_000,
}, _suffix: :action
- before_validation :before_validate
+ normalizes :text, with: ->(text) { text.to_s }, apply_to_nil: true
belongs_to :account, inverse_of: :account_warnings
belongs_to :target_account, class_name: 'Account', inverse_of: :strikes
@@ -50,10 +50,4 @@ def overruled?
def to_log_human_identifier
target_account.acct
end
-
- private
-
- def before_validate
- self.text = '' if text.blank?
- end
end
diff --git a/app/models/admin/action_log_filter.rb b/app/models/admin/action_log_filter.rb
index f89d452ef4f7bc..0117974628b7b7 100644
--- a/app/models/admin/action_log_filter.rb
+++ b/app/models/admin/action_log_filter.rb
@@ -38,7 +38,7 @@ class Admin::ActionLogFilter
destroy_status: { target_type: 'Status', action: 'destroy' }.freeze,
destroy_user_role: { target_type: 'UserRole', action: 'destroy' }.freeze,
destroy_canonical_email_block: { target_type: 'CanonicalEmailBlock', action: 'destroy' }.freeze,
- disable_2fa_user: { target_type: 'User', action: 'disable' }.freeze,
+ disable_2fa_user: { target_type: 'User', action: 'disable_2fa' }.freeze,
disable_custom_emoji: { target_type: 'CustomEmoji', action: 'disable' }.freeze,
disable_user: { target_type: 'User', action: 'disable' }.freeze,
enable_custom_emoji: { target_type: 'CustomEmoji', action: 'enable' }.freeze,
diff --git a/app/models/concerns/has_user_settings.rb b/app/models/concerns/has_user_settings.rb
index 789ca32c162a81..cd9dc8de5119a9 100644
--- a/app/models/concerns/has_user_settings.rb
+++ b/app/models/concerns/has_user_settings.rb
@@ -4,7 +4,7 @@ module HasUserSettings
extend ActiveSupport::Concern
included do
- serialize :settings, UserSettingsSerializer
+ serialize :settings, coder: UserSettingsSerializer
end
def settings_attributes=(attributes)
diff --git a/app/models/concerns/status_safe_reblog_insert.rb b/app/models/concerns/status_safe_reblog_insert.rb
index 5d464697c5cdbd..0007b46d402084 100644
--- a/app/models/concerns/status_safe_reblog_insert.rb
+++ b/app/models/concerns/status_safe_reblog_insert.rb
@@ -15,7 +15,7 @@ module StatusSafeReblogInsert
#
# The code is kept similar to ActiveRecord::Persistence code and calls it
# directly when we are not handling a reblog.
- def _insert_record(values)
+ def _insert_record(values, returning)
return super unless values.is_a?(Hash) && values['reblog_of_id']&.value.present?
primary_key = self.primary_key
@@ -34,7 +34,7 @@ def _insert_record(values)
# Instead, we use a custom builder when a reblog is happening:
im = _compile_reblog_insert(values)
- connection.insert(im, "#{self} Create", primary_key || false, primary_key_value).tap do |result|
+ connection.insert(im, "#{self} Create", primary_key || false, primary_key_value, returning: returning).tap do |result|
# Since we are using SELECT instead of VALUES, a non-error `nil` return is possible.
# For our purposes, it's equivalent to a foreign key constraint violation
raise ActiveRecord::InvalidForeignKey, "(reblog_of_id)=(#{values['reblog_of_id'].value}) is not present in table \"statuses\"" if result.nil?
diff --git a/app/models/featured_tag.rb b/app/models/featured_tag.rb
index 587dcf9912ae29..7c36aa8b0bc174 100644
--- a/app/models/featured_tag.rb
+++ b/app/models/featured_tag.rb
@@ -23,7 +23,7 @@ class FeaturedTag < ApplicationRecord
validate :validate_tag_uniqueness, on: :create
validate :validate_featured_tags_limit, on: :create
- before_validation :strip_name
+ normalizes :name, with: ->(name) { name.strip.delete_prefix('#') }
before_create :set_tag
before_create :reset_data
@@ -50,10 +50,6 @@ def decrement(deleted_status_id)
private
- def strip_name
- self.name = name&.strip&.gsub(/\A#/, '')
- end
-
def set_tag
self.tag = Tag.find_or_create_by_names(name)&.first
end
diff --git a/app/models/form/custom_emoji_batch.rb b/app/models/form/custom_emoji_batch.rb
index 484415f9022f82..c63996e06950b2 100644
--- a/app/models/form/custom_emoji_batch.rb
+++ b/app/models/form/custom_emoji_batch.rb
@@ -34,7 +34,7 @@ def custom_emojis
end
def update!
- custom_emojis.each { |custom_emoji| authorize(custom_emoji, :update?) }
+ verify_authorization(:update?)
category = if category_id.present?
CustomEmojiCategory.find(category_id)
@@ -49,7 +49,7 @@ def update!
end
def list!
- custom_emojis.each { |custom_emoji| authorize(custom_emoji, :update?) }
+ verify_authorization(:update?)
custom_emojis.each do |custom_emoji|
custom_emoji.update(visible_in_picker: true)
@@ -58,7 +58,7 @@ def list!
end
def unlist!
- custom_emojis.each { |custom_emoji| authorize(custom_emoji, :update?) }
+ verify_authorization(:update?)
custom_emojis.each do |custom_emoji|
custom_emoji.update(visible_in_picker: false)
@@ -67,7 +67,7 @@ def unlist!
end
def enable!
- custom_emojis.each { |custom_emoji| authorize(custom_emoji, :enable?) }
+ verify_authorization(:enable?)
custom_emojis.each do |custom_emoji|
custom_emoji.update(disabled: false)
@@ -76,7 +76,7 @@ def enable!
end
def disable!
- custom_emojis.each { |custom_emoji| authorize(custom_emoji, :disable?) }
+ verify_authorization(:disable?)
custom_emojis.each do |custom_emoji|
custom_emoji.update(disabled: true)
@@ -85,7 +85,7 @@ def disable!
end
def copy!
- custom_emojis.each { |custom_emoji| authorize(custom_emoji, :copy?) }
+ verify_authorization(:copy?)
custom_emojis.each do |custom_emoji|
copied_custom_emoji = custom_emoji.copy!
@@ -94,11 +94,15 @@ def copy!
end
def delete!
- custom_emojis.each { |custom_emoji| authorize(custom_emoji, :destroy?) }
+ verify_authorization(:destroy?)
custom_emojis.each do |custom_emoji|
custom_emoji.destroy
log_action :destroy, custom_emoji
end
end
+
+ def verify_authorization(permission)
+ custom_emojis.each { |custom_emoji| authorize(custom_emoji, permission) }
+ end
end
diff --git a/app/models/form/import.rb b/app/models/form/import.rb
index 2fc74715b5fd80..29a2975c7be187 100644
--- a/app/models/form/import.rb
+++ b/app/models/form/import.rb
@@ -43,14 +43,14 @@ class EmptyFileError < StandardError; end
validate :validate_data
def guessed_type
- return :muting if csv_data.headers.include?('Hide notifications')
- return :following if csv_data.headers.include?('Show boosts') || csv_data.headers.include?('Notify on new posts') || csv_data.headers.include?('Languages')
- return :following if data.original_filename&.start_with?('follows') || data.original_filename&.start_with?('following_accounts')
- return :blocking if data.original_filename&.start_with?('blocks') || data.original_filename&.start_with?('blocked_accounts')
- return :muting if data.original_filename&.start_with?('mutes') || data.original_filename&.start_with?('muted_accounts')
- return :domain_blocking if data.original_filename&.start_with?('domain_blocks') || data.original_filename&.start_with?('blocked_domains')
- return :bookmarks if data.original_filename&.start_with?('bookmarks')
- return :lists if data.original_filename&.start_with?('lists')
+ return :muting if csv_headers_match?('Hide notifications')
+ return :following if csv_headers_match?('Show boosts') || csv_headers_match?('Notify on new posts') || csv_headers_match?('Languages')
+ return :following if file_name_matches?('follows') || file_name_matches?('following_accounts')
+ return :blocking if file_name_matches?('blocks') || file_name_matches?('blocked_accounts')
+ return :muting if file_name_matches?('mutes') || file_name_matches?('muted_accounts')
+ return :domain_blocking if file_name_matches?('domain_blocks') || file_name_matches?('blocked_domains')
+ return :bookmarks if file_name_matches?('bookmarks')
+ return :lists if file_name_matches?('lists')
end
# Whether the uploaded CSV file seems to correspond to a different import type than the one selected
@@ -79,6 +79,14 @@ def mode=(str)
private
+ def file_name_matches?(string)
+ data.original_filename&.start_with?(string)
+ end
+
+ def csv_headers_match?(string)
+ csv_data.headers.include?(string)
+ end
+
def default_csv_headers
case type.to_sym
when :following, :blocking, :muting
diff --git a/app/models/form/ip_block_batch.rb b/app/models/form/ip_block_batch.rb
index f6fe9b59357779..bdfeb91c8a810f 100644
--- a/app/models/form/ip_block_batch.rb
+++ b/app/models/form/ip_block_batch.rb
@@ -21,11 +21,15 @@ def ip_blocks
end
def delete!
- ip_blocks.each { |ip_block| authorize(ip_block, :destroy?) }
+ verify_authorization(:destroy?)
ip_blocks.each do |ip_block|
ip_block.destroy
log_action :destroy, ip_block
end
end
+
+ def verify_authorization(permission)
+ ip_blocks.each { |ip_block| authorize(ip_block, permission) }
+ end
end
diff --git a/app/models/preview_card.rb b/app/models/preview_card.rb
index 4e24fab2402c03..a1751c426dc0fc 100644
--- a/app/models/preview_card.rb
+++ b/app/models/preview_card.rb
@@ -55,7 +55,7 @@ class PreviewCard < ApplicationRecord
has_attached_file :image, processors: [:thumbnail, :blurhash_transcoder], styles: ->(f) { image_styles(f) }, convert_options: { all: '-quality 90 +profile "!icc,*" +set date:modify +set date:create +set date:timestamp' }, validate_media_type: false
- validates :url, presence: true, uniqueness: true
+ validates :url, presence: true, uniqueness: true, url: true
validates_attachment_content_type :image, content_type: IMAGE_MIME_TYPES
validates_attachment_size :image, less_than: LIMIT
remotable_attachment :image, LIMIT
diff --git a/app/models/relationship_filter.rb b/app/models/relationship_filter.rb
index 955d7d188ae2a5..d686f9ed89db44 100644
--- a/app/models/relationship_filter.rb
+++ b/app/models/relationship_filter.rb
@@ -114,7 +114,7 @@ def order_scope(value)
def activity_scope(value)
case value
when 'dormant'
- AccountStat.where(last_status_at: nil).or(AccountStat.where(AccountStat.arel_table[:last_status_at].lt(1.month.ago)))
+ Account.joins(:account_stat).where(account_stat: { last_status_at: [nil, ...1.month.ago] })
else
raise Mastodon::InvalidParameterError, "Unknown activity: #{value}"
end
diff --git a/app/models/relay.rb b/app/models/relay.rb
index a5fa03a99cda92..8d697b891f9360 100644
--- a/app/models/relay.rb
+++ b/app/models/relay.rb
@@ -19,7 +19,8 @@ class Relay < ApplicationRecord
scope :enabled, -> { accepted }
- before_validation :strip_url
+ normalizes :inbox_url, with: ->(inbox_url) { inbox_url.strip }
+
before_destroy :ensure_disabled
alias enabled? accepted?
@@ -76,8 +77,4 @@ def some_local_account
def ensure_disabled
disable! if enabled?
end
-
- def strip_url
- inbox_url&.strip!
- end
end
diff --git a/app/models/report.rb b/app/models/report.rb
index eaf662d1e29441..81ad721df12644 100644
--- a/app/models/report.rb
+++ b/app/models/report.rb
@@ -142,6 +142,11 @@ def history
target_type: 'Status',
target_id: status_ids
).unscope(:order).arel,
+
+ Admin::ActionLog.where(
+ target_type: 'AccountWarning',
+ target_id: AccountWarning.where(report_id: id).select(:id)
+ ).unscope(:order).arel,
].reduce { |union, query| Arel::Nodes::UnionAll.new(union, query) }
Admin::ActionLog.from(Arel::Nodes::As.new(subquery, Admin::ActionLog.arel_table))
diff --git a/app/models/report_filter.rb b/app/models/report_filter.rb
index c9b3bce2d128fc..fd0e23cb81705d 100644
--- a/app/models/report_filter.rb
+++ b/app/models/report_filter.rb
@@ -19,7 +19,7 @@ def results
scope = Report.unresolved
params.each do |key, value|
- scope = scope.merge scope_for(key, value), rewhere: true
+ scope = scope.merge scope_for(key, value)
end
scope
diff --git a/app/models/tag.rb b/app/models/tag.rb
index 672d80c8b871c3..413f6f5004766e 100644
--- a/app/models/tag.rb
+++ b/app/models/tag.rb
@@ -35,7 +35,7 @@ class Tag < ApplicationRecord
HASHTAG_LAST_SEQUENCE = '([[:word:]_]*[[:alpha:]][[:word:]_]*)'
HASHTAG_NAME_PAT = "#{HASHTAG_FIRST_SEQUENCE}|#{HASHTAG_LAST_SEQUENCE}"
- HASHTAG_RE = %r{(?:^|[^/)\w])#(#{HASHTAG_NAME_PAT})}i
+ HASHTAG_RE = %r{(?= ?', MIN_AGE.ago).count.zero?
diff --git a/app/serializers/manifest_serializer.rb b/app/serializers/manifest_serializer.rb
index 48f3aa7a6a3cfb..501bb788e7cdbe 100644
--- a/app/serializers/manifest_serializer.rb
+++ b/app/serializers/manifest_serializer.rb
@@ -16,11 +16,18 @@ class ManifestSerializer < ActiveModel::Serializer
512
).freeze
- attributes :name, :short_name,
+ attributes :id, :name, :short_name,
:icons, :theme_color, :background_color,
:display, :start_url, :scope,
:share_target, :shortcuts
+ def id
+ # This is set to `/home` because that was the old value of `start_url` and
+ # thus the fallback ID computed by Chrome:
+ # https://developer.chrome.com/blog/pwa-manifest-id/
+ '/home'
+ end
+
def name
object.title
end
@@ -53,7 +60,7 @@ def display
end
def start_url
- '/home'
+ '/'
end
def scope
@@ -84,6 +91,10 @@ def shortcuts
name: 'Notifications',
url: '/notifications',
},
+ {
+ name: 'Explore',
+ url: '/explore',
+ },
]
end
end
diff --git a/app/serializers/rest/application_serializer.rb b/app/serializers/rest/application_serializer.rb
index ab68219ade8fb2..e4806a3c9fc5b4 100644
--- a/app/serializers/rest/application_serializer.rb
+++ b/app/serializers/rest/application_serializer.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class REST::ApplicationSerializer < ActiveModel::Serializer
- attributes :id, :name, :website, :redirect_uri,
+ attributes :id, :name, :website, :scopes, :redirect_uri,
:client_id, :client_secret, :vapid_key
def id
diff --git a/app/services/activitypub/process_status_update_service.rb b/app/services/activitypub/process_status_update_service.rb
index ec983510b91414..4ff92da01fb2c7 100644
--- a/app/services/activitypub/process_status_update_service.rb
+++ b/app/services/activitypub/process_status_update_service.rb
@@ -97,8 +97,6 @@ def update_media_attachments!
end
end
- added_media_attachments = @next_media_attachments - previous_media_attachments
-
@status.ordered_media_attachment_ids = @next_media_attachments.map(&:id)
@media_attachments_changed = true if @status.ordered_media_attachment_ids != previous_media_attachments_ids
diff --git a/app/services/report_service.rb b/app/services/report_service.rb
index 22d788d5439752..b4015d1cbf6065 100644
--- a/app/services/report_service.rb
+++ b/app/services/report_service.rb
@@ -57,7 +57,7 @@ def forward_to_origin!
def forward_to_replied_to!
# Send report to servers to which the account was replying to, so they also have a chance to act
- inbox_urls = Account.remote.where(domain: forward_to_domains).where(id: Status.where(id: reported_status_ids).where.not(in_reply_to_account_id: nil).select(:in_reply_to_account_id)).inboxes - [@target_account.inbox_url]
+ inbox_urls = Account.remote.where(domain: forward_to_domains).where(id: Status.where(id: reported_status_ids).where.not(in_reply_to_account_id: nil).select(:in_reply_to_account_id)).inboxes - [@target_account.inbox_url, @target_account.shared_inbox_url]
inbox_urls.each do |inbox_url|
ActivityPub::DeliveryWorker.perform_async(payload, some_local_account.id, inbox_url)
diff --git a/app/services/software_update_check_service.rb b/app/services/software_update_check_service.rb
index 49b92f104db0f7..c8ce1753f5f6c6 100644
--- a/app/services/software_update_check_service.rb
+++ b/app/services/software_update_check_service.rb
@@ -35,11 +35,13 @@ def version
end
def process_update_notices!(update_notices)
- return if update_notices.blank? || update_notices['updatesAvailable'].blank?
+ return if update_notices.blank? || update_notices['updatesAvailable'].nil?
# Clear notices that are not listed by the update server anymore
SoftwareUpdate.where.not(version: update_notices['updatesAvailable'].pluck('version')).delete_all
+ return if update_notices['updatesAvailable'].blank?
+
# Check if any of the notices is new, and issue notifications
known_versions = SoftwareUpdate.where(version: update_notices['updatesAvailable'].pluck('version')).pluck(:version)
new_update_notices = update_notices['updatesAvailable'].filter { |notice| known_versions.exclude?(notice['version']) }
diff --git a/app/services/update_account_service.rb b/app/services/update_account_service.rb
index 4604d71b2b07da..a98f4d31e49b3d 100644
--- a/app/services/update_account_service.rb
+++ b/app/services/update_account_service.rb
@@ -28,7 +28,13 @@ def authorize_all_follow_requests(account)
end
def check_links(account)
- VerifyAccountLinksWorker.perform_async(account.id) if account.fields.any?(&:requires_verification?)
+ return unless account.fields.any?(&:requires_verification?)
+
+ if account.local?
+ VerifyAccountLinksWorker.perform_async(account.id)
+ else
+ VerifyAccountLinksWorker.perform_in(rand(10.minutes.to_i), account.id)
+ end
end
def process_hashtags(account)
diff --git a/app/validators/existing_username_validator.rb b/app/validators/existing_username_validator.rb
index 037d92f39bd0e9..09d53ca6809fdb 100644
--- a/app/validators/existing_username_validator.rb
+++ b/app/validators/existing_username_validator.rb
@@ -2,25 +2,40 @@
class ExistingUsernameValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
- return if value.blank?
+ @value = value
+ return if @value.blank?
- usernames_and_domains = value.split(',').filter_map do |str|
- username, domain = str.strip.gsub(/\A@/, '').split('@', 2)
+ if options[:multiple]
+ record.errors.add(attribute, not_found_multiple_message) if usernames_with_no_accounts.any?
+ elsif usernames_with_no_accounts.any? || usernames_and_domains.size > 1
+ record.errors.add(attribute, not_found_message)
+ end
+ end
+
+ private
+
+ def usernames_and_domains
+ @value.split(',').filter_map do |string|
+ username, domain = string.strip.gsub(/\A@/, '').split('@', 2)
domain = nil if TagManager.instance.local_domain?(domain)
next if username.blank?
- [str, username, domain]
+ [string, username, domain]
end
+ end
- usernames_with_no_accounts = usernames_and_domains.filter_map do |(str, username, domain)|
- str unless Account.find_remote(username, domain)
+ def usernames_with_no_accounts
+ usernames_and_domains.filter_map do |(string, username, domain)|
+ string unless Account.find_remote(username, domain)
end
+ end
- if options[:multiple]
- record.errors.add(attribute, I18n.t('existing_username_validator.not_found_multiple', usernames: usernames_with_no_accounts.join(', '))) if usernames_with_no_accounts.any?
- elsif usernames_with_no_accounts.any? || usernames_and_domains.size > 1
- record.errors.add(attribute, I18n.t('existing_username_validator.not_found'))
- end
+ def not_found_multiple_message
+ I18n.t('existing_username_validator.not_found_multiple', usernames: usernames_with_no_accounts.join(', '))
+ end
+
+ def not_found_message
+ I18n.t('existing_username_validator.not_found')
end
end
diff --git a/app/validators/unreserved_username_validator.rb b/app/validators/unreserved_username_validator.rb
index f82f4b91d03282..55a8c835fae1c4 100644
--- a/app/validators/unreserved_username_validator.rb
+++ b/app/validators/unreserved_username_validator.rb
@@ -11,16 +11,31 @@ def validate(account)
private
+ def reserved_username?
+ pam_username_reserved? || settings_username_reserved?
+ end
+
+ def pam_username_reserved?
+ pam_controlled? && pam_reserves_username?
+ end
+
def pam_controlled?
- return false unless Devise.pam_authentication && Devise.pam_controlled_service
+ Devise.pam_authentication && Devise.pam_controlled_service
+ end
- Rpam2.account(Devise.pam_controlled_service, @username).present?
+ def pam_reserves_username?
+ Rpam2.account(Devise.pam_controlled_service, @username)
end
- def reserved_username?
- return true if pam_controlled?
- return false unless Setting.reserved_usernames
+ def settings_username_reserved?
+ settings_has_reserved_usernames? && settings_reserves_username?
+ end
+
+ def settings_has_reserved_usernames?
+ Setting.reserved_usernames.present?
+ end
+ def settings_reserves_username?
Setting.reserved_usernames.include?(@username.downcase)
end
end
diff --git a/app/views/.rubocop.yml b/app/views/.rubocop.yml
new file mode 100644
index 00000000000000..4e268848c7d9b6
--- /dev/null
+++ b/app/views/.rubocop.yml
@@ -0,0 +1,5 @@
+inherit_from: ../../.rubocop.yml
+
+# Disable for the `Rubocop` lints in haml-lint
+Style/IfUnlessModifier:
+ Enabled: false
diff --git a/app/views/accounts/show.html.haml b/app/views/accounts/show.html.haml
index e8fd27e10913ed..d56f10a7ff30b1 100644
--- a/app/views/accounts/show.html.haml
+++ b/app/views/accounts/show.html.haml
@@ -1,5 +1,5 @@
- content_for :page_title do
- = "#{display_name(@account)} (#{acct(@account)})"
+ #{display_name(@account)} (#{acct(@account)})
- content_for :header_tags do
- if @account.user_prefers_noindex?
diff --git a/app/views/admin/accounts/_account.html.haml b/app/views/admin/accounts/_account.html.haml
index 82dd8dfb2ba760..755b987a877cd7 100644
--- a/app/views/admin/accounts/_account.html.haml
+++ b/app/views/admin/accounts/_account.html.haml
@@ -30,6 +30,6 @@
\-
%br/
%samp.ellipsized-ip= relevant_account_ip(account, params[:ip])
- - if !account.suspended? && account.user_pending? && account.user&.invite_request&.text&.present?
+ - if !account.suspended? && account.user_pending? && account.user&.invite_request&.text.present?
.batch-table__row__content__quote
%p= account.user&.invite_request&.text
diff --git a/app/views/admin/accounts/_buttons.html.haml b/app/views/admin/accounts/_buttons.html.haml
new file mode 100644
index 00000000000000..6eb141abc9ad7b
--- /dev/null
+++ b/app/views/admin/accounts/_buttons.html.haml
@@ -0,0 +1,41 @@
+- if account.suspended?
+ %hr.spacer/
+ - if account.suspension_origin_remote?
+ %p.muted-hint= deletion_request.present? ? t('admin.accounts.remote_suspension_reversible_hint_html', date: content_tag(:strong, l(deletion_request.due_at.to_date))) : t('admin.accounts.remote_suspension_irreversible')
+ - else
+ %p.muted-hint= deletion_request.present? ? t('admin.accounts.suspension_reversible_hint_html', date: content_tag(:strong, l(deletion_request.due_at.to_date))) : t('admin.accounts.suspension_irreversible')
+ = link_to t('admin.accounts.undo_suspension'), unsuspend_admin_account_path(account.id), method: :post, class: 'button' if can?(:unsuspend, account)
+ = link_to t('admin.accounts.redownload'), redownload_admin_account_path(account.id), method: :post, class: 'button' if can?(:redownload, account) && account.suspension_origin_remote?
+ - if deletion_request.present?
+ = link_to t('admin.accounts.delete'), admin_account_path(account.id), method: :delete, class: 'button button--destructive', data: { confirm: t('admin.accounts.are_you_sure') } if can?(:destroy, account)
+- else
+ .action-buttons
+ %div
+ - if account.local? && account.user_approved?
+ = link_to t('admin.accounts.warn'), new_admin_account_action_path(account.id, type: 'none'), class: 'button' if can?(:warn, account)
+ - if account.user_disabled?
+ = link_to t('admin.accounts.enable'), enable_admin_account_path(account.id), method: :post, class: 'button' if can?(:enable, account.user)
+ - else
+ = link_to t('admin.accounts.disable'), new_admin_account_action_path(account.id, type: 'disable'), class: 'button' if can?(:disable, account.user)
+ - if account.sensitized?
+ = link_to t('admin.accounts.undo_sensitized'), unsensitive_admin_account_path(account.id), method: :post, class: 'button' if can?(:unsensitive, account)
+ - elsif !account.local? || account.user_approved?
+ = link_to t('admin.accounts.sensitive'), new_admin_account_action_path(account.id, type: 'sensitive'), class: 'button' if can?(:sensitive, account)
+ - if account.silenced?
+ = link_to t('admin.accounts.undo_silenced'), unsilence_admin_account_path(account.id), method: :post, class: 'button' if can?(:unsilence, account)
+ - elsif !account.local? || account.user_approved?
+ = link_to t('admin.accounts.silence'), new_admin_account_action_path(account.id, type: 'silence'), class: 'button' if can?(:silence, account)
+ - if account.local?
+ - if account.user_pending?
+ = link_to t('admin.accounts.approve'), approve_admin_account_path(account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button' if can?(:approve, account.user)
+ = link_to t('admin.accounts.reject'), reject_admin_account_path(account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button button--destructive' if can?(:reject, account.user)
+ - unless account.user_confirmed?
+ = link_to t('admin.accounts.confirm'), admin_account_confirmation_path(account.id), method: :post, class: 'button' if can?(:confirm, account.user)
+ - if !account.local? || account.user_approved?
+ = link_to t('admin.accounts.perform_full_suspension'), new_admin_account_action_path(account.id, type: 'suspend'), class: 'button' if can?(:suspend, account)
+ %div
+ - if account.local?
+ - if !account.memorial? && account.user_approved?
+ = link_to t('admin.accounts.memorialize'), memorialize_admin_account_path(account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button button--destructive' if can?(:memorialize, account)
+ - else
+ = link_to t('admin.accounts.redownload'), redownload_admin_account_path(account.id), method: :post, class: 'button' if can?(:redownload, account)
diff --git a/app/views/admin/accounts/_counters.html.haml b/app/views/admin/accounts/_counters.html.haml
new file mode 100644
index 00000000000000..00ab98d094a5b8
--- /dev/null
+++ b/app/views/admin/accounts/_counters.html.haml
@@ -0,0 +1,43 @@
+.dashboard__counters.admin-account-counters
+ %div
+ = link_to admin_account_statuses_path(account.id) do
+ .dashboard__counters__num= number_with_delimiter account.statuses_count
+ .dashboard__counters__label= t 'admin.accounts.statuses'
+ %div
+ = link_to admin_account_statuses_path(account.id, { media: true }) do
+ .dashboard__counters__num= number_to_human_size account.media_attachments.sum('file_file_size')
+ .dashboard__counters__label= t 'admin.accounts.media_attachments'
+ %div
+ = link_to admin_account_relationships_path(account.id, location: account.local? ? nil : 'local', relationship: 'followed_by') do
+ .dashboard__counters__num= number_with_delimiter account.local_followers_count
+ .dashboard__counters__label= t 'admin.accounts.followers'
+ %div
+ = link_to admin_reports_path(account_id: account.id) do
+ .dashboard__counters__num= number_with_delimiter account.reports.count
+ .dashboard__counters__label= t 'admin.accounts.show.created_reports'
+ %div
+ = link_to admin_reports_path(target_account_id: account.id) do
+ .dashboard__counters__num= number_with_delimiter account.targeted_reports.count
+ .dashboard__counters__label= t 'admin.accounts.show.targeted_reports'
+ %div
+ = link_to admin_action_logs_path(target_account_id: account.id) do
+ .dashboard__counters__text
+ - if account.local? && account.user.nil?
+ = t('admin.accounts.deleted')
+ - elsif account.memorial?
+ = t('admin.accounts.memorialized')
+ - elsif account.suspended?
+ = t('admin.accounts.suspended')
+ - elsif account.silenced?
+ = t('admin.accounts.silenced')
+ - elsif account.local? && account.user&.disabled?
+ = t('admin.accounts.disabled')
+ - elsif account.local? && !account.user&.confirmed?
+ = t('admin.accounts.confirming')
+ - elsif account.local? && !account.user_approved?
+ = t('admin.accounts.pending')
+ - elsif account.sensitized?
+ = t('admin.accounts.sensitive')
+ - else
+ = t('admin.accounts.no_limits_imposed')
+ .dashboard__counters__label= t 'admin.accounts.login_status'
diff --git a/app/views/admin/accounts/_local_account.html.haml b/app/views/admin/accounts/_local_account.html.haml
new file mode 100644
index 00000000000000..4b361fc8d10c96
--- /dev/null
+++ b/app/views/admin/accounts/_local_account.html.haml
@@ -0,0 +1,82 @@
+- if account.avatar?
+ %tr
+ %th= t('admin.accounts.avatar')
+ %td= table_link_to 'trash', t('admin.accounts.remove_avatar'), remove_avatar_admin_account_path(account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:remove_avatar, account)
+ %td
+- if account.header?
+ %tr
+ %th= t('admin.accounts.header')
+ %td= table_link_to 'trash', t('admin.accounts.remove_header'), remove_header_admin_account_path(account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:remove_header, account)
+ %td
+%tr
+ %th= t('admin.accounts.role')
+ %td
+ - if account.user_role&.everyone?
+ = t('admin.accounts.no_role_assigned')
+ - else
+ = account.user_role&.name
+ %td
+ = table_link_to 'vcard', t('admin.accounts.change_role.label'), admin_user_role_path(account.user) if can?(:change_role, account.user)
+%tr
+ %th{ rowspan: can?(:create, :email_domain_block) ? 3 : 2 }= t('admin.accounts.email')
+ %td{ rowspan: can?(:create, :email_domain_block) ? 3 : 2 }= account.user_email
+ %td= table_link_to 'edit', t('admin.accounts.change_email.label'), admin_account_change_email_path(account.id) if can?(:change_email, account.user)
+%tr
+ %td= table_link_to 'search', t('admin.accounts.search_same_email_domain'), admin_accounts_path(email: "%@#{account.user_email.split('@').last}")
+- if can?(:create, :email_domain_block)
+ %tr
+ %td= table_link_to 'ban', t('admin.accounts.add_email_domain_block'), new_admin_email_domain_block_path(_domain: account.user_email.split('@').last)
+- if account.user_unconfirmed_email.present?
+ %tr
+ %th= t('admin.accounts.unconfirmed_email')
+ %td= account.user_unconfirmed_email
+ %td
+%tr
+ %th= t('admin.accounts.email_status')
+ %td
+ - if account.user&.confirmed?
+ = t('admin.accounts.confirmed')
+ - else
+ = t('admin.accounts.confirming')
+ %td= table_link_to 'refresh', t('admin.accounts.resend_confirmation.send'), resend_admin_account_confirmation_path(account.id), method: :post if can?(:confirm, account.user)
+%tr
+ %th{ rowspan: can?(:reset_password, account.user) ? 2 : 1 }= t('admin.accounts.security')
+ %td{ rowspan: can?(:reset_password, account.user) ? 2 : 1 }
+ - if account.user&.two_factor_enabled?
+ = t 'admin.accounts.security_measures.password_and_2fa'
+ - else
+ = t 'admin.accounts.security_measures.only_password'
+ %td
+ - if account.user&.two_factor_enabled?
+ = table_link_to 'unlock', t('admin.accounts.disable_two_factor_authentication'), admin_user_two_factor_authentication_path(account.user.id), method: :delete if can?(:disable_2fa, account.user)
+- if can?(:reset_password, account.user)
+ %tr
+ %td
+ = table_link_to 'key', t('admin.accounts.reset_password'), admin_account_reset_path(account.id), method: :create, data: { confirm: t('admin.accounts.are_you_sure') }
+%tr
+ %th= t('simple_form.labels.defaults.locale')
+ %td= standard_locale_name(account.user_locale)
+ %td
+%tr
+ %th= t('admin.accounts.joined')
+ %td
+ %time.formatted{ datetime: account.created_at.iso8601, title: l(account.created_at) }= l account.created_at
+ %td
+- recent_ips = account.user.ips.order(used_at: :desc).to_a
+- recent_ips.each_with_index do |recent_ip, i|
+ %tr
+ - if i.zero?
+ %th{ rowspan: recent_ips.size }= t('admin.accounts.most_recent_ip')
+ %td= recent_ip.ip
+ %td= table_link_to 'search', t('admin.accounts.search_same_ip'), admin_accounts_path(ip: recent_ip.ip)
+%tr
+ %th= t('admin.accounts.most_recent_activity')
+ %td
+ - if account.user_current_sign_in_at
+ %time.formatted{ datetime: account.user_current_sign_in_at.iso8601, title: l(account.user_current_sign_in_at) }= l account.user_current_sign_in_at
+ %td
+- if account.user&.invited?
+ %tr
+ %th= t('admin.accounts.invited_by')
+ %td= admin_account_link_to account.user.invite.user.account
+ %td
diff --git a/app/views/admin/accounts/_remote_account.html.haml b/app/views/admin/accounts/_remote_account.html.haml
new file mode 100644
index 00000000000000..99996e1d46d657
--- /dev/null
+++ b/app/views/admin/accounts/_remote_account.html.haml
@@ -0,0 +1,15 @@
+%tr
+ %th= t('admin.accounts.inbox_url')
+ %td
+ = account.inbox_url
+ = fa_icon DeliveryFailureTracker.available?(account.inbox_url) ? 'check' : 'times'
+ %td
+ = table_link_to 'search', domain_block.present? ? t('admin.domain_blocks.view') : t('admin.accounts.view_domain'), admin_instance_path(account.domain)
+%tr
+ %th= t('admin.accounts.shared_inbox_url')
+ %td
+ = account.shared_inbox_url
+ = fa_icon DeliveryFailureTracker.available?(account.shared_inbox_url) ? 'check' : 'times'
+ %td
+ - if domain_block.nil?
+ = table_link_to 'ban', t('admin.domain_blocks.add_new'), new_admin_domain_block_path(_domain: account.domain)
diff --git a/app/views/admin/accounts/show.html.haml b/app/views/admin/accounts/show.html.haml
index 44867d0a26b7bf..da2f2055d073c8 100644
--- a/app/views/admin/accounts/show.html.haml
+++ b/app/views/admin/accounts/show.html.haml
@@ -27,222 +27,20 @@
%div
.account__header__content.emojify= prerender_custom_emojis(account_bio_format(account), account.emojis)
-.dashboard__counters.admin-account-counters
- %div
- = link_to admin_account_statuses_path(@account.id) do
- .dashboard__counters__num= number_with_delimiter @account.statuses_count
- .dashboard__counters__label= t 'admin.accounts.statuses'
- %div
- = link_to admin_account_statuses_path(@account.id, { media: true }) do
- .dashboard__counters__num= number_to_human_size @account.media_attachments.sum('file_file_size')
- .dashboard__counters__label= t 'admin.accounts.media_attachments'
- %div
- = link_to admin_account_relationships_path(@account.id, location: @account.local? ? nil : 'local', relationship: 'followed_by') do
- .dashboard__counters__num= number_with_delimiter @account.local_followers_count
- .dashboard__counters__label= t 'admin.accounts.followers'
- %div
- = link_to admin_reports_path(account_id: @account.id) do
- .dashboard__counters__num= number_with_delimiter @account.reports.count
- .dashboard__counters__label= t '.created_reports'
- %div
- = link_to admin_reports_path(target_account_id: @account.id) do
- .dashboard__counters__num= number_with_delimiter @account.targeted_reports.count
- .dashboard__counters__label= t '.targeted_reports'
- %div
- = link_to admin_action_logs_path(target_account_id: @account.id) do
- .dashboard__counters__text
- - if @account.local? && @account.user.nil?
- = t('admin.accounts.deleted')
- - elsif @account.memorial?
- = t('admin.accounts.memorialized')
- - elsif @account.suspended?
- = t('admin.accounts.suspended')
- - elsif @account.silenced?
- = t('admin.accounts.silenced')
- - elsif @account.local? && @account.user&.disabled?
- = t('admin.accounts.disabled')
- - elsif @account.local? && !@account.user&.confirmed?
- = t('admin.accounts.confirming')
- - elsif @account.local? && !@account.user_approved?
- = t('admin.accounts.pending')
- - elsif @account.sensitized?
- = t('admin.accounts.sensitive')
- - else
- = t('admin.accounts.no_limits_imposed')
- .dashboard__counters__label= t 'admin.accounts.login_status'
+= render 'admin/accounts/counters', account: @account
- if @account.local? && @account.user.nil?
- = link_to t('admin.accounts.unblock_email'), unblock_email_admin_account_path(@account.id), method: :post, class: 'button' if can?(:unblock_email, @account) && CanonicalEmailBlock.where(reference_account_id: @account.id).exists?
+ = link_to t('admin.accounts.unblock_email'), unblock_email_admin_account_path(@account.id), method: :post, class: 'button' if can?(:unblock_email, @account) && CanonicalEmailBlock.exists?(reference_account_id: @account.id)
- else
.table-wrapper
%table.table.inline-table
%tbody
- if @account.local?
- - if @account.avatar?
- %tr
- %th= t('admin.accounts.avatar')
- %td= table_link_to 'trash', t('admin.accounts.remove_avatar'), remove_avatar_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:remove_avatar, @account)
- %td
-
- - if @account.header?
- %tr
- %th= t('admin.accounts.header')
- %td= table_link_to 'trash', t('admin.accounts.remove_header'), remove_header_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:remove_header, @account)
- %td
-
- %tr
- %th= t('admin.accounts.role')
- %td
- - if @account.user_role&.everyone?
- = t('admin.accounts.no_role_assigned')
- - else
- = @account.user_role&.name
- %td
- = table_link_to 'vcard', t('admin.accounts.change_role.label'), admin_user_role_path(@account.user) if can?(:change_role, @account.user)
-
- %tr
- %th{ rowspan: can?(:create, :email_domain_block) ? 3 : 2 }= t('admin.accounts.email')
- %td{ rowspan: can?(:create, :email_domain_block) ? 3 : 2 }= @account.user_email
- %td= table_link_to 'edit', t('admin.accounts.change_email.label'), admin_account_change_email_path(@account.id) if can?(:change_email, @account.user)
-
- %tr
- %td= table_link_to 'search', t('admin.accounts.search_same_email_domain'), admin_accounts_path(email: "%@#{@account.user_email.split('@').last}")
-
- - if can?(:create, :email_domain_block)
- %tr
- %td= table_link_to 'ban', t('admin.accounts.add_email_domain_block'), new_admin_email_domain_block_path(_domain: @account.user_email.split('@').last)
-
- - if @account.user_unconfirmed_email.present?
- %tr
- %th= t('admin.accounts.unconfirmed_email')
- %td= @account.user_unconfirmed_email
- %td
-
- %tr
- %th= t('admin.accounts.email_status')
- %td
- - if @account.user&.confirmed?
- = t('admin.accounts.confirmed')
- - else
- = t('admin.accounts.confirming')
- %td= table_link_to 'refresh', t('admin.accounts.resend_confirmation.send'), resend_admin_account_confirmation_path(@account.id), method: :post if can?(:confirm, @account.user)
- %tr
- %th{ rowspan: can?(:reset_password, @account.user) ? 2 : 1 }= t('admin.accounts.security')
- %td{ rowspan: can?(:reset_password, @account.user) ? 2 : 1 }
- - if @account.user&.two_factor_enabled?
- = t 'admin.accounts.security_measures.password_and_2fa'
- - else
- = t 'admin.accounts.security_measures.only_password'
- %td
- - if @account.user&.two_factor_enabled?
- = table_link_to 'unlock', t('admin.accounts.disable_two_factor_authentication'), admin_user_two_factor_authentication_path(@account.user.id), method: :delete if can?(:disable_2fa, @account.user)
-
- - if can?(:reset_password, @account.user)
- %tr
- %td
- = table_link_to 'key', t('admin.accounts.reset_password'), admin_account_reset_path(@account.id), method: :create, data: { confirm: t('admin.accounts.are_you_sure') }
-
- %tr
- %th= t('simple_form.labels.defaults.locale')
- %td= standard_locale_name(@account.user_locale)
- %td
-
- %tr
- %th= t('admin.accounts.joined')
- %td
- %time.formatted{ datetime: @account.created_at.iso8601, title: l(@account.created_at) }= l @account.created_at
- %td
-
- - recent_ips = @account.user.ips.order(used_at: :desc).to_a
-
- - recent_ips.each_with_index do |recent_ip, i|
- %tr
- - if i.zero?
- %th{ rowspan: recent_ips.size }= t('admin.accounts.most_recent_ip')
- %td= recent_ip.ip
- %td= table_link_to 'search', t('admin.accounts.search_same_ip'), admin_accounts_path(ip: recent_ip.ip)
-
- %tr
- %th= t('admin.accounts.most_recent_activity')
- %td
- - if @account.user_current_sign_in_at
- %time.formatted{ datetime: @account.user_current_sign_in_at.iso8601, title: l(@account.user_current_sign_in_at) }= l @account.user_current_sign_in_at
- %td
-
- - if @account.user&.invited?
- %tr
- %th= t('admin.accounts.invited_by')
- %td= admin_account_link_to @account.user.invite.user.account
- %td
-
+ = render 'admin/accounts/local_account', account: @account
- else
- %tr
- %th= t('admin.accounts.inbox_url')
- %td
- = @account.inbox_url
- = fa_icon DeliveryFailureTracker.available?(@account.inbox_url) ? 'check' : 'times'
- %td
- = table_link_to 'search', @domain_block.present? ? t('admin.domain_blocks.view') : t('admin.accounts.view_domain'), admin_instance_path(@account.domain)
- %tr
- %th= t('admin.accounts.shared_inbox_url')
- %td
- = @account.shared_inbox_url
- = fa_icon DeliveryFailureTracker.available?(@account.shared_inbox_url) ? 'check' : 'times'
- %td
- - if @domain_block.nil?
- = table_link_to 'ban', t('admin.domain_blocks.add_new'), new_admin_domain_block_path(_domain: @account.domain)
+ = render 'admin/accounts/remote_account', account: @account, domain_block: @domain_block
- - if @account.suspended?
- %hr.spacer/
-
- - if @account.suspension_origin_remote?
- %p.muted-hint= @deletion_request.present? ? t('admin.accounts.remote_suspension_reversible_hint_html', date: content_tag(:strong, l(@deletion_request.due_at.to_date))) : t('admin.accounts.remote_suspension_irreversible')
- - else
- %p.muted-hint= @deletion_request.present? ? t('admin.accounts.suspension_reversible_hint_html', date: content_tag(:strong, l(@deletion_request.due_at.to_date))) : t('admin.accounts.suspension_irreversible')
-
- = link_to t('admin.accounts.undo_suspension'), unsuspend_admin_account_path(@account.id), method: :post, class: 'button' if can?(:unsuspend, @account)
- = link_to t('admin.accounts.redownload'), redownload_admin_account_path(@account.id), method: :post, class: 'button' if can?(:redownload, @account) && @account.suspension_origin_remote?
-
- - if @deletion_request.present?
- = link_to t('admin.accounts.delete'), admin_account_path(@account.id), method: :delete, class: 'button button--destructive', data: { confirm: t('admin.accounts.are_you_sure') } if can?(:destroy, @account)
- - else
- .action-buttons
- %div
- - if @account.local? && @account.user_approved?
- = link_to t('admin.accounts.warn'), new_admin_account_action_path(@account.id, type: 'none'), class: 'button' if can?(:warn, @account)
-
- - if @account.user_disabled?
- = link_to t('admin.accounts.enable'), enable_admin_account_path(@account.id), method: :post, class: 'button' if can?(:enable, @account.user)
- - else
- = link_to t('admin.accounts.disable'), new_admin_account_action_path(@account.id, type: 'disable'), class: 'button' if can?(:disable, @account.user)
-
- - if @account.sensitized?
- = link_to t('admin.accounts.undo_sensitized'), unsensitive_admin_account_path(@account.id), method: :post, class: 'button' if can?(:unsensitive, @account)
- - elsif !@account.local? || @account.user_approved?
- = link_to t('admin.accounts.sensitive'), new_admin_account_action_path(@account.id, type: 'sensitive'), class: 'button' if can?(:sensitive, @account)
-
- - if @account.silenced?
- = link_to t('admin.accounts.undo_silenced'), unsilence_admin_account_path(@account.id), method: :post, class: 'button' if can?(:unsilence, @account)
- - elsif !@account.local? || @account.user_approved?
- = link_to t('admin.accounts.silence'), new_admin_account_action_path(@account.id, type: 'silence'), class: 'button' if can?(:silence, @account)
-
- - if @account.local?
- - if @account.user_pending?
- = link_to t('admin.accounts.approve'), approve_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button' if can?(:approve, @account.user)
- = link_to t('admin.accounts.reject'), reject_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button button--destructive' if can?(:reject, @account.user)
-
- - unless @account.user_confirmed?
- = link_to t('admin.accounts.confirm'), admin_account_confirmation_path(@account.id), method: :post, class: 'button' if can?(:confirm, @account.user)
-
- - if !@account.local? || @account.user_approved?
- = link_to t('admin.accounts.perform_full_suspension'), new_admin_account_action_path(@account.id, type: 'suspend'), class: 'button' if can?(:suspend, @account)
-
- %div
- - if @account.local?
- - if !@account.memorial? && @account.user_approved?
- = link_to t('admin.accounts.memorialize'), memorialize_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button button--destructive' if can?(:memorialize, @account)
- - else
- = link_to t('admin.accounts.redownload'), redownload_admin_account_path(@account.id), method: :post, class: 'button' if can?(:redownload, @account)
+ = render 'admin/accounts/buttons', account: @account, deletion_request: @deletion_request
%hr.spacer/
@@ -275,7 +73,7 @@
%hr.spacer/
- - if @account.user&.invite_request&.text&.present?
+ - if @account.user&.invite_request&.text.present?
.speech-bubble
.speech-bubble__bubble
= @account.user&.invite_request&.text
diff --git a/app/views/admin/announcements/edit.html.haml b/app/views/admin/announcements/edit.html.haml
index df1ac455fb8390..150d98272fcd65 100644
--- a/app/views/admin/announcements/edit.html.haml
+++ b/app/views/admin/announcements/edit.html.haml
@@ -5,8 +5,8 @@
= render 'shared/error_messages', object: @announcement
.fields-group
- = f.input :starts_at, include_blank: true, wrapper: :with_block_label, html5: true, input_html: { pattern: '[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}(:[0-9]{2}){1,2}', placeholder: Time.now.strftime('%FT%R') }
- = f.input :ends_at, include_blank: true, wrapper: :with_block_label, html5: true, input_html: { pattern: '[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}(:[0-9]{2}){1,2}', placeholder: Time.now.strftime('%FT%R') }
+ = f.input :starts_at, include_blank: true, wrapper: :with_block_label, html5: true, input_html: { pattern: datetime_pattern, placeholder: datetime_placeholder }
+ = f.input :ends_at, include_blank: true, wrapper: :with_block_label, html5: true, input_html: { pattern: datetime_pattern, placeholder: datetime_placeholder }
.fields-group
= f.input :all_day, as: :boolean, wrapper: :with_label
@@ -16,7 +16,7 @@
- unless @announcement.published?
.fields-group
- = f.input :scheduled_at, include_blank: true, wrapper: :with_block_label, html5: true, input_html: { pattern: '[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}(:[0-9]{2}){1,2}', placeholder: Time.now.strftime('%FT%R') }
+ = f.input :scheduled_at, include_blank: true, wrapper: :with_block_label, html5: true, input_html: { pattern: datetime_pattern, placeholder: datetime_placeholder }
.actions
= f.button :button, t('generic.save_changes'), type: :submit
diff --git a/app/views/admin/announcements/new.html.haml b/app/views/admin/announcements/new.html.haml
index cb39672e1659fd..0123632ff47a53 100644
--- a/app/views/admin/announcements/new.html.haml
+++ b/app/views/admin/announcements/new.html.haml
@@ -5,8 +5,8 @@
= render 'shared/error_messages', object: @announcement
.fields-group
- = f.input :starts_at, include_blank: true, wrapper: :with_block_label, html5: true, input_html: { pattern: '[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}(:[0-9]{2}){1,2}', placeholder: Time.now.strftime('%FT%R') }
- = f.input :ends_at, include_blank: true, wrapper: :with_block_label, html5: true, input_html: { pattern: '[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}(:[0-9]{2}){1,2}', placeholder: Time.now.strftime('%FT%R') }
+ = f.input :starts_at, include_blank: true, wrapper: :with_block_label, html5: true, input_html: { pattern: datetime_pattern, placeholder: datetime_placeholder }
+ = f.input :ends_at, include_blank: true, wrapper: :with_block_label, html5: true, input_html: { pattern: datetime_pattern, placeholder: datetime_placeholder }
.fields-group
= f.input :all_day, as: :boolean, wrapper: :with_label
@@ -15,7 +15,7 @@
= f.input :text, wrapper: :with_block_label
.fields-group
- = f.input :scheduled_at, include_blank: true, wrapper: :with_block_label, html5: true, input_html: { pattern: '[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}(:[0-9]{2}){1,2}', placeholder: Time.now.strftime('%FT%R') }
+ = f.input :scheduled_at, include_blank: true, wrapper: :with_block_label, html5: true, input_html: { pattern: datetime_pattern, placeholder: datetime_placeholder }
.actions
= f.button :button, t('.create'), type: :submit
diff --git a/app/views/admin/custom_emojis/_custom_emoji.html.haml b/app/views/admin/custom_emojis/_custom_emoji.html.haml
index c6789d4f890518..f0cb64ec526f7a 100644
--- a/app/views/admin/custom_emojis/_custom_emoji.html.haml
+++ b/app/views/admin/custom_emojis/_custom_emoji.html.haml
@@ -6,7 +6,7 @@
= custom_emoji_tag(custom_emoji)
.batch-table__row__content__text
- %samp= ":#{custom_emoji.shortcode}:"
+ %samp :#{custom_emoji.shortcode}:
- if custom_emoji.local?
%span.information-badge= custom_emoji.category&.name || t('admin.custom_emojis.uncategorized')
diff --git a/app/views/admin/disputes/appeals/_appeal.html.haml b/app/views/admin/disputes/appeals/_appeal.html.haml
index 3f6efb856e5046..d5611211ed134b 100644
--- a/app/views/admin/disputes/appeals/_appeal.html.haml
+++ b/app/views/admin/disputes/appeals/_appeal.html.haml
@@ -4,7 +4,7 @@
= image_tag appeal.account.avatar.url(:original), alt: '', width: 40, height: 40, class: 'avatar'
.log-entry__content
.log-entry__title
- = t(appeal.strike.action, scope: 'admin.strikes.actions', name: content_tag(:span, appeal.strike.account.username, class: 'username'), target: content_tag(:span, appeal.account.username, class: 'target')).html_safe
+ = strike_action_label(appeal)
.log-entry__timestamp
%time.formatted{ datetime: appeal.strike.created_at.iso8601 }
= l(appeal.strike.created_at)
diff --git a/app/views/admin/domain_blocks/confirm_suspension.html.haml b/app/views/admin/domain_blocks/confirm_suspension.html.haml
index e0e55e70f39cf4..a5df8ba3f3adb5 100644
--- a/app/views/admin/domain_blocks/confirm_suspension.html.haml
+++ b/app/views/admin/domain_blocks/confirm_suspension.html.haml
@@ -2,7 +2,6 @@
= t('.title', domain: Addressable::IDNA.to_unicode(@domain_block.domain))
= simple_form_for @domain_block, url: admin_domain_blocks_path, method: :post do |f|
-
%p.hint= t('.preamble_html', domain: Addressable::IDNA.to_unicode(@domain_block.domain))
%ul.hint
%li= t('.stop_communication')
diff --git a/app/views/admin/instances/show.html.haml b/app/views/admin/instances/show.html.haml
index 46b5c301b53db6..5f2664df76dc11 100644
--- a/app/views/admin/instances/show.html.haml
+++ b/app/views/admin/instances/show.html.haml
@@ -7,27 +7,31 @@
= ' - '
= l(@time_period.last)
- %p
- = fa_icon 'info fw'
- = t('admin.instances.totals_time_period_hint_html')
+ - if @instance.persisted?
+ %p
+ = fa_icon 'info fw'
+ = t('admin.instances.totals_time_period_hint_html')
- .dashboard
- .dashboard__item
- = react_admin_component :counter, measure: 'instance_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_accounts_measure'), href: admin_accounts_path(origin: 'remote', by_domain: @instance.domain)
- .dashboard__item
- = react_admin_component :counter, measure: 'instance_statuses', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_statuses_measure')
- .dashboard__item
- = react_admin_component :counter, measure: 'instance_media_attachments', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_media_attachments_measure')
- .dashboard__item
- = react_admin_component :counter, measure: 'instance_follows', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_follows_measure')
- .dashboard__item
- = react_admin_component :counter, measure: 'instance_followers', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_followers_measure')
- .dashboard__item
- = react_admin_component :counter, measure: 'instance_reports', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_reports_measure'), href: admin_reports_path(by_target_domain: @instance.domain)
- .dashboard__item
- = react_admin_component :dimension, dimension: 'instance_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, limit: 8, label: t('admin.instances.dashboard.instance_accounts_dimension')
- .dashboard__item
- = react_admin_component :dimension, dimension: 'instance_languages', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, limit: 8, label: t('admin.instances.dashboard.instance_languages_dimension')
+ .dashboard
+ .dashboard__item
+ = react_admin_component :counter, measure: 'instance_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_accounts_measure'), href: admin_accounts_path(origin: 'remote', by_domain: @instance.domain)
+ .dashboard__item
+ = react_admin_component :counter, measure: 'instance_statuses', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_statuses_measure')
+ .dashboard__item
+ = react_admin_component :counter, measure: 'instance_media_attachments', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_media_attachments_measure')
+ .dashboard__item
+ = react_admin_component :counter, measure: 'instance_follows', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_follows_measure')
+ .dashboard__item
+ = react_admin_component :counter, measure: 'instance_followers', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_followers_measure')
+ .dashboard__item
+ = react_admin_component :counter, measure: 'instance_reports', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_reports_measure'), href: admin_reports_path(by_target_domain: @instance.domain)
+ .dashboard__item
+ = react_admin_component :dimension, dimension: 'instance_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, limit: 8, label: t('admin.instances.dashboard.instance_accounts_dimension')
+ .dashboard__item
+ = react_admin_component :dimension, dimension: 'instance_languages', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, limit: 8, label: t('admin.instances.dashboard.instance_languages_dimension')
+ - else
+ %p
+ = t('admin.instances.unknown_instance')
%hr.spacer/
@@ -62,33 +66,34 @@
- else
= link_to t('admin.domain_blocks.add_new'), new_admin_domain_block_path(_domain: @instance.domain), class: 'button'
-%hr.spacer/
+- if @instance.persisted?
+ %hr.spacer/
-%h3= t('admin.instances.availability.title')
+ %h3= t('admin.instances.availability.title')
-%p
- = t('admin.instances.availability.description_html', count: DeliveryFailureTracker::FAILURE_DAYS_THRESHOLD)
+ %p
+ = t('admin.instances.availability.description_html', count: DeliveryFailureTracker::FAILURE_DAYS_THRESHOLD)
-.availability-indicator
- %ul.availability-indicator__graphic
- - @instance.availability_over_days(14).each do |(date, failing)|
- %li.availability-indicator__graphic__item{ class: failing ? 'negative' : 'neutral', title: l(date) }
- .availability-indicator__hint
- - if @instance.unavailable?
- %span.negative-hint
- = t('admin.instances.availability.failure_threshold_reached', date: l(@instance.unavailable_domain.created_at.to_date))
- = link_to t('admin.instances.delivery.restart'), restart_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post }
- - elsif @instance.exhausted_deliveries_days.empty?
- %span.positive-hint
- = t('admin.instances.availability.no_failures_recorded')
- = link_to t('admin.instances.delivery.stop'), stop_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post }
- - else
- %span.negative-hint
- = t('admin.instances.availability.failures_recorded', count: @instance.delivery_failure_tracker.days)
- %span= link_to t('admin.instances.delivery.clear'), clear_delivery_errors_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post } unless @instance.exhausted_deliveries_days.empty?
- %span= link_to t('admin.instances.delivery.stop'), stop_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post }
+ .availability-indicator
+ %ul.availability-indicator__graphic
+ - @instance.availability_over_days(14).each do |(date, failing)|
+ %li.availability-indicator__graphic__item{ class: failing ? 'negative' : 'neutral', title: l(date) }
+ .availability-indicator__hint
+ - if @instance.unavailable?
+ %span.negative-hint
+ = t('admin.instances.availability.failure_threshold_reached', date: l(@instance.unavailable_domain.created_at.to_date))
+ = link_to t('admin.instances.delivery.restart'), restart_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post }
+ - elsif @instance.exhausted_deliveries_days.empty?
+ %span.positive-hint
+ = t('admin.instances.availability.no_failures_recorded')
+ = link_to t('admin.instances.delivery.stop'), stop_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post }
+ - else
+ %span.negative-hint
+ = t('admin.instances.availability.failures_recorded', count: @instance.delivery_failure_tracker.days)
+ %span= link_to t('admin.instances.delivery.clear'), clear_delivery_errors_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post } unless @instance.exhausted_deliveries_days.empty?
+ %span= link_to t('admin.instances.delivery.stop'), stop_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post }
-- if @instance.purgeable?
- %p= t('admin.instances.purge_description_html')
+ - if @instance.purgeable?
+ %p= t('admin.instances.purge_description_html')
- = link_to t('admin.instances.purge'), admin_instance_path(@instance), data: { confirm: t('admin.instances.confirm_purge'), method: :delete }, class: 'button button--destructive'
+ = link_to t('admin.instances.purge'), admin_instance_path(@instance), data: { confirm: t('admin.instances.confirm_purge'), method: :delete }, class: 'button button--destructive'
diff --git a/app/views/admin/invites/index.html.haml b/app/views/admin/invites/index.html.haml
index ee6ba0f574255a..964deaba8f3da1 100644
--- a/app/views/admin/invites/index.html.haml
+++ b/app/views/admin/invites/index.html.haml
@@ -14,7 +14,8 @@
- if policy(:invite).create?
%p= t('invites.prompt')
- = render 'invites/form'
+ = simple_form_for(@invite, url: admin_invites_path) do |form|
+ = render partial: 'invites/form', object: form
%hr.spacer/
diff --git a/app/views/admin/relays/_relay.html.haml b/app/views/admin/relays/_relay.html.haml
index 6678218947e609..f1dd2b2dd14be3 100644
--- a/app/views/admin/relays/_relay.html.haml
+++ b/app/views/admin/relays/_relay.html.haml
@@ -5,16 +5,16 @@
- if relay.accepted?
%span.positive-hint
= fa_icon('check')
- = ' '
+
= t 'admin.relays.enabled'
- elsif relay.pending?
= fa_icon('hourglass')
- = ' '
+
= t 'admin.relays.pending'
- else
%span.negative-hint
= fa_icon('times')
- = ' '
+
= t 'admin.relays.disabled'
%td
- if relay.accepted?
diff --git a/app/views/admin/reports/_actions.html.haml b/app/views/admin/reports/_actions.html.haml
index aad4416257ab10..da9ac8931572b8 100644
--- a/app/views/admin/reports/_actions.html.haml
+++ b/app/views/admin/reports/_actions.html.haml
@@ -1,11 +1,11 @@
-= form_tag preview_admin_report_actions_path(@report), method: :post do
+= form_tag preview_admin_report_actions_path(report), method: :post do
.report-actions
.report-actions__item
.report-actions__item__button
- = link_to t('admin.reports.mark_as_resolved'), resolve_admin_report_path(@report), method: :post, class: 'button'
+ = link_to t('admin.reports.mark_as_resolved'), resolve_admin_report_path(report), method: :post, class: 'button'
.report-actions__item__description
= t('admin.reports.actions.resolve_description_html')
- - if @statuses.any? { |status| (status.with_media? || status.with_preview_card?) && !status.discarded? }
+ - if statuses.any? { |status| (status.with_media? || status.with_preview_card?) && !status.discarded? }
.report-actions__item
.report-actions__item__button
= button_tag t('admin.reports.mark_as_sensitive'), name: :mark_as_sensitive, class: 'button'
@@ -28,6 +28,6 @@
= t('admin.reports.actions.suspend_description_html')
.report-actions__item
.report-actions__item__button
- = link_to t('admin.accounts.custom'), new_admin_account_action_path(@report.target_account_id, report_id: @report.id), class: 'button'
+ = link_to t('admin.accounts.custom'), new_admin_account_action_path(report.target_account_id, report_id: report.id), class: 'button'
.report-actions__item__description
= t('admin.reports.actions.other_description_html')
diff --git a/app/views/admin/reports/_comment.html.haml b/app/views/admin/reports/_comment.html.haml
new file mode 100644
index 00000000000000..8c07210af971b9
--- /dev/null
+++ b/app/views/admin/reports/_comment.html.haml
@@ -0,0 +1,24 @@
+- if report.account.instance_actor?
+ %p= t('admin.reports.comment_description_html', name: content_tag(:strong, site_hostname, class: 'username'))
+- elsif report.account.local?
+ %p= t('admin.reports.comment_description_html', name: content_tag(:strong, report.account.username, class: 'username'))
+- else
+ %p= t('admin.reports.comment_description_html', name: t('admin.reports.remote_user_placeholder', instance: report.account.domain))
+.report-notes
+ .report-notes__item
+ - if report.account.local? && !report.account.instance_actor?
+ = image_tag report.account.avatar.url, class: 'report-notes__item__avatar'
+ - else
+ = image_tag(full_asset_url('avatars/original/missing.png', skip_pipeline: true), class: 'report-notes__item__avatar')
+ .report-notes__item__header
+ %span.username
+ - if report.account.instance_actor?
+ = site_hostname
+ - elsif report.account.local?
+ = link_to report.account.username, admin_account_path(report.account_id)
+ - else
+ = link_to report.account.domain, admin_instance_path(report.account.domain)
+ %time.relative-formatted{ datetime: report.created_at.iso8601 }
+ = l report.created_at.to_date
+ .report-notes__item__content
+ = simple_format(h(report.comment))
diff --git a/app/views/admin/reports/_header_card.html.haml b/app/views/admin/reports/_header_card.html.haml
new file mode 100644
index 00000000000000..6fd8b4ecc8be98
--- /dev/null
+++ b/app/views/admin/reports/_header_card.html.haml
@@ -0,0 +1,46 @@
+.report-header__card
+ .account-card
+ .account-card__header
+ = image_tag report.target_account.header.url, alt: ''
+ .account-card__title
+ .account-card__title__avatar
+ = image_tag report.target_account.avatar.url, alt: ''
+ .display-name
+ %bdi
+ %strong.emojify.p-name= display_name(report.target_account, custom_emojify: true)
+ %span
+ = acct(report.target_account)
+ = fa_icon('lock') if report.target_account.locked?
+ - if report.target_account.note.present?
+ .account-card__bio.emojify
+ = prerender_custom_emojis(account_bio_format(report.target_account), report.target_account.emojis)
+ .account-card__actions
+ .account-card__counters
+ .account-card__counters__item
+ = friendly_number_to_human report.target_account.statuses_count
+ %small= t('accounts.posts', count: report.target_account.statuses_count).downcase
+ .account-card__counters__item
+ = friendly_number_to_human report.target_account.followers_count
+ %small= t('accounts.followers', count: report.target_account.followers_count).downcase
+ .account-card__counters__item
+ = friendly_number_to_human report.target_account.following_count
+ %small= t('accounts.following', count: report.target_account.following_count).downcase
+ .account-card__actions__button
+ = link_to t('admin.reports.view_profile'), admin_account_path(report.target_account_id), class: 'button'
+ .report-header__details.report-header__details--horizontal
+ .report-header__details__item
+ .report-header__details__item__header
+ %strong= t('admin.accounts.joined')
+ .report-header__details__item__content
+ %time.time-ago{ datetime: report.target_account.created_at.iso8601, title: l(report.target_account.created_at) }= l report.target_account.created_at
+ .report-header__details__item
+ .report-header__details__item__header
+ %strong= t('accounts.last_active')
+ .report-header__details__item__content
+ - if report.target_account.last_status_at.present?
+ %time.time-ago{ datetime: report.target_account.last_status_at.to_date.iso8601, title: l(report.target_account.last_status_at.to_date) }= l report.target_account.last_status_at
+ .report-header__details__item
+ .report-header__details__item__header
+ %strong= t('admin.accounts.strikes')
+ .report-header__details__item__content
+ = report.target_account.previous_strikes_count
diff --git a/app/views/admin/reports/_header_details.html.haml b/app/views/admin/reports/_header_details.html.haml
new file mode 100644
index 00000000000000..5878cd2ff8a529
--- /dev/null
+++ b/app/views/admin/reports/_header_details.html.haml
@@ -0,0 +1,53 @@
+.report-header__details
+ .report-header__details__item
+ .report-header__details__item__header
+ %strong= t('admin.reports.created_at')
+ .report-header__details__item__content
+ %time.formatted{ datetime: report.created_at.iso8601 }
+ .report-header__details__item
+ .report-header__details__item__header
+ %strong= t('admin.reports.reported_by')
+ .report-header__details__item__content
+ - if report.account.instance_actor?
+ = site_hostname
+ - elsif report.account.local?
+ = admin_account_link_to report.account
+ - else
+ = report.account.domain
+ .report-header__details__item
+ .report-header__details__item__header
+ %strong= t('admin.reports.status')
+ .report-header__details__item__content
+ - if report.action_taken?
+ = t('admin.reports.resolved')
+ - else
+ = t('admin.reports.unresolved')
+ - unless report.target_account.local?
+ .report-header__details__item
+ .report-header__details__item__header
+ %strong= t('admin.reports.forwarded')
+ .report-header__details__item__content
+ - if report.forwarded?
+ = t('simple_form.yes')
+ - else
+ = t('simple_form.no')
+ - if report.action_taken_by_account.present?
+ .report-header__details__item
+ .report-header__details__item__header
+ %strong= t('admin.reports.action_taken_by')
+ .report-header__details__item__content
+ = admin_account_link_to report.action_taken_by_account
+ - else
+ .report-header__details__item
+ .report-header__details__item__header
+ %strong= t('admin.reports.assigned')
+ .report-header__details__item__content
+ - if report.assigned_account.nil?
+ = t 'admin.reports.no_one_assigned'
+ - else
+ = admin_account_link_to report.assigned_account
+ —
+ - if report.assigned_account != current_user.account
+ = table_link_to 'user', t('admin.reports.assign_to_self'), assign_to_self_admin_report_path(report), method: :post
+ - elsif !report.assigned_account.nil?
+ = table_link_to 'trash', t('admin.reports.unassign'), unassign_admin_report_path(report), method: :post
diff --git a/app/views/admin/reports/actions/preview.html.haml b/app/views/admin/reports/actions/preview.html.haml
index eb67eebe0d0509..8634bb215c4e19 100644
--- a/app/views/admin/reports/actions/preview.html.haml
+++ b/app/views/admin/reports/actions/preview.html.haml
@@ -61,7 +61,7 @@
= fa_icon 'link'
= media_attachment.file_file_name
.strike-card__statuses-list__item__meta
- = link_to ActivityPub::TagManager.instance.url_for(status), target: '_blank' do
+ = link_to ActivityPub::TagManager.instance.url_for(status), target: '_blank', rel: 'noopener noreferrer' do
%time.formatted{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at)
- unless status.application.nil?
·
diff --git a/app/views/admin/reports/show.html.haml b/app/views/admin/reports/show.html.haml
index 2508bc2b5b5673..13a4d48344d068 100644
--- a/app/views/admin/reports/show.html.haml
+++ b/app/views/admin/reports/show.html.haml
@@ -8,106 +8,8 @@
= link_to t('admin.reports.mark_as_unresolved'), reopen_admin_report_path(@report), method: :post, class: 'button'
.report-header
- .report-header__card
- .account-card
- .account-card__header
- = image_tag @report.target_account.header.url, alt: ''
- .account-card__title
- .account-card__title__avatar
- = image_tag @report.target_account.avatar.url, alt: ''
- .display-name
- %bdi
- %strong.emojify.p-name= display_name(@report.target_account, custom_emojify: true)
- %span
- = acct(@report.target_account)
- = fa_icon('lock') if @report.target_account.locked?
- - if @report.target_account.note.present?
- .account-card__bio.emojify
- = prerender_custom_emojis(account_bio_format(@report.target_account), @report.target_account.emojis)
- .account-card__actions
- .account-card__counters
- .account-card__counters__item
- = friendly_number_to_human @report.target_account.statuses_count
- %small= t('accounts.posts', count: @report.target_account.statuses_count).downcase
- .account-card__counters__item
- = friendly_number_to_human @report.target_account.followers_count
- %small= t('accounts.followers', count: @report.target_account.followers_count).downcase
- .account-card__counters__item
- = friendly_number_to_human @report.target_account.following_count
- %small= t('accounts.following', count: @report.target_account.following_count).downcase
- .account-card__actions__button
- = link_to t('admin.reports.view_profile'), admin_account_path(@report.target_account_id), class: 'button'
- .report-header__details.report-header__details--horizontal
- .report-header__details__item
- .report-header__details__item__header
- %strong= t('admin.accounts.joined')
- .report-header__details__item__content
- %time.time-ago{ datetime: @report.target_account.created_at.iso8601, title: l(@report.target_account.created_at) }= l @report.target_account.created_at
- .report-header__details__item
- .report-header__details__item__header
- %strong= t('accounts.last_active')
- .report-header__details__item__content
- - if @report.target_account.last_status_at.present?
- %time.time-ago{ datetime: @report.target_account.last_status_at.to_date.iso8601, title: l(@report.target_account.last_status_at.to_date) }= l @report.target_account.last_status_at
- .report-header__details__item
- .report-header__details__item__header
- %strong= t('admin.accounts.strikes')
- .report-header__details__item__content
- = @report.target_account.previous_strikes_count
-
- .report-header__details
- .report-header__details__item
- .report-header__details__item__header
- %strong= t('admin.reports.created_at')
- .report-header__details__item__content
- %time.formatted{ datetime: @report.created_at.iso8601 }
- .report-header__details__item
- .report-header__details__item__header
- %strong= t('admin.reports.reported_by')
- .report-header__details__item__content
- - if @report.account.instance_actor?
- = site_hostname
- - elsif @report.account.local?
- = admin_account_link_to @report.account
- - else
- = @report.account.domain
- .report-header__details__item
- .report-header__details__item__header
- %strong= t('admin.reports.status')
- .report-header__details__item__content
- - if @report.action_taken?
- = t('admin.reports.resolved')
- - else
- = t('admin.reports.unresolved')
- - unless @report.target_account.local?
- .report-header__details__item
- .report-header__details__item__header
- %strong= t('admin.reports.forwarded')
- .report-header__details__item__content
- - if @report.forwarded?
- = t('simple_form.yes')
- - else
- = t('simple_form.no')
- - if @report.action_taken_by_account.present?
- .report-header__details__item
- .report-header__details__item__header
- %strong= t('admin.reports.action_taken_by')
- .report-header__details__item__content
- = admin_account_link_to @report.action_taken_by_account
- - else
- .report-header__details__item
- .report-header__details__item__header
- %strong= t('admin.reports.assigned')
- .report-header__details__item__content
- - if @report.assigned_account.nil?
- = t 'admin.reports.no_one_assigned'
- - else
- = admin_account_link_to @report.assigned_account
- —
- - if @report.assigned_account != current_user.account
- = table_link_to 'user', t('admin.reports.assign_to_self'), assign_to_self_admin_report_path(@report), method: :post
- - elsif !@report.assigned_account.nil?
- = table_link_to 'trash', t('admin.reports.unassign'), unassign_admin_report_path(@report), method: :post
+ = render 'admin/reports/header_card', report: @report
+ = render 'admin/reports/header_details', report: @report
%hr.spacer
@@ -118,33 +20,7 @@
= react_admin_component :report_reason_selector, id: @report.id, category: @report.category, rule_ids: @report.rule_ids&.map(&:to_s), disabled: @report.action_taken?
- if @report.comment.present?
- - if @report.account.instance_actor?
- %p= t('admin.reports.comment_description_html', name: content_tag(:strong, site_hostname, class: 'username'))
- - elsif @report.account.local?
- %p= t('admin.reports.comment_description_html', name: content_tag(:strong, @report.account.username, class: 'username'))
- - else
- %p= t('admin.reports.comment_description_html', name: t('admin.reports.remote_user_placeholder', instance: @report.account.domain))
-
- .report-notes
- .report-notes__item
- - if @report.account.local? && !@report.account.instance_actor?
- = image_tag @report.account.avatar.url, class: 'report-notes__item__avatar'
- - else
- = image_tag(full_asset_url('avatars/original/missing.png', skip_pipeline: true), class: 'report-notes__item__avatar')
-
- .report-notes__item__header
- %span.username
- - if @report.account.instance_actor?
- = site_hostname
- - elsif @report.account.local?
- = link_to @report.account.username, admin_account_path(@report.account_id)
- - else
- = link_to @report.account.domain, admin_instance_path(@report.account.domain)
- %time.relative-formatted{ datetime: @report.created_at.iso8601 }
- = l @report.created_at.to_date
-
- .report-notes__item__content
- = simple_format(h(@report.comment))
+ = render 'admin/reports/comment', report: @report
%hr.spacer/
@@ -179,7 +55,7 @@
%p#actions= t(@report.target_account.local? ? 'admin.reports.actions_description_html' : 'admin.reports.actions_description_remote_html')
- = render partial: 'admin/reports/actions'
+ = render partial: 'admin/reports/actions', locals: { report: @report, statuses: @statuses }
- unless @action_logs.empty?
%hr.spacer/
diff --git a/app/views/admin/roles/_form.html.haml b/app/views/admin/roles/_form.html.haml
index 3cbec0d0b57758..2400332145be1f 100644
--- a/app/views/admin/roles/_form.html.haml
+++ b/app/views/admin/roles/_form.html.haml
@@ -1,40 +1,36 @@
-= simple_form_for @role, url: @role.new_record? ? admin_roles_path : admin_role_path(@role) do |f|
- = render 'shared/error_messages', object: @role
+= render 'shared/error_messages', object: form.object
- - if @role.everyone?
- .flash-message.info
- = t('admin.roles.everyone_full_description_html')
- - else
- .fields-group
- = f.input :name, wrapper: :with_label
-
- - unless current_user.role.id == @role.id
- .fields-group
- = f.input :position, wrapper: :with_label, input_html: { max: current_user.role.position - 1 }
+- if form.object.everyone?
+ .flash-message.info
+ = t('admin.roles.everyone_full_description_html')
+- else
+ .fields-group
+ = form.input :name, wrapper: :with_label
+ - unless current_user.role == form.object
.fields-group
- = f.input :color, wrapper: :with_label, input_html: { placeholder: '#000000', type: 'color' }
+ = form.input :position, wrapper: :with_label, input_html: { max: current_user.role.position - 1 }
- %hr.spacer/
+ .fields-group
+ = form.input :color, wrapper: :with_label, input_html: { placeholder: '#000000', type: 'color' }
- .fields-group
- = f.input :highlighted, wrapper: :with_label
+ %hr.spacer/
- %hr.spacer/
+ .fields-group
+ = form.input :highlighted, wrapper: :with_label
- - unless current_user.role.id == @role.id
+ %hr.spacer/
- .field-group
- .input.with_block_label
- %label= t('simple_form.labels.user_role.permissions_as_keys')
- %span.hint= t('simple_form.hints.user_role.permissions_as_keys')
+- unless current_user.role == form.object
- - (@role.everyone? ? UserRole::Flags::CATEGORIES.slice(:invites) : UserRole::Flags::CATEGORIES).each do |category, permissions|
- %h4= t(category, scope: 'admin.roles.categories')
+ .field-group
+ .input.with_block_label
+ %label= t('simple_form.labels.user_role.permissions_as_keys')
+ %span.hint= t('simple_form.hints.user_role.permissions_as_keys')
- = f.input :permissions_as_keys, collection: permissions, wrapper: :with_block_label, include_blank: false, label_method: ->(privilege) { safe_join([t("admin.roles.privileges.#{privilege}"), content_tag(:span, t("admin.roles.privileges.#{privilege}_description"), class: 'hint')]) }, required: false, as: :check_boxes, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li', label: false, hint: false, disabled: permissions.filter { |privilege| UserRole::FLAGS[privilege] & current_user.role.computed_permissions == 0 }
+ - (form.object.everyone? ? UserRole::Flags::CATEGORIES.slice(:invites) : UserRole::Flags::CATEGORIES).each do |category, permissions|
+ %h4= t(category, scope: 'admin.roles.categories')
- %hr.spacer/
+ = form.input :permissions_as_keys, collection: permissions, wrapper: :with_block_label, include_blank: false, label_method: ->(privilege) { safe_join([t("admin.roles.privileges.#{privilege}"), content_tag(:span, t("admin.roles.privileges.#{privilege}_description"), class: 'hint')]) }, required: false, as: :check_boxes, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li', label: false, hint: false, disabled: permissions.filter { |privilege| UserRole::FLAGS[privilege] & current_user.role.computed_permissions == 0 }
- .actions
- = f.button :button, @role.new_record? ? t('admin.roles.add_new') : t('generic.save_changes'), type: :submit
+ %hr.spacer/
diff --git a/app/views/admin/roles/edit.html.haml b/app/views/admin/roles/edit.html.haml
index 5688b69b1fdee0..ec3f5b6fbe6b59 100644
--- a/app/views/admin/roles/edit.html.haml
+++ b/app/views/admin/roles/edit.html.haml
@@ -4,4 +4,7 @@
- content_for :heading_actions do
= link_to t('admin.roles.delete'), admin_role_path(@role), method: :delete, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button button--destructive' if can?(:destroy, @role)
-= render partial: 'form'
+= simple_form_for @role, url: admin_role_path(@role) do |form|
+ = render partial: 'form', object: form
+ .actions
+ = form.button :button, t('generic.save_changes'), type: :submit
diff --git a/app/views/admin/roles/new.html.haml b/app/views/admin/roles/new.html.haml
index 821079271851fa..6ca0c2137b19e4 100644
--- a/app/views/admin/roles/new.html.haml
+++ b/app/views/admin/roles/new.html.haml
@@ -1,4 +1,7 @@
- content_for :page_title do
= t('admin.roles.add_new')
-= render partial: 'form'
+= simple_form_for @role, url: admin_roles_path do |form|
+ = render partial: 'form', object: form
+ .actions
+ = form.button :button, t('admin.roles.add_new'), type: :submit
diff --git a/app/views/admin/rules/_rule.html.haml b/app/views/admin/rules/_rule.html.haml
index f8a9ac7868df98..a0896fe806e333 100644
--- a/app/views/admin/rules/_rule.html.haml
+++ b/app/views/admin/rules/_rule.html.haml
@@ -1,6 +1,6 @@
.announcements-list__item
= link_to edit_admin_rule_path(rule), class: 'announcements-list__item__title' do
- = "#{rule_counter + 1}."
+ #{rule_counter + 1}.
= truncate(rule.text)
.announcements-list__item__action-bar
diff --git a/app/views/admin/settings/appearance/show.html.haml b/app/views/admin/settings/appearance/show.html.haml
index 60522240f5e118..89eddfdc42244b 100644
--- a/app/views/admin/settings/appearance/show.html.haml
+++ b/app/views/admin/settings/appearance/show.html.haml
@@ -11,7 +11,7 @@
%p.lead= t('admin.settings.appearance.preamble')
.fields-group
- = f.input :flavour_and_skin, collection: Themes.instance.flavours_and_skins, group_label_method: -> (flavour_and_skin) { I18n.t("flavours.#{flavour_and_skin}.name", default: flavour_and_skin) }, wrapper: :with_label, label: t('admin.settings.flavour_and_skin.title'), include_blank: false, as: :grouped_select, label_method: :last, value_method: lambda { |value| value.join('/') }, group_method: :last
+ = f.input :flavour_and_skin, collection: Themes.instance.flavours_and_skins, group_label_method: ->(flavour_and_skin) { I18n.t("flavours.#{flavour_and_skin}.name", default: flavour_and_skin) }, wrapper: :with_label, label: t('admin.settings.flavour_and_skin.title'), include_blank: false, as: :grouped_select, label_method: :last, value_method: ->(value) { value.join('/') }, group_method: :last
.fields-group
= f.input :custom_css, wrapper: :with_block_label, as: :text, input_html: { rows: 8 }
diff --git a/app/views/admin/software_updates/index.html.haml b/app/views/admin/software_updates/index.html.haml
index 7a223ee07b3347..d2ba115590afd3 100644
--- a/app/views/admin/software_updates/index.html.haml
+++ b/app/views/admin/software_updates/index.html.haml
@@ -23,7 +23,7 @@
%td= update.version
%td= t("admin.software_updates.types.#{update.type}")
- if update.urgent?
- %td.critical= t("admin.software_updates.critical_update")
+ %td.critical= t('admin.software_updates.critical_update')
- else
%td
%td= table_link_to 'link', t('admin.software_updates.release_notes'), update.release_notes
diff --git a/app/views/admin/statuses/index.html.haml b/app/views/admin/statuses/index.html.haml
index 9163dee795fc1f..a2e3cbc0daf09a 100644
--- a/app/views/admin/statuses/index.html.haml
+++ b/app/views/admin/statuses/index.html.haml
@@ -1,7 +1,7 @@
- content_for :page_title do
= t('admin.statuses.title')
\-
- = "@#{@account.pretty_acct}"
+ @#{@account.pretty_acct}
.filters
.filter-subset
diff --git a/app/views/admin/statuses/show.html.haml b/app/views/admin/statuses/show.html.haml
index e070e5872bd869..5fda50a94eea7b 100644
--- a/app/views/admin/statuses/show.html.haml
+++ b/app/views/admin/statuses/show.html.haml
@@ -2,7 +2,7 @@
= t('statuses.title', name: display_name(@account), quote: truncate(@status.spoiler_text.presence || @status.text, length: 50, omission: '…', escape: false))
- content_for :heading_actions do
- = link_to t('admin.statuses.open'), ActivityPub::TagManager.instance.url_for(@status), class: 'button', target: '_blank'
+ = link_to t('admin.statuses.open'), ActivityPub::TagManager.instance.url_for(@status), class: 'button', target: '_blank', rel: 'noopener noreferrer'
%h3= t('admin.statuses.metadata')
diff --git a/app/views/admin/tags/show.html.haml b/app/views/admin/tags/show.html.haml
index 71bce0c0cb2044..e4c985c19e2afb 100644
--- a/app/views/admin/tags/show.html.haml
+++ b/app/views/admin/tags/show.html.haml
@@ -9,7 +9,7 @@
.dashboard
.dashboard__item
- = react_admin_component :counter, measure: 'tag_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { id: @tag.id }, label: t('admin.trends.tags.dashboard.tag_accounts_measure'), href: tag_url(@tag), target: '_blank'
+ = react_admin_component :counter, measure: 'tag_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { id: @tag.id }, label: t('admin.trends.tags.dashboard.tag_accounts_measure'), href: tag_url(@tag), target: '_blank', rel: 'noopener noreferrer'
.dashboard__item
= react_admin_component :counter, measure: 'tag_uses', start_at: @time_period.first, end_at: @time_period.last, params: { id: @tag.id }, label: t('admin.trends.tags.dashboard.tag_uses_measure')
.dashboard__item
@@ -35,7 +35,6 @@
%span= t('admin.trends.tags.not_trendable')
= fa_icon 'lock fw'
-
= link_to admin_tag_path(@tag.id), class: ['dashboard__quick-access', @tag.listable? ? 'positive' : 'negative'] do
- if @tag.listable?
%span= t('admin.trends.tags.listable')
diff --git a/app/views/admin/trends/links/_preview_card.html.haml b/app/views/admin/trends/links/_preview_card.html.haml
index 1ca34837151477..ee3774790c45ad 100644
--- a/app/views/admin/trends/links/_preview_card.html.haml
+++ b/app/views/admin/trends/links/_preview_card.html.haml
@@ -4,7 +4,7 @@
.batch-table__row__content.pending-account
.pending-account__header
- = link_to preview_card.title, preview_card.url
+ = link_to preview_card.title, url_for_preview_card(preview_card)
%br/
diff --git a/app/views/admin/trends/tags/_tag.html.haml b/app/views/admin/trends/tags/_tag.html.haml
index 72f8178ef28055..70c7d8dbd42cd7 100644
--- a/app/views/admin/trends/tags/_tag.html.haml
+++ b/app/views/admin/trends/tags/_tag.html.haml
@@ -10,7 +10,7 @@
%br/
- = link_to tag_path(tag), target: '_blank' do
+ = link_to tag_path(tag), target: '_blank', rel: 'noopener noreferrer' do
= t('admin.trends.tags.used_by_over_week', count: tag.history.reduce(0) { |sum, day| sum + day.accounts })
- if tag.trendable? && (rank = Trends.tags.rank(tag.id))
diff --git a/app/views/admin/webhooks/_form.html.haml b/app/views/admin/webhooks/_form.html.haml
index c870e943f4ca23..6c4574fd3bc087 100644
--- a/app/views/admin/webhooks/_form.html.haml
+++ b/app/views/admin/webhooks/_form.html.haml
@@ -1,14 +1,10 @@
-= simple_form_for @webhook, url: @webhook.new_record? ? admin_webhooks_path : admin_webhook_path(@webhook) do |f|
- = render 'shared/error_messages', object: @webhook
+= render 'shared/error_messages', object: form.object
- .fields-group
- = f.input :url, wrapper: :with_block_label, input_html: { placeholder: 'https://' }
+.fields-group
+ = form.input :url, wrapper: :with_block_label, input_html: { placeholder: 'https://' }
- .fields-group
- = f.input :events, collection: Webhook::EVENTS, wrapper: :with_block_label, include_blank: false, as: :check_boxes, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li', disabled: Webhook::EVENTS.filter { |event| !current_user.role.can?(Webhook.permission_for_event(event)) }
+.fields-group
+ = form.input :events, collection: Webhook::EVENTS, wrapper: :with_block_label, include_blank: false, as: :check_boxes, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li', disabled: Webhook::EVENTS.filter { |event| !current_user.role.can?(Webhook.permission_for_event(event)) }
- .fields-group
- = f.input :template, wrapper: :with_block_label, input_html: { placeholder: '{ "content": "Hello {{object.username}}" }' }
-
- .actions
- = f.button :button, @webhook.new_record? ? t('admin.webhooks.add_new') : t('generic.save_changes'), type: :submit
+.fields-group
+ = form.input :template, wrapper: :with_block_label, input_html: { placeholder: '{ "content": "Hello {{object.username}}" }' }
diff --git a/app/views/admin/webhooks/edit.html.haml b/app/views/admin/webhooks/edit.html.haml
index 3dc0ace9bfbb05..2c2a7aa0342153 100644
--- a/app/views/admin/webhooks/edit.html.haml
+++ b/app/views/admin/webhooks/edit.html.haml
@@ -1,4 +1,7 @@
- content_for :page_title do
= t('admin.webhooks.edit')
-= render partial: 'form'
+= simple_form_for @webhook, url: admin_webhook_path(@webhook) do |form|
+ = render partial: 'form', object: form
+ .actions
+ = form.button :button, t('generic.save_changes'), type: :submit
diff --git a/app/views/admin/webhooks/new.html.haml b/app/views/admin/webhooks/new.html.haml
index 1258df74abef67..f51b039ce8e888 100644
--- a/app/views/admin/webhooks/new.html.haml
+++ b/app/views/admin/webhooks/new.html.haml
@@ -1,4 +1,7 @@
- content_for :page_title do
= t('admin.webhooks.new')
-= render partial: 'form'
+= simple_form_for @webhook, url: admin_webhooks_path do |form|
+ = render partial: 'form', object: form
+ .actions
+ = form.button :button, t('admin.webhooks.add_new'), type: :submit
diff --git a/app/views/auth/registrations/_session.html.haml b/app/views/auth/registrations/_session.html.haml
index 11eae566fadb99..28499a7c91c35c 100644
--- a/app/views/auth/registrations/_session.html.haml
+++ b/app/views/auth/registrations/_session.html.haml
@@ -2,7 +2,7 @@
%td
%span{ title: session.user_agent }<
= fa_icon "#{session_device_icon(session)} fw", 'aria-label': session_device_icon(session)
- = ' '
+
= t 'sessions.description', browser: t("sessions.browsers.#{session.browser}", default: session.browser.to_s), platform: t("sessions.platforms.#{session.platform}", default: session.platform.to_s)
%td
%samp= session.ip
diff --git a/app/views/auth/registrations/_status.html.haml b/app/views/auth/registrations/_status.html.haml
index 759bbc41c0dbdd..8f44eee015ccef 100644
--- a/app/views/auth/registrations/_status.html.haml
+++ b/app/views/auth/registrations/_status.html.haml
@@ -1,30 +1,30 @@
-- if !@user.confirmed?
+- if !user.confirmed?
.flash-message.warning
= t('auth.status.confirming')
= link_to t('auth.didnt_get_confirmation'), new_user_confirmation_path
-- elsif !@user.approved?
+- elsif !user.approved?
.flash-message.warning
= t('auth.status.pending')
-- elsif @user.account.moved_to_account_id.present?
+- elsif user.account.moved_to_account_id.present?
.flash-message.warning
- = t('auth.status.redirecting_to', acct: @user.account.moved_to_account.pretty_acct)
+ = t('auth.status.redirecting_to', acct: user.account.moved_to_account.pretty_acct)
= link_to t('migrations.cancel'), settings_migration_path
%h3= t('auth.status.account_status')
%p.hint
- - if @user.account.suspended?
+ - if user.account.suspended?
%span.negative-hint= t('user_mailer.warning.explanation.suspend')
- - elsif @user.disabled?
+ - elsif user.disabled?
%span.negative-hint= t('user_mailer.warning.explanation.disable')
- - elsif @user.account.silenced?
+ - elsif user.account.silenced?
%span.warning-hint= t('user_mailer.warning.explanation.silence')
- else
%span.positive-hint= t('auth.status.functional')
-= render partial: 'account_warning', collection: @strikes
+= render partial: 'account_warning', collection: strikes
-- if @user.account.strikes.exists?
+- if user.account.strikes.exists?
%hr.spacer/
%p.muted-hint
diff --git a/app/views/auth/registrations/edit.html.haml b/app/views/auth/registrations/edit.html.haml
index 3e9b0cb6bda1d9..f5ef4e97e4017e 100644
--- a/app/views/auth/registrations/edit.html.haml
+++ b/app/views/auth/registrations/edit.html.haml
@@ -1,7 +1,11 @@
- content_for :page_title do
= t('settings.account_settings')
-= render 'status'
+- if self_destruct?
+ .flash-message.warning
+ = t('auth.status.self_destruct', domain: ENV.fetch('LOCAL_DOMAIN'))
+- else
+ = render partial: 'status', locals: { user: @user, strikes: @strikes }
%h3= t('auth.security')
@@ -32,7 +36,7 @@
= render partial: 'sessions', object: @sessions
-- unless current_account.suspended?
+- unless current_account.suspended? || self_destruct?
%hr.spacer/
%h3= t('auth.migrate_account')
diff --git a/app/views/auth/registrations/new.html.haml b/app/views/auth/registrations/new.html.haml
index f473a993b07236..4cac7b51bd0a58 100644
--- a/app/views/auth/registrations/new.html.haml
+++ b/app/views/auth/registrations/new.html.haml
@@ -26,14 +26,13 @@
= f.input :confirm_password, as: :string, placeholder: t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), required: false, input_html: { 'aria-label': t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), autocomplete: 'off' }, hint: false
= f.input :website, as: :url, wrapper: :with_label, label: t('simple_form.labels.defaults.honeypot', label: 'Website'), required: false, input_html: { 'aria-label': t('simple_form.labels.defaults.honeypot', label: 'Website'), autocomplete: 'off' }
- - if approved_registrations? && !@invite.present?
+ - if approved_registrations? && @invite.blank?
%p.lead= t('auth.sign_up.manual_review', domain: site_hostname)
.fields-group
= f.simple_fields_for :invite_request, resource.invite_request || resource.build_invite_request do |invite_request_fields|
= invite_request_fields.input :text, as: :text, wrapper: :with_block_label, required: Setting.require_invite_text, label: false, hint: false
-
= hidden_field_tag :accept, params[:accept]
= f.input :invite_code, as: :hidden
diff --git a/app/views/auth/sessions/two_factor.html.haml b/app/views/auth/sessions/two_factor.html.haml
index 1867ec7f8a1409..0892101b57cc67 100644
--- a/app/views/auth/sessions/two_factor.html.haml
+++ b/app/views/auth/sessions/two_factor.html.haml
@@ -1,7 +1,7 @@
- content_for :page_title do
= t('auth.login')
-- if @webauthn_enabled
+- if webauthn_enabled?
= render partial: 'auth/sessions/two_factor/webauthn_form', locals: { hidden: @scheme_type != 'webauthn' }
= render partial: 'auth/sessions/two_factor/otp_authentication_form', locals: { hidden: @scheme_type != 'totp' }
diff --git a/app/views/auth/sessions/two_factor/_otp_authentication_form.html.haml b/app/views/auth/sessions/two_factor/_otp_authentication_form.html.haml
index 094b502b177a58..8cc2c8561032ff 100644
--- a/app/views/auth/sessions/two_factor/_otp_authentication_form.html.haml
+++ b/app/views/auth/sessions/two_factor/_otp_authentication_form.html.haml
@@ -13,6 +13,6 @@
- if Setting.site_contact_email.present?
%p.hint.subtle-hint= t('users.otp_lost_help_html', email: mail_to(Setting.site_contact_email, nil))
- - if @webauthn_enabled
+ - if webauthn_enabled?
.form-footer
= link_to(t('auth.link_to_webauth'), '#', id: 'link-to-webauthn')
diff --git a/app/views/disputes/strikes/_card.html.haml b/app/views/disputes/strikes/_card.html.haml
new file mode 100644
index 00000000000000..55551cc7d0482b
--- /dev/null
+++ b/app/views/disputes/strikes/_card.html.haml
@@ -0,0 +1,38 @@
+.strike-card
+ - unless strike.none_action?
+ %p= t "user_mailer.warning.explanation.#{strike.action}", instance: Rails.configuration.x.local_domain
+ - if strike.text.present?
+ = linkify(strike.text)
+ - if strike.report && !strike.report.other?
+ %p
+ %strong= t('user_mailer.warning.reason')
+ = t("user_mailer.warning.categories.#{strike.report.category}")
+ - if strike.report.violation? && strike.report.rule_ids.present?
+ %ul.strike-card__rules
+ - strike.report.rules.each do |rule|
+ %li
+ %span.strike-card__rules__text= rule.text
+ - if strike.status_ids.present? && !strike.status_ids.empty?
+ %p
+ %strong= t('user_mailer.warning.statuses')
+ .strike-card__statuses-list
+ - status_map = strike.statuses.includes(:application, :media_attachments).index_by(&:id)
+ - strike.status_ids.each do |status_id|
+ .strike-card__statuses-list__item
+ - if (status = status_map[status_id.to_i])
+ .one-liner
+ .emojify= one_line_preview(status)
+ - status.ordered_media_attachments.each do |media_attachment|
+ %abbr{ title: media_attachment.description }
+ = fa_icon 'link'
+ = media_attachment.file_file_name
+ .strike-card__statuses-list__item__meta
+ = link_to ActivityPub::TagManager.instance.url_for(status), target: '_blank', rel: 'noopener noreferrer' do
+ %time.formatted{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at)
+ - unless status.application.nil?
+ ·
+ = status.application.name
+ - else
+ .one-liner= t('disputes.strikes.status', id: status_id)
+ .strike-card__statuses-list__item__meta
+ = t('disputes.strikes.status_removed')
diff --git a/app/views/disputes/strikes/show.html.haml b/app/views/disputes/strikes/show.html.haml
index ce52e470d9d070..62695b155e0a83 100644
--- a/app/views/disputes/strikes/show.html.haml
+++ b/app/views/disputes/strikes/show.html.haml
@@ -10,62 +10,18 @@
%p.hint
%span.positive-hint
= fa_icon 'check'
- = ' '
+
= t 'disputes.strikes.appeal_approved'
- elsif @appeal.persisted? && @appeal.rejected?
%p.hint
%span.negative-hint
= fa_icon 'times'
- = ' '
+
= t 'disputes.strikes.appeal_rejected'
.report-header
.report-header__card
- .strike-card
- - unless @strike.none_action?
- %p= t "user_mailer.warning.explanation.#{@strike.action}", instance: Rails.configuration.x.local_domain
-
- - unless @strike.text.blank?
- = linkify(@strike.text)
-
- - if @strike.report && !@strike.report.other?
- %p
- %strong= t('user_mailer.warning.reason')
- = t("user_mailer.warning.categories.#{@strike.report.category}")
-
- - if @strike.report.violation? && @strike.report.rule_ids.present?
- %ul.strike-card__rules
- - @strike.report.rules.each do |rule|
- %li
- %span.strike-card__rules__text= rule.text
-
- - if @strike.status_ids.present? && !@strike.status_ids.empty?
- %p
- %strong= t('user_mailer.warning.statuses')
-
- .strike-card__statuses-list
- - status_map = @strike.statuses.includes(:application, :media_attachments).index_by(&:id)
-
- - @strike.status_ids.each do |status_id|
- .strike-card__statuses-list__item
- - if (status = status_map[status_id.to_i])
- .one-liner
- .emojify= one_line_preview(status)
-
- - status.ordered_media_attachments.each do |media_attachment|
- %abbr{ title: media_attachment.description }
- = fa_icon 'link'
- = media_attachment.file_file_name
- .strike-card__statuses-list__item__meta
- = link_to ActivityPub::TagManager.instance.url_for(status), target: '_blank' do
- %time.formatted{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at)
- - unless status.application.nil?
- ·
- = status.application.name
- - else
- .one-liner= t('disputes.strikes.status', id: status_id)
- .strike-card__statuses-list__item__meta
- = t('disputes.strikes.status_removed')
+ = render 'card', strike: @strike
.report-header__details
.report-header__details__item
diff --git a/app/views/errors/self_destruct.html.haml b/app/views/errors/self_destruct.html.haml
new file mode 100644
index 00000000000000..09b17a5a9439b2
--- /dev/null
+++ b/app/views/errors/self_destruct.html.haml
@@ -0,0 +1,20 @@
+- content_for :page_title do
+ = t('self_destruct.title')
+
+.simple_form
+ %h1.title= t('self_destruct.title')
+ %p.lead= t('self_destruct.lead_html', domain: ENV.fetch('LOCAL_DOMAIN'))
+
+.form-footer
+ %ul.no-list
+ - if user_signed_in?
+ %li= link_to t('settings.account_settings'), edit_user_registration_path
+ - else
+ - if controller_name != 'sessions'
+ %li= link_to_login t('auth.login')
+
+ - if controller_name != 'passwords' && controller_name != 'registrations'
+ %li= link_to t('auth.forgot_password'), new_user_password_path
+
+ - if user_signed_in?
+ %li= link_to t('auth.logout'), destroy_user_session_path, data: { method: :delete }
diff --git a/app/views/invites/_form.html.haml b/app/views/invites/_form.html.haml
index 7ea521ebc70b6e..dbbb785e835e2a 100644
--- a/app/views/invites/_form.html.haml
+++ b/app/views/invites/_form.html.haml
@@ -1,14 +1,13 @@
-= simple_form_for(@invite, url: controller.is_a?(Admin::InvitesController) ? admin_invites_path : invites_path) do |f|
- = render 'shared/error_messages', object: @invite
+= render 'shared/error_messages', object: form.object
- .fields-row
- .fields-row__column.fields-row__column-6.fields-group
- = f.input :max_uses, wrapper: :with_label, collection: [1, 5, 10, 25, 50, 100], label_method: ->(num) { I18n.t('invites.max_uses', count: num) }, prompt: I18n.t('invites.max_uses_prompt')
- .fields-row__column.fields-row__column-6.fields-group
- = f.input :expires_in, wrapper: :with_label, collection: [30.minutes, 1.hour, 6.hours, 12.hours, 1.day, 1.week].map(&:to_i), label_method: ->(i) { I18n.t("invites.expires_in.#{i}") }, prompt: I18n.t('invites.expires_in_prompt')
+.fields-row
+ .fields-row__column.fields-row__column-6.fields-group
+ = form.input :max_uses, wrapper: :with_label, collection: invites_max_uses_options, label_method: ->(num) { I18n.t('invites.max_uses', count: num) }, prompt: I18n.t('invites.max_uses_prompt')
+ .fields-row__column.fields-row__column-6.fields-group
+ = form.input :expires_in, wrapper: :with_label, collection: invites_expires_options.map(&:to_i), label_method: ->(i) { I18n.t("invites.expires_in.#{i}") }, prompt: I18n.t('invites.expires_in_prompt')
- .fields-group
- = f.input :autofollow, wrapper: :with_label
+.fields-group
+ = form.input :autofollow, wrapper: :with_label
- .actions
- = f.button :button, t('invites.generate'), type: :submit
+.actions
+ = form.button :button, t('invites.generate'), type: :submit
diff --git a/app/views/invites/index.html.haml b/app/views/invites/index.html.haml
index 61420ab1e40797..88ed662af89acb 100644
--- a/app/views/invites/index.html.haml
+++ b/app/views/invites/index.html.haml
@@ -4,7 +4,8 @@
- if policy(:invite).create?
%p= t('invites.prompt')
- = render 'form'
+ = simple_form_for(@invite, url: invites_path) do |form|
+ = render partial: 'form', object: form
%hr.spacer/
diff --git a/app/views/layouts/_theme.html.haml b/app/views/layouts/_theme.html.haml
index 71e661de653bfe..2b40d408f25ae8 100644
--- a/app/views/layouts/_theme.html.haml
+++ b/app/views/layouts/_theme.html.haml
@@ -1,6 +1,5 @@
- if theme
- - if theme[:pack] != 'common' && theme[:common]
- = render partial: 'layouts/theme', object: theme[:common]
+ = render partial: 'layouts/theme', object: theme[:common] if theme[:pack] != 'common' && theme[:common]
- if theme[:pack]
- pack_path = theme[:flavour] ? "flavours/#{theme[:flavour]}/#{theme[:pack]}" : "core/#{theme[:pack]}"
= javascript_pack_tag pack_path, crossorigin: 'anonymous'
diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml
index 3b5ab297666056..a836ac406fe0a3 100755
--- a/app/views/layouts/application.html.haml
+++ b/app/views/layouts/application.html.haml
@@ -35,17 +35,19 @@
= csrf_meta_tags unless skip_csrf_meta_tags?
%meta{ name: 'style-nonce', content: request.content_security_policy_nonce }
- :javascript
- var nonce = document.querySelector('meta[name="style-nonce"]').getAttribute('content');
- window.MathJax = {
- chtml: {nonce: nonce},
- tex: {
- processEnvironments: false,
- processRefs: false,
- inlineMath: [['\\(', '\\)']],
- displayMath: [['\\[', '\\]']]
+ %script{ nonce: request.content_security_policy_nonce }
+ :plain
+ var nonce = document.querySelector('meta[name="style-nonce"]').getAttribute('content');
+ window.MathJax = {
+ chtml: {nonce: nonce},
+ tex: {
+ processEnvironments: false,
+ processRefs: false,
+ inlineMath: [['\\(', '\\)']],
+ displayMath: [['\\[', '\\]']]
}
};
+
%script{ src: '/MathJax/es5/tex-chtml.js' }
= stylesheet_link_tag '/inert.css', skip_pipeline: true, media: 'all', id: 'inert-style'
diff --git a/app/views/layouts/error.html.haml b/app/views/layouts/error.html.haml
index d3210c33f9f33c..faedd43d09d976 100644
--- a/app/views/layouts/error.html.haml
+++ b/app/views/layouts/error.html.haml
@@ -1,11 +1,11 @@
!!!
%html{ lang: I18n.locale }
%head
- %meta{ content: 'text/html; charset=UTF-8', 'http-equiv' => 'Content-Type' }/
+ %meta{ 'content' => 'text/html; charset=UTF-8', 'http-equiv' => 'Content-Type' }/
%meta{ charset: 'utf-8' }/
%title= safe_join([yield(:page_title), Setting.default_settings['site_title']], ' - ')
%meta{ content: 'width=device-width,initial-scale=1', name: 'viewport' }/
- = javascript_pack_tag "common", crossorigin: 'anonymous'
+ = javascript_pack_tag 'common', crossorigin: 'anonymous'
= render partial: 'layouts/theme', object: (@core || { pack: 'common' })
= render partial: 'layouts/theme', object: (@theme || { pack: 'error', flavour: 'glitch', common: { pack: 'common', flavour: 'glitch', skin: 'default' } })
%body.error
diff --git a/app/views/notification_mailer/_status.html.haml b/app/views/notification_mailer/_status.html.haml
index 7f614e99cb7961..e053a30fdec591 100644
--- a/app/views/notification_mailer/_status.html.haml
+++ b/app/views/notification_mailer/_status.html.haml
@@ -23,7 +23,7 @@
= image_tag full_asset_url(status.account.avatar.url), alt: ''
%td{ align: 'left' }
%bdi= display_name(status.account)
- = "@#{status.account.pretty_acct}"
+ @#{status.account.pretty_acct}
- if status.spoiler_text?
.auto-dir
diff --git a/app/views/oauth/authorizations/error.html.haml b/app/views/oauth/authorizations/error.html.haml
index 408ca2b86e00d8..cd6e6f64e2daaa 100644
--- a/app/views/oauth/authorizations/error.html.haml
+++ b/app/views/oauth/authorizations/error.html.haml
@@ -1,3 +1,3 @@
.form-container
- .flash-message#error_explanation
+ .flash-message
= @pre_auth.error_response.body[:error_description]
diff --git a/app/views/relationships/_account.html.haml b/app/views/relationships/_account.html.haml
index 0fa3cffb552fcc..43a3d64bc859fc 100644
--- a/app/views/relationships/_account.html.haml
+++ b/app/views/relationships/_account.html.haml
@@ -6,7 +6,7 @@
%tbody
%tr
%td.accounts-table__interrelationships
- = interrelationships_icon(@relationships, account.id)
+ = interrelationships_icon(relationships, account.id)
%td= account_link_to account
%td.accounts-table__count.optional
= friendly_number_to_human account.statuses_count
diff --git a/app/views/relationships/show.html.haml b/app/views/relationships/show.html.haml
index fcda6317ec62a6..6b87bef2ecdaee 100644
--- a/app/views/relationships/show.html.haml
+++ b/app/views/relationships/show.html.haml
@@ -50,6 +50,6 @@
- if @accounts.empty?
= nothing_here 'nothing-here--under-tabs'
- else
- = render partial: 'account', collection: @accounts, locals: { f: f }
+ = render partial: 'account', collection: @accounts, locals: { f: f, relationships: @relationships }
= paginate @accounts
diff --git a/app/views/settings/preferences/appearance/show.html.haml b/app/views/settings/preferences/appearance/show.html.haml
index c08836d178aa90..959b72361ae977 100644
--- a/app/views/settings/preferences/appearance/show.html.haml
+++ b/app/views/settings/preferences/appearance/show.html.haml
@@ -7,8 +7,7 @@
= simple_form_for current_user, url: settings_preferences_appearance_path, html: { method: :put, id: 'edit_user' } do |f|
.fields-row
.fields-group.fields-row__column.fields-row__column-6
- = f.input :locale, collection: I18n.available_locales, wrapper: :with_label, include_blank: false, label_method: ->(locale) { native_locale_name(locale) }, selected: I18n.locale, hint: false
-
+ = f.input :locale, collection: ui_languages, wrapper: :with_label, include_blank: false, label_method: ->(locale) { native_locale_name(locale) }, selected: I18n.locale, hint: false
.fields-group.fields-row__column.fields-row__column-6
= f.input :time_zone, wrapper: :with_label, collection: ActiveSupport::TimeZone.all.map { |tz| ["(GMT#{tz.formatted_offset}) #{tz.name}", tz.tzinfo.name] }, hint: false
diff --git a/app/views/settings/preferences/other/show.html.haml b/app/views/settings/preferences/other/show.html.haml
index afe8529e00b36b..fe1cdbf48f1be0 100644
--- a/app/views/settings/preferences/other/show.html.haml
+++ b/app/views/settings/preferences/other/show.html.haml
@@ -24,7 +24,7 @@
= ff.input :default_sensitive, wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_default_sensitive'), hint: I18n.t('simple_form.hints.defaults.setting_default_sensitive')
.fields-group
- = ff.input :default_content_type, collection: ['text/plain', 'text/markdown', 'text/html'], wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_default_content_type'), include_blank: false, label_method: lambda { |item| safe_join([t("simple_form.labels.defaults.setting_default_content_type_#{item.split('/')[1]}"), content_tag(:span, t("simple_form.hints.defaults.setting_default_content_type_#{item.split('/')[1]}"), class: 'hint')]) }, required: false, as: :radio_buttons, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li', glitch_only: true
+ = ff.input :default_content_type, collection: ['text/plain', 'text/markdown', 'text/html'], wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_default_content_type'), include_blank: false, label_method: ->(item) { safe_join([t("simple_form.labels.defaults.setting_default_content_type_#{item.split('/')[1]}"), content_tag(:span, t("simple_form.hints.defaults.setting_default_content_type_#{item.split('/')[1]}"), class: 'hint')]) }, required: false, as: :radio_buttons, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li', glitch_only: true
%h4= t 'preferences.public_timelines'
diff --git a/app/views/settings/two_factor_authentication_methods/index.html.haml b/app/views/settings/two_factor_authentication_methods/index.html.haml
index 315443e6d59508..51141fab4fd2eb 100644
--- a/app/views/settings/two_factor_authentication_methods/index.html.haml
+++ b/app/views/settings/two_factor_authentication_methods/index.html.haml
@@ -7,7 +7,7 @@
%p.hint
%span.positive-hint
= fa_icon 'check'
- = ' '
+
= t 'two_factor_authentication.enabled'
.table-wrapper
diff --git a/app/views/shared/_error_messages.html.haml b/app/views/shared/_error_messages.html.haml
index 4916bd424e8a44..94841cc615caf9 100644
--- a/app/views/shared/_error_messages.html.haml
+++ b/app/views/shared/_error_messages.html.haml
@@ -1,5 +1,5 @@
- if object.errors.any?
- .flash-message.alert#error_explanation
+ .flash-message.alert
%strong= t('generic.validation_errors', count: object.errors.count)
- object.errors[:base].each do |error|
.flash-message.alert
diff --git a/app/views/shared/_og.html.haml b/app/views/shared/_og.html.haml
index a5d99ae33ac6f8..385351ee14aff4 100644
--- a/app/views/shared/_og.html.haml
+++ b/app/views/shared/_og.html.haml
@@ -1,12 +1,12 @@
-- thumbnail = @instance_presenter.thumbnail
-- description ||= @instance_presenter.description.presence || strip_tags(t('about.about_mastodon_html'))
+- thumbnail = instance_presenter.thumbnail
+- description ||= instance_presenter.description.presence || strip_tags(t('about.about_mastodon_html'))
%meta{ name: 'description', content: description }/
= opengraph 'og:site_name', t('about.hosted_on', domain: site_hostname)
= opengraph 'og:url', url_for(only_path: false)
= opengraph 'og:type', 'website'
-= opengraph 'og:title', @instance_presenter.title
+= opengraph 'og:title', instance_presenter.title
= opengraph 'og:description', description
= opengraph 'og:image', full_asset_url(thumbnail&.file&.url(:'@1x') || asset_pack_path('media/images/preview.png', protocol: :request))
= opengraph 'og:image:width', thumbnail ? thumbnail.meta['width'] : '1200'
diff --git a/app/views/statuses/_detailed_status.html.haml b/app/views/statuses/_detailed_status.html.haml
index 70cfbd6b87f669..c55dff5d9694e5 100644
--- a/app/views/statuses/_detailed_status.html.haml
+++ b/app/views/statuses/_detailed_status.html.haml
@@ -62,19 +62,19 @@
- else
= fa_icon('reply-all')
%span.detailed-status__reblogs>= friendly_number_to_human status.replies_count
- = ' '
+
·
- if status.public_visibility? || status.unlisted_visibility?
%span.detailed-status__link
= fa_icon('retweet')
%span.detailed-status__reblogs>= friendly_number_to_human status.reblogs_count
- = ' '
+
·
%span.detailed-status__link
= fa_icon('star')
%span.detailed-status__favorites>= friendly_number_to_human status.favourites_count
- = ' '
+
- if user_signed_in?
·
- = link_to t('statuses.open_in_web'), web_url("@#{status.account.pretty_acct}/#{status.id}"), class: 'detailed-status__application', target: '_blank'
+ = link_to t('statuses.open_in_web'), web_url("@#{status.account.pretty_acct}/#{status.id}"), class: 'detailed-status__application', target: '_blank', rel: 'noopener noreferrer'
diff --git a/app/views/statuses/_poll.html.haml b/app/views/statuses/_poll.html.haml
index b537eb48cac0b0..cf01b1da018dd6 100644
--- a/app/views/statuses/_poll.html.haml
+++ b/app/views/statuses/_poll.html.haml
@@ -11,7 +11,7 @@
- percent = total_votes_count.positive? ? 100 * option.votes_count / total_votes_count : 0
%label.poll__option><
%span.poll__number><
- = "#{percent.round}%"
+ #{percent.round}%
%span.poll__option__text
= prerender_custom_emojis(h(option.title), status.emojis)
- if own_votes.include?(index)
diff --git a/app/views/statuses/_simple_status.html.haml b/app/views/statuses/_simple_status.html.haml
index ecbabf34cf6733..6aa4d23dab4097 100644
--- a/app/views/statuses/_simple_status.html.haml
+++ b/app/views/statuses/_simple_status.html.haml
@@ -23,7 +23,7 @@
%span.display-name
%bdi
%strong.display-name__html.p-name.emojify= display_name(status.account, custom_emojify: true, autoplay: prefers_autoplay?)
- = ' '
+
%span.display-name__account
= acct(status.account)
= fa_icon('lock') if status.account.locked?
diff --git a/app/views/statuses_cleanup/show.html.haml b/app/views/statuses_cleanup/show.html.haml
index 99b9ddab938caf..bd4cc1d86c7a42 100644
--- a/app/views/statuses_cleanup/show.html.haml
+++ b/app/views/statuses_cleanup/show.html.haml
@@ -5,7 +5,6 @@
= button_tag t('generic.save_changes'), class: 'button', form: 'edit_policy'
= simple_form_for @policy, url: statuses_cleanup_path, method: :put, html: { id: 'edit_policy' } do |f|
-
.fields-row
.fields-row__column.fields-row__column-6.fields-group
= f.input :enabled, as: :boolean, wrapper: :with_label, label: t('statuses_cleanup.enabled'), hint: t('statuses_cleanup.enabled_hint')
diff --git a/app/views/user_mailer/suspicious_sign_in.html.haml b/app/views/user_mailer/suspicious_sign_in.html.haml
index 75bcb2d54b875d..5bafe9d1b23f17 100644
--- a/app/views/user_mailer/suspicious_sign_in.html.haml
+++ b/app/views/user_mailer/suspicious_sign_in.html.haml
@@ -41,10 +41,10 @@
%tr
%td.column-cell.text-center
%p
- %strong= "#{t('sessions.ip')}:"
+ %strong #{t('sessions.ip')}:
= @remote_ip
%br/
- %strong= "#{t('sessions.browser')}:"
+ %strong #{t('sessions.browser')}:
%span{ title: @user_agent }= t 'sessions.description', browser: t("sessions.browsers.#{@detection.id}", default: @detection.id.to_s), platform: t("sessions.platforms.#{@detection.platform.id}", default: @detection.platform.id.to_s)
%br/
= l(@timestamp.in_time_zone(@resource.time_zone.presence), format: :with_time_zone)
diff --git a/app/views/user_mailer/warning.html.haml b/app/views/user_mailer/warning.html.haml
index 8a878bead60b3d..5d64e83247cd62 100644
--- a/app/views/user_mailer/warning.html.haml
+++ b/app/views/user_mailer/warning.html.haml
@@ -39,7 +39,7 @@
- unless @warning.none_action?
%p= t "user_mailer.warning.explanation.#{@warning.action}", instance: @instance
- - unless @warning.text.blank?
+ - if @warning.text.present?
= linkify(@warning.text)
- if @warning.report && !@warning.report.other?
@@ -68,7 +68,7 @@
%table.content-section{ cellspacing: 0, cellpadding: 0 }
%tbody
%tr
- %td.content-cell{ class: @statuses.nil? || @statuses.empty? ? '' : 'content-start' }
+ %td.content-cell{ class: @statuses.blank? ? '' : 'content-start' }
%table.column{ cellspacing: 0, cellpadding: 0 }
%tbody
%tr
diff --git a/app/views/user_mailer/webauthn_credential_added.html.haml b/app/views/user_mailer/webauthn_credential_added.html.haml
index c91c96d6fa25df..2ecb62d967ab20 100644
--- a/app/views/user_mailer/webauthn_credential_added.html.haml
+++ b/app/views/user_mailer/webauthn_credential_added.html.haml
@@ -20,7 +20,7 @@
= image_tag full_pack_url('media/images/mailer/icon_lock_open.png'), alt: ''
%h1= t 'devise.mailer.webauthn_credential.added.title'
- %p.lead= "#{t('devise.mailer.webauthn_credential.added.explanation')}:"
+ %p.lead #{t('devise.mailer.webauthn_credential.added.explanation')}:
%p.lead= @webauthn_credential.nickname
%table.email-table{ cellspacing: 0, cellpadding: 0 }
diff --git a/app/views/user_mailer/webauthn_credential_deleted.html.haml b/app/views/user_mailer/webauthn_credential_deleted.html.haml
index 578a080220141a..f282985b1485a8 100644
--- a/app/views/user_mailer/webauthn_credential_deleted.html.haml
+++ b/app/views/user_mailer/webauthn_credential_deleted.html.haml
@@ -20,7 +20,7 @@
= image_tag full_pack_url('media/images/mailer/icon_lock_open.png'), alt: ''
%h1= t 'devise.mailer.webauthn_credential.deleted.title'
- %p.lead= "#{t('devise.mailer.webauthn_credential.deleted.explanation')}:"
+ %p.lead #{t('devise.mailer.webauthn_credential.deleted.explanation')}:
%p.lead= @webauthn_credential.nickname
%table.email-table{ cellspacing: 0, cellpadding: 0 }
diff --git a/app/views/user_mailer/welcome.html.haml b/app/views/user_mailer/welcome.html.haml
index 3ab994ad3fc321..0d8a15cfd794dd 100644
--- a/app/views/user_mailer/welcome.html.haml
+++ b/app/views/user_mailer/welcome.html.haml
@@ -41,7 +41,7 @@
%table.input{ align: 'center', cellspacing: 0, cellpadding: 0 }
%tbody
%tr
- %td= "@#{@resource.account.username}@#{@instance}"
+ %td @#{@resource.account.username}@#{@instance}
.col-3
%table.column{ cellspacing: 0, cellpadding: 0 }
%tbody
diff --git a/app/workers/account_deletion_worker.rb b/app/workers/account_deletion_worker.rb
index b5015117282f62..e4f943fbd1fffd 100644
--- a/app/workers/account_deletion_worker.rb
+++ b/app/workers/account_deletion_worker.rb
@@ -3,7 +3,7 @@
class AccountDeletionWorker
include Sidekiq::Worker
- sidekiq_options queue: 'pull', lock: :until_executed
+ sidekiq_options queue: 'pull', lock: :until_executed, lock_ttl: 1.week.to_i
def perform(account_id, options = {})
account = Account.find(account_id)
diff --git a/app/workers/activitypub/synchronize_featured_collection_worker.rb b/app/workers/activitypub/synchronize_featured_collection_worker.rb
index f67d693cb3ab3c..7a187d7f53eede 100644
--- a/app/workers/activitypub/synchronize_featured_collection_worker.rb
+++ b/app/workers/activitypub/synchronize_featured_collection_worker.rb
@@ -3,7 +3,7 @@
class ActivityPub::SynchronizeFeaturedCollectionWorker
include Sidekiq::Worker
- sidekiq_options queue: 'pull', lock: :until_executed
+ sidekiq_options queue: 'pull', lock: :until_executed, lock_ttl: 1.day.to_i
def perform(account_id, options = {})
options = { note: true, hashtag: false }.deep_merge(options.deep_symbolize_keys)
diff --git a/app/workers/activitypub/synchronize_featured_tags_collection_worker.rb b/app/workers/activitypub/synchronize_featured_tags_collection_worker.rb
index 14af4f725cdd62..570415c82149c5 100644
--- a/app/workers/activitypub/synchronize_featured_tags_collection_worker.rb
+++ b/app/workers/activitypub/synchronize_featured_tags_collection_worker.rb
@@ -3,7 +3,7 @@
class ActivityPub::SynchronizeFeaturedTagsCollectionWorker
include Sidekiq::Worker
- sidekiq_options queue: 'pull', lock: :until_executed
+ sidekiq_options queue: 'pull', lock: :until_executed, lock_ttl: 1.day.to_i
def perform(account_id, url)
ActivityPub::FetchFeaturedTagsCollectionService.new.call(Account.find(account_id), url)
diff --git a/app/workers/activitypub/update_distribution_worker.rb b/app/workers/activitypub/update_distribution_worker.rb
index d0391bb6f61169..a04ac621f30e02 100644
--- a/app/workers/activitypub/update_distribution_worker.rb
+++ b/app/workers/activitypub/update_distribution_worker.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class ActivityPub::UpdateDistributionWorker < ActivityPub::RawDistributionWorker
- sidekiq_options queue: 'push', lock: :until_executed
+ sidekiq_options queue: 'push', lock: :until_executed, lock_ttl: 1.day.to_i
# Distribute an profile update to servers that might have a copy
# of the account in question
diff --git a/app/workers/admin/account_deletion_worker.rb b/app/workers/admin/account_deletion_worker.rb
index 6e0eb331bef83d..5dfdfb6e73c14d 100644
--- a/app/workers/admin/account_deletion_worker.rb
+++ b/app/workers/admin/account_deletion_worker.rb
@@ -3,7 +3,7 @@
class Admin::AccountDeletionWorker
include Sidekiq::Worker
- sidekiq_options queue: 'pull', lock: :until_executed
+ sidekiq_options queue: 'pull', lock: :until_executed, lock_ttl: 1.week.to_i
def perform(account_id)
DeleteAccountService.new.call(Account.find(account_id), reserve_username: true, reserve_email: true)
diff --git a/app/workers/admin/domain_purge_worker.rb b/app/workers/admin/domain_purge_worker.rb
index 095232a6d74af1..6c5250b660c380 100644
--- a/app/workers/admin/domain_purge_worker.rb
+++ b/app/workers/admin/domain_purge_worker.rb
@@ -3,7 +3,7 @@
class Admin::DomainPurgeWorker
include Sidekiq::Worker
- sidekiq_options queue: 'pull', lock: :until_executed
+ sidekiq_options queue: 'pull', lock: :until_executed, lock_ttl: 1.week.to_i
def perform(domain)
PurgeDomainService.new.call(domain)
diff --git a/app/workers/import/row_worker.rb b/app/workers/import/row_worker.rb
index 09dd6ce736143b..c86900e6adc3bc 100644
--- a/app/workers/import/row_worker.rb
+++ b/app/workers/import/row_worker.rb
@@ -8,7 +8,7 @@ class Import::RowWorker
sidekiq_retries_exhausted do |msg, _exception|
ActiveRecord::Base.connection_pool.with_connection do
# Increment the total number of processed items, and bump the state of the import if needed
- bulk_import_id = BulkImportRow.where(id: msg['args'][0]).pick(:id)
+ bulk_import_id = BulkImportRow.where(id: msg['args'][0]).pick(:bulk_import_id)
BulkImport.progress!(bulk_import_id) unless bulk_import_id.nil?
end
end
diff --git a/app/workers/publish_scheduled_status_worker.rb b/app/workers/publish_scheduled_status_worker.rb
index ce42f7be7c6e21..aa5c4a834a0510 100644
--- a/app/workers/publish_scheduled_status_worker.rb
+++ b/app/workers/publish_scheduled_status_worker.rb
@@ -3,7 +3,7 @@
class PublishScheduledStatusWorker
include Sidekiq::Worker
- sidekiq_options lock: :until_executed
+ sidekiq_options lock: :until_executed, lock_ttl: 1.hour.to_i
def perform(scheduled_status_id)
scheduled_status = ScheduledStatus.find(scheduled_status_id)
diff --git a/app/workers/resolve_account_worker.rb b/app/workers/resolve_account_worker.rb
index 2b5be6d1b217da..4ae2442af52e02 100644
--- a/app/workers/resolve_account_worker.rb
+++ b/app/workers/resolve_account_worker.rb
@@ -3,7 +3,7 @@
class ResolveAccountWorker
include Sidekiq::Worker
- sidekiq_options queue: 'pull', lock: :until_executed
+ sidekiq_options queue: 'pull', lock: :until_executed, lock_ttl: 1.day.to_i
def perform(uri)
ResolveAccountService.new.call(uri)
diff --git a/app/workers/scheduler/indexing_scheduler.rb b/app/workers/scheduler/indexing_scheduler.rb
index ff1b744442e9c7..5c985e25a0b5bf 100644
--- a/app/workers/scheduler/indexing_scheduler.rb
+++ b/app/workers/scheduler/indexing_scheduler.rb
@@ -5,7 +5,7 @@ class Scheduler::IndexingScheduler
include Redisable
include DatabaseHelper
- sidekiq_options retry: 0, lock: :until_executed, lock_ttl: 1.day.to_i
+ sidekiq_options retry: 0, lock: :until_executed, lock_ttl: 30.minutes.to_i
IMPORT_BATCH_SIZE = 1000
SCAN_BATCH_SIZE = 10 * IMPORT_BATCH_SIZE
diff --git a/app/workers/scheduler/scheduled_statuses_scheduler.rb b/app/workers/scheduler/scheduled_statuses_scheduler.rb
index b5801248f2e1f8..fe60d5524eaf20 100644
--- a/app/workers/scheduler/scheduled_statuses_scheduler.rb
+++ b/app/workers/scheduler/scheduled_statuses_scheduler.rb
@@ -3,7 +3,7 @@
class Scheduler::ScheduledStatusesScheduler
include Sidekiq::Worker
- sidekiq_options retry: 0, lock: :until_executed, lock_ttl: 1.day.to_i
+ sidekiq_options retry: 0, lock: :until_executed, lock_ttl: 1.hour.to_i
def perform
publish_scheduled_statuses!
diff --git a/app/workers/scheduler/self_destruct_scheduler.rb b/app/workers/scheduler/self_destruct_scheduler.rb
new file mode 100644
index 00000000000000..d0b6ce8a076d30
--- /dev/null
+++ b/app/workers/scheduler/self_destruct_scheduler.rb
@@ -0,0 +1,72 @@
+# frozen_string_literal: true
+
+class Scheduler::SelfDestructScheduler
+ include Sidekiq::Worker
+ include SelfDestructHelper
+
+ MAX_ENQUEUED = 10_000
+ MAX_REDIS_MEM_USAGE = 0.5
+ MAX_ACCOUNT_DELETIONS_PER_JOB = 50
+
+ sidekiq_options retry: 0, lock: :until_executed, lock_ttl: 1.day.to_i
+
+ def perform
+ return unless self_destruct?
+ return if sidekiq_overwhelmed?
+
+ delete_accounts!
+ end
+
+ private
+
+ def sidekiq_overwhelmed?
+ redis_mem_info = Sidekiq.redis_info
+
+ Sidekiq::Stats.new.enqueued > MAX_ENQUEUED || redis_mem_info['used_memory'].to_f > redis_mem_info['total_system_memory'].to_f * MAX_REDIS_MEM_USAGE
+ end
+
+ def delete_accounts!
+ # We currently do not distinguish between deleted accounts and suspended
+ # accounts, and we do not want to remove the records in this scheduler, as
+ # we still rely on it for account delivery and don't want to perform
+ # needless work when the database can be outright dropped after the
+ # self-destruct.
+ # Deleted accounts are suspended accounts that do not have a pending
+ # deletion request.
+
+ # This targets accounts that have not been deleted nor marked for deletion yet
+ Account.local.without_suspended.reorder(id: :asc).take(MAX_ACCOUNT_DELETIONS_PER_JOB).each do |account|
+ delete_account!(account)
+ end
+
+ return if sidekiq_overwhelmed?
+
+ # This targets accounts that have been marked for deletion but have not been
+ # deleted yet
+ Account.local.suspended.joins(:deletion_request).take(MAX_ACCOUNT_DELETIONS_PER_JOB).each do |account|
+ delete_account!(account)
+ account.deletion_request&.destroy
+ end
+ end
+
+ def inboxes
+ @inboxes ||= Account.inboxes
+ end
+
+ def delete_account!(account)
+ payload = ActiveModelSerializers::SerializableResource.new(
+ account,
+ serializer: ActivityPub::DeleteActorSerializer,
+ adapter: ActivityPub::Adapter
+ ).as_json
+
+ json = Oj.dump(ActivityPub::LinkedDataSignature.new(payload).sign!(account))
+
+ ActivityPub::DeliveryWorker.push_bulk(inboxes, limit: 1_000) do |inbox_url|
+ [json, account.id, inbox_url]
+ end
+
+ # Do not call `Account#suspend!` because we don't want to issue a deletion request
+ account.update!(suspended_at: Time.now.utc, suspension_origin: :local)
+ end
+end
diff --git a/app/workers/scheduler/trends/refresh_scheduler.rb b/app/workers/scheduler/trends/refresh_scheduler.rb
index b559ba46b4b521..85c000deea786d 100644
--- a/app/workers/scheduler/trends/refresh_scheduler.rb
+++ b/app/workers/scheduler/trends/refresh_scheduler.rb
@@ -3,7 +3,7 @@
class Scheduler::Trends::RefreshScheduler
include Sidekiq::Worker
- sidekiq_options retry: 0
+ sidekiq_options retry: 0, lock: :until_executed, lock_ttl: 30.minutes.to_i
def perform
Trends.refresh!
diff --git a/app/workers/verify_account_links_worker.rb b/app/workers/verify_account_links_worker.rb
index f606e6c26fefdf..ad27f450b78996 100644
--- a/app/workers/verify_account_links_worker.rb
+++ b/app/workers/verify_account_links_worker.rb
@@ -3,7 +3,7 @@
class VerifyAccountLinksWorker
include Sidekiq::Worker
- sidekiq_options queue: 'default', retry: false, lock: :until_executed
+ sidekiq_options queue: 'default', retry: false, lock: :until_executed, lock_ttl: 1.hour.to_i
def perform(account_id)
account = Account.find(account_id)
diff --git a/config/application.rb b/config/application.rb
index 2a62c37e8be4e5..7f7f8b5d6cc8be 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -5,15 +5,15 @@
require 'rails'
require 'active_record/railtie'
-#require 'active_storage/engine'
+# require 'active_storage/engine'
require 'action_controller/railtie'
require 'action_view/railtie'
require 'action_mailer/railtie'
require 'active_job/railtie'
-#require 'action_cable/engine'
-#require 'action_mailbox/engine'
-#require 'action_text/engine'
-#require 'rails/test_unit/railtie'
+# require 'action_cable/engine'
+# require 'action_mailbox/engine'
+# require 'action_text/engine'
+# require 'rails/test_unit/railtie'
require 'sprockets/railtie'
# Used to be implicitly required in action_mailbox/engine
@@ -71,15 +71,20 @@ class Application < Rails::Application
# https://github.com/mastodon/mastodon/pull/24241#discussion_r1162890242
config.active_support.cache_format_version = 6.1
- config.add_autoload_paths_to_load_path = false
-
- # Settings in config/environments/* take precedence over those specified here.
- # Application configuration should go into files in config/initializers
- # -- all .rb files in that directory are automatically loaded.
-
- # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
- # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
- # config.time_zone = 'Central Time (US & Canada)'
+ # Please, add to the `ignore` list any other `lib` subdirectories that do
+ # not contain `.rb` files, or that should not be reloaded or eager loaded.
+ # Common ones are `templates`, `generators`, or `middleware`, for example.
+ # config.autoload_lib(ignore: %w(assets tasks templates generators))
+ # TODO: We should enable this eventually, but for now there are many things
+ # in the wrong path from the perspective of zeitwerk.
+
+ # Configuration for the application, engines, and railties goes here.
+ #
+ # These settings can be overridden in specific environments using the files
+ # in config/environments, which are processed later.
+ #
+ # config.time_zone = "Central Time (US & Canada)"
+ # config.eager_load_paths << Rails.root.join("extras")
# All translations from config/locales/*.rb,yml are auto loaded.
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
@@ -196,7 +201,7 @@ class Application < Rails::Application
config.active_job.queue_adapter = :sidekiq
config.action_mailer.deliver_later_queue_name = 'mailers'
- config.action_mailer.preview_path = Rails.root.join('spec', 'mailers', 'previews')
+ config.action_mailer.preview_paths << Rails.root.join('spec', 'mailers', 'previews')
# We use our own middleware for this
config.public_file_server.enabled = false
@@ -205,6 +210,10 @@ class Application < Rails::Application
config.middleware.use Rack::Attack
config.middleware.use Mastodon::RackMiddleware
+ initializer :deprecator do |app|
+ app.deprecators[:mastodon] = ActiveSupport::Deprecation.new('4.3', 'mastodon/mastodon')
+ end
+
config.to_prepare do
Doorkeeper::AuthorizationsController.layout 'modal'
Doorkeeper::AuthorizedApplicationsController.layout 'admin'
diff --git a/config/brakeman.ignore b/config/brakeman.ignore
deleted file mode 100644
index 02ce23a0750da8..00000000000000
--- a/config/brakeman.ignore
+++ /dev/null
@@ -1,96 +0,0 @@
-{
- "ignored_warnings": [
- {
- "warning_type": "Cross-Site Scripting",
- "warning_code": 2,
- "fingerprint": "71cf98c8235b5cfa9946b5db8fdc1a2f3a862566abb34e4542be6f3acae78233",
- "check_name": "CrossSiteScripting",
- "message": "Unescaped model attribute",
- "file": "app/views/admin/disputes/appeals/_appeal.html.haml",
- "line": 7,
- "link": "https://brakemanscanner.org/docs/warning_types/cross_site_scripting",
- "code": "t((Unresolved Model).new.strike.action, :scope => \"admin.strikes.actions\", :name => content_tag(:span, (Unresolved Model).new.strike.account.username, :class => \"username\"), :target => content_tag(:span, (Unresolved Model).new.account.username, :class => \"target\"))",
- "render_path": [
- {
- "type": "template",
- "name": "admin/disputes/appeals/index",
- "line": 20,
- "file": "app/views/admin/disputes/appeals/index.html.haml",
- "rendered": {
- "name": "admin/disputes/appeals/_appeal",
- "file": "app/views/admin/disputes/appeals/_appeal.html.haml"
- }
- }
- ],
- "location": {
- "type": "template",
- "template": "admin/disputes/appeals/_appeal"
- },
- "user_input": "(Unresolved Model).new.strike",
- "confidence": "Weak",
- "cwe_id": [
- 79
- ],
- "note": ""
- },
- {
- "warning_type": "Denial of Service",
- "warning_code": 76,
- "fingerprint": "7b6abba5699755348e7ee82a4694bfbf574b41c7cce2d0db0f7c11ae3f983c72",
- "check_name": "RegexDoS",
- "message": "Model attribute used in regular expression",
- "file": "lib/mastodon/cli/domains.rb",
- "line": 128,
- "link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/",
- "code": "/\\.?(#{DomainBlock.where(:severity => 1).pluck(:domain).map do\n Regexp.escape(domain)\n end.join(\"|\")})$/",
- "render_path": null,
- "location": {
- "type": "method",
- "class": "Mastodon::CLI::Domains",
- "method": "crawl"
- },
- "user_input": "DomainBlock.where(:severity => 1).pluck(:domain)",
- "confidence": "Weak",
- "cwe_id": [
- 20,
- 185
- ],
- "note": ""
- },
- {
- "warning_type": "Cross-Site Scripting",
- "warning_code": 4,
- "fingerprint": "cd5cfd7f40037fbfa753e494d7129df16e358bfc43ef0da3febafbf4ee1ed3ac",
- "check_name": "LinkToHref",
- "message": "Potentially unsafe model attribute in `link_to` href",
- "file": "app/views/admin/trends/links/_preview_card.html.haml",
- "line": 7,
- "link": "https://brakemanscanner.org/docs/warning_types/link_to_href",
- "code": "link_to((Unresolved Model).new.title, (Unresolved Model).new.url)",
- "render_path": [
- {
- "type": "template",
- "name": "admin/trends/links/index",
- "line": 49,
- "file": "app/views/admin/trends/links/index.html.haml",
- "rendered": {
- "name": "admin/trends/links/_preview_card",
- "file": "app/views/admin/trends/links/_preview_card.html.haml"
- }
- }
- ],
- "location": {
- "type": "template",
- "template": "admin/trends/links/_preview_card"
- },
- "user_input": "(Unresolved Model).new.url",
- "confidence": "Weak",
- "cwe_id": [
- 79
- ],
- "note": ""
- }
- ],
- "updated": "2023-07-12 11:20:51 -0400",
- "brakeman_version": "6.0.0"
-}
diff --git a/config/brakeman.yml b/config/brakeman.yml
index 95ebc13865cd89..9ac95c80068e1b 100644
--- a/config/brakeman.yml
+++ b/config/brakeman.yml
@@ -1,3 +1,5 @@
---
:skip_checks:
- CheckPermitAttributes
+:url_safe_methods:
+ - url_for_preview_card
diff --git a/config/environments/development.rb b/config/environments/development.rb
index 9a6637bdb9596d..e601fc014c4715 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -68,6 +68,9 @@
# Highlight code that triggered database queries in logs.
config.active_record.verbose_query_logs = true
+ # Highlight code that enqueued background job in logs.
+ config.active_job.verbose_enqueue_logs = true
+
# Debug mode disables concatenation and preprocessing of assets.
config.assets.debug = true
@@ -98,6 +101,9 @@
# We provide a default secret for the development environment here.
# This value should not be used in production environments!
config.x.otp_secret = ENV.fetch('OTP_SECRET', '1fc2b87989afa6351912abeebe31ffc5c476ead9bf8b3d74cbc4a302c7b69a45b40b1bbef3506ddad73e942e15ed5ca4b402bf9a66423626051104f4b5f05109')
+
+ # Raise error when a before_action's only/except options reference missing actions
+ config.action_controller.raise_on_missing_callback_actions = true
end
Redis.raise_deprecations = true
diff --git a/config/environments/production.rb b/config/environments/production.rb
index 7ee5c898e2c665..0fb03be8dc257a 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -6,7 +6,7 @@
# Settings specified here will take precedence over those in config/application.rb.
# Code is not reloaded between requests.
- config.cache_classes = true
+ config.enable_reloading = false
# Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both threaded web servers
@@ -19,8 +19,8 @@
config.action_controller.perform_caching = true
config.action_controller.asset_host = ENV['CDN_HOST'] if ENV['CDN_HOST'].present?
- # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
- # or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
+ # Ensures that a master key has been made available in ENV["RAILS_MASTER_KEY"], config/master.key, or an environment
+ # key such as config/credentials/production.key. This key is used to decrypt credentials (and other encrypted files).
# config.require_master_key = true
# Compress CSS using a preprocessor.
@@ -44,14 +44,13 @@
config.force_ssl = true
config.ssl_options = {
redirect: {
- exclude: -> request { request.path.start_with?('/health') || request.headers["Host"].end_with?('.onion') || request.headers["Host"].end_with?('.i2p') }
+ exclude: ->request { request.path.start_with?('/health') || request.headers["Host"].end_with?('.onion') || request.headers["Host"].end_with?('.i2p') }
}
}
- # Include generic and useful information about system operation, but avoid logging too much
- # information to avoid inadvertent exposure of personally identifiable information (PII).
- # Use the lowest log level to ensure availability of diagnostic information
- # when problems arise.
+ # Info include generic and useful information about system operation, but avoids logging too much
+ # information to avoid inadvertent exposure of personally identifiable information (PII). If you
+ # want to log everything, set the level to "debug".
config.log_level = ENV.fetch('RAILS_LOG_LEVEL', 'info').to_sym
# Prepend all log lines with the following tags.
@@ -72,10 +71,13 @@
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# English when a translation cannot be found).
+ # This setting would typically be `true` to use the `I18n.default_locale`.
+ # Some locales are missing translation entries and would have errors:
+ # https://github.com/mastodon/mastodon/pull/24727
config.i18n.fallbacks = [:en]
- # Send deprecation notices to registered listeners.
- config.active_support.deprecation = :notify
+ # Don't log any deprecations.
+ config.active_support.report_deprecations = false
# Use default logging formatter so that PID and timestamp are not suppressed.
config.log_formatter = ::Logger::Formatter.new
@@ -93,10 +95,10 @@
# require "syslog/logger"
# config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name")
- ActiveSupport::Logger.new(STDOUT).tap do |logger|
- logger.formatter = config.log_formatter
- config.logger = ActiveSupport::TaggedLogging.new(logger)
- end
+ # Log to STDOUT by default
+ config.logger = ActiveSupport::Logger.new(STDOUT)
+ .tap { |logger| logger.formatter = ::Logger::Formatter.new }
+ .then { |logger| ActiveSupport::TaggedLogging.new(logger) }
# Do not dump schema after migrations.
config.active_record.dump_schema_after_migration = false
@@ -148,13 +150,21 @@
config.action_mailer.delivery_method = ENV.fetch('SMTP_DELIVERY_METHOD', 'smtp').to_sym
config.action_dispatch.default_headers = {
- 'Server' => 'Mastodon',
- 'X-Frame-Options' => 'DENY',
+ 'Server' => 'Mastodon',
+ 'X-Frame-Options' => 'DENY',
'X-Content-Type-Options' => 'nosniff',
- 'X-XSS-Protection' => '0',
- 'X-Clacks-Overhead' => 'GNU Natalie Nguyen',
- 'Referrer-Policy' => 'same-origin',
+ 'X-XSS-Protection' => '0',
+ 'X-Clacks-Overhead' => 'GNU Natalie Nguyen',
+ 'Referrer-Policy' => 'same-origin',
}
config.x.otp_secret = ENV.fetch('OTP_SECRET')
+
+ # Enable DNS rebinding protection and other `Host` header attacks.
+ # config.hosts = [
+ # "example.com", # Allow requests from example.com
+ # /.*\.example\.com/ # Allow requests from subdomains like `www.example.com`
+ # ]
+ # Skip DNS rebinding protection for the default health check endpoint.
+ # config.host_authorization = { exclude: ->(request) { request.path == "/up" } }
end
diff --git a/config/environments/test.rb b/config/environments/test.rb
index 210329848ed348..0b2f57fba7c339 100644
--- a/config/environments/test.rb
+++ b/config/environments/test.rb
@@ -10,12 +10,13 @@
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
- # Turn false under Spring and add config.action_view.cache_template_loading = true.
- config.cache_classes = true
+ # While tests run files are not watched, reloading is not necessary.
+ config.enable_reloading = false
- # Eager loading loads your whole application. When running a single test locally,
- # this probably isn't necessary. It's a good idea to do in a continuous integration
- # system, or in some way before deploying your code.
+ # Eager loading loads your entire application. When running a single test locally,
+ # this is usually not necessary, and can slow down your test suite. However, it's
+ # recommended that you enable it in continuous integration systems to ensure eager
+ # loading is working properly before deploying your code.
config.eager_load = ENV['CI'].present?
config.assets_digest = false
@@ -26,7 +27,7 @@
config.cache_store = :memory_store
# Raise exceptions instead of rendering exception templates.
- config.action_dispatch.show_exceptions = false
+ config.action_dispatch.show_exceptions = :rescuable
# Disable request forgery protection in test environment.
config.action_controller.allow_forgery_protection = false
@@ -73,11 +74,14 @@
# Annotate rendered view with file names.
# config.action_view.annotate_rendered_view_with_filenames = true
+
+ # Raise error when a before_action's only/except options reference missing actions
+ config.action_controller.raise_on_missing_callback_actions = true
end
Paperclip::Attachment.default_options[:path] = Rails.root.join('spec', 'test_files', ':class', ':id_partition', ':style.:extension')
-# set fake_data for pam, don't do real calls, just use fake data
+# Enable fake_data for PAM
if ENV['PAM_ENABLED'] == 'true'
Rpam2.fake_data =
{
diff --git a/config/initializers/0_duplicate_migrations.rb b/config/initializers/0_duplicate_migrations.rb
index 1b8b59025543d0..e99b5f13924c7f 100644
--- a/config/initializers/0_duplicate_migrations.rb
+++ b/config/initializers/0_duplicate_migrations.rb
@@ -18,7 +18,7 @@
module ActiveRecord
class Migrator
- def self.new(direction, migrations, schema_migration, target_version = nil)
+ def self.new(direction, migrations, schema_migration, internal_metadata, target_version = nil)
migrated = Set.new(Base.connection.migration_context.get_all_versions)
migrations.group_by(&:name).each do |_name, duplicates|
@@ -38,7 +38,7 @@ def self.new(direction, migrations, schema_migration, target_version = nil)
end
end
- super(direction, migrations, schema_migration, target_version)
+ super(direction, migrations, schema_migration, internal_metadata, target_version)
end
end
diff --git a/config/initializers/3_omniauth.rb b/config/initializers/3_omniauth.rb
index 7520f09e5e64be..d316c3b73a7411 100644
--- a/config/initializers/3_omniauth.rb
+++ b/config/initializers/3_omniauth.rb
@@ -9,9 +9,6 @@
end
Devise.setup do |config|
- # Devise omniauth strategies
- options = {}
-
# CAS strategy
if ENV['CAS_ENABLED'] == 'true'
cas_options = {}
@@ -76,35 +73,35 @@
# OpenID Connect Strategy
if ENV['OIDC_ENABLED'] == 'true'
oidc_options = {}
- oidc_options[:display_name] = ENV['OIDC_DISPLAY_NAME'] #OPTIONAL
- oidc_options[:issuer] = ENV['OIDC_ISSUER'] if ENV['OIDC_ISSUER'] #NEED
- oidc_options[:discovery] = ENV['OIDC_DISCOVERY'] == 'true' if ENV['OIDC_DISCOVERY'] #OPTIONAL (default: false)
- oidc_options[:client_auth_method] = ENV['OIDC_CLIENT_AUTH_METHOD'] if ENV['OIDC_CLIENT_AUTH_METHOD'] #OPTIONAL (default: basic)
- scope_string = ENV['OIDC_SCOPE'] if ENV['OIDC_SCOPE'] #NEED
+ oidc_options[:display_name] = ENV['OIDC_DISPLAY_NAME'] # OPTIONAL
+ oidc_options[:issuer] = ENV['OIDC_ISSUER'] if ENV['OIDC_ISSUER'] # NEED
+ oidc_options[:discovery] = ENV['OIDC_DISCOVERY'] == 'true' if ENV['OIDC_DISCOVERY'] # OPTIONAL (default: false)
+ oidc_options[:client_auth_method] = ENV['OIDC_CLIENT_AUTH_METHOD'] if ENV['OIDC_CLIENT_AUTH_METHOD'] # OPTIONAL (default: basic)
+ scope_string = ENV['OIDC_SCOPE'] if ENV['OIDC_SCOPE'] # NEED
scopes = scope_string.split(',')
oidc_options[:scope] = scopes.map { |x| x.to_sym }
- oidc_options[:response_type] = ENV['OIDC_RESPONSE_TYPE'] if ENV['OIDC_RESPONSE_TYPE'] #OPTIONAL (default: code)
- oidc_options[:response_mode] = ENV['OIDC_RESPONSE_MODE'] if ENV['OIDC_RESPONSE_MODE'] #OPTIONAL (default: query)
- oidc_options[:display] = ENV['OIDC_DISPLAY'] if ENV['OIDC_DISPLAY'] #OPTIONAL (default: page)
- oidc_options[:prompt] = ENV['OIDC_PROMPT'] if ENV['OIDC_PROMPT'] #OPTIONAL
- oidc_options[:send_nonce] = ENV['OIDC_SEND_NONCE'] == 'true' if ENV['OIDC_SEND_NONCE'] #OPTIONAL (default: true)
- oidc_options[:send_scope_to_token_endpoint] = ENV['OIDC_SEND_SCOPE_TO_TOKEN_ENDPOINT'] == 'true' if ENV['OIDC_SEND_SCOPE_TO_TOKEN_ENDPOINT'] #OPTIONAL (default: true)
- oidc_options[:post_logout_redirect_uri] = ENV['OIDC_IDP_LOGOUT_REDIRECT_URI'] if ENV['OIDC_IDP_LOGOUT_REDIRECT_URI'] #OPTIONAL
- oidc_options[:uid_field] = ENV['OIDC_UID_FIELD'] if ENV['OIDC_UID_FIELD'] #NEED
+ oidc_options[:response_type] = ENV['OIDC_RESPONSE_TYPE'] if ENV['OIDC_RESPONSE_TYPE'] # OPTIONAL (default: code)
+ oidc_options[:response_mode] = ENV['OIDC_RESPONSE_MODE'] if ENV['OIDC_RESPONSE_MODE'] # OPTIONAL (default: query)
+ oidc_options[:display] = ENV['OIDC_DISPLAY'] if ENV['OIDC_DISPLAY'] # OPTIONAL (default: page)
+ oidc_options[:prompt] = ENV['OIDC_PROMPT'] if ENV['OIDC_PROMPT'] # OPTIONAL
+ oidc_options[:send_nonce] = ENV['OIDC_SEND_NONCE'] == 'true' if ENV['OIDC_SEND_NONCE'] # OPTIONAL (default: true)
+ oidc_options[:send_scope_to_token_endpoint] = ENV['OIDC_SEND_SCOPE_TO_TOKEN_ENDPOINT'] == 'true' if ENV['OIDC_SEND_SCOPE_TO_TOKEN_ENDPOINT'] # OPTIONAL (default: true)
+ oidc_options[:post_logout_redirect_uri] = ENV['OIDC_IDP_LOGOUT_REDIRECT_URI'] if ENV['OIDC_IDP_LOGOUT_REDIRECT_URI'] # OPTIONAL
+ oidc_options[:uid_field] = ENV['OIDC_UID_FIELD'] if ENV['OIDC_UID_FIELD'] # NEED
oidc_options[:client_options] = {}
- oidc_options[:client_options][:identifier] = ENV['OIDC_CLIENT_ID'] if ENV['OIDC_CLIENT_ID'] #NEED
- oidc_options[:client_options][:secret] = ENV['OIDC_CLIENT_SECRET'] if ENV['OIDC_CLIENT_SECRET'] #NEED
- oidc_options[:client_options][:redirect_uri] = ENV['OIDC_REDIRECT_URI'] if ENV['OIDC_REDIRECT_URI'] #NEED
- oidc_options[:client_options][:scheme] = ENV['OIDC_HTTP_SCHEME'] if ENV['OIDC_HTTP_SCHEME'] #OPTIONAL (default: https)
- oidc_options[:client_options][:host] = ENV['OIDC_HOST'] if ENV['OIDC_HOST'] #OPTIONAL
- oidc_options[:client_options][:port] = ENV['OIDC_PORT'] if ENV['OIDC_PORT'] #OPTIONAL
- oidc_options[:client_options][:authorization_endpoint] = ENV['OIDC_AUTH_ENDPOINT'] if ENV['OIDC_AUTH_ENDPOINT'] #NEED when discovery != true
- oidc_options[:client_options][:token_endpoint] = ENV['OIDC_TOKEN_ENDPOINT'] if ENV['OIDC_TOKEN_ENDPOINT'] #NEED when discovery != true
- oidc_options[:client_options][:userinfo_endpoint] = ENV['OIDC_USER_INFO_ENDPOINT'] if ENV['OIDC_USER_INFO_ENDPOINT'] #NEED when discovery != true
- oidc_options[:client_options][:jwks_uri] = ENV['OIDC_JWKS_URI'] if ENV['OIDC_JWKS_URI'] #NEED when discovery != true
- oidc_options[:client_options][:end_session_endpoint] = ENV['OIDC_END_SESSION_ENDPOINT'] if ENV['OIDC_END_SESSION_ENDPOINT'] #OPTIONAL
+ oidc_options[:client_options][:identifier] = ENV['OIDC_CLIENT_ID'] if ENV['OIDC_CLIENT_ID'] # NEED
+ oidc_options[:client_options][:secret] = ENV['OIDC_CLIENT_SECRET'] if ENV['OIDC_CLIENT_SECRET'] # NEED
+ oidc_options[:client_options][:redirect_uri] = ENV['OIDC_REDIRECT_URI'] if ENV['OIDC_REDIRECT_URI'] # NEED
+ oidc_options[:client_options][:scheme] = ENV['OIDC_HTTP_SCHEME'] if ENV['OIDC_HTTP_SCHEME'] # OPTIONAL (default: https)
+ oidc_options[:client_options][:host] = ENV['OIDC_HOST'] if ENV['OIDC_HOST'] # OPTIONAL
+ oidc_options[:client_options][:port] = ENV['OIDC_PORT'] if ENV['OIDC_PORT'] # OPTIONAL
+ oidc_options[:client_options][:authorization_endpoint] = ENV['OIDC_AUTH_ENDPOINT'] if ENV['OIDC_AUTH_ENDPOINT'] # NEED when discovery != true
+ oidc_options[:client_options][:token_endpoint] = ENV['OIDC_TOKEN_ENDPOINT'] if ENV['OIDC_TOKEN_ENDPOINT'] # NEED when discovery != true
+ oidc_options[:client_options][:userinfo_endpoint] = ENV['OIDC_USER_INFO_ENDPOINT'] if ENV['OIDC_USER_INFO_ENDPOINT'] # NEED when discovery != true
+ oidc_options[:client_options][:jwks_uri] = ENV['OIDC_JWKS_URI'] if ENV['OIDC_JWKS_URI'] # NEED when discovery != true
+ oidc_options[:client_options][:end_session_endpoint] = ENV['OIDC_END_SESSION_ENDPOINT'] if ENV['OIDC_END_SESSION_ENDPOINT'] # OPTIONAL
oidc_options[:security] = {}
- oidc_options[:security][:assume_email_is_verified] = ENV['OIDC_SECURITY_ASSUME_EMAIL_IS_VERIFIED'] == 'true' #OPTIONAL
+ oidc_options[:security][:assume_email_is_verified] = ENV['OIDC_SECURITY_ASSUME_EMAIL_IS_VERIFIED'] == 'true' # OPTIONAL
config.omniauth :openid_connect, oidc_options
end
end
diff --git a/config/initializers/chewy.rb b/config/initializers/chewy.rb
index 66008a000924e9..076f38332479e7 100644
--- a/config/initializers/chewy.rb
+++ b/config/initializers/chewy.rb
@@ -3,9 +3,9 @@
enabled = ENV['ES_ENABLED'] == 'true'
host = ENV.fetch('ES_HOST') { 'localhost' }
port = ENV.fetch('ES_PORT') { 9200 }
-user = ENV.fetch('ES_USER') { nil }
-password = ENV.fetch('ES_PASS') { nil }
-fallback_prefix = ENV.fetch('REDIS_NAMESPACE') { nil }
+user = ENV.fetch('ES_USER', nil).presence
+password = ENV.fetch('ES_PASS', nil).presence
+fallback_prefix = ENV.fetch('REDIS_NAMESPACE', nil).presence
prefix = ENV.fetch('ES_PREFIX') { fallback_prefix }
Chewy.settings = {
diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb
index 4a0dabb6a915f7..8214844746166b 100644
--- a/config/initializers/content_security_policy.rb
+++ b/config/initializers/content_security_policy.rb
@@ -1,8 +1,18 @@
# frozen_string_literal: true
-# Define an application-wide content security policy
-# For further information see the following documentation
-# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
+# Be sure to restart your server when you modify this file.
+
+# Define an application-wide content security policy.
+# See the Securing Rails Applications Guide for more information:
+# https://guides.rubyonrails.org/security.html#content-security-policy-header
+
+def host_to_url(str)
+ return if str.blank?
+
+ uri = Addressable::URI.parse("http#{Rails.configuration.x.use_https ? 's' : ''}://#{str}")
+ uri.path += '/' unless uri.path.blank? || uri.path.end_with?('/')
+ uri.to_s
+end
def sso_host
return unless ENV['ONE_CLICK_SSO_LOGIN'] == 'true'
@@ -27,8 +37,7 @@ def sso_host
data_hosts = [assets_host]
if ENV['S3_ENABLED'] == 'true' || ENV['AZURE_ENABLED'] == 'true'
- attachments_host = "https://#{ENV['S3_ALIAS_HOST'] || ENV['S3_CLOUDFRONT_HOST'] || ENV['AZURE_ALIAS_HOST'] || ENV['S3_HOSTNAME'] || "s3-#{ENV['S3_REGION'] || 'us-east-1'}.amazonaws.com"}"
- attachments_host = "https://#{Addressable::URI.parse(attachments_host).host}"
+ attachments_host = host_to_url(ENV['S3_ALIAS_HOST'] || ENV['S3_CLOUDFRONT_HOST'] || ENV['AZURE_ALIAS_HOST'] || ENV['S3_HOSTNAME'] || "s3-#{ENV['S3_REGION'] || 'us-east-1'}.amazonaws.com")
elsif ENV['SWIFT_ENABLED'] == 'true'
attachments_host = ENV['SWIFT_OBJECT_URL']
attachments_host = "https://#{Addressable::URI.parse(attachments_host).host}"
@@ -75,9 +84,9 @@ def sso_host
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
# Rails.application.config.content_security_policy_report_only = true
-Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
+Rails.application.config.content_security_policy_nonce_generator = ->request { SecureRandom.base64(16) }
-Rails.application.config.content_security_policy_nonce_directives = %w(style-src)
+Rails.application.config.content_security_policy_nonce_directives = %w(style-src script-src)
Rails.application.reloader.to_prepare do
PgHero::HomeController.content_security_policy do |p|
diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb
index b416332707fe7a..37a818bf467bf9 100644
--- a/config/initializers/cors.rb
+++ b/config/initializers/cors.rb
@@ -3,7 +3,7 @@
# Be sure to restart your server when you modify this file.
# Avoid CORS issues when API is called from the frontend app.
-# Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin AJAX requests.
+# Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin Ajax requests.
# Read more: https://github.com/cyu/rack-cors
@@ -11,30 +11,17 @@
allow do
origins '*'
- resource '/.well-known/*',
- headers: :any,
- methods: [:get],
- credentials: false
- resource '/@:username',
- headers: :any,
- methods: [:get],
- credentials: false
- resource '/users/:username',
- headers: :any,
- methods: [:get],
- credentials: false
- resource '/api/*',
- headers: :any,
- methods: [:post, :put, :delete, :get, :patch, :options],
- credentials: false,
- expose: ['Link', 'X-RateLimit-Reset', 'X-RateLimit-Limit', 'X-RateLimit-Remaining', 'X-Request-Id']
- resource '/oauth/token',
- headers: :any,
- methods: [:post],
- credentials: false
- resource '/assets/*', headers: :any, methods: [:get, :head, :options]
- resource '/stylesheets/*', headers: :any, methods: [:get, :head, :options]
- resource '/javascripts/*', headers: :any, methods: [:get, :head, :options]
- resource '/packs/*', headers: :any, methods: [:get, :head, :options]
+ with_options headers: :any, credentials: false do
+ with_options methods: [:get] do
+ resource '/.well-known/*'
+ resource '/nodeinfo/*'
+ resource '/@:username'
+ resource '/users/:username'
+ end
+ resource '/api/*',
+ expose: %w(Link X-RateLimit-Reset X-RateLimit-Limit X-RateLimit-Remaining X-Request-Id),
+ methods: %i(post put delete get patch options)
+ resource '/oauth/token', methods: [:post]
+ end
end
end
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index 7bbaff71f0bd9f..41d0ee25b78642 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -394,7 +394,7 @@ def session_cookie
config.check_at_sign = true
config.pam_default_suffix = ENV.fetch('PAM_EMAIL_DOMAIN') { ENV['LOCAL_DOMAIN'] }
config.pam_default_service = ENV.fetch('PAM_DEFAULT_SERVICE') { 'rpam' }
- config.pam_controlled_service = ENV.fetch('PAM_CONTROLLED_SERVICE') { nil }
+ config.pam_controlled_service = ENV.fetch('PAM_CONTROLLED_SERVICE', nil).presence
end
if ENV['LDAP_ENABLED'] == 'true'
diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb
index ca55f952da0054..a119afa1244622 100644
--- a/config/initializers/filter_parameter_logging.rb
+++ b/config/initializers/filter_parameter_logging.rb
@@ -2,9 +2,9 @@
# Be sure to restart your server when you modify this file.
-# Configure parameters to be filtered from the log file. Use this to limit dissemination of
-# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported
-# notations and behaviors.
+# Configure parameters to be partially matched (e.g. passw matches password) and filtered from the log file.
+# Use this to limit dissemination of sensitive information.
+# See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors.
Rails.application.config.filter_parameters += [
:passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn
]
diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb
index 0dad009b1fb97a..727a1350d00c36 100644
--- a/config/initializers/inflections.rb
+++ b/config/initializers/inflections.rb
@@ -6,9 +6,9 @@
# are locale specific, and you may define rules for as many different
# locales as you wish. All of these examples are active by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
-# inflect.plural /^(ox)$/i, '\1en'
-# inflect.singular /^(ox)en/i, '\1'
-# inflect.irregular 'person', 'people'
+# inflect.plural /^(ox)$/i, "\\1en"
+# inflect.singular /^(ox)en/i, "\\1"
+# inflect.irregular "person", "people"
# inflect.uncountable %w( fish sheep )
# end
@@ -32,3 +32,8 @@
inflect.singular 'data', 'data'
end
+
+# These inflection rules are supported but not enabled by default:
+# ActiveSupport::Inflector.inflections(:en) do |inflect|
+# inflect.acronym "RESTful"
+# end
diff --git a/config/initializers/new_framework_defaults_7_1.rb b/config/initializers/new_framework_defaults_7_1.rb
new file mode 100644
index 00000000000000..2fa0e42746ce22
--- /dev/null
+++ b/config/initializers/new_framework_defaults_7_1.rb
@@ -0,0 +1,225 @@
+# frozen_string_literal: true
+
+# Be sure to restart your server when you modify this file.
+#
+# This file eases your Rails 7.1 framework defaults upgrade.
+#
+# Uncomment each configuration one by one to switch to the new default.
+# Once your application is ready to run with all new defaults, you can remove
+# this file and set the `config.load_defaults` to `7.1`.
+#
+# Read the Guide for Upgrading Ruby on Rails for more info on each option.
+# https://guides.rubyonrails.org/upgrading_ruby_on_rails.html
+
+# No longer add autoloaded paths into `$LOAD_PATH`. This means that you won't be able
+# to manually require files that are managed by the autoloader, which you shouldn't do anyway.
+# This will reduce the size of the load path, making `require` faster if you don't use bootsnap, or reduce the size
+# of the bootsnap cache if you use it.
+Rails.application.config.add_autoload_paths_to_load_path = false
+
+# Remove the default X-Download-Options headers since it is used only by Internet Explorer.
+# If you need to support Internet Explorer, add back `"X-Download-Options" => "noopen"`.
+# Rails.application.config.action_dispatch.default_headers = {
+# "X-Frame-Options" => "SAMEORIGIN",
+# "X-XSS-Protection" => "0",
+# "X-Content-Type-Options" => "nosniff",
+# "X-Permitted-Cross-Domain-Policies" => "none",
+# "Referrer-Policy" => "strict-origin-when-cross-origin"
+# }
+
+# Do not treat an `ActionController::Parameters` instance
+# as equal to an equivalent `Hash` by default.
+# Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality = false
+
+# Active Record Encryption now uses SHA-256 as its hash digest algorithm. Important: If you have
+# data encrypted with previous Rails versions, there are two scenarios to consider:
+#
+# 1. If you have +config.active_support.key_generator_hash_digest_class+ configured as SHA1 (the default
+# before Rails 7.0), you need to configure SHA-1 for Active Record Encryption too:
+# Rails.application.config.active_record.encryption.hash_digest_class = OpenSSL::Digest::SHA1
+# 2. If you have +config.active_support.key_generator_hash_digest_class+ configured as SHA256 (the new default
+# in 7.0), then you need to configure SHA-256 for Active Record Encryption:
+# Rails.application.config.active_record.encryption.hash_digest_class = OpenSSL::Digest::SHA256
+#
+# If you don't currently have data encrypted with Active Record encryption, you can disable this setting to
+# configure the default behavior starting 7.1+:
+# Rails.application.config.active_record.encryption.support_sha1_for_non_deterministic_encryption = false
+
+# No longer run after_commit callbacks on the first of multiple Active Record
+# instances to save changes to the same database row within a transaction.
+# Instead, run these callbacks on the instance most likely to have internal
+# state which matches what was committed to the database, typically the last
+# instance to save.
+# Rails.application.config.active_record.run_commit_callbacks_on_first_saved_instances_in_transaction = false
+
+# Configures SQLite with a strict strings mode, which disables double-quoted string literals.
+#
+# SQLite has some quirks around double-quoted string literals.
+# It first tries to consider double-quoted strings as identifier names, but if they don't exist
+# it then considers them as string literals. Because of this, typos can silently go unnoticed.
+# For example, it is possible to create an index for a non existing column.
+# See https://www.sqlite.org/quirks.html#double_quoted_string_literals_are_accepted for more details.
+# Rails.application.config.active_record.sqlite3_adapter_strict_strings_by_default = true
+
+# Disable deprecated singular associations names
+# Rails.application.config.active_record.allow_deprecated_singular_associations_name = false
+
+# Enable the Active Job `BigDecimal` argument serializer, which guarantees
+# roundtripping. Without this serializer, some queue adapters may serialize
+# `BigDecimal` arguments as simple (non-roundtrippable) strings.
+#
+# When deploying an application with multiple replicas, old (pre-Rails 7.1)
+# replicas will not be able to deserialize `BigDecimal` arguments from this
+# serializer. Therefore, this setting should only be enabled after all replicas
+# have been successfully upgraded to Rails 7.1.
+# Rails.application.config.active_job.use_big_decimal_serializer = true
+
+# Specify if an `ArgumentError` should be raised if `Rails.cache` `fetch` or
+# `write` are given an invalid `expires_at` or `expires_in` time.
+# Options are `true`, and `false`. If `false`, the exception will be reported
+# as `handled` and logged instead.
+# Rails.application.config.active_support.raise_on_invalid_cache_expiration_time = true
+
+# Specify whether Query Logs will format tags using the SQLCommenter format
+# (https://open-telemetry.github.io/opentelemetry-sqlcommenter/), or using the legacy format.
+# Options are `:legacy` and `:sqlcommenter`.
+# Rails.application.config.active_record.query_log_tags_format = :sqlcommenter
+
+# Specify the default serializer used by `MessageEncryptor` and `MessageVerifier`
+# instances.
+#
+# The legacy default is `:marshal`, which is a potential vector for
+# deserialization attacks in cases where a message signing secret has been
+# leaked.
+#
+# In Rails 7.1, the new default is `:json_allow_marshal` which serializes and
+# deserializes with `ActiveSupport::JSON`, but can fall back to deserializing
+# with `Marshal` so that legacy messages can still be read.
+#
+# In Rails 7.2, the default will become `:json` which serializes and
+# deserializes with `ActiveSupport::JSON` only.
+#
+# Alternatively, you can choose `:message_pack` or `:message_pack_allow_marshal`,
+# which serialize with `ActiveSupport::MessagePack`. `ActiveSupport::MessagePack`
+# can roundtrip some Ruby types that are not supported by JSON, and may provide
+# improved performance, but it requires the `msgpack` gem.
+#
+# For more information, see
+# https://guides.rubyonrails.org/v7.1/configuring.html#config-active-support-message-serializer
+#
+# If you are performing a rolling deploy of a Rails 7.1 upgrade, wherein servers
+# that have not yet been upgraded must be able to read messages from upgraded
+# servers, first deploy without changing the serializer, then set the serializer
+# in a subsequent deploy.
+# Rails.application.config.active_support.message_serializer = :json_allow_marshal
+
+# Enable a performance optimization that serializes message data and metadata
+# together. This changes the message format, so messages serialized this way
+# cannot be read by older versions of Rails. However, messages that use the old
+# format can still be read, regardless of whether this optimization is enabled.
+#
+# To perform a rolling deploy of a Rails 7.1 upgrade, wherein servers that have
+# not yet been upgraded must be able to read messages from upgraded servers,
+# leave this optimization off on the first deploy, then enable it on a
+# subsequent deploy.
+# Rails.application.config.active_support.use_message_serializer_for_metadata = true
+
+# Set the maximum size for Rails log files.
+#
+# `config.load_defaults 7.1` does not set this value for environments other than
+# development and test.
+#
+# if Rails.env.local?
+# Rails.application.config.log_file_size = 100 * 1024 * 1024
+# end
+
+# Enable raising on assignment to attr_readonly attributes. The previous
+# behavior would allow assignment but silently not persist changes to the
+# database.
+# Rails.application.config.active_record.raise_on_assign_to_attr_readonly = true
+
+# Enable validating only parent-related columns for presence when the parent is mandatory.
+# The previous behavior was to validate the presence of the parent record, which performed an extra query
+# to get the parent every time the child record was updated, even when parent has not changed.
+# Rails.application.config.active_record.belongs_to_required_validates_foreign_key = false
+
+# Enable precompilation of `config.filter_parameters`. Precompilation can
+# improve filtering performance, depending on the quantity and types of filters.
+# Rails.application.config.precompile_filter_parameters = true
+
+# Enable before_committed! callbacks on all enrolled records in a transaction.
+# The previous behavior was to only run the callbacks on the first copy of a record
+# if there were multiple copies of the same record enrolled in the transaction.
+# Rails.application.config.active_record.before_committed_on_all_records = true
+
+# Disable automatic column serialization into YAML.
+# To keep the historic behavior, you can set it to `YAML`, however it is
+# recommended to explicitly define the serialization method for each column
+# rather than to rely on a global default.
+# Rails.application.config.active_record.default_column_serializer = nil
+
+# Enable a performance optimization that serializes Active Record models
+# in a faster and more compact way.
+#
+# To perform a rolling deploy of a Rails 7.1 upgrade, wherein servers that have
+# not yet been upgraded must be able to read caches from upgraded servers,
+# leave this optimization off on the first deploy, then enable it on a
+# subsequent deploy.
+# Rails.application.config.active_record.marshalling_format_version = 7.1
+
+# Run `after_commit` and `after_*_commit` callbacks in the order they are defined in a model.
+# This matches the behaviour of all other callbacks.
+# In previous versions of Rails, they ran in the inverse order.
+# Rails.application.config.active_record.run_after_transaction_callbacks_in_order_defined = true
+
+# Whether a `transaction` block is committed or rolled back when exited via `return`, `break` or `throw`.
+#
+# Rails.application.config.active_record.commit_transaction_on_non_local_return = true
+
+# Controls when to generate a value for has_secure_token declarations.
+#
+# Rails.application.config.active_record.generate_secure_token_on = :initialize
+
+# ** Please read carefully, this must be configured in config/application.rb **
+# Change the format of the cache entry.
+# Changing this default means that all new cache entries added to the cache
+# will have a different format that is not supported by Rails 7.0
+# applications.
+# Only change this value after your application is fully deployed to Rails 7.1
+# and you have no plans to rollback.
+# When you're ready to change format, add this to `config/application.rb` (NOT
+# this file):
+# config.active_support.cache_format_version = 7.1
+
+# Configure Action View to use HTML5 standards-compliant sanitizers when they are supported on your
+# platform.
+#
+# `Rails::HTML::Sanitizer.best_supported_vendor` will cause Action View to use HTML5-compliant
+# sanitizers if they are supported, else fall back to HTML4 sanitizers.
+#
+# In previous versions of Rails, Action View always used `Rails::HTML4::Sanitizer` as its vendor.
+#
+# Rails.application.config.action_view.sanitizer_vendor = Rails::HTML::Sanitizer.best_supported_vendor
+
+# Configure Action Text to use an HTML5 standards-compliant sanitizer when it is supported on your
+# platform.
+#
+# `Rails::HTML::Sanitizer.best_supported_vendor` will cause Action Text to use HTML5-compliant
+# sanitizers if they are supported, else fall back to HTML4 sanitizers.
+#
+# In previous versions of Rails, Action Text always used `Rails::HTML4::Sanitizer` as its vendor.
+#
+# Rails.application.config.action_text.sanitizer_vendor = Rails::HTML::Sanitizer.best_supported_vendor
+
+# Configure the log level used by the DebugExceptions middleware when logging
+# uncaught exceptions during requests
+# Rails.application.config.action_dispatch.debug_exception_log_level = :error
+
+# Configure the test helpers in Action View, Action Dispatch, and rails-dom-testing to use HTML5
+# parsers.
+#
+# Nokogiri::HTML5 isn't supported on JRuby, so JRuby applications must set this to :html4.
+#
+# In previous versions of Rails, these test helpers always used an HTML4 parser.
+#
+# Rails.application.config.dom_testing_default_html_version = :html5
diff --git a/config/initializers/permissions_policy.rb b/config/initializers/permissions_policy.rb
index 50bcf4eadec581..e8d0b2ae81179c 100644
--- a/config/initializers/permissions_policy.rb
+++ b/config/initializers/permissions_policy.rb
@@ -1,12 +1,15 @@
# frozen_string_literal: true
+
+# Be sure to restart your server when you modify this file.
+
# Define an application-wide HTTP permissions policy. For further
-# information see https://developers.google.com/web/updates/2018/06/feature-policy
-#
-# Rails.application.config.permissions_policy do |f|
-# f.camera :none
-# f.gyroscope :none
-# f.microphone :none
-# f.usb :none
-# f.fullscreen :self
-# f.payment :self, "https://secure.example.com"
+# information see: https://developers.google.com/web/updates/2018/06/feature-policy
+
+# Rails.application.config.permissions_policy do |policy|
+# policy.camera :none
+# policy.gyroscope :none
+# policy.microphone :none
+# policy.usb :none
+# policy.fullscreen :self
+# policy.payment :self, "https://secure.example.com"
# end
diff --git a/config/initializers/rack_attack.rb b/config/initializers/rack_attack.rb
index d0af0fe9409fb0..429dbd3248f814 100644
--- a/config/initializers/rack_attack.rb
+++ b/config/initializers/rack_attack.rb
@@ -142,10 +142,10 @@ def paging_request?
match_data = request.env['rack.attack.match_data']
headers = {
- 'Content-Type' => 'application/json',
- 'X-RateLimit-Limit' => match_data[:limit].to_s,
+ 'Content-Type' => 'application/json',
+ 'X-RateLimit-Limit' => match_data[:limit].to_s,
'X-RateLimit-Remaining' => '0',
- 'X-RateLimit-Reset' => (now + (match_data[:period] - (now.to_i % match_data[:period]))).iso8601(6),
+ 'X-RateLimit-Reset' => (now + (match_data[:period] - (now.to_i % match_data[:period]))).iso8601(6),
}
[429, headers, [{ error: I18n.t('errors.429') }.to_json]]
diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb
index b29e0a815943bc..eac23a79b980a0 100644
--- a/config/initializers/session_store.rb
+++ b/config/initializers/session_store.rb
@@ -2,7 +2,10 @@
# Be sure to restart your server when you modify this file.
-Rails.application.config.session_store :cookie_store,
- key: '_mastodon_session',
- secure: false, # All cookies have their secure flag set by the force_ssl option in production
- same_site: :lax
+Rails
+ .application
+ .config
+ .session_store :cookie_store,
+ key: '_mastodon_session',
+ secure: false, # All cookies have their secure flag set by the force_ssl option in production
+ same_site: :lax
diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb
index 9d2abf0745eca9..319b386645ff81 100644
--- a/config/initializers/sidekiq.rb
+++ b/config/initializers/sidekiq.rb
@@ -17,6 +17,18 @@
chain.add SidekiqUniqueJobs::Middleware::Client
end
+ config.on(:startup) do
+ if SelfDestructHelper.self_destruct?
+ Sidekiq.schedule = {
+ 'self_destruct_scheduler' => {
+ 'interval' => ['1m'],
+ 'class' => 'Scheduler::SelfDestructScheduler',
+ 'queue' => 'scheduler',
+ },
+ }
+ end
+ end
+
SidekiqUniqueJobs::Server.configure(config)
end
diff --git a/config/locales/activerecord.fi.yml b/config/locales/activerecord.fi.yml
index a06cd399a8b018..93f338b5d5daef 100644
--- a/config/locales/activerecord.fi.yml
+++ b/config/locales/activerecord.fi.yml
@@ -11,7 +11,7 @@ fi:
locale: Alue
password: Salasana
user/account:
- username: Käyttäjätunnus
+ username: Käyttäjänimi
user/invite_request:
text: Syy
errors:
diff --git a/config/locales/activerecord.hr.yml b/config/locales/activerecord.hr.yml
index 98ca8155fdaa25..b095244dd6bc8a 100644
--- a/config/locales/activerecord.hr.yml
+++ b/config/locales/activerecord.hr.yml
@@ -5,3 +5,16 @@ hr:
poll:
expires_at: Krajnji rok
options: Opcije
+ user:
+ email: E-mail adresa
+ password: Lozinka
+ user/account:
+ username: Korisničko ime
+ user/invite_request:
+ text: Razlog
+ errors:
+ models:
+ account:
+ attributes:
+ username:
+ invalid: mora sadržavati samo slova, brojeve i _
diff --git a/config/locales/activerecord.sk.yml b/config/locales/activerecord.sk.yml
index 33f53a88ed988f..d13c416e516a63 100644
--- a/config/locales/activerecord.sk.yml
+++ b/config/locales/activerecord.sk.yml
@@ -53,3 +53,7 @@ sk:
position:
elevated: nemôže byť vyššia ako vaša súčasná rola
own_role: nie je možné zmeniť s vašou aktuálnou rolou
+ webhook:
+ attributes:
+ events:
+ invalid_permissions: nemožno zahrnúť udalosti, ku ktorým nemáte práva
diff --git a/config/locales/activerecord.zh-CN.yml b/config/locales/activerecord.zh-CN.yml
index a52e7cff6f8e75..c510a58d1446cc 100644
--- a/config/locales/activerecord.zh-CN.yml
+++ b/config/locales/activerecord.zh-CN.yml
@@ -36,7 +36,7 @@ zh-CN:
status:
attributes:
reblog:
- taken: 已被转嘟过
+ taken: 已经被转嘟过
user:
attributes:
email:
diff --git a/config/locales/cs.yml b/config/locales/cs.yml
index 03ec9708d54d3c..15ca09470894d3 100644
--- a/config/locales/cs.yml
+++ b/config/locales/cs.yml
@@ -556,6 +556,7 @@ cs:
total_reported: Hlášení o nich
total_storage: Mediální přílohy
totals_time_period_hint_html: Níže zobrazené součty zahrnují data za celou dobu.
+ unknown_instance: Na tomto serveru momentálně neexistuje žádný záznam o této doméně.
invites:
deactivate_all: Deaktivovat vše
filter:
@@ -1134,6 +1135,7 @@ cs:
functional: Váš účet je plně funkční.
pending: Vaše žádost čeká na posouzení naším personálem. To může nějakou dobu trvat. Pokud bude váš požadavek schválen, obdržíte e-mail.
redirecting_to: Váš účet je neaktivní, protože je právě přesměrován na účet %{acct}.
+ self_destruct: Protože %{domain} končí, budete mít k účtu jen omezený přístup.
view_strikes: Zobrazit minulé prohřešky vašeho účtu
too_fast: Formulář byl odeslán příliš rychle, zkuste to znovu.
use_security_key: Použít bezpečnostní klíč
@@ -1585,6 +1587,9 @@ cs:
over_daily_limit: Pro dnešek jste překročili limit %{limit} naplánovaných příspěvků
over_total_limit: Překročili jste limit %{limit} naplánovaných příspěvků
too_soon: Plánované datum musí být v budoucnosti
+ self_destruct:
+ lead_html: "%{domain} bohužel končí nadobro. Pokud jste tam měli účet, nebudete jej moci dále používat, ale stále si můžete vyžádat zálohu vašich dat."
+ title: Tento server končí
sessions:
activity: Nejnovější aktivita
browser: Prohlížeč
diff --git a/config/locales/cy.yml b/config/locales/cy.yml
index a975457cf9d985..09e201f55a957d 100644
--- a/config/locales/cy.yml
+++ b/config/locales/cy.yml
@@ -578,6 +578,7 @@ cy:
total_reported: Adroddiadau amdanyn nhw
total_storage: Atodiadau cyfryngau
totals_time_period_hint_html: Mae'r cyfansymiau sy'n cael eu dangos isod yn cynnwys data am y cyfnod cyfan.
+ unknown_instance: Nid oes cofnod o'r parth hwn ar y gweinydd hwn ar hyn o bryd.
invites:
deactivate_all: Dadweithredu popeth
filter:
diff --git a/config/locales/da.yml b/config/locales/da.yml
index ce53168fb320cc..9ffece04d70007 100644
--- a/config/locales/da.yml
+++ b/config/locales/da.yml
@@ -534,6 +534,7 @@ da:
total_reported: Anmeldelser om dem
total_storage: Medievedhæftninger
totals_time_period_hint_html: Nedenfor viste totaler omfatter data for alle tidsperioder.
+ unknown_instance: Der er i pt. ingen post for dette domæne på denne server.
invites:
deactivate_all: Deaktivér alle
filter:
diff --git a/config/locales/de.yml b/config/locales/de.yml
index 69151b2e705ea9..c6b3218ee9a160 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -534,6 +534,7 @@ de:
total_reported: Beschwerden über sie
total_storage: Medienanhänge
totals_time_period_hint_html: Die unten angezeigten Summen enthalten Daten für alle Zeiten.
+ unknown_instance: Auf diesem Server gibt es derzeit keinen Eintrag dieser Domain.
invites:
deactivate_all: Alle deaktivieren
filter:
@@ -1069,7 +1070,7 @@ de:
cas: CAS
saml: SAML
register: Registrieren
- registration_closed: "%{instance} akzeptiert keine neuen Mitglieder*innen"
+ registration_closed: "%{instance} akzeptiert keine neuen Mitglieder"
resend_confirmation: Bestätigungslink erneut zusenden
reset_password: Passwort zurücksetzen
rules:
@@ -1101,6 +1102,7 @@ de:
functional: Dein Konto ist voll funktionsfähig.
pending: Die Prüfung deiner Bewerbung steht noch aus. Dies kann einige Zeit in Anspruch nehmen. Sobald deine Bewerbung genehmigt wurde, erhältst du eine E-Mail.
redirecting_to: Dein Konto ist inaktiv, weil es zu %{acct} umgezogen ist.
+ self_destruct: Da %{domain} den Betrieb einstellen wird, wirst du nur begrenzten Zugriff auf dein Konto haben.
view_strikes: Vorherige Verstöße deines Kontos ansehen
too_fast: Formular zu schnell übermittelt. Bitte versuche es erneut.
use_security_key: Sicherheitsschlüssel verwenden
@@ -1570,6 +1572,9 @@ de:
over_daily_limit: Du hast das Limit von %{limit} geplanten Beiträgen für heute erreicht
over_total_limit: Du hast das Limit für geplante Beiträge, das %{limit} beträgt, erreicht
too_soon: Das geplante Datum muss in der Zukunft liegen
+ self_destruct:
+ lead_html: Bedauerlicherweise wird %{domain} den Betrieb für immer einstellen. Wenn du dort ein Konto angelegt hast, wirst du es nicht weiter verwenden können. Du kannst allerdings eine Sicherung deiner Daten anfordern.
+ title: Dieser Server wird den Betrieb einstellen
sessions:
activity: Letzte Aktivität
browser: Browser
@@ -1769,7 +1774,7 @@ de:
subject: Dein Einspruch vom %{date} wurde abgelehnt
title: Einspruch abgelehnt
backup_ready:
- explanation: Du hast eine vollständige Sicherung deines Mastodon-Kontos angefordert. Das Backup kann jetzt heruntergeladen werden!
+ explanation: Du hast eine vollständige Sicherung deines Mastodon-Kontos angefordert. Die Sicherung kann jetzt heruntergeladen werden!
subject: Dein persönliches Archiv kann heruntergeladen werden
title: Archiv-Download
suspicious_sign_in:
diff --git a/config/locales/devise.en-GB.yml b/config/locales/devise.en-GB.yml
index 9a51d075763541..e7ab9462dc31aa 100644
--- a/config/locales/devise.en-GB.yml
+++ b/config/locales/devise.en-GB.yml
@@ -6,22 +6,22 @@ en-GB:
send_instructions: You will receive an email with instructions for how to confirm your email address in a few minutes. Please check your spam folder if you didn't receive this email.
send_paranoid_instructions: If your email address exists in our database, you will receive an email with instructions for how to confirm your email address in a few minutes. Please check your spam folder if you didn't receive this email.
failure:
- already_authenticated: You are already signed in.
+ already_authenticated: You are already logged in.
inactive: Your account is not activated yet.
invalid: Invalid %{authentication_keys} or password.
last_attempt: You have one more attempt before your account is locked.
locked: Your account is locked.
not_found_in_database: Invalid %{authentication_keys} or password.
pending: Your account is still under review.
- timeout: Your session expired. Please sign in again to continue.
- unauthenticated: You need to sign in or sign up before continuing.
+ timeout: Your session expired. Please log in again to continue.
+ unauthenticated: You need to log in or sign up before continuing.
unconfirmed: You have to confirm your email address before continuing.
mailer:
confirmation_instructions:
action: Verify email address
action_with_app: Confirm and return to %{app}
explanation: You have created an account on %{host} with this email address. You are one click away from activating it. If this wasn't you, please ignore this email.
- explanation_when_pending: You applied for an invite to %{host} with this email address. Once you confirm your e-mail address, we will review your application. You can login to change your details or delete your account, but you cannot access most of the functions until your account is approved. If your application is rejected, your data will be removed, so no further action will be required from you. If this wasn't you, please ignore this email.
+ explanation_when_pending: You applied for an invite to %{host} with this email address. Once you confirm your e-mail address, we will review your application. You can log in to change your details or delete your account, but you cannot access most of the functions until your account is approved. If your application is rejected, your data will be removed, so no further action will be required from you. If this wasn't you, please ignore this email.
extra_html: Please also check out the rules of the server and our terms of service.
subject: 'Mastodon: Confirmation instructions for %{instance}'
title: Verify email address
@@ -84,28 +84,28 @@ en-GB:
no_token: You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided.
send_instructions: If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes. Please check your spam folder if you didn't receive this email.
send_paranoid_instructions: If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes. Please check your spam folder if you didn't receive this email.
- updated: Your password has been changed successfully. You are now signed in.
+ updated: Your password has been changed successfully. You are now logged in.
updated_not_active: Your password has been changed successfully.
registrations:
destroyed: Bye! Your account has been successfully cancelled. We hope to see you again soon.
signed_up: Welcome! You have signed up successfully.
- signed_up_but_inactive: You have signed up successfully. However, we could not sign you in because your account is not yet activated.
- signed_up_but_locked: You have signed up successfully. However, we could not sign you in because your account is locked.
+ signed_up_but_inactive: You have signed up successfully. However, we could not log you in because your account is not yet activated.
+ signed_up_but_locked: You have signed up successfully. However, we could not log you in because your account is locked.
signed_up_but_pending: A message with a confirmation link has been sent to your email address. After you click the link, we will review your application. You will be notified if it is approved.
signed_up_but_unconfirmed: A message with a confirmation link has been sent to your email address. Please follow the link to activate your account. Please check your spam folder if you didn't receive this email.
update_needs_confirmation: You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirm link to confirm your new email address. Please check your spam folder if you didn't receive this email.
updated: Your account has been updated successfully.
sessions:
- already_signed_out: Signed out successfully.
- signed_in: Signed in successfully.
- signed_out: Signed out successfully.
+ already_signed_out: Logged out successfully.
+ signed_in: Logged in successfully.
+ signed_out: Logged out successfully.
unlocks:
send_instructions: You will receive an email with instructions for how to unlock your account in a few minutes. Please check your spam folder if you didn't receive this email.
send_paranoid_instructions: If your account exists, you will receive an email with instructions for how to unlock it in a few minutes. Please check your spam folder if you didn't receive this email.
- unlocked: Your account has been unlocked successfully. Please sign in to continue.
+ unlocked: Your account has been unlocked successfully. Please log in to continue.
errors:
messages:
- already_confirmed: was already confirmed, please try signing in
+ already_confirmed: was already confirmed, please try logging in
confirmation_period_expired: needs to be confirmed within %{period}, please request a new one
expired: has expired, please request a new one
not_found: not found
diff --git a/config/locales/devise.fi.yml b/config/locales/devise.fi.yml
index eecbb3897a978c..8bbcb071e36adb 100644
--- a/config/locales/devise.fi.yml
+++ b/config/locales/devise.fi.yml
@@ -27,12 +27,12 @@ fi:
title: Vahvista sähköpostiosoite
email_changed:
explanation: 'Tilin sähköpostiosoitteeksi vaihdetaan:'
- extra: Jos et vaihtanut sähköpostiosoitettasi, joku muu on todennäköisesti päässyt käyttämään tiliäsi. Vaihda salasanasi viipymättä. Jos et pääse kirjautumaan tilillesi, ota yhteyttä instanssin ylläpitäjään.
+ extra: Jos et vaihtanut sähköpostiosoitettasi, joku muu on todennäköisesti päässyt käyttämään tiliäsi. Vaihda salasanasi viipymättä, tai ota yhteyttä palvelimen ylläpitäjään, jos et pääse kirjautumaan tilillesi.
subject: 'Mastodon: Sähköpostiosoite vaihdettu'
title: Uusi sähköpostiosoite
password_change:
explanation: Tilisi salasana on vaihdettu.
- extra: Jos et vaihtanut salasanaasi, joku muu on todennäköisesti päässyt käyttämään tiliäsi. Vaihda salasanasi viipymättä. Jos et pääse kirjautumaan tilillesi, ota yhteyttä instanssin ylläpitäjään.
+ extra: Jos et vaihtanut salasanaasi, joku muu on todennäköisesti päässyt käyttämään tiliäsi. Vaihda salasanasi viipymättä, tai ota yhteyttä palvelimen ylläpitäjään, jos et pääse kirjautumaan tilillesi.
subject: 'Mastodon: salasana vaihdettu'
title: Salasana vaihdettu
reconfirmation_instructions:
@@ -47,11 +47,11 @@ fi:
subject: 'Mastodon: ohjeet salasanan vaihtoon'
title: Salasanan vaihto
two_factor_disabled:
- explanation: Kaksivaiheinen todennus tilillesi poistettiin käytöstä. Kirjautuminen onnistuu nyt käyttäen pelkkää sähköpostiosoitetta ja salasanaa.
+ explanation: Tilisi kaksivaiheinen todennus poistettiin käytöstä. Kirjautuminen onnistuu nyt pelkällä sähköpostiosoitella ja salasanalla.
subject: 'Mastodon: kaksivaiheinen todennus poistettu käytöstä'
title: 2-vaiheinen todennus pois käytöstä
two_factor_enabled:
- explanation: Kaksivaiheinen tunnistus on otettu käyttöön tilillesi. Kaksivaiheisen tunnistuksen sovelluksesta saatu koodi tarvitaan kirjautumiseen.
+ explanation: Kaksivaiheinen todennus on otettu käyttöön tilillesi. Kirjautumiseen tarvitaan kaksivaiheisen todennuksen sovelluksesta saatu koodi.
subject: 'Mastodon: kaksivaiheinen todennus otettu käyttöön'
title: 2-vaiheinen todennus käytössä
two_factor_recovery_codes_changed:
@@ -70,11 +70,11 @@ fi:
subject: 'Mastodon: suojausavain poistettu'
title: Yksi suojausavaimistasi on poistettu
webauthn_disabled:
- explanation: Suojausavaimilla todennus on poistettu käytöstä tililtäsi. Kirjautuminen on nyt mahdollista käyttämällä vain paritetun TOTP-sovelluksen luomaa tokenia.
- subject: 'Mastodon: Todennus suoja-avaimilla poistettu käytöstä'
+ explanation: Suojausavaimilla todennus on poistettu käytöstä tililtäsi. Kirjautuminen on nyt mahdollista vain paritetun TOTP-sovelluksen luomaa koodia käyttämällä.
+ subject: 'Mastodon: Todennus suojausavaimilla poistettu käytöstä'
title: Suojausavaimet poistettu käytöstä
webauthn_enabled:
- explanation: Todennus suojausavaimella on otettu käyttöön tililläsi. Suojausavaintasi voidaan nyt käyttää kirjautumiseen.
+ explanation: Todennus suojausavaimella on otettu käyttöön tilillesi. Suojausavaintasi voidaan nyt käyttää kirjautumiseen.
subject: 'Mastodon: Todennus suojausavaimella on otettu käyttöön'
title: Suojausavaimet käytössä
omniauth_callbacks:
diff --git a/config/locales/devise.fy.yml b/config/locales/devise.fy.yml
index 9e93d2c19f947e..910d2d30947b1b 100644
--- a/config/locales/devise.fy.yml
+++ b/config/locales/devise.fy.yml
@@ -13,7 +13,7 @@ fy:
locked: Jo account is blokkearre.
not_found_in_database: "%{authentication_keys} of wachtwurd ûnjildich."
pending: Jo account moat noch hieltyd beoardiele wurde.
- timeout: Dyn sesje is ferrûn, meld dy opnij oan.
+ timeout: Jo sesje is ferrûn. Meld jo opnij oan om troch te gean.
unauthenticated: Jo moatte oanmelde of registrearje.
unconfirmed: Jo moatte earst jo account befêstigje.
mailer:
diff --git a/config/locales/devise.si.yml b/config/locales/devise.si.yml
index a20057cef94282..362f97b8a9b030 100644
--- a/config/locales/devise.si.yml
+++ b/config/locales/devise.si.yml
@@ -23,7 +23,6 @@ si:
explanation: ඔබ මෙම ඊමේල් ලිපිනය සමඟ %{host} හි ගිණුමක් සාදා ඇත. ඔබ එය සක්රිය කිරීමට එක ක්ලික් කිරීමක් ඇත. මේ ඔබ නොවේ නම්, කරුණාකර මෙම විද්යුත් තැපෑල නොසලකා හරින්න.
explanation_when_pending: ඔබ මෙම විද්යුත් තැපැල් ලිපිනය සමඟ %{host} වෙත ආරාධනාවක් සඳහා ඉල්ලුම් කළා. ඔබ ඔබගේ විද්යුත් තැපැල් ලිපිනය තහවුරු කළ පසු, අපි ඔබගේ අයදුම්පත සමාලෝචනය කරන්නෙමු. ඔබගේ විස්තර වෙනස් කිරීමට හෝ ඔබගේ ගිණුම මකා දැමීමට ඔබට පුරනය විය හැක, නමුත් ඔබගේ ගිණුම අනුමත වන තුරු ඔබට බොහෝ කාර්යයන් වෙත ප්රවේශ විය නොහැක. ඔබගේ අයදුම්පත ප්රතික්ෂේප කළහොත්, ඔබගේ දත්ත ඉවත් කරනු ඇත, එබැවින් ඔබෙන් වැඩිදුර ක්රියාමාර්ග අවශ්ය නොවනු ඇත. මේ ඔබ නොවේ නම්, කරුණාකර මෙම විද්යුත් තැපෑල නොසලකා හරින්න.
extra_html: කරුණාකර සේවාදායකයේ නීති සහ අපගේ සේවා කොන්දේසිද පරීක්ෂා කරන්න.
- subject: 'Mastodon: %{instance}සඳහා තහවුරු කිරීමේ උපදෙස්'
title: වි. තැපෑල තහවුරු කරන්න
email_changed:
explanation: 'ඔබගේ ගිණුම සඳහා ඊමේල් ලිපිනය වෙනස් වෙමින් පවතී:'
@@ -33,30 +32,26 @@ si:
password_change:
explanation: ඔබගේ ගිණුම සඳහා මුරපදය වෙනස් කර ඇත.
extra: ඔබ ඔබගේ මුරපදය වෙනස් නොකළේ නම්, යමෙකු ඔබගේ ගිණුමට ප්රවේශය ලබා ගෙන ඇති බව පෙනෙන්නට තිබේ. ඔබගේ ගිණුමෙන් අගුලු දමා ඇත්නම් කරුණාකර ඔබගේ මුරපදය වහාම වෙනස් කරන්න හෝ සේවාදායක පරිපාලක අමතන්න.
- subject: 'Mastodon: මුරපදය වෙනස් විය'
+ subject: 'මාස්ටඩන්: මුරපදය වෙනස් විය'
title: මුරපදය වෙනස් විය
reconfirmation_instructions:
explanation: ඔබගේ ඊමේල් වෙනස් කිරීමට නව ලිපිනය තහවුරු කරන්න.
- extra: මෙම වෙනස ඔබ විසින් ආරම්භ කරන ලද්දක් නොවේ නම්, කරුණාකර මෙම විද්යුත් තැපෑල නොසලකා හරින්න. ඔබ ඉහත සබැඳියට ප්රවේශ වන තෙක් Mastodon ගිණුම සඳහා ඊමේල් ලිපිනය වෙනස් නොවේ.
- subject: 'Mastodon: %{instance}සඳහා විද්යුත් තැපෑල තහවුරු කරන්න'
title: වි-තැපෑල තහවුරු කරන්න
reset_password_instructions:
action: මුරපදය වෙනස් කරන්න
explanation: ඔබ ඔබගේ ගිණුම සඳහා නව මුරපදයක් ඉල්ලා ඇත.
extra: ඔබ මෙය ඉල්ලා නොසිටියේ නම්, කරුණාකර මෙම විද්යුත් තැපෑල නොසලකා හරින්න. ඔබ ඉහත සබැඳියට ප්රවේශ වී අලුත් එකක් සාදන තෙක් ඔබේ මුරපදය වෙනස් නොවනු ඇත.
- subject: 'Mastodon: මුරපද උපදෙස් යළි පිහිටුවන්න'
+ subject: 'මාස්ටඩන්: මුරපදය යළි සැකසීමේ උපදෙස්'
title: මුරපදය යළි සැකසීම
two_factor_disabled:
explanation: ඔබගේ ගිණුම සඳහා ද්වි-සාධක සත්යාපනය අබල කර ඇත. විද්යුත් තැපැල් ලිපිනය සහ මුරපදය පමණක් භාවිතයෙන් දැන් පුරනය විය හැක.
- subject: 'Mastodon: ද්වි සාධක සත්යාපනය අක්රීය කර ඇත'
title: ද්විපියවර අබලයි
two_factor_enabled:
explanation: ඔබගේ ගිණුම සඳහා ද්වි-සාධක සත්යාපනය සක්රීය කර ඇත. යුගල කළ TOTP යෙදුම මගින් ජනනය කරන ලද ටෝකනයක් පුරනය වීමට අවශ්ය වනු ඇත.
- subject: 'Mastodon: ද්වි සාධක සත්යාපනය සක්රීය කර ඇත'
title: ද්විපියවර සබලයි
two_factor_recovery_codes_changed:
explanation: පෙර ප්රතිසාධන කේත අවලංගු කර නව ඒවා උත්පාදනය කර ඇත.
- subject: 'Mastodon: ද්වි-සාධක ප්රතිසාධන කේත නැවත උත්පාදනය කරන ලදී'
+ subject: 'මාස්ටඩන්: ද්වි-සාධක ප්රතිසාධන කේත නැවත උත්පාදනය කෙරිණි'
title: ද්විපියවර ප්රතිසාධන කේත වෙනස් විය
unlock_instructions:
subject: 'මාස්ටඩන්: අගුළු හැරීමේ උපදේශ'
@@ -67,15 +62,13 @@ si:
title: ආරක්ෂණ යතුරක් එකතු කර ඇත
deleted:
explanation: පහත ආරක්ෂක යතුර ඔබගේ ගිණුමෙන් මකා ඇත
- subject: 'Mastodon: ආරක්ෂක යතුර මකා ඇත'
+ subject: 'මාස්ටඩන්: ආරක්ෂණ යතුර මකා ඇත'
title: ඔබගේ ආරක්ෂක යතුරු වලින් එකක් මකා ඇත
webauthn_disabled:
explanation: ඔබගේ ගිණුම සඳහා ආරක්ෂක යතුරු සමඟ සත්යාපනය අබල කර ඇත. යුගල කළ TOTP යෙදුම මගින් ජනනය කරන ලද ටෝකනය පමණක් භාවිතයෙන් දැන් පුරනය විය හැක.
- subject: 'Mastodon: ආරක්ෂක යතුරු සමඟ සත්යාපනය අක්රිය කර ඇත'
title: ආරක්ෂණ යතුරු අබල කර ඇත
webauthn_enabled:
explanation: ඔබගේ ගිණුම සඳහා ආරක්ෂක යතුරු සත්යාපනය සක්රීය කර ඇත. ඔබගේ ආරක්ෂක යතුර දැන් පුරනය වීම සඳහා භාවිතා කළ හැක.
- subject: 'Mastodon: ආරක්ෂක යතුරු සත්යාපනය සක්රීය කර ඇත'
title: ආරක්ෂණ යතුරු සබල කර ඇත
omniauth_callbacks:
failure: '"%{reason}" නිසා %{kind} සිට ඔබව සත්යාපනය කළ නොහැක.'
@@ -93,7 +86,7 @@ si:
signed_up_but_locked: ඔබ සාර්ථකව ලියාපදිංචි වී ඇත. කෙසේ වෙතත්, ඔබගේ ගිණුම අගුලු දමා ඇති නිසා අපට ඔබව පුරනය කිරීමට නොහැකි විය.
signed_up_but_pending: තහවුරු කිරීමේ සබැඳියක් සහිත පණිවිඩයක් ඔබගේ විද්යුත් තැපැල් ලිපිනයට යවා ඇත. ඔබ සබැඳිය ක්ලික් කළ පසු, අපි ඔබගේ අයදුම්පත සමාලෝචනය කරන්නෙමු. එය අනුමත වුවහොත් ඔබට දැනුම් දෙනු ලැබේ.
signed_up_but_unconfirmed: තහවුරු කිරීමේ සබැඳියක් සහිත පණිවිඩයක් ඔබගේ විද්යුත් තැපැල් ලිපිනයට යවා ඇත. ඔබගේ ගිණුම සක්රිය කිරීමට කරුණාකර සබැඳිය අනුගමනය කරන්න. ඔබට මෙම විද්යුත් තැපෑල නොලැබුනේ නම් කරුණාකර ඔබගේ අයාචිත තැපැල් ෆෝල්ඩරය පරීක්ෂා කරන්න.
- update_needs_confirmation: ඔබගේ ගිණුම සාර්ථකව යාවත්කාලීන වුවද අපට නව වි-තැපැල් ලිපිනය තහවුරු කර ගැනීමට වුවමනා කෙරේ. කරුණාකර ඔබගේ වි-තැපෑල පරීක්ෂා කර ඊට අදාළ සබැඳිය අනුගමනය කර ඔබගේ නව වි-තැපැල් ලිපිනය තහවුරු කරන්න. ඔබට මෙම වි-තැපෑල නොලැබුණේ නම් කරුණාකර අයාචිත තැපැල් බහාලුම බලන්න.
+ update_needs_confirmation: ඔබගේ ගිණුම සාර්ථකව යාවත්කාලීන වුවද අපට නව වි-තැපැල් ලිපිනය සත්යාපනය කර ගැනීමට වුවමනා කෙරේ. කරුණාකර ඔබගේ වි-තැපෑල පරීක්ෂා කර ඊට අදාළ සබැඳිය අනුගමනය කර ඔබගේ නව වි-තැපැල් ලිපිනය තහවුරු කරන්න. ඔබට මෙම වි-තැපෑල නොලැබුණේ නම් කරුණාකර අයාචිත තැපැල් බහාලුම බලන්න.
updated: ඔබගේ ගිණුම සාර්ථකව යාවත්කාලීන කර ඇත.
sessions:
already_signed_out: සාර්ථකව නික්මිණි.
@@ -108,8 +101,7 @@ si:
already_confirmed: දැනටමත් තහවුරු කර ඇත, කරුණාකර පුරනය වීමට උත්සාහ කරන්න
confirmation_period_expired: "%{period}තුළ තහවුරු කළ යුතුය, කරුණාකර අලුත් එකක් ඉල්ලන්න"
expired: කල් ඉකුත් වී ඇත, කරුණාකර අලුත් එකක් ඉල්ලන්න
- not_found: හමු වුණේ නැහැ
- not_locked: අගුලු දමා නොතිබුණි
+ not_found: හමු නොවිණි
not_saved:
one: '1 දෝෂයක් මෙම %{resource} සුරැකීම තහනම් කර ඇත:'
other: 'දෝෂ %{count} කින් මෙම %{resource} සුරැකීම තහනම් කර ඇත:'
diff --git a/config/locales/devise.zh-CN.yml b/config/locales/devise.zh-CN.yml
index 5a3dbff7e42570..e46c4335301dc2 100644
--- a/config/locales/devise.zh-CN.yml
+++ b/config/locales/devise.zh-CN.yml
@@ -9,7 +9,7 @@ zh-CN:
already_authenticated: 你已登录。
inactive: 你还没有激活账户。
invalid: "%{authentication_keys} 无效或密码错误。"
- last_attempt: 你只有最后一次尝试机会,若未通过,账号将被锁定。
+ last_attempt: 你只有最后一次尝试机会,若未通过,帐号将被锁定。
locked: 你的账户已被锁定。
not_found_in_database: "%{authentication_keys}或密码错误。"
pending: 你的账号仍在审核中。
@@ -85,7 +85,7 @@ zh-CN:
send_instructions: 如果你的电子邮件地址存在于我们的数据库中,你将在几分钟后收到一个密码恢复链接。如果你没有收到这封邮件,请检查你邮箱的垃圾箱。
send_paranoid_instructions: 如果你的电子邮件地址存在于我们的数据库中,你将在几分钟后收到一个密码恢复链接。如果你没有收到这封邮件,请检查你邮箱的垃圾箱。
updated: 你的密码已成功修改,现在你已登录。
- updated_not_active: 你的密码已成功修改。
+ updated_not_active: 你的密码已修改成功。
registrations:
destroyed: 再见!你的账户已成功注销。我们希望很快可以再见到你。
signed_up: 欢迎!你已成功注册。
diff --git a/config/locales/devise.zh-TW.yml b/config/locales/devise.zh-TW.yml
index ea1813e413e130..c01beb796b39db 100644
--- a/config/locales/devise.zh-TW.yml
+++ b/config/locales/devise.zh-TW.yml
@@ -4,7 +4,7 @@ zh-TW:
confirmations:
confirmed: 您的電子郵件地址已確認成功。
send_instructions: 幾分鐘後您將收到確認信件。若未收到此信件,請檢查垃圾郵件資料夾。
- send_paranoid_instructions: 如果您的電子郵件存在於我們的資料庫,您將會在幾分鐘內收到確認信。若未收到請檢查垃圾郵件資料夾。
+ send_paranoid_instructions: 如果您的電子郵件存在於我們的資料庫,您將於幾分鐘內收到確認信。若未收到請檢查垃圾郵件資料夾。
failure:
already_authenticated: 您已登入。
inactive: 您的帳號尚未啟用。
@@ -43,7 +43,7 @@ zh-TW:
reset_password_instructions:
action: 變更密碼
explanation: 您已請求帳號的新密碼。
- extra: 若您並未請求,請忽略此信件。您的密碼在存取上方連結並建立新密碼前不會變更。
+ extra: 若您並未請求,請忽略此信件。您的密碼於存取上方連結並建立新密碼前不會變更。
subject: Mastodon:重設密碼指引
title: 重設密碼
two_factor_disabled:
diff --git a/config/locales/doorkeeper.fa.yml b/config/locales/doorkeeper.fa.yml
index 085507f8bf99e9..c56e76e346286c 100644
--- a/config/locales/doorkeeper.fa.yml
+++ b/config/locales/doorkeeper.fa.yml
@@ -149,6 +149,7 @@ fa:
scopes:
admin:read: خواندن تمام دادهها روی کارساز
admin:read:accounts: خواندن اطّلاعات حساس از همهٔ حسابها
+ admin:read:canonical_email_blocks: خواندن اطّلاعات حسّاس از همهٔ انسدادهای رایانامهٔ متعارف
admin:read:domain_allows: خواندن اطّلاعات حساس از همهٔ دامنه ها اجازه داده شد
admin:read:domain_blocks: خواندن اطّلاعات حساس از همهٔ دامنه های مسدودشده
admin:read:email_domain_blocks: خواندن اطّلاعات حساس از همهٔ دامنه های رایانامه های مسدودشده
@@ -156,6 +157,7 @@ fa:
admin:read:reports: خواندن اطّلاعات حساس از همهٔ گزارشها و حسابهای گزارششده
admin:write: تغییر تمام دادهها روی کارساز
admin:write:accounts: انجام کنش مدیریتی روی حسابها
+ admin:write:canonical_email_blocks: انجام کنشهای نظارتی روی همهٔ انسدادهای رایانامهٔ متعارف
admin:write:domain_allows: انجام کنش مدیریتی روی اجازههای دامنه
admin:write:domain_blocks: انجام کنش مدیریتی روی انسدادهای دامنه
admin:write:email_domain_blocks: انجام کنش مدیریتی روی انسدادهای دامنهٔ رایانامه
diff --git a/config/locales/doorkeeper.fi.yml b/config/locales/doorkeeper.fi.yml
index 71958c5b3d0e54..fea01d107660cd 100644
--- a/config/locales/doorkeeper.fi.yml
+++ b/config/locales/doorkeeper.fi.yml
@@ -6,7 +6,7 @@ fi:
name: Sovelluksen nimi
redirect_uri: Uudelleenohjauksen URI
scopes: Oikeudet
- website: Sovelluksen verkkosivu
+ website: Sovelluksen verkkosivusto
errors:
models:
doorkeeper/application:
@@ -67,13 +67,13 @@ fi:
title: Kopioi tämä valtuutuskoodi ja liitä se sovellukseen.
authorized_applications:
buttons:
- revoke: Peru
+ revoke: Hylkää
confirmations:
revoke: Oletko varma?
index:
authorized_at: Valtuutettu %{date}
- description_html: Nämä ovat sovelluksia, jotka voivat käyttää tiliäsi käyttäen API. Jos et tunnista sitä tai sovellus toimii väärin, voit peruuttaa sen käyttöoikeuden.
- last_used_at: Viimeksi käytetty %{date}
+ description_html: Nämä sovellukset voivat käyttää tiliäsi ohjelmointirajapinnan kautta. Jos tässä on sovelluksia, joita et tunnista, tai sovellus toimii väärin, voit peruuttaa sen käyttöoikeuden.
+ last_used_at: Käytetty viimeksi %{date}
never_used: Ei käytetty
scopes: Oikeudet
superapp: Sisäinen
@@ -114,16 +114,16 @@ fi:
notice: Sovellus poistettu.
grouped_scopes:
access:
- read: Vain luku
+ read: Vain lukuoikeus
read/write: Luku- ja kirjoitusoikeudet
write: Vain kirjoitusoikeus
title:
accounts: Tilit
- admin/accounts: Tilien hallinta
+ admin/accounts: Tilien hallinnointi
admin/all: Kaikki hallinnolliset toiminnot
- admin/reports: Raporttien hallinta
+ admin/reports: Raporttien hallinnointi
all: Täysi pääsy Mastodon-tiliisi
- blocks: Torjutut
+ blocks: Estot
bookmarks: Kirjanmerkit
conversations: Keskustelut
crypto: Päästä päähän -salaus
@@ -135,7 +135,7 @@ fi:
media: Medialiitteet
mutes: Mykistykset
notifications: Ilmoitukset
- push: Push-ilmoitukset
+ push: Puskuilmoitukset
reports: Raportit
search: Hae
statuses: Viestit
@@ -147,49 +147,49 @@ fi:
application:
title: OAuth-valtuutus tarvitaan
scopes:
- admin:read: lukea kaikkia tietoja palvelimelta
- admin:read:accounts: lue arkaluontoinen sisältö kaikilta tileiltä
- admin:read:canonical_email_blocks: lue arkaluonteisia tietoja kaikista kanonisesti sallituista sähköpostiosoitteista
+ admin:read: lue kaikkia palvelimen tietoja
+ admin:read:accounts: lue arkaluonteisia tietoja kaikista tileistä
+ admin:read:canonical_email_blocks: lue arkaluonteisia tietoja kaikista estetyistä kanonisista sähköpostiosoitteista
admin:read:domain_allows: lue arkaluonteisia tietoja kaikista sallituista verkkotunnuksista
admin:read:domain_blocks: lue arkaluonteisia tietoja kaikista estetyistä verkkotunnuksista
admin:read:email_domain_blocks: lue arkaluonteisia tietoja kaikista estetyistä sähköpostiverkkotunnuksista
admin:read:ip_blocks: lue arkaluonteisia tietoja kaikista estetyistä IP-osoitteista
- admin:read:reports: lue arkaluonteiset tiedot kaikista raporteista ja raportoiduista tileistä
- admin:write: muokata kaikkia tietoja palvelimella
- admin:write:accounts: suorita moderointitoiminnot tileillä
- admin:write:canonical_email_blocks: toteuta moderointitoimenpiteitä kanonisille sähköpostiosoite-estoille
- admin:write:domain_allows: toteuta moderointitoimenpiteitä sallituille verkkotunnuksille
- admin:write:domain_blocks: toteuta moderointitoimenpiteitä estetyille verkkotunnuksille
- admin:write:email_domain_blocks: toteuta moderointitoimenpiteitä estetyille sähköpostiverkkotunnuksille
- admin:write:ip_blocks: toteuta moderointitoimenpiteitä estetyille IP-osoitteille
- admin:write:reports: suorita moderointitoiminnot raporteissa
- crypto: käytä päästä päähän salausta
- follow: seurata, estää, perua eston ja lopettaa tilien seuraaminen
- push: vastaanottaa push-ilmoituksesi
- read: lukea tilin tietoja
- read:accounts: nähdä tilin tiedot
- read:blocks: katso lohkosi
- read:bookmarks: katso kirjanmerkkisi
- read:favourites: näytä suosikkisi
- read:filters: katso suodattimesi
- read:follows: katso ketä seuraat
- read:lists: katso listasi
- read:mutes: katso mykistyksesi
- read:notifications: katso ilmoitukset
- read:reports: katso raporttisi
- read:search: haku sinun puolesta
- read:statuses: katso kaikki viestit
- write: julkaista puolestasi
- write:accounts: muokata profiiliasi
- write:blocks: estää tilit ja palvelimet
- write:bookmarks: kirjanmerkki viestit
- write:conversations: mykistä ja poistaa keskustelut
+ admin:read:reports: lue arkaluonteisia tietoja kaikista raporteista ja raportoiduista tileistä
+ admin:write: muokkaa kaikkia palvelimen tietoja
+ admin:write:accounts: suorita valvontatoimia tileille
+ admin:write:canonical_email_blocks: suorita valvontatoimia estetyille kanonisille sähköpostiosoitteille
+ admin:write:domain_allows: suorita valvontatoimia sallituille verkkotunnuksille
+ admin:write:domain_blocks: suorita valvontatoimia estetyille verkkotunnuksille
+ admin:write:email_domain_blocks: suorita valvontatoimia estetyille sähköpostiverkkotunnuksille
+ admin:write:ip_blocks: suorita valvontatoimia estetyille IP-osoitteille
+ admin:write:reports: suorita valvontatoimia raporteille
+ crypto: käytä päästä päähän -salausta
+ follow: muokkaa tilin suhteita
+ push: vastaanota puskuilmoituksiasi
+ read: lue kaikkia tilin tietoja
+ read:accounts: katso tilien tietoja
+ read:blocks: katso estojasi
+ read:bookmarks: katso kirjanmerkkejäsi
+ read:favourites: katso suosikkejasi
+ read:filters: katso suodattimiasi
+ read:follows: katso seurattujasi
+ read:lists: katso listojasi
+ read:mutes: katso mykistyksiäsi
+ read:notifications: katso ilmoituksiasi
+ read:reports: katso raporttejasi
+ read:search: hae puolestasi
+ read:statuses: katso kaikkia julkaisujasi
+ write: muokkaa kaikkia tilisi tietoja
+ write:accounts: muokkaa profiiliasi
+ write:blocks: estä tilejä ja verkkotunnuksia
+ write:bookmarks: lisää julkaisuja kirjanmerkkeihin
+ write:conversations: mykistä ja poista keskusteluja
write:favourites: suosikkijulkaisut
- write:filters: luoda suodattimia
- write:follows: seurata ihmisiä
- write:lists: luoda listoja
- write:media: lähettää mediatiedostoja
- write:mutes: mykistää ihmisiä ja keskusteluja
- write:notifications: tyhjentää ilmoituksesi
- write:reports: raportoi muille ihmisille
- write:statuses: julkaise viestejä
+ write:filters: luo suodattimia
+ write:follows: seuraa käyttäjiä
+ write:lists: luo listoja
+ write:media: lähetä mediatiedostoja
+ write:mutes: mykistä käyttäjiä ja keskusteluja
+ write:notifications: tyhjennä ilmoituksesi
+ write:reports: raportoi muita käyttäjiä
+ write:statuses: julkaise julkaisuja
diff --git a/config/locales/doorkeeper.fy.yml b/config/locales/doorkeeper.fy.yml
index 8acf7ea9b8f754..a43defc427ef67 100644
--- a/config/locales/doorkeeper.fy.yml
+++ b/config/locales/doorkeeper.fy.yml
@@ -43,7 +43,7 @@ fy:
new: Nije tapassing
scopes: Tastimmingen
show: Toane
- title: Dyn tapassingen
+ title: Jo tapassingen
new:
title: Nije tapassing
show:
@@ -60,7 +60,7 @@ fy:
error:
title: Der is in flater bard
new:
- prompt_html: "%{client_name} hat tastimming nedich om tagong te krijen ta dyn account. It giet om in tapassing fan in tredde partij.Asto dit net fertroust, moatsto gjin tastimming jaan."
+ prompt_html: "%{client_name} hat tastimming nedich om tagong te krijen ta jo account. It giet om in tapassing fan in tredde partij.As jo dit net fertrouwe, moatte jo gjin tastimming jaan."
review_permissions: Tastimmingen beoardiele
title: Autorisaasje fereaske
show:
@@ -69,15 +69,15 @@ fy:
buttons:
revoke: Ynlûke
confirmations:
- revoke: Bisto wis?
+ revoke: Binne jo wis?
index:
authorized_at: Autorisearre op %{date}
- description_html: Dit binne tapassingen dy’t tagong hawwe ta dyn account fia de API. As der tapassingen tusken steane dy’tsto net werkenst of in tapassing harren misdraacht, kinsto de tagongsrjochten fan de tapassing ynlûke.
+ description_html: Dit binne tapassingen dy’t fia de API tagong hawwe ta jo account. As der tapassingen tusken steane dy’t jo net werkenne of in tapassing harren misdraacht, kinne jo de tagongsrjochten fan de tapassing ynlûke.
last_used_at: Lêst brûkt op %{date}
never_used: Nea brûkt
scopes: Tastimmingen
superapp: Yntern
- title: Dyn autorisearre tapassingen
+ title: Jo autorisearre tapassingen
errors:
messages:
access_denied: De boarne-eigener of autorisaasjeserver hat it fersyk wegere.
@@ -165,22 +165,22 @@ fy:
admin:write:reports: moderaasjemaatregelen nimme yn rapportaazjes
crypto: ein-ta-ein-fersifering brûke
follow: relaasjes tusken accounts bewurkje
- push: dyn pushmeldingen ûntfange
- read: alle gegevens fan dyn account lêze
+ push: jo pushmeldingen ûntfange
+ read: alle gegevens fan jo account lêze
read:accounts: accountynformaasje besjen
- read:blocks: dyn blokkearre brûkers besjen
- read:bookmarks: dyn blêdwizers besjen
+ read:blocks: jo blokkearre brûkers besjen
+ read:bookmarks: jo blêdwizers besjen
read:favourites: jo favoriten besjen
- read:filters: dyn filters besjen
+ read:filters: jo filters besjen
read:follows: de accounts dy’tsto folgest besjen
- read:lists: dyn listen besjen
- read:mutes: dyn negearre brûkers besjen
- read:notifications: dyn meldingen besjen
- read:reports: dyn rapportearre berjochten besjen
- read:search: út dyn namme sykje
+ read:lists: jo listen besjen
+ read:mutes: jo negearre brûkers besjen
+ read:notifications: jo meldingen besjen
+ read:reports: jo rapportearre berjochten besjen
+ read:search: út jo namme sykje
read:statuses: alle berjochten besjen
- write: alle gegevens fan dyn account bewurkje
- write:accounts: dyn profyl bewurkje
+ write: alle gegevens fan jo account bewurkje
+ write:accounts: jo profyl bewurkje
write:blocks: accounts en domeinen blokkearje
write:bookmarks: berjochten oan blêdwizers tafoegje
write:conversations: petearen negearre en fuortsmite
diff --git a/config/locales/doorkeeper.si.yml b/config/locales/doorkeeper.si.yml
index 2307f63c0ae73c..d3550cf5989b78 100644
--- a/config/locales/doorkeeper.si.yml
+++ b/config/locales/doorkeeper.si.yml
@@ -58,10 +58,10 @@ si:
authorize: සත්යාපනය
deny: ප්රතික්ෂේප කරන්න
error:
- title: දෝෂයක් සිදුවී ඇත
+ title: දෝෂයක් සිදු වී ඇත
new:
prompt_html: "%{client_name} ඔබගේ ගිණුමට ප්රවේශ වීමට අවසර ලබා ගැනීමට කැමති වේ. එය තෙවන පාර්ශවීය යෙදුමකි. ඔබ එය විශ්වාස නොකරන්නේ නම්, ඔබ එයට අවසර නොදිය යුතුය."
- review_permissions: අවසර සමාලෝචනය කරන්න
+ review_permissions: අවසර සමාලෝචනය
title: බලය පැවරීමේ අවශ්ය
show:
title: මෙම අවසර කේතය පිටපත් කර එය යෙදුමට අලවන්න.
@@ -73,11 +73,11 @@ si:
index:
authorized_at: "%{date}මත අවසර දී ඇත"
description_html: මේවා API භාවිතයෙන් ඔබගේ ගිණුමට ප්රවේශ විය හැකි යෙදුම් වේ. ඔබ මෙහි හඳුනා නොගත් යෙදුම් තිබේ නම්, හෝ යෙදුමක් වැරදි ලෙස හැසිරෙන්නේ නම්, ඔබට එහි ප්රවේශය අවලංගු කළ හැක.
- last_used_at: අවසන් වරට භාවිතා කළේ %{date}
- never_used: කවදාවත් පාවිච්චි කළේ නැහැ
+ last_used_at: අන්තිම භාවිතය %{date}
+ never_used: භාවිතා කර නැත
scopes: අවසර
- superapp: අභ්යන්තර
- title: ඔබගේ බලයලත් අයදුම්පත්
+ superapp: අභ්යන්තර
+ title: ඔබගේ බලයලත් යෙදුම්
errors:
messages:
access_denied: සම්පත් හිමිකරු හෝ අවසර සේවාදායකය ඉල්ලීම ප්රතික්ෂේප කළේය.
@@ -104,33 +104,34 @@ si:
flash:
applications:
create:
- notice: යෙදුම නිර්මාණය කරන ලදී.
+ notice: යෙදුම සෑදිණි.
destroy:
- notice: යෙදුම මකා ඇත.
+ notice: යෙදුම මැකිණි.
update:
- notice: යෙදුම යාවත්කාලීන කරන ලදී.
+ notice: යෙදුම යාවත්කාල විය.
authorized_applications:
destroy:
notice: අයදුම්පත අවලංගු කරන ලදී.
grouped_scopes:
access:
- read: කියවීමට පමණක් ප්රවේශය
- read/write: කියවීමට සහ ලිවීමට ප්රවේශය
- write: ලිවීමට පමණක් ප්රවේශය
+ read: ප්රවේශය කියවීමට පමණි
+ read/write: කියවීමට හා ලිවීමට ප්රවේශය
+ write: ප්රවේශය ලිවීමට පමණි
title:
accounts: ගිණුම්
- admin/accounts: ගිණුම් පරිපාලනය
+ admin/accounts: ගිණුම් කළමනාකරණය
admin/all: සියලුම පරිපාලන කාර්යයන්
admin/reports: වාර්තා පරිපාලනය
+ all: ඔබගේ මාස්ටඩන් ගිණුමට පූර්ණ ප්රවේශය
blocks: කුට්ටි
- bookmarks: පිටු සලකුණු
+ bookmarks: පොත්යොමු
conversations: සංවාද
crypto: අන්ත සංකේතනය
+ favourites: ප්රියතමයන්
filters: පෙරහන්
follows: පහත සඳහන්
lists: ලැයිස්තු
- media: මාධ්ය ඇමුණුම්
- mutes: නිහඬ කරයි
+ media: මාධ්ය ඇමුණුම්
notifications: දැනුම්දීම්
push: තල්ලු දැනුම්දීම්
reports: වාර්තා
@@ -142,39 +143,40 @@ si:
applications: යෙදුම්
oauth2_provider: වි.සත්යා.2 (OAuth) සැපයුම්කරු
application:
- title: වි.සත්යා. (OAuth) තොරතුරු අවශ්යයි
+ title: වි.සත්යා. (OAuth) අනුමැතිය අවශ්යයයි
scopes:
- admin:read: සේවාදායකයේ ඇති සියලුම දත්ත කියවන්න
- admin:read:accounts: සියලුම ගිණුම් වල සංවේදී තොරතුරු කියවන්න
- admin:read:reports: සියලුම වාර්තා සහ වාර්තා කළ ගිණුම් වල සංවේදී තොරතුරු කියවන්න
- admin:write: සේවාදායකයේ සියලුම දත්ත වෙනස් කරන්න
- admin:write:accounts: ගිණුම් මත මධ්යස්ථ ක්රියා සිදු කරන්න
- admin:write:reports: වාර්තා මත මධ්යස්ථ ක්රියා සිදු කරන්න
- crypto: end-to-end encryption භාවිතා කරන්න
+ admin:read: සේවාදායකයේ ඇති සියලුම දත්ත කියවයි
+ admin:read:accounts: සියලුම ගිණුම් වල සංවේදී තොරතුරු කියවයි
+ admin:read:reports: සියලුම වාර්තා සහ වාර්තා කළ ගිණුම් වල සංවේදී තොරතුරු කියවයි
+ admin:write: සේවාදායකයේ සියලුම දත්ත සංශෝධනය කරයි
+ admin:write:accounts: ගිණුම් සඳහා මැදිහත්කරණ ක්රියාමාර්ග ගනියි
+ admin:write:reports: වාර්තා සඳහා මැදිහත්කරණ ක්රියාමාර්ග ගනියි
+ crypto: අන්ත සංකේතනය භාවිතා කරයි
follow: ගිණුම් සබඳතා වෙනස් කරන්න
- push: ඔබගේ තල්ලු දැනුම්දීම් ලබා ගන්න
- read: ඔබගේ ගිණුමේ සියලුම දත්ත කියවන්න
- read:accounts: ගිණුම් තොරතුරු බලන්න
+ push: ඔබගේ තල්ලු දැනුම්දීම් ලබන්න
+ read: ඔබගේ ගිණුමේ සියලුම දත්ත කියවයි
+ read:accounts: ගිණුම්වල තොරතුරු දකියි
read:blocks: ඔබගේ වාරණ බලන්න
- read:bookmarks: ඔබගේ පිටු සලකුණු බලන්න
+ read:bookmarks: ඔබගේ පොත්යොමු දකියි
+ read:favourites: ඔබගේ ප්රියතමයන් බලන්න
read:filters: ඔබගේ පෙරහන් බලන්න
read:follows: ඔබගේ පහත සඳහන් බලන්න
read:lists: ඔබගේ ලැයිස්තු බලන්න
read:mutes: ඔබේ ගොළු බලන්න
- read:notifications: ඔබගේ දැනුම්දීම් බලන්න
+ read:notifications: ඔබගේ දැනුම්දීම් බලයි
read:reports: ඔබගේ වාර්තා බලන්න
- read:search: ඔබ වෙනුවෙන් සොයන්න
- read:statuses: සියලුම පෝස්ට් බලන්න
+ read:search: ඔබ වෙනුවෙන් සොයයි
+ read:statuses: සියලු ලිපි බලයි
write: ඔබගේ ගිණුමේ සියලුම දත්ත වෙනස් කරන්න
write:accounts: ඔබගේ පැතිකඩ වෙනස් කරන්න
- write:blocks: ගිණුම් සහ වසම් අවහිර කරන්න
- write:bookmarks: පිටු සලකුණු සටහන්
+ write:blocks: ගිණුම් සහ වසම් අවහිර කරයි
+ write:bookmarks: ලිපි වලට පොත්යොමු තබයි
write:conversations: සංවාද නිහඬ කිරීම සහ මකා දැමීම
- write:filters: පෙරහන් කරන්න
+ write:favourites: ප්රියතම ලිපි
+ write:filters: පෙරහන් සාදයි
write:follows: මිනිසුන් අනුගමනය කරන්න
write:lists: ලැයිස්තු සාදන්න
- write:media: මාධ්ය ගොනු උඩුගත කරන්න
- write:mutes: මිනිසුන් සහ සංවාද කරන්න
- write:notifications: ඔබගේ දැනුම්දීම් හිස්කරන්න
- write:reports: වෙනත් පුද්ගලයින් වාර්තා කරන්න
- write:statuses: පළ කිරීම් පළ කරන්න
+ write:media: මාධ්ය ගොනු උඩුගත කරයි
+ write:mutes: සංවාද හා පුද්ගලයින් නිහඬ කරයි
+ write:notifications: ඔබගේ දැනුම්දීම් හිස් කරයි
+ write:statuses: ලිපි පළ කරයි
diff --git a/config/locales/doorkeeper.sk.yml b/config/locales/doorkeeper.sk.yml
index acfd59b3e77011..91c9430b3029c5 100644
--- a/config/locales/doorkeeper.sk.yml
+++ b/config/locales/doorkeeper.sk.yml
@@ -129,6 +129,7 @@ sk:
crypto: Šifrovanie End-to-end
favourites: Obľúbené
filters: Filtre
+ follow: Sledovanie, stlmenie a blokovanie
follows: Sledovania
lists: Zoznamy
media: Mediálne prílohy
@@ -148,9 +149,19 @@ sk:
scopes:
admin:read: prezeraj všetky dáta na serveri
admin:read:accounts: prezeraj chúlostivé informácie na všetkých účtoch
+ admin:read:canonical_email_blocks: čítať citlivé informácie všetkých kanonických e-mailových blokov
+ admin:read:domain_allows: čítať citlivé informácie zo všetkých povolených domén
+ admin:read:domain_blocks: čítať citlivé informácie zo všetkých blokov domén
+ admin:read:email_domain_blocks: čítať citlivé informácie zo všetkých blokov emailových domén
+ admin:read:ip_blocks: čítať citlivé informácie zo všetkých blokov IP
admin:read:reports: čítaj chulostivé informácie o všetkých hláseniach a nahlásených účtoch
admin:write: uprav všetky dáta na serveri
admin:write:accounts: urob moderovacie úkony na účtoch
+ admin:write:canonical_email_blocks: vykonať akcie moderácie na kanonických emailových blokoch
+ admin:write:domain_allows: vykonať akcie moderácie na povolených doménach
+ admin:write:domain_blocks: vykonať akcie moderácie na doménových blokoch
+ admin:write:email_domain_blocks: vykonať akcie moderácie na blokoch emailových domén
+ admin:write:ip_blocks: vykonať akcie moderácie na blokoch IP
admin:write:reports: urob moderovacie úkony voči hláseniam
crypto: používať end-to-end šifrovanie
follow: uprav vzťahy svojho účtu
@@ -159,6 +170,7 @@ sk:
read:accounts: prezri si informácie o účte
read:blocks: prezri svoje bloky
read:bookmarks: pozri svoje záložky
+ read:favourites: zobraziť vaše obľúbené
read:filters: prezri svoje filtrovanie
read:follows: prezri si svoje sledovania
read:lists: prezri si svoje zoznamy
diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml
index ca61644632bc23..98a40c45cffd4b 100644
--- a/config/locales/en-GB.yml
+++ b/config/locales/en-GB.yml
@@ -1028,7 +1028,7 @@ en-GB:
applications:
created: Application successfully created
destroyed: Application successfully deleted
- logout: Logout
+ logout: Log out
regenerate_token: Regenerate access token
token_regenerated: Access token successfully regenerated
warning: Be very careful with this data. Never share it with anyone!
@@ -1055,7 +1055,7 @@ en-GB:
link_to_webauth: Use your security key device
log_in_with: Log in with
login: Log in
- logout: Logout
+ logout: Log out
migrate_account: Move to a different account
migrate_account_html: If you wish to redirect this account to a different one, you can configure it here.
or_log_in_with: Or log in with
@@ -1089,8 +1089,8 @@ en-GB:
new_confirmation_instructions_sent: You will receive a new e-mail with the confirmation link in a few minutes!
title: Check your inbox
sign_in:
- preamble_html: Sign in with your %{domain} credentials. If your account is hosted on a different server, you will not be able to log in here.
- title: Sign in to %{domain}
+ preamble_html: Log in with your %{domain} credentials. If your account is hosted on a different server, you will not be able to log in here.
+ title: Log in to %{domain}
sign_up:
manual_review: Sign-ups on %{domain} go through manual review by our moderators. To help us process your registration, write a bit about yourself and why you want an account on %{domain}.
preamble: With an account on this Mastodon server, you'll be able to follow any other person on the network, regardless of where their account is hosted.
@@ -1379,8 +1379,8 @@ en-GB:
webauthn: security keys
description_html: If you see activity that you don't recognise, consider changing your password and enabling two-factor authentication.
empty: No authentication history available
- failed_sign_in_html: Failed sign-in attempt with %{method} from %{ip} (%{browser})
- successful_sign_in_html: Successful sign-in with %{method} from %{ip} (%{browser})
+ failed_sign_in_html: Failed login attempt with %{method} from %{ip} (%{browser})
+ successful_sign_in_html: Successful login with %{method} from %{ip} (%{browser})
title: Authentication history
mail_subscriptions:
unsubscribe:
@@ -1773,11 +1773,11 @@ en-GB:
title: Archive takeout
suspicious_sign_in:
change_password: change your password
- details: 'Here are details of the sign-in:'
- explanation: We've detected a sign-in to your account from a new IP address.
+ details: 'Here are details of the login:'
+ explanation: We've detected a login to your account from a new IP address.
further_actions_html: If this wasn't you, we recommend that you %{action} immediately and enable two-factor authentication to keep your account secure.
subject: Your account has been accessed from a new IP address
- title: A new sign-in
+ title: A new login
warning:
appeal: Submit an appeal
appeal_description: If you believe this is an error, you can submit an appeal to the staff of %{instance}.
@@ -1790,7 +1790,7 @@ en-GB:
mark_statuses_as_sensitive: Some of your posts have been marked as sensitive by the moderators of %{instance}. This means that people will need to tap the media in the posts before a preview is displayed. You can mark media as sensitive yourself when posting in the future.
sensitive: From now on, all your uploaded media files will be marked as sensitive and hidden behind a click-through warning.
silence: You can still use your account but only people who are already following you will see your posts on this server, and you may be excluded from various discovery features. However, others may still manually follow you.
- suspend: You can no longer use your account, and your profile and other data are no longer accessible. You can still login to request a backup of your data until the data is fully removed in about 30 days, but we will retain some basic data to prevent you from evading the suspension.
+ suspend: You can no longer use your account, and your profile and other data are no longer accessible. You can still log in to request a backup of your data until the data is fully removed in about 30 days, but we will retain some basic data to prevent you from evading the suspension.
reason: 'Reason:'
statuses: 'Posts cited:'
subject:
@@ -1825,7 +1825,7 @@ en-GB:
invalid_otp_token: Invalid two-factor code
otp_lost_help_html: If you lost access to both, you may get in touch with %{email}
seamless_external_login: You are logged in via an external service, so password and e-mail settings are not available.
- signed_in_as: 'Signed in as:'
+ signed_in_as: 'Logged in as:'
verification:
extra_instructions_html: Tip: The link on your website can be invisible. The important part is rel="me"
which prevents impersonation on websites with user-generated content. You can even use a link
tag in the header of the page instead of a
, but the HTML must be accessible without executing JavaScript.
here_is_how: Here's how
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 71b8f27aacb32a..e8e0f21e1c3db5 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -534,6 +534,7 @@ en:
total_reported: Reports about them
total_storage: Media attachments
totals_time_period_hint_html: The totals displayed below include data for all time.
+ unknown_instance: There is currently no record of this domain on this server.
invites:
deactivate_all: Deactivate all
filter:
@@ -1101,6 +1102,7 @@ en:
functional: Your account is fully operational.
pending: Your application is pending review by our staff. This may take some time. You will receive an e-mail if your application is approved.
redirecting_to: Your account is inactive because it is currently redirecting to %{acct}.
+ self_destruct: As %{domain} is closing down, you will only get limited access to your account.
view_strikes: View past strikes against your account
too_fast: Form submitted too fast, try again.
use_security_key: Use security key
@@ -1571,6 +1573,9 @@ en:
over_daily_limit: You have exceeded the limit of %{limit} scheduled posts for today
over_total_limit: You have exceeded the limit of %{limit} scheduled posts
too_soon: The scheduled date must be in the future
+ self_destruct:
+ lead_html: Unfortunately, %{domain} is permanently closing down. If you had an account there, you will not be able to continue using it, but you can still request a backup of your data.
+ title: This server is closing down
sessions:
activity: Last activity
browser: Browser
diff --git a/config/locales/es-AR.yml b/config/locales/es-AR.yml
index 8357c314908c84..fcff9469100c82 100644
--- a/config/locales/es-AR.yml
+++ b/config/locales/es-AR.yml
@@ -534,6 +534,7 @@ es-AR:
total_reported: Denuncias sobre ellas
total_storage: Adjuntos
totals_time_period_hint_html: Los datos totales mostrados a continuación incluyen datos para todo el tiempo.
+ unknown_instance: Actualmente no hay ningún registro de este dominio en este servidor.
invites:
deactivate_all: Desactivar todas
filter:
@@ -1101,6 +1102,7 @@ es-AR:
functional: Tu cuenta está totalmente operativa.
pending: Tu solicitud está pendiente de revisión por nuestra administración. Eso puede tardar algún tiempo. Si se aprueba tu solicitud, vas a recibir un correo electrónico.
redirecting_to: Tu cuenta se encuentra inactiva porque está siendo redirigida a %{acct}.
+ self_destruct: Como %{domain} está en proceso de cierre, solo tendrás acceso limitado a tu cuenta.
view_strikes: Ver incumplimientos pasados contra tu cuenta
too_fast: Formulario enviado demasiado rápido, probá de nuevo.
use_security_key: Usar la llave de seguridad
@@ -1570,6 +1572,9 @@ es-AR:
over_daily_limit: Superaste el límite de %{limit} mensajes programados para ese día
over_total_limit: Superaste el límite de %{limit} mensajes programados
too_soon: La fecha programada debe estar en el futuro
+ self_destruct:
+ lead_html: Desafortunadamente, %{domain} va a cerrar permanentemente. Si tenías una cuenta ahí, no podrás continuar usándola, pero aún podés solicitar una copia de tus datos.
+ title: Este servidor está cerrando
sessions:
activity: Última actividad
browser: Navegador web
diff --git a/config/locales/es-MX.yml b/config/locales/es-MX.yml
index 542478f7167555..e055ff4c799f63 100644
--- a/config/locales/es-MX.yml
+++ b/config/locales/es-MX.yml
@@ -534,6 +534,7 @@ es-MX:
total_reported: Informes sobre ellas
total_storage: Archivos multimedia
totals_time_period_hint_html: Los totales mostrados a continuación incluyen datos para todo el tiempo.
+ unknown_instance: Actualmente no hay registros de este dominio en el servidor.
invites:
deactivate_all: Desactivar todos
filter:
@@ -1101,6 +1102,7 @@ es-MX:
functional: Tu cuenta está completamente operativa.
pending: Su solicitud está pendiente de revisión por nuestros administradores. Eso puede tardar algún tiempo. Usted recibirá un correo electrónico si el solicitud sea aprobada.
redirecting_to: Tu cuenta se encuentra inactiva porque está siendo redirigida a %{acct}.
+ self_destruct: Como %{domain} está cerrando, solo tendrás acceso limitado a tu cuenta.
view_strikes: Ver amonestaciones pasadas contra tu cuenta
too_fast: Formulario enviado demasiado rápido, inténtelo de nuevo.
use_security_key: Usar la clave de seguridad
@@ -1570,6 +1572,9 @@ es-MX:
over_daily_limit: Ha superado el límite de %{limit} toots programados para ese día
over_total_limit: Ha superado el límite de %{limit} toots programados
too_soon: La fecha programada debe estar en el futuro
+ self_destruct:
+ lead_html: Desafortunadamente, %{domain} está cerrando de manera permanente. Si tenías una cuenta ahí, no puedes continuar utilizándolo, pero puedes solicitar un respaldo de tus datos.
+ title: Este servidor está cerrando
sessions:
activity: Última actividad
browser: Navegador
diff --git a/config/locales/es.yml b/config/locales/es.yml
index 4ad353e3aac114..5dce6330d6c3f7 100644
--- a/config/locales/es.yml
+++ b/config/locales/es.yml
@@ -534,6 +534,7 @@ es:
total_reported: Informes sobre ellas
total_storage: Archivos multimedia
totals_time_period_hint_html: Los totales mostrados a continuación incluyen datos para todo el tiempo.
+ unknown_instance: Actualmente no hay ningún registro de este dominio en este servidor.
invites:
deactivate_all: Desactivar todos
filter:
@@ -1101,6 +1102,7 @@ es:
functional: Tu cuenta está completamente operativa.
pending: Su solicitud está pendiente de revisión por nuestros administradores. Eso puede tardar algún tiempo. Usted recibirá un correo electrónico si el solicitud sea aprobada.
redirecting_to: Tu cuenta se encuentra inactiva porque está siendo redirigida a %{acct}.
+ self_destruct: Como %{domain} está en proceso de cierre, solo tendrás acceso limitado a tu cuenta.
view_strikes: Ver amonestaciones pasadas contra tu cuenta
too_fast: Formulario enviado demasiado rápido, inténtelo de nuevo.
use_security_key: Usar la clave de seguridad
@@ -1570,6 +1572,9 @@ es:
over_daily_limit: Ha superado el límite de %{limit} publicaciones programadas para ese día
over_total_limit: Ha superado el límite de %{limit} publicaciones programadas
too_soon: La fecha programada debe estar en el futuro
+ self_destruct:
+ lead_html: Desafortunadamente, %{domain} va a cerrar permanentemente. Si tenías una cuenta allí, no podrás continuar usándola, pero aún puedes solicitar una copia de tus datos.
+ title: Este servidor está cerrando
sessions:
activity: Última actividad
browser: Navegador
diff --git a/config/locales/eu.yml b/config/locales/eu.yml
index 7ca7f63a5bdb62..3ce8cc728765e5 100644
--- a/config/locales/eu.yml
+++ b/config/locales/eu.yml
@@ -536,6 +536,7 @@ eu:
total_reported: Heiei buruzko txostenak
total_storage: Multimedia eranskinak
totals_time_period_hint_html: Behean bistaratutako guztizkoek datu guztiak hartzen dituzte barne.
+ unknown_instance: Ez dago domeinu honen erregistrorik zerbitzarian orain.
invites:
deactivate_all: Desgaitu guztiak
filter:
@@ -785,6 +786,9 @@ eu:
release_notes: Bertsio oharrak
title: Eguneraketak eskuragarri
type: Mota
+ types:
+ major: Argitalpen handia
+ minor: Argitalpen txikia
version: Bertsioa
statuses:
account: Egilea
@@ -1090,6 +1094,7 @@ eu:
functional: Zure kontua guztiz erabilgarri dago.
pending: Zure eskaera gainbegiratzeko dago oraindik. Honek denbora behar lezake. Zure eskaera onartzen bada e-mail bat jasoko duzu.
redirecting_to: Zure kontua ez dago aktibo orain %{acct} kontura birbideratzen duelako.
+ self_destruct: "%{domain} domeinua itxiko denez, konturako sarbide mugatua soilik izango duzu."
view_strikes: Ikusi zure kontuaren aurkako neurriak
too_fast: Formularioa azkarregi bidali duzu, saiatu berriro.
use_security_key: Erabili segurtasun gakoa
@@ -1561,6 +1566,9 @@ eu:
over_daily_limit: 'Egun horretarako programatutako bidalketa kopuruaren muga gainditu duzu: %{limit}'
over_total_limit: 'Programatutako bidalketa kopuruaren muga gainditu duzu: %{limit}'
too_soon: Programatutako data etorkizunean egon behar du
+ self_destruct:
+ lead_html: Zoritxarrez, %{domain} betirako itxiko da. Kontu bat baduzu bertan, ezin izango duzu erabiltzen jarraitu, baina, oraindik zure datuen babeskopia bat eska dezakezu.
+ title: Zerbitzari hau ixtear dago
sessions:
activity: Azken jarduera
browser: Nabigatzailea
@@ -1730,6 +1738,10 @@ eu:
month: "%Y(e)ko %b"
time: "%H:%M"
with_time_zone: "%Y(e)ko %b %d, %H:%M %Z"
+ translation:
+ errors:
+ quota_exceeded: Zerbitzari osoko itzulpen-zerbitzuaren erabileraren kuota gainditu da.
+ too_many_requests: Itzulpen-zerbitzurako eskaera gehiegi egon dira berriki.
two_factor_authentication:
add: Gehitu
disable: Desgaitu
diff --git a/config/locales/fi.yml b/config/locales/fi.yml
index 5403f224731740..c8c17b853a11ef 100644
--- a/config/locales/fi.yml
+++ b/config/locales/fi.yml
@@ -1,7 +1,7 @@
---
fi:
about:
- about_mastodon_html: 'Tulevaisuuden sosiaalinen verkosto: Ei mainoksia, ei valvontaa, toteutettu avoimilla protokollilla ja hajautettu! Pidä tietosi ominasi Mastodonilla!'
+ about_mastodon_html: 'Tulevaisuuden sosiaalinen verkosto: ei mainoksia, ei valvontaa, toteutettu avoimilla protokollilla ja hajautettu rakenne! Pidä tietosi ominasi Mastodonin avulla!'
contact_missing: Ei asetettu
contact_unavailable: Ei saatavilla
hosted_on: Mastodon palvelimella %{domain}
@@ -12,28 +12,28 @@ fi:
one: seuraaja
other: seuraajaa
following: seurattu(a)
- instance_actor_flash: Tämä on virtuaalitili, jota käytetään edustamaan itse palvelinta eikä yksittäistä käyttäjää. Sitä käytetään yhdistämistarkoituksiin, eikä sitä tule jäädyttää.
+ instance_actor_flash: Tämä tili on virtuaalinen toimija, jota käytetään edustamaan itse palvelinta eikä yksittäistä käyttäjää. Sitä käytetään liittoutumistarkoituksiin, eikä sitä tule jäädyttää.
last_active: viimeksi aktiivinen
link_verified_on: Tämän linkin omistus on tarkastettu %{date}
nothing_here: Täällä ei ole mitään!
pin_errors:
following: Sinun täytyy seurata henkilöä jota haluat tukea
posts:
- one: viesti
+ one: Julkaisu
other: viestiä
- posts_tab_heading: Viestit
+ posts_tab_heading: Julkaisut
admin:
account_actions:
action: Suorita toimenpide
- title: Suorita moderointitoiminto %{acct}
+ title: Suorita valvontatoimi käyttäjälle %{acct}
account_moderation_notes:
create: Jätä muistiinpano
- created_msg: Moderointimerkinnän luonti onnistui!
- destroyed_msg: Moderointimerkinnän poisto onnistui!
+ created_msg: Valvontamuistiinpanon luonti onnistui!
+ destroyed_msg: Valvontamuistiinpanon poisto onnistui!
accounts:
- add_email_domain_block: Estä sähköpostidomain
+ add_email_domain_block: Estä sähköpostiverkkotunnus
approve: Hyväksy
- approved_msg: Käyttäjän %{username} liittymishakemus hyväksyttiin
+ approved_msg: Käyttäjän %{username} rekisteröitymishakemus hyväksyttiin
are_you_sure: Oletko varma?
avatar: Profiilikuva
by_domain: Verkkotunnus
@@ -48,7 +48,7 @@ fi:
changed_msg: Rooli vaihdettu onnistuneesti!
label: Vaihda roolia
no_role: Ei roolia
- title: Vaihda roolia käyttäjälle %{username}
+ title: Vaihda käyttäjän %{username} roolia
confirm: Vahvista
confirmed: Vahvistettu
confirming: Vahvistetaan
@@ -61,7 +61,7 @@ fi:
disable_sign_in_token_auth: Poista sähköpostitunnuksen todennus käytöstä
disable_two_factor_authentication: Poista 2FA käytöstä
disabled: Poistettu käytöstä
- display_name: Nimimerkki
+ display_name: Näyttönimi
domain: Verkkotunnus
edit: Muokkaa
email: Sähköposti
@@ -71,12 +71,12 @@ fi:
enabled: Käytössä
enabled_msg: Käyttäjän %{username} tili palautettu onnistuneesti käyttöön
followers: Seuraajat
- follows: Seuraa
+ follows: Seuratut
header: Otsakekuva
inbox_url: Saapuvan postilaatikon osoite
invite_request_text: Syitä liittymiseen
invited_by: Kutsuja
- ip: IP
+ ip: IP-osoite
joined: Liittynyt
location:
all: Kaikki
@@ -94,17 +94,17 @@ fi:
disabled: Ei käytössä
pending: Odottavat
silenced: Rajoitettu
- suspended: Jäähyllä
- title: Moderointi
- moderation_notes: Moderointimerkinnät
+ suspended: Jäädytetty
+ title: Valvonta
+ moderation_notes: Valvontamuistiinpanot
most_recent_activity: Viimeisin toiminta
most_recent_ip: Viimeisin IP
- no_account_selected: Yhtään tiliä ei muutettu, koska mitään ei valittu
+ no_account_selected: Tilejä ei muutettu, koska yhtään ei ollut valittuna
no_limits_imposed: Rajoituksia ei ole asetettu
no_role_assigned: Roolia ei ole määritetty
not_subscribed: Ei tilaaja
pending: Odottaa tarkistusta
- perform_full_suspension: Siirrä kokonaan jäähylle
+ perform_full_suspension: Jäädytä
previous_strikes: Aiemmat varoitukset
previous_strikes_description_html:
one: Tällä tilillä on yksi varoitus.
@@ -118,7 +118,7 @@ fi:
reject: Hylkää
rejected_msg: Käyttäjän %{username} rekisteröitymishakemus hylättiin
remote_suspension_irreversible: Tämän tilin tiedot on poistettu peruuttamattomasti.
- remote_suspension_reversible_hint_html: Tili on jäädytetty heidän palvelimellaan, ja tilin kaikki tiedot poistetaan %{date}. Ennen tätä ajankohtaa on kyseessä olevan palvelimen ylläpidolla mahdollisuus palauttaa tili ongelmitta. Jos puolestaan haluat poistaa tilin tietoineen heti, onnistuu se alta.
+ remote_suspension_reversible_hint_html: Tili on jäädytetty omalla palvelimellaan, ja kaikki tiedot poistetaan %{date}. Sitä ennen etäpalvelin voi palauttaa tilin ongelmitta. Jos haluat poistaa kaikki tilin tiedot heti, onnistuu se alta.
remove_avatar: Poista profiilikuva
remove_header: Poista otsakekuva
removed_avatar_msg: Käyttäjän %{username} avatar-kuva poistettu onnistuneesti
@@ -138,36 +138,36 @@ fi:
security_measures:
only_password: Vain salasana
password_and_2fa: Salasana ja kaksivaiheinen tunnistautuminen
- sensitive: Pakotus arkaluonteiseksi
+ sensitive: Pakota arkaluonteiseksi
sensitized: Merkitty arkaluonteiseksi
shared_inbox_url: Jaetun saapuvan postilaatikon osoite
show:
created_reports: Tämän tilin luomat raportit
targeted_reports: Tästä tilistä tehdyt raportit
- silence: Hiljennä
- silenced: Mykistetty
- statuses: Viestit
+ silence: Rajoita
+ silenced: Rajoitettu
+ statuses: Julkaisut
strikes: Aiemmat varoitukset
subscribe: Tilaa
suspend: Jäädytä
- suspended: Jäähyllä
- suspension_irreversible: Tämän tilin tiedot on poistettu peruuttamattomasti. Voit peruuttaa tilin jäädyttämisen, jolloin siitä tulee käyttökelpoinen, mutta toiminto ei palauta sillä aiemmin olleita tietoja.
- suspension_reversible_hint_html: Tili on jäädytetty, ja tiedot poistetaan kokonaan %{date}. Siihen asti tili voidaan palauttaa ilman haitallisia vaikutuksia. Jos haluat poistaa kaikki tilin tiedot välittömästi, voit tehdä sen alla.
+ suspended: Jäädytetty
+ suspension_irreversible: Tämän tilin tiedot on poistettu peruuttamattomasti. Voit kumota tilin jäädytyksen, jolloin siitä tulee käyttökelpoinen, mutta toiminto ei palauta sillä aiemmin olleita tietoja.
+ suspension_reversible_hint_html: Tili on jäädytetty, ja tiedot poistetaan kokonaan %{date}. Siihen asti tili voidaan palauttaa ongelmitta. Jos haluat poistaa kaikki tilin tiedot heti, onnistuu se alta.
title: Tilit
unblock_email: Poista sähköpostiosoitteen esto
unblocked_email_msg: Käyttäjän %{username} sähköpostiosoitteen esto kumottiin
unconfirmed_email: Sähköpostia ei vahvistettu
- undo_sensitized: Kumoa pakotus arkaluonteiseksi tiliksi
- undo_silenced: Peru hiljennys
+ undo_sensitized: Kumoa pakotus arkaluonteiseksi
+ undo_silenced: Kumoa rajoitus
undo_suspension: Peru jäähy
unsilenced_msg: Tilin %{username} rajoituksen kumoaminen onnistui
unsubscribe: Lopeta tilaus
unsuspended_msg: Tilin %{username} jäädytyksen kumoaminen onnistui
- username: Käyttäjätunnus
+ username: Käyttäjänimi
view_domain: Näytä verkkotunnuksen yhteenveto
warn: Varoita
web: Verkko
- whitelisted: Sallittu federaatioon
+ whitelisted: Sallittu liittoutua
action_logs:
action_types:
approve_appeal: Hyväksy valitus
@@ -177,25 +177,25 @@ fi:
change_role_user: Muuta käyttäjän roolia
confirm_user: Vahvista käyttäjä
create_account_warning: Luo varoitus
- create_announcement: Luo ilmoitus
+ create_announcement: Luo tiedote
create_canonical_email_block: Luo sähköpostin esto
create_custom_emoji: Luo mukautettu emoji
create_domain_allow: Luo verkkotunnuksen salliminen
create_domain_block: Luo verkkotunnuksen esto
- create_email_domain_block: Luo sähköpostin verkkotunnuksen esto
+ create_email_domain_block: Luo sähköpostiverkkotunnuksen esto
create_ip_block: Luo IP-sääntö
create_unavailable_domain: Luo ei-saatavilla oleva verkkotunnus
create_user_role: Luo rooli
demote_user: Alenna käyttäjä
- destroy_announcement: Poista ilmoitus
+ destroy_announcement: Poista tiedote
destroy_canonical_email_block: Poista sähköpostin esto
destroy_custom_emoji: Poista mukautettu emoji
destroy_domain_allow: Poista verkkotunnuksen salliminen
destroy_domain_block: Poista verkkotunnuksen esto
- destroy_email_domain_block: Poista sähköpostin verkkotunnuksen esto
+ destroy_email_domain_block: Poista sähköpostiverkkotunnuksen esto
destroy_instance: Tyhjennä verkkotunnus
destroy_ip_block: Poista IP-sääntö
- destroy_status: Poista viesti
+ destroy_status: Poista julkaisu
destroy_unavailable_domain: Poista ei-saatavilla oleva verkkotunnus
destroy_user_role: Hävitä rooli
disable_2fa_user: Poista kaksivaiheinen tunnistautuminen käytöstä
@@ -214,78 +214,78 @@ fi:
resend_user: Lähetä vahvistusviesti uudelleen
reset_password_user: Nollaa salasana
resolve_report: Selvitä raportti
- sensitive_account: Pakotus arkaluontoiseksi tiliksi
- silence_account: Hiljennä tili
+ sensitive_account: Pakotus arkaluonteiseksi tiliksi
+ silence_account: Rajoita tiliä
suspend_account: Jäädytä tili
unassigned_report: Peruuta raportin määritys
unblock_email_account: Poista sähköpostiosoitteen esto
- unsensitive_account: Kumoa pakotus arkaluontoiseksi tiliksi
- unsilence_account: Peruuta tilin rajoitus
- unsuspend_account: Peruuta tilin jäädytys
- update_announcement: Päivitä ilmoitus
- update_custom_emoji: Päivitä muokattu emoji
+ unsensitive_account: Kumoa pakotus arkaluonteiseksi tiliksi
+ unsilence_account: Kumoa tilin rajoitus
+ unsuspend_account: Kumoa tilin jäädytys
+ update_announcement: Päivitä tiedote
+ update_custom_emoji: Päivitä mukautettu emoji
update_domain_block: Päivitä verkkotunnuksen esto
update_ip_block: Päivitä IP-sääntö
- update_status: Päivitä viesti
+ update_status: Päivitä julkaisu
update_user_role: Päivitä rooli
actions:
- approve_appeal_html: "%{name} hyväksyi moderointipäätöksen muutoksenhaun lähettäjältä %{target}"
+ approve_appeal_html: "%{name} hyväksyi valvontapäätöksen valituksen käyttäjältä %{target}"
approve_user_html: "%{name} hyväksyi käyttäjän rekisteröitymisen kohteesta %{target}"
assigned_to_self_report_html: "%{name} otti raportin %{target} tehtäväkseen"
change_email_user_html: "%{name} vaihtoi käyttäjän %{target} sähköpostiosoitteen"
change_role_user_html: "%{name} muutti käyttäjän %{target} roolia"
confirm_user_html: "%{name} vahvisti käyttäjän %{target} sähköpostiosoitteen"
create_account_warning_html: "%{name} lähetti varoituksen käyttäjälle %{target}"
- create_announcement_html: "%{name} loi uuden ilmoituksen %{target}"
- create_canonical_email_block_html: "%{name} esti sähköpostin hashilla %{target}"
+ create_announcement_html: "%{name} loi uuden tiedotteen %{target}"
+ create_canonical_email_block_html: "%{name} esti sähköpostin tiivisteellä %{target}"
create_custom_emoji_html: "%{name} lähetti uuden emojin %{target}"
- create_domain_allow_html: "%{name} salli federaation verkkotunnuksella %{target}"
+ create_domain_allow_html: "%{name} salli liittoutumisen verkkotunnuksen %{target} kanssa"
create_domain_block_html: "%{name} esti verkkotunnuksen %{target}"
- create_email_domain_block_html: "%{name} esti sähköpostin %{target}"
+ create_email_domain_block_html: "%{name} esti sähköpostiverkkotunnuksen %{target}"
create_ip_block_html: "%{name} loi IP-säännön %{target}"
create_unavailable_domain_html: "%{name} pysäytti toimituksen verkkotunnukseen %{target}"
create_user_role_html: "%{name} loi roolin %{target}"
demote_user_html: "%{name} alensi käyttäjän %{target}"
- destroy_announcement_html: "%{name} poisti ilmoituksen %{target}"
- destroy_canonical_email_block_html: "%{name} poisti sähköpostieston hashilla %{target}"
+ destroy_announcement_html: "%{name} poisti tiedotteen %{target}"
+ destroy_canonical_email_block_html: "%{name} poisti sähköpostin eston tiivisteellä %{target}"
destroy_custom_emoji_html: "%{name} poisti emojin %{target}"
- destroy_domain_allow_html: "%{name} esti federaation verkkotunnuksella %{target}"
+ destroy_domain_allow_html: "%{name} kielsi liittoutumisen verkkotunnuksen %{target} kanssa"
destroy_domain_block_html: "%{name} poisti verkkotunnuksen %{target} eston"
- destroy_email_domain_block_html: "%{name} poisti sähköpostin verkkotunnuksen %{target} eston"
+ destroy_email_domain_block_html: "%{name} poisti sähköpostiverkkotunnuksen %{target} eston"
destroy_instance_html: "%{name} tyhjensi verkkotunnuksen %{target}"
destroy_ip_block_html: "%{name} poisti IP-säännön %{target}"
- destroy_status_html: "%{name} poisti käyttäjän %{target} viestin"
+ destroy_status_html: "%{name} poisti käyttäjän %{target} julkaisun"
destroy_unavailable_domain_html: "%{name} jatkoi toimitusta verkkotunnukseen %{target}"
destroy_user_role_html: "%{name} poisti roolin %{target}"
disable_2fa_user_html: "%{name} poisti käyttäjältä %{target} vaatimuksen kaksivaiheisen todentamiseen"
disable_custom_emoji_html: "%{name} poisti käytöstä emojin %{target}"
disable_sign_in_token_auth_user_html: "%{name} poisti sähköpostitunnuksen %{target} todennuksen käytöstä"
disable_user_html: "%{name} poisti kirjautumisen käyttäjältä %{target}"
- enable_custom_emoji_html: "%{name} salli emojin %{target}"
- enable_sign_in_token_auth_user_html: "%{name} aktivoi sähköpostitunnuksen käyttäjälle %{target}"
- enable_user_html: "%{name} salli kirjautumisen käyttäjälle %{target}"
+ enable_custom_emoji_html: "%{name} otti käyttöön emojin %{target}"
+ enable_sign_in_token_auth_user_html: "%{name} otti todennuksen sähköpostivaltuutuksella käyttöön käyttäjälle %{target}"
+ enable_user_html: "%{name} otti kirjautumisen käyttöön käyttäjälle %{target}"
memorialize_account_html: "%{name} muutti käyttäjän %{target} tilin muistosivuksi"
promote_user_html: "%{name} ylensi käyttäjän %{target}"
- reject_appeal_html: "%{name} hylkäsi moderointipäätöksen muutoksenhaun %{target}"
+ reject_appeal_html: "%{name} hylkäsi valvontapäätöksen valituksen käyttäjältä %{target}"
reject_user_html: "%{name} hylkäsi käyttäjän rekisteröitymisen kohteesta %{target}"
remove_avatar_user_html: "%{name} poisti käyttäjän %{target} profiilikuvan"
reopen_report_html: "%{name} avasi uudelleen raportin %{target}"
- resend_user_html: "%{name} lähetti vahvistusviestin sähköpostitse käyttäjälle %{target}"
+ resend_user_html: "%{name} lähetti vahvistussähköpostiviestin uudelleen käyttäjälle %{target}"
reset_password_user_html: "%{name} palautti käyttäjän %{target} salasanan"
resolve_report_html: "%{name} ratkaisi raportin %{target}"
sensitive_account_html: "%{name} merkitsi käyttäjän %{target} median arkaluonteiseksi"
- silence_account_html: "%{name} rajoitti käyttäjän %{target} tilin"
- suspend_account_html: "%{name} siirsi käyttäjän %{target} jäähylle"
+ silence_account_html: "%{name} rajoitti käyttäjän %{target} tiliä"
+ suspend_account_html: "%{name} jäädytti käyttäjän %{target} tilin"
unassigned_report_html: "%{name} peruutti raportin määrityksen %{target}"
unblock_email_account_html: "%{name} poisti käyttäjän %{target} sähköpostiosoitteen eston"
- unsensitive_account_html: "%{name} poisti käyttäjän %{target} median arkaluonteisen merkinnän"
- unsilence_account_html: "%{name} ei tehnyt rajoitusta %{target} tilille"
- unsuspend_account_html: "%{name} perui käyttäjän %{target} jäähyn"
- update_announcement_html: "%{name} päivitti ilmoituksen %{target}"
+ unsensitive_account_html: "%{name} kumosi käyttäjän %{target} median arkaluonteisuusmerkinnän"
+ unsilence_account_html: "%{name} kumosi käyttäjän %{target} rajoituksen"
+ unsuspend_account_html: "%{name} kumosi käyttäjän %{target} tilin jäädytyksen"
+ update_announcement_html: "%{name} päivitti tiedotteen %{target}"
update_custom_emoji_html: "%{name} päivitti emojin %{target}"
update_domain_block_html: "%{name} päivitti verkkotunnuksen %{target} eston"
update_ip_block_html: "%{name} muutti sääntöä IP-osoitteelle %{target}"
- update_status_html: "%{name} päivitti viestin %{target}"
+ update_status_html: "%{name} päivitti käyttäjän %{target} julkaisun"
update_user_role_html: "%{name} muutti roolia %{target}"
deleted_account: poisti tilin
empty: Lokeja ei löytynyt.
@@ -293,46 +293,46 @@ fi:
filter_by_user: Suodata käyttäjän mukaan
title: Auditointiloki
announcements:
- destroyed_msg: Ilmoitus poistettu onnistuneesti!
+ destroyed_msg: Tiedote poistettu onnistuneesti!
edit:
- title: Muokkaa ilmoitusta
- empty: Yhtään ilmoitusta ei löytynyt.
- live: Suora
+ title: Muokkaa tiedotetta
+ empty: Tiedotteita ei löytynyt.
+ live: Julki
new:
- create: Luo ilmoitus
- title: Uusi ilmoitus
+ create: Luo tiedote
+ title: Uusi tiedote
publish: Julkaise
- published_msg: Ilmoitus julkaistu onnistuneesti!
- scheduled_for: Ajastettu %{time}
- scheduled_msg: Ilmoitus on ajastettu julkaisua varten!
- title: Ilmoitukset
+ published_msg: Tiedote julkaistu onnistuneesti!
+ scheduled_for: Ajoitettu %{time}
+ scheduled_msg: Tiedotteen julkaisu ajoitettu!
+ title: Tiedotteet
unpublish: Lopeta julkaisu
- unpublished_msg: Ilmoituksen julkaisu lopetettu!
- updated_msg: Ilmoitus päivitetty onnistuneesti!
+ unpublished_msg: Tiedotteen julkaisu lopetettu onnistuneesti!
+ updated_msg: Tiedote päivitetty onnistuneesti!
critical_update_pending: Kriittinen päivitys odottaa
custom_emojis:
- assign_category: Aseta kategoria
+ assign_category: Aseta luokka
by_domain: Verkkotunnus
copied_msg: Emojin paikallisen kopion luonti onnistui
copy: Kopioi
copy_failed_msg: Emojista ei voitu tehdä paikallista kopiota
- create_new_category: Luo uusi kategoria
- created_msg: Emojin luotu!
+ create_new_category: Luo uusi luokka
+ created_msg: Emojin luonti onnistui!
delete: Poista
- destroyed_msg: Emojo poistettu!
+ destroyed_msg: Emojon poisto onnistui!
disable: Poista käytöstä
disabled: Ei käytössä
- disabled_msg: Emojin poisto käytöstä onnistui
+ disabled_msg: Emojin käytöstäpoisto onnistui
emoji: Emoji
enable: Ota käyttöön
enabled: Käytössä
enabled_msg: Emojin käyttöönotto onnistui
image_hint: PNG tai GIF, enintään %{size}
- list: Listaa
- listed: Listassa
+ list: Lisää listalle
+ listed: Listalla
new:
title: Lisää uusi mukautettu emoji
- no_emoji_selected: Emojeita ei muutettu, koska yhtään ei valittu
+ no_emoji_selected: Emojeita ei muutettu, koska yhtään ei ollut valittuna
not_permitted: Sinulla ei ole oikeutta suorittaa tätä toimintoa
overwrite: Korvaa
shortcode: Lyhennekoodi
@@ -340,7 +340,7 @@ fi:
title: Mukautetut emojit
uncategorized: Luokittelemattomat
unlist: Poista listalta
- unlisted: Ei listassa
+ unlisted: Ei listalla
update_failed_msg: Emojin päivitys epäonnistui
updated_msg: Emojin päivitys onnistui!
upload: Lähetä
@@ -349,86 +349,86 @@ fi:
interactions: vuorovaikutukset
media_storage: Median tallennustila
new_users: uudet käyttäjät
- opened_reports: raportit avattu
+ opened_reports: avatut raportit
pending_appeals_html:
one: "%{count} vireillä oleva valitus"
- other: "%{count} vireillä olevat valitukset"
+ other: "%{count} vireillä olevaa valitusta"
pending_reports_html:
one: "%{count} odottava raportti"
- other: "%{count} odottavat raportit"
+ other: "%{count} odottavaa raporttia"
pending_tags_html:
- one: "%{count} odottava hashtagi"
+ one: "%{count} odottava aihetunniste"
other: "%{count} odottavaa aihetunnistetta"
pending_users_html:
one: "%{count} odottava käyttäjä"
- other: "%{count} odottavat käyttäjät"
- resolved_reports: raportit ratkaistu
+ other: "%{count} odottavaa käyttäjää"
+ resolved_reports: ratkaistut raportit
software: Ohjelmisto
- sources: Rekisteröitymisen lähteet
+ sources: Rekisteröitymislähteet
space: Tilankäyttö
title: Hallintapaneeli
- top_languages: Aktiiviset kielet
- top_servers: Aktiiviset palvelimet
+ top_languages: Aktiivisimmat kielet
+ top_servers: Aktiivisimmat palvelimet
website: Sivusto
disputes:
appeals:
empty: Valituksia ei löytynyt.
title: Valitukset
domain_allows:
- add_new: Salli liitto verkkotunnuksella
- created_msg: Verkkotunnus on onnistuneesti sallittu federaatiolle
- destroyed_msg: Verkkotunnus on estetty federaatiossa
+ add_new: Salli liittoutuminen tämän verkkotunnuksen kanssa
+ created_msg: Verkkotunnuksen on onnistuneesti sallittu liittoutua
+ destroyed_msg: Verkkotunnusta on kielletty liittoutumasta
export: Vie
import: Tuo
- undo: Estä liitto verkkotunnukselle
+ undo: Kiellä liittoutuminen tämän verkkotunnuksen kanssa
domain_blocks:
- add_new: Lisää uusi
+ add_new: Lisää uusi verkkotunnuksen esto
confirm_suspension:
cancel: Peruuta
confirm: Jäädytä
permanent_action: Jäädytyksen kumoaminen ei palauta mitään tietoja tai suhteita.
preamble_html: Olet jäädyttämässä verkkotunnuksen %{domain} ja sen aliverkkotunnukset.
remove_all_data: Tämä toiminto poistaa palvelimeltasi kaiken sisällön, median ja profiilitiedot tämän palvelun tileiltä.
- stop_communication: Palvelimesi lopettaa näiden palvelinten viestinnän.
+ stop_communication: Palvelimesi lopettaa viestinnän näiden palvelinten kanssa.
title: Vahvista verkkotunnuksen %{domain} esto
undo_relationships: Tämä kumoaa näiden palvelimien ja sinun tilien välisen seurannan.
created_msg: Verkkotunnuksen estoa käsitellään
destroyed_msg: Verkkotunnuksen esto on peruttu
domain: Verkkotunnus
edit: Muokkaa verkkotunnuksen estoa
- existing_domain_block: Olet jo asettanut tiukemmat rajoitukset %{name}.
- existing_domain_block_html: Olet jo asettanut %{name} tiukemmat rajat ja sinun täytyy poistaa se ensin.
+ existing_domain_block: Olet jo asettanut tiukemmat rajoitukset käyttäjälle %{name}.
+ existing_domain_block_html: Olet jo asettanut tiukemmat rajoitukset käyttäjälle %{name}, joten sinun täytyy poistaa sen esto ensin.
export: Vie
import: Tuo
new:
create: Luo esto
- hint: Verkkotunnuksen esto ei estä tilien luomista ja lisäämistä tietokantaan, mutta se soveltaa näihin tileihin automaattisesti määrättyjä moderointitoimia tilin luomisen jälkeen.
+ hint: Verkkotunnuksen esto ei estä tilien lisäämistä tietokantaan, mutta se soveltaa näihin tileihin takautuvasti ja automaattisesti tiettyjä valvontatoimia.
severity:
- desc_html: "Rajoita -valinta piilottaa tämän verkkoalueen tilien julkaisut heiltä, jotka eivät seuraa kyseisiä tilejä. Lopeta poistaa kaiken sisällön, median ja profiilien tiedot tämän verkkotunnuksen tileiltä palvelimellasi. Käytä valintaa Ei mitään, jos haluat vain estää mediatiedostojen julkaisemisen."
+ desc_html: Valinta Rajoita piilottaa tässä verkkotunnuksessa sijaitsevien tilien julkaisut kaikilta, jotka eivät seuraa näitä tilejä. Valinta Jäädytä poistaa palvelimeltasi kaikkien tässä verkkotunnuksessa sijaitsevien tilien sisällön, median ja profiilitiedot. Käytä valintaa Ei mitään, jos haluat vain hylätä mediatiedostot.
noop: Ei mitään
silence: Rajoita
- suspend: Jäähy
+ suspend: Jäädytä
title: Uusi verkkotunnuksen esto
- no_domain_block_selected: Verkkoalue-estoihin ei tehty muutoksia, koska valintoja ei tehty
+ no_domain_block_selected: Verkkotunnusten estoja ei muutettu, koska yhtään ei ollut valittuna
not_permitted: Nykyiset käyttöoikeutesi eivät kata tätä toimintoa
obfuscate: Peitä verkkotunnuksen nimi
- obfuscate_hint: Peitä verkkotunnus osittain luettelossa, jos verkkotunnuksen rajoitusten luettelo on käytössä
+ obfuscate_hint: Peitä verkkotunnus osittain luettelossa, jos julkinen verkkotunnusten rajoitusluettelo on käytössä
private_comment: Yksityinen kommentti
private_comment_hint: Kommentoi tätä verkkotunnuksen rajoitusta, valvojien sisäiseen käyttöön.
public_comment: Julkinen kommentti
- public_comment_hint: Kommentoi tätä verkkotunnukselle koskevaa rajoitusta suurelle yleisölle, jos verkkotunnusten luettelon mainonta on käytössä.
+ public_comment_hint: Kommentoi tätä verkkotunnuksen rajoitusta suurelle yleisölle, jos julkinen verkkotunnusten rajoitusluettelo on käytössä.
reject_media: Hylkää mediatiedostot
reject_media_hint: Poistaa paikallisesti tallennetut mediatiedostot eikä lataa niitä enää jatkossa. Ei merkitystä jäähyn kohdalla
reject_reports: Hylkää raportit
reject_reports_hint: Ohita kaikki tästä verkkotunnuksesta tulevat raportit. Erottamisen kannalta ei merkitystä
- undo: Peru
+ undo: Peru verkkotunnuksen esto
view: Näytä verkkotunnuksen esto
email_domain_blocks:
add_new: Lisää uusi
attempts_over_week:
one: "%{count} yritystä viimeisen viikon aikana"
other: "%{count} rekisteröitymisyritystä viimeisen viikon aikana"
- created_msg: Sähköpostiverkkotunnuksen lisäys estolistalle onnistui
+ created_msg: Sähköpostiverkkotunnus estetty onnistuneesti
delete: Poista
dns:
types:
@@ -437,35 +437,35 @@ fi:
new:
create: Lisää verkkotunnus
resolve: Ratkaise verkkotunnus
- title: Uusi sähköpostiestolistan merkintä
- no_email_domain_block_selected: Sähköpostin verkkotunnuksia ei muutettu, koska yhtään ei valittu
+ title: Estä uusi sähköpostiverkkotunnus
+ no_email_domain_block_selected: Sähköpostin verkkotunnuksia ei muutettu, koska yhtään ei ollut valittuna
not_permitted: Ei sallittu
- resolved_dns_records_hint_html: Verkkotunnuksen nimi määräytyy seuraaviin MX-verkkotunnuksiin, jotka ovat viime kädessä vastuussa sähköpostin vastaanottamisesta. MX-verkkotunnuksen estäminen estää kirjautumisen mistä tahansa sähköpostiosoitteesta, joka käyttää samaa MX-verkkotunnusta, vaikka näkyvä verkkotunnuksen nimi olisikin erilainen. Varo estämästä suuria sähköpostin palveluntarjoajia.
+ resolved_dns_records_hint_html: Verkkotunnuksen nimi määräytyy seuraaviin MX-verkkotunnuksiin, jotka ovat viime kädessä vastuussa sähköpostin vastaanottamisesta. MX-verkkotunnuksen estäminen estää rekisteröitymisen mistä tahansa sähköpostiosoitteesta, joka käyttää samaa MX-verkkotunnusta, vaikka näkyvä verkkotunnuksen nimi olisikin erilainen. Varo estämästä suuria sähköpostin palveluntarjoajia.
resolved_through_html: Ratkaistu %{domain} kautta
- title: Sähköpostiestolista
+ title: Estetyt sähköpostiverkkotunnukset
export_domain_allows:
new:
- title: Tuo sallitut verkkoalueet
+ title: Tuo sallittuja verkkotunnuksia
no_file: Yhtäkään tiedostoa ei ole valittu
export_domain_blocks:
import:
- description_html: Olet tuomassa järjestelmään luetteloa verkkoalue-estoista. Tarkista luettelo huolella – etenkin, ellet ole itse tehnyt listausta.
+ description_html: Olet tuomassa verkkotunnusten estoluetteloa. Tarkista luettelo huolella – etenkin, jos et ole laatinut sitä itse.
existing_relationships_warning: Olemassa olevat seuraussuhteet
- private_comment_description_html: 'Tuodun estolistan alkuperän selvillä pitämiseksi, lisätään tietojen yhteyteen seuraava yksityinen kommentti: %{comment}
'
- private_comment_template: Tuotu lähteestä %{source}, pvm %{date}
- title: Tuo luettelo verkkoalue-estoista
- invalid_domain_block: 'Yksi tai useampi verkkotunnuksen lohko ohitettiin seuraavien virheiden vuoksi: %{error}'
+ private_comment_description_html: 'Seurataksesi tuotujen estojen alkuperää lisätään estojen yhteyteen seuraava yksityinen kommentti: %{comment}
'
+ private_comment_template: Tuotu lähteestä %{source} %{date}
+ title: Tuo verkkotunnusten estoja
+ invalid_domain_block: 'Yksi tai useampi verkkotunnuksen esto ohitettiin seuraavien virheiden vuoksi: %{error}'
new:
- title: Tuo luettelo verkkoalue-estoista
+ title: Tuo verkkotunnusten estoja
no_file: Yhtäkään tiedostoa ei ole valittu
follow_recommendations:
- description_html: "Suositusten noudattaminen auttaa uusia käyttäjiä löytämään nopeasti mielenkiintoista sisältöä.. Jos käyttäjä ei ole ollut vuorovaikutuksessa tarpeeksi muiden kanssa luodakseen henkilökohtaisia seuraajia, näitä muita tilejä suositellaan sen sijaan. Ne lasketaan uudelleen päivittäin yhdistelmästä tilejä, joilla on korkein viimeaikainen käyttö ja korkein paikallinen seuraajien määrä tietyllä kielellä."
+ description_html: "Seuraamissuositukset auttavat uusia käyttäjiä löytämään nopeasti kiinnostavaa sisältöä. Kun käyttäjä ei ole ollut tarpeeksi vuorovaikutuksessa muiden kanssa, jotta hänelle olisi muodostunut henkilökohtaisia seuraamissuosituksia, suositellaan niiden sijaan näitä tilejä. Ne lasketaan päivittäin uudelleen yhdistelmästä tilejä, jotka ovat viime aikoina olleet aktiivisimmin sitoutuneita ja joilla on suurimmat paikalliset seuraajamäärät tietyllä kielellä."
language: Kielelle
status: Tila
- suppress: Peitä noudata suosituksia
- suppressed: Rajoitettu
- title: Noudata suosituksia
- unsuppress: Palauta seuraa suositus
+ suppress: Hylkää seuraamissuositus
+ suppressed: Hylätty
+ title: Seuraamissuositukset
+ unsuppress: Palauta seuraamissuositus
instances:
availability:
description_html:
@@ -482,15 +482,15 @@ fi:
back_to_limited: Rajoitettu
back_to_warning: Varoitus
by_domain: Verkkotunnus
- confirm_purge: Oletko varma, että haluat pysyvästi poistaa tiedot tältä verkkotunnukselta?
+ confirm_purge: Haluatko varmasti poistaa pysyvästi tämän verkkotunnuksen tiedot?
content_policies:
- comment: Sisäinen huomautus
+ comment: Sisäinen muistiinpano
description_html: Voit määrittää sisältökäytännöt, joita sovelletaan kaikkiin tämän verkkotunnuksen ja sen aliverkkotunnuksien tileihin.
limited_federation_mode_description_html: Voit valita sallitaanko federointi tällä verkkotunnuksella.
policies:
reject_media: Hylkää media
reject_reports: Hylkää raportit
- silence: Rajoitus
+ silence: Rajoita
suspend: Jäädytä
policy: Käytännöt
reason: Julkinen syy
@@ -503,7 +503,7 @@ fi:
instance_languages_dimension: Suosituimmat kielet
instance_media_attachments_measure: tallennetut median liitteet
instance_reports_measure: niitä koskevat raportit
- instance_statuses_measure: tallennetut viestit
+ instance_statuses_measure: tallennetut julkaisut
delivery:
all: Kaikki
clear: Tyhjennä toimitusvirheet
@@ -522,18 +522,19 @@ fi:
moderation:
all: Kaikki
limited: Rajoitettu
- title: Moderointi
+ title: Valvonta
private_comment: Yksityinen kommentti
public_comment: Julkinen kommentti
purge: Tyhjennä
- purge_description_html: Jos uskot tämän verkkotunnuksen olevan offline-tilassa, voit poistaa kaikki tilitietueet ja niihin liittyvät tiedot sinun tallennustilasta. Tämä voi kestää jonkin aikaa.
- title: Tiedossa olevat instanssit
- total_blocked_by_us: Estetty meidän toimesta
+ purge_description_html: Jos uskot, että tämä verkkotunnus on offline-tilassa tarkoituksella, voit poistaa kaikki verkkotunnuksen tilitietueet ja niihin liittyvät tiedot tallennustilastasi. Tämä voi kestää jonkin aikaa.
+ title: Liittoutuminen
+ total_blocked_by_us: Estämämme
total_followed_by_them: Heidän seuraama
total_followed_by_us: Meidän seuraama
total_reported: Niitä koskevat raportit
total_storage: Medialiitteet
totals_time_period_hint_html: Alla näkyvät yhteenlasketut tiedot sisältävät koko ajan.
+ unknown_instance: Tällä palvelimella ei ole tällä hetkellä tähän verkkotunnukseen liittyviä tietueita.
invites:
deactivate_all: Poista kaikki käytöstä
filter:
@@ -555,18 +556,18 @@ fi:
'94670856': 3 vuotta
new:
title: Luo uusi IP-sääntö
- no_ip_block_selected: IP-sääntöjä ei muutettu, koska yhtään ei ole valittuna
+ no_ip_block_selected: IP-sääntöjä ei muutettu, koska yhtään ei ollut valittuna
title: IP-säännöt
relationships:
title: "%{acct}n suhteet"
relays:
add_new: Lisää uusi välittäjä
delete: Poista
- description_html: "federaatiovälittäjä on välityspalvelin, joka siirtää siihen liittyneiden palvelimien välillä suuria julksia viestimääriä. Tämä voi auttaa pieniä ja keskikokoisia palvelimia löytämään fediversen sisältöä, joka muutoin vaatisi paikallisia käyttäjiä seuraamaan etäpalvelimien käyttäjiä manuaalisesti."
+ description_html: "Liittoutumisvälittäjä on välityspalvelin, joka siirtää suuria määriä julkisia julkaisuja siihen liittyneiden palvelinten välillä. Se voi auttaa pieniä ja keskisuuria palvelimia löytämään fediversumin sisältöä, mikä muutoin vaatisi paikallisia käyttäjiä seuraamaan etäpalvalinten käyttäjiä manuaalisesti."
disable: Poista käytöstä
- disabled: Ei käytössä
+ disabled: Poissa käytöstä
enable: Ota käyttöön
- enable_hint: Kun tämä on otettu käyttöön, palvelimesi liittyy välittäjään ja vastaanottaa jatkossa kaikki sen jakelemat julkiset julkaisut sekä välittää omat julkiset julkaisunsa sille.
+ enable_hint: Kun tämä on otettu käyttöön, palvelimesi tilaa välittäjältä kaikki sen välittämät julkiset julkaisut ja alkaa lähettää omansa sille.
enabled: Käytössä
inbox_url: Välittäjän URL
pending: Odotetaan välittäjän hyväksyntää
@@ -576,23 +577,23 @@ fi:
status: Tila
title: Välittäjät
report_notes:
- created_msg: Muistiinpano onnistuneesti lisätty raporttiin!
- destroyed_msg: Muistiinpano onnistuneesti poistettu raportista!
+ created_msg: Muistiinpano lisätty raporttiin onnistuneesti!
+ destroyed_msg: Muistiinpano poistettu raportista onnistuneesti!
reports:
account:
notes:
- one: "%{count} ilmoitus"
- other: "%{count} ilmoitusta"
+ one: "%{count} muistiinpano"
+ other: "%{count} muistiinpanoa"
action_log: Tarkastusloki
- action_taken_by: Toimenpiteen tekijä
+ action_taken_by: Toimen tehnyt
actions:
- delete_description_html: Ilmoitetut viestit poistetaan ja kirjataan varoitus, joka auttaa sinua saman tilin tulevista rikkomuksista.
- mark_as_sensitive_description_html: Ilmoitettujen viestien media merkitään arkaluonteisiksi ja varoitus tallennetaan, jotta voit kärjistää saman tilin tulevia rikkomuksia.
- other_description_html: Katso lisää vaihtoehtoja tilin käytöksen hallitsemiseksi ja ilmoitetun tilin viestinnän mukauttamiseksi.
- resolve_description_html: Ilmoitettua tiliä vastaan ei ryhdytä toimenpiteisiin, varoitusta ei kirjata ja raportti suljetaan.
- silence_description_html: Tili näkyy vain niille, jotka jo seuraavat sitä tai estävät sen manuaalisesti, mikä rajoittaa merkittävästi sen kattavuutta. Se voidaan aina palauttaa. Sulkee kaikki raportit tätä tiliä vastaan.
- suspend_description_html: Tili ja kaikki sen sisältö eivät ole käytettävissä ja vuorovaikutus sen kanssa on mahdotonta, sekä lopulta poistetaan. Palautettava 30 päivän kuluessa. Sulkee kaikki raportit tätä tiliä vastaan.
- actions_description_html: Päätä, mihin toimiin ryhdyt tämän ilmoituksen ratkaisemiseksi. Jos ryhdyt rangaistustoimeen ilmoitettua tiliä vastaan, heille lähetetään sähköposti-ilmoitus, paitsi jos Roskaposti luokka on valittuna.
+ delete_description_html: Raportoidut julkaisut poistetaan ja kirjataan varoitus, joka auttaa suhtautumaan vakavammin saman tilin tuleviin rikkomuksiin.
+ mark_as_sensitive_description_html: Raportoitujen julkaisujen media merkitään arkaluonteiseksi ja kirjataan varoitus, joka auttaa suhtautumaan vakavammin saman tilin tuleviin rikkomuksiin.
+ other_description_html: Katso lisää vaihtoehtoja tilin käytöksen hallitsemiseksi ja raportoidulle tilille kohdistuvan viestinnän mukauttamiseksi.
+ resolve_description_html: Ilmoitettua tiliä kohtaan ei ryhdytä toimiin, varoitusta ei kirjata ja raportti suljetaan.
+ silence_description_html: Tili näkyy vain niille, jotka jo seuraavat sitä tai etsivät sen manuaalisesti, mikä rajoittaa merkittävästi sen tavoitettavuutta. Voidaan perua milloin vain. Sulkee kaikki tilin vastaiset raportit.
+ suspend_description_html: Tili ja mikään sen sisältö eivät ole käytettävissä, ja lopulta ne poistetaan, ja vuorovaikutus tilin kanssa on mahdotonta. Peruttavissa 30 päivän ajan. Sulkee kaikki tämän tilin vastaiset raportit.
+ actions_description_html: Päätä, mihin toimiin ryhdyt tämän raportin ratkaisemiseksi. Jos ryhdyt rangaistustoimeen ilmoitettua tiliä kohtaan, hänelle lähetetään sähköposti-ilmoitus, paitsi jos Roskaposti-luokka on valittuna.
actions_description_remote_html: Päätä, mihin toimiin ryhdyt tämän raportin ratkaisemiseksi. Tämä vaikuttaa vain siihen, miten palvelimesi kommunikoi tämän etätilin kanssa ja käsittelee sen sisältöä.
add_to_report: Lisää raporttiin
are_you_sure: Oletko varma?
@@ -600,15 +601,15 @@ fi:
assigned: Määritetty valvoja
by_target_domain: Ilmoitetun tilin verkkotunnus
cancel: Peruuta
- category: Kategoria
- category_description_html: Syy, miksi tämä tili ja/tai sisältö ilmoitettiin, mainitaan yhteydenotossa ilmoitettuun tiliin
+ category: Luokka
+ category_description_html: Syy siihen, miksi tämä tili ja/tai sisältö raportoitiin, mainitaan ilmoitetun tilin kanssa viestiessä
comment:
none: Ei mitään
comment_description_html: 'Antaakseen lisätietoja %{name} kirjoitti:'
confirm: Vahvista
- confirm_action: Vahvista moderointitoiminto käyttäjää @%{acct} kohtaan
+ confirm_action: Vahvista valvontatoimi käyttäjää @%{acct} kohtaan
created_at: Raportoitu
- delete_and_resolve: Poista viestejä
+ delete_and_resolve: Poista julkaisut
forwarded: Välitetty
forwarded_to: Välitetty %{domain}
mark_as_resolved: Merkitse ratkaistuksi
@@ -621,8 +622,8 @@ fi:
create_and_unresolve: Avaa uudelleen ja lisää muistiinpano
delete: Poista
placeholder: Kuvaile mitä toimia on tehty tai muita päivityksiä tähän raporttiin…
- title: Merkinnät
- notes_description_html: Tarkastele ja jätä merkintöjä muille valvojille ja itsellesi tulevaisuuteen
+ title: Muistiinpanot
+ notes_description_html: Tarkastele ja jätä muistiinpanoja muille valvojille ja itsellesi tulevaisuuteen
processed_msg: 'Raportti #%{id} käsitelty'
quick_actions_description_html: 'Suorita nopea toiminto tai vieritä alas nähdäksesi raportoitu sisältö:'
remote_user_placeholder: etäkäyttäjä instanssista %{instance}
@@ -638,22 +639,22 @@ fi:
statuses_description_html: Loukkaava sisältö mainitaan ilmoitetun tilin yhteydessä
summary:
action_preambles:
- delete_html: 'Olet aikeissa poistaa joitain käyttäjän @%{acct} viestejä. Tästä seuraa:'
- mark_as_sensitive_html: 'Olet aikeissa merkitä joitain käyttäjän @%{acct} viestejä arkaluonteisiksi. Tästä seuraa:'
+ delete_html: 'Olet aikeissa poistaa käyttäjän @%{acct} julkaisuja. Tästä seuraa:'
+ mark_as_sensitive_html: 'Olet aikeissa merkitä käyttäjän @%{acct} julkaisuja arkaluonteisiksi. Tästä seuraa:'
silence_html: 'Olet aikeissa rajoittaa käyttäjän @%{acct} tiliä. Tästä seuraa:'
- suspend_html: 'Olet aikeissa rajoittaa käyttäjän @%{acct} tiliä. Tästä seuraa:'
+ suspend_html: 'Olet aikeissa jäädyttää käyttäjän @%{acct} tilin. Tästä seuraa:'
actions:
- delete_html: Loukkaavat viestit poistetaan
- mark_as_sensitive_html: Loukkaavien viestien media merkitään arkaluonteiseksi
- silence_html: Vakavasti rajoittaa käyttäjän @%{acct} tavoitettavuutta tekemällä profiilista ja sen sisällöstä näkyviä vain jo häntä seuraaville tai niille, jotka etsivät profiilia manuaalisesti
- suspend_html: Rajoita @%{acct}, jolloin heidän profiilinsa ja sisällönsä ei ole käytettävissä ja on mahdotonta olla vuorovaikutuksessa
+ delete_html: Poista loukkaavat julkaisut
+ mark_as_sensitive_html: Merkitse loukkaavien julkaisujen media arkaluonteiseksi
+ silence_html: Rajoita merkittävästi käyttäjän @%{acct} tavoitettavuutta tekemällä profiilista ja sen sisällöstä näkyviä vain niille, jotka jo seuraavat tiliä tai etsivät sen manuaalisesti
+ suspend_html: Jäädytä @%{acct}, jolloin hänen profiilinsa ja sisältönsä ei ole käytettävissä ja hänen kanssaan on mahdotonta olla vuorovaikutuksessa
close_report: 'Merkitse raportti #%{id} selvitetyksi'
close_reports_html: Merkitse kaikki käyttäjään @%{acct} kohdistuvat raportit ratkaistuiksi
- delete_data_html: Poista @%{acct}profiili ja sisältö 30 päivän kuluttua, ellei jäädytystä tällä välin peruuteta
+ delete_data_html: Poista käyttäjän @%{acct} profiili ja sen sisältö 30 päivän kuluttua, ellei jäädytystä sillä välin kumota
preview_preamble_html: "@%{acct} saa varoituksen, jonka sisältö on seuraava:"
record_strike_html: Tallenna varoitus @%{acct} vastaan, joka auttaa sinua selvittämään tulevia rikkomuksia tältä tililtä
send_email_html: Lähetä käyttäjälle @%{acct} varoitus sähköpostitse
- warning_placeholder: Valinnaiset lisäperustelut moderointitoimenpiteelle.
+ warning_placeholder: Valinnaiset lisäperustelut valvontatoimelle.
target_origin: Raportoidun tilin alkuperä
title: Raportit
unassign: Määrittämätön
@@ -670,76 +671,76 @@ fi:
administration: Ylläpito
devops: DevOps
invites: Kutsut
- moderation: Moderointi
- special: Erikois
+ moderation: Valvonta
+ special: Erityistä
delete: Poista
- description_html: Käyttäjän roolit, voit muokata toimintoja ja alueita mitä sinun Mastodon käyttäjät voivat käyttää.
- edit: Muokkaa "%{name}" roolia
- everyone: Oletus käyttöoikeudet
- everyone_full_description_html: Tämä on perusrooli joka vaikuttaa kaikkiin käyttäjiin, jopa ilman määrättyä roolia. Kaikki muut roolit perivät sen käyttöoikeudet.
+ description_html: "Käyttäjärooleilla voit muokata, mihin toimintoihin ja alueisiin käyttäjäsi pääsevät käsiksi."
+ edit: Muokkaa roolia ”%{name}”
+ everyone: Oletuskäyttöoikeudet
+ everyone_full_description_html: Tämä on perusrooli, joka vaikuttaa kaikkiin käyttäjiin, jopa ilman määrättyä roolia. Kaikki muut roolit perivät sen käyttöoikeudet.
permissions_count:
one: "%{count} käyttöoikeus"
other: "%{count} käyttöoikeutta"
privileges:
administrator: Ylläpitäjä
administrator_description: Käyttäjät, joilla on tämä käyttöoikeus, ohittavat jokaisen käyttöoikeuden
- delete_user_data: Poista käyttäjän tiedot
+ delete_user_data: Poistaa käyttäjän tiedot
delete_user_data_description: Salli käyttäjien poistaa muiden käyttäjien tiedot viipymättä
- invite_users: Kutsu käyttäjiä
+ invite_users: Kutsua käyttäjiä
invite_users_description: Sallii käyttäjien kutsua uusia ihmisiä palvelimelle
- manage_announcements: Hallitse Ilmoituksia
- manage_announcements_description: Salli käyttäjien hallita ilmoituksia palvelimella
- manage_appeals: Hallitse valituksia
- manage_appeals_description: Antaa käyttäjien tarkastella valvontatoimia koskevia valituksia
- manage_blocks: Hallitse lohkoja
- manage_blocks_description: Sallii käyttäjien estää sähköpostipalvelujen ja IP-osoitteiden käytön
- manage_custom_emojis: Hallita mukautettuja hymiöitä
- manage_custom_emojis_description: Salli käyttäjien hallita mukautettuja hymiöitä palvelimella
- manage_federation: Hallita liitoksia
- manage_federation_description: Sallii käyttäjien estää tai sallia liitoksen muiden verkkotunnusten kanssa ja hallita toimitusta
+ manage_announcements: Hallita tiedotteita
+ manage_announcements_description: Sallii käyttäjien hallita tiedotteita palvelimella
+ manage_appeals: Hallita valituksia
+ manage_appeals_description: Sallii käyttäjien tarkistaa valvontatoimia koskevia valituksia
+ manage_blocks: Hallita estoja
+ manage_blocks_description: Sallii käyttäjien estää sähköpostipalveluntarjoajia ja IP-osoitteita
+ manage_custom_emojis: Hallita mukautettuja emojeita
+ manage_custom_emojis_description: Sallii käyttäjien hallita mukautettuja emojeita palvelimella
+ manage_federation: Hallita liittoutumista
+ manage_federation_description: Sallii käyttäjien estää tai sallia liittoutuminen muiden verkkotunnusten kanssa ja hallita toimitusta
manage_invites: Hallita kutsuja
manage_invites_description: Sallii käyttäjien selata ja poistaa kutsulinkkejä käytöstä
manage_reports: Hallita raportteja
- manage_reports_description: Sallii käyttäjien tarkastella raportteja ja suorittaa valvontatoimia niitä vastaan
+ manage_reports_description: Sallii käyttäjien tarkistaa raportteja ja suorittaa valvontatoimia niitä vastaan
manage_roles: Hallita rooleja
manage_roles_description: Sallii käyttäjien hallita ja määrittää rooleja heidän alapuolellaan
manage_rules: Hallita sääntöjä
- manage_rules_description: Sallii käyttäjien vaihtaa palvelinsääntöjä
+ manage_rules_description: Sallii käyttäjien muuttaa palvelimen sääntöjä
manage_settings: Hallita asetuksia
- manage_settings_description: Salli käyttäjien muuttaa sivuston asetuksia
+ manage_settings_description: Sallii käyttäjien muuttaa sivuston asetuksia
manage_taxonomies: Hallita luokittelua
- manage_taxonomies_description: Sallii käyttäjien tarkistaa nousussa olevan sisällön ja päivittää aihetunnisteiden asetuksia
- manage_user_access: Hallita käyttäjän oikeuksia
- manage_user_access_description: Sallii käyttäjien poistaa käytöstä muiden käyttäjien kaksivaiheisen todennuksen, muuttaa heidän sähköpostiosoitettaan ja nollata heidän salasanansa
+ manage_taxonomies_description: Sallii käyttäjien tarkistaa suositun sisällön ja päivittää aihetunnisteiden asetuksia
+ manage_user_access: Hallita käyttäjäoikeuksia
+ manage_user_access_description: Sallii käyttäjien poistaa muiden käyttäjien kaksivaiheinen todennus käytöstä, vaihtaa heidän sähköpostiosoitteensa ja nollata heidän salasanansa
manage_users: Hallita käyttäjiä
- manage_users_description: Sallii käyttäjien tarkastella muiden käyttäjien tietoja ja suorittaa valvontatoimia heitä vastaan
- manage_webhooks: Hallita Webhookit
- manage_webhooks_description: Sallii käyttäjien luoda webhookit hallinnollisiin tapahtumiin
+ manage_users_description: Sallii käyttäjien tarkastella muiden käyttäjien tietoja ja suorittaa valvontatoimia heitä kohtaan
+ manage_webhooks: Hallita webhookeja
+ manage_webhooks_description: Sallii käyttäjien luoda webhookeja hallinnollisiin tapahtumiin
view_audit_log: Katsoa valvontalokia
view_audit_log_description: Sallii käyttäjien nähdä palvelimen hallinnollisten toimien historian
- view_dashboard: Näytä koontinäyttö
+ view_dashboard: Katsoa koontinäyttöä
view_dashboard_description: Sallii käyttäjien käyttää kojelautaa ja erilaisia mittareita
view_devops: DevOps
- view_devops_description: Sallii käyttäjille oikeuden käyttää Sidekiq ja pgHero dashboardeja
+ view_devops_description: Sallii käyttäjille pääsyn Sidekiq- ja pgHero-hallintapaneeleihin
title: Roolit
rules:
add_new: Lisää sääntö
delete: Poista
- description_html: Vaikka useimmat väittävät, että ovat lukenut ja hyväksyneet käyttöehdot niin yleensä ihmiset eivät lue niitä läpi ennen kuin ongelma syntyy. Tee helpoksi nähdä palvelimen säännöt yhdellä silmäyksellä tarjoamalla ne tiiviissä luettelossa. Yritä pitää säännöt lyhyinä ja yksinkertaisina, mutta yritä olla jakamatta niitä moniin erillisiin kohteisiin.
+ description_html: Vaikka useimmat väittävät, että ovat lukeneet ja hyväksyneet käyttöehdot, niin yleensä ihmiset eivät lue niitä läpi ennen kuin ilmenee ongelma. Helpota palvelimen sääntöjen näkemistä yhdellä silmäyksellä tarjoamalla ne tiiviissä luettelossa. Yritä pitää säännöt lyhyinä ja yksinkertaisina, mutta yritä olla jakamatta niitä useisiin erillisiin kohtiin.
edit: Muokkaa sääntöä
empty: Palvelimen sääntöjä ei ole vielä määritelty.
title: Palvelimen säännöt
settings:
about:
- manage_rules: Hallinnoi palvelimen sääntöjä
- preamble: Anna perusteellista tietoa siitä, miten palvelinta käytetään, valvotaan, rahoitetaan.
+ manage_rules: Hallitse palvelimen sääntöjä
+ preamble: Anna perusteellista tietoa siitä, miten palvelinta käytetään, valvotaan ja rahoitetaan.
rules_hint: On olemassa erityinen alue sääntöjä, joita käyttäjien odotetaan noudattavan.
title: Tietoja
appearance:
- preamble: Muokkaa Mastodonin web-käyttöliittymää.
+ preamble: Mukauta Mastodonin selainkäyttöliittymää.
title: Ulkoasu
branding:
- preamble: Palvelimesi brändäys erottaa sen muista verkon palvelimista. Nämä tiedot voidaan näyttää useissa eri ympäristöissä, kuten Mastodonin käyttöliittymässä, sovelluksissa, linkkien esikatselu muilla sivustoilla ja viestisovelluksien sisällä ja niin edelleen. Tästä syystä on parasta pitää nämä tiedot selkeinä, lyhyinä ja ytimekkäinä.
+ preamble: Palvelimesi brändäys erottaa sen muista verkon palvelimista. Nämä tiedot voivat näkyä monissa eri ympäristöissä, kuten Mastodonin selainkäyttöliittymässä, natiivisovelluksissa, linkkien esikatseluissa muilla sivustoilla, viestintäsovelluksissa ja niin edelleen. Siksi nämä tiedot kannattaa pitää selkeinä, lyhyinä ja ytimekkäinä.
title: Brändäys
captcha_enabled:
desc_html: Tämä perustuu ulkoisiin skripteihin hCaptchasta, mikä voi olla turvallisuus- ja yksityisyysongelma. Lisäksi tämä voi tehdä rekisteröinnin ihmisille huomattavasti (erityisesti vammaisten) helpommaksi. Harkitse vaihtoehtoisia toimenpiteitä, kuten hyväksymisperusteista tai kutsupohjaista rekisteröintiä.
@@ -751,8 +752,8 @@ fi:
desc_html: Vaikuttaa kaikkiin käyttäjiin, jotka eivät ole muuttaneet tätä asetusta itse
title: Jätä käyttäjät oletusarvoisesti hakukoneindeksoinnin ulkopuolelle
discovery:
- follow_recommendations: Noudata suosituksia
- preamble: Mielenkiintoisen sisällön esille tuominen auttaa saamaan uusia käyttäjiä, jotka eivät ehkä tunne ketään Mastodonista. Määrittele, kuinka erilaiset etsintäominaisuudet toimivat palvelimellasi.
+ follow_recommendations: Seuraamissuositukset
+ preamble: Mielenkiintoisen sisällön esille tuominen auttaa saamaan uusia käyttäjiä, jotka eivät ehkä tunne ketään Mastodonista. Määrittele, kuinka erilaiset löytämisominaisuudet toimivat palvelimellasi.
profile_directory: Profiilihakemisto
public_timelines: Julkiset aikajanat
publish_discovered_servers: Julkaise löydetyt palvelimet
@@ -765,17 +766,17 @@ fi:
users: Kirjautuneille paikallisille käyttäjille
registrations:
preamble: Määritä, kuka voi luoda tilin palvelimellesi.
- title: Rekisteröinnit
+ title: Rekisteröityminen
registrations_mode:
modes:
approved: Rekisteröinti vaatii hyväksynnän
none: Kukaan ei voi rekisteröityä
open: Kaikki voivat rekisteröityä
security:
- authorized_fetch: Vaadi todennus yhdistetyiltä palvelimilta
- authorized_fetch_hint: Todennuksen vaatiminen yhdistetyiltä palvelimilta mahdollistaa sekä käyttäjätason että palvelintason alueiden tiukemmat estot. Tämä tapahtuu kuitenkin suorituskyvyn kustannuksella, vähentää vastauksien ulottuvuutta ja voi luoda yhteensopivuusongelmia joidenkin yhdistettyjen palveluiden kanssa. Lisäksi, tämä ei myöskään estä muita toimijoita hakemasta julkisia viestejäsi ja tilejäsi.
+ authorized_fetch: Vaadi todennus liittoutuvilta palvelimilta
+ authorized_fetch_hint: Todennuksen vaatiminen liittoutuvilta palvelimilta mahdollistaa sekä käyttäjä- että palvelintason estojen tiukemman valvonnan. Tämä tapahtuu kuitenkin suorituskyvyn kustannuksella, vähentää vastauksiesi tavoittavuutta ja voi aiheuttaa yhteensopivuusongelmia joidenkin liittoutuvien palvelujen kanssa. Tämä ei myöskään estä omistautuneita toimijoita hakemasta julkisia julkaisujasi ja tilejäsi.
authorized_fetch_overridden_hint: Et voi tällä hetkellä muuttaa tätä asetusta, koska se on ohitettu ympäristömuuttujalla.
- federation_authentication: Yhdistettyjen palvelinten todentamisen täytäntöönpano
+ federation_authentication: Liittoutumisen todentamisen täytäntöönpano
title: Palvelimen asetukset
site_uploads:
delete: Poista ladattu tiedosto
@@ -808,23 +809,23 @@ fi:
media:
title: Media
metadata: Metadata
- no_status_selected: Viestejä ei muutettu, koska yhtään ei ole valittuna
- open: Avaa viesti
- original_status: Alkuperäinen viesti
+ no_status_selected: Julkaisuja ei muutettu, koska yhtään ei ollut valittuna
+ open: Avaa julkaisu
+ original_status: Alkuperäinen julkaisu
reblogs: Edelleen jako
- status_changed: Viesti muutettu
+ status_changed: Julkaisua muutettu
title: Tilin tilat
- trending: Nousussa
+ trending: Suosituttua
visibility: Näkyvyys
with_media: Sisältää mediaa
strikes:
actions:
- delete_statuses: "%{name} poisti käyttäjän %{target} viestit"
+ delete_statuses: "%{name} poisti käyttäjän %{target} julkaisut"
disable: "%{name} jäädytti %{target} tilin"
- mark_statuses_as_sensitive: "%{name} merkitsi käyttäjän %{target} viestit arkaluonteisiksi"
+ mark_statuses_as_sensitive: "%{name} merkitsi käyttäjän %{target} julkaisut arkaluonteisiksi"
none: "%{name} lähetti varoituksen henkilölle %{target}"
sensitive: "%{name} merkitsi käyttäjän %{target} tilin arkaluonteiseksi"
- silence: "%{name} rajoitti käyttäjän %{target} tilin"
+ silence: "%{name} rajoitti käyttäjän %{target} tiliä"
suspend: "%{name} jäädytti käyttäjän %{target} tilin"
appeal_approved: Valitti
appeal_pending: Valitus vireillä
@@ -833,7 +834,7 @@ fi:
database_schema_check:
message_html: Tietokannan siirto on vireillä. Suorita ne varmistaaksesi, että sovellus toimii odotetulla tavalla
elasticsearch_health_red:
- message_html: Elasticsearch-klusteri on vikatilassa (punainen tila); hakuominaisuudet eivät ole käytettävissä
+ message_html: Elasticsearch-klusteri on vikatilassa (punainen tila), joten hakuominaisuudet eivät ole käytettävissä
elasticsearch_health_yellow:
message_html: Elasticsearch-klusteri on häiriötilassa (keltainen tila), joten suosittelemme tutkimaan syyn
elasticsearch_index_mismatch:
@@ -843,17 +844,17 @@ fi:
message_html: Elasticsearch-klusterissa on useampi kuin yksi solmu, mutta Mastodonia ei ole määritetty käyttämään niitä.
elasticsearch_preset_single_node:
action: Katso käyttöohjeet
- message_html: Elasticsearch-klusterissa on vain yksi solmu, ES_PRESET
tulisi asettaa arvoon single_node_cluster
.
+ message_html: Elasticsearch-klusterissa on vain yksi solmu. ES_PRESET
tulisi asettaa arvoon single_node_cluster
.
elasticsearch_reset_chewy:
message_html: Elasticsearch-järjestelmäindeksi on vanhentunut asetusmuutoksen vuoksi. Suorita tootctl search deploy --reset-chewy
päivittääksesi sen.
elasticsearch_running_check:
- message_html: Ei saatu yhteyttä Elasticsearch. Tarkista, että se on käynnissä tai poista kokotekstihaku käytöstä
+ message_html: Ei saatu yhteyttä Elasticsearchiin. Tarkista, että se on käynnissä tai poista kokotekstihaku käytöstä
elasticsearch_version_check:
- message_html: 'Yhteensopimaton Elasticsearch versio: %{value}'
+ message_html: 'Yhteensopimaton Elasticsearch-versio: %{value}'
version_comparison: Elasticsearch %{running_version} on käynnissä, kun %{required_version} vaaditaan
rules_check:
- action: Hallinnoi palvelimen sääntöjä
- message_html: Et ole määrittänyt mitään palvelimen sääntöä.
+ action: Hallitse palvelimen sääntöjä
+ message_html: Et ole määrittänyt lainkaan palvelimen sääntöjä.
sidekiq_process_check:
message_html: Ei ole Sidekiq-prosessia käynnissä jonossa %{value}. Tarkista Sidekiq-asetukset
software_version_critical_check:
@@ -864,7 +865,7 @@ fi:
message_html: Mastodonin virhekorjauspäivitys on saatavilla.
upload_check_privacy_error:
action: Katso täältä lisätietoja
- message_html: "Verkkopalvelimesi on määritetty virheellisesti, ja käyttäjiesi yksityisyys on vaarassa."
+ message_html: "Verkkopalvelimesi on määritetty väärin. Käyttäjiesi yksityisyys on vaarassa."
upload_check_privacy_error_object_storage:
action: Katso täältä lisätietoja
message_html: "Objektivarastosi on määritetty virheellisesti, ja käyttäjiesi yksityisyys on vaarassa."
@@ -882,9 +883,9 @@ fi:
description_html: Nämä ovat linkkejä, joita jaetaan tällä hetkellä paljon tileillä, joilta palvelimesi näkee viestejä. Se voi auttaa käyttäjiäsi saamaan selville, mitä maailmassa tapahtuu. Linkkejä ei näytetä julkisesti, ennen kuin hyväksyt julkaisijan. Voit myös sallia tai hylätä yksittäiset linkit.
disallow: Hylkää linkki
disallow_provider: Estä julkaisija
- no_link_selected: Yhtään linkkiä ei muutettu, koska yhtään ei valittu
+ no_link_selected: Linkkejä ei muutettu, koska yhtään ei ollut valittuna
publishers:
- no_publisher_selected: Julkaisijoita ei muutettu, koska yhtään ei valittu
+ no_publisher_selected: Julkaisijoita ei muutettu, koska yhtään ei ollut valittuna
shared_by_over_week:
one: Yksi henkilö jakanut viimeisen viikon aikana
other: Jakanut %{count} henkilöä viimeisen viikon aikana
@@ -900,17 +901,17 @@ fi:
title: Julkaisijat
rejected: Hylätty
statuses:
- allow: Salli viesti
+ allow: Salli julkaisu
allow_account: Salli tekijä
- description_html: Nämä ovat viestejä, jotka palvelimesi tietää tällä hetkellä jaetuksi ja suosituksi. Tämä voi auttaa uusia ja palaavia ihmisiä löytämään lisää ihmisiä, joita seurata seurata. Julkaisuja ei näytetä julkisesti ennen kuin hyväksyt tekijän ja kirjoittaja sallii tilinsä ehdottamisen muille. Voit myös sallia tai hylätä yksittäiset viestit.
- disallow: Estä viesti
+ description_html: Nämä ovat julkaisuja, joita palvelimesi tietää jaettavan ja lisättävän suosikkeihin paljon tällä hetkellä. Listaus voi auttaa uusia ja palaavia käyttäjiäsi löytämään lisää seurattavia. Julkaisut eivät näy julkisesti ennen kuin hyväksyt niiden julkaisijan ja julkaisija sallii tilinsä ehdottamisen. Voit myös sallia tai hylätä yksittäisiä julkaisuja.
+ disallow: Kiellä julkaisu
disallow_account: Estä tekijä
- no_status_selected: Suosittuja viestejä ei muutettu, koska yhtään ei valittu
+ no_status_selected: Suosittuja julkaisuja ei muutettu, koska yhtään ei ollut valittuna
not_discoverable: Tekijä ei ole ilmoittanut olevansa löydettävissä
shared_by:
- one: Jaettu tai merkitty suosikiksi kerran
+ one: Jaettu tai lisätty suosikkeihin kerran
other: Jaettu tai merkitty suosikiksi %{friendly_count} kertaa
- title: Suositut viestit
+ title: Suositut julkaisut
tags:
current_score: Nykyinen tulos %{score}
dashboard:
@@ -921,35 +922,35 @@ fi:
tag_uses_measure: käyttökerrat
description_html: Nämä ovat aihetunnisteita, jotka näkyvät tällä hetkellä monissa julkaisuissa, jotka palvelimesi näkee. Tämä voi auttaa käyttäjiäsi selvittämään, mistä ihmiset puhuvat eniten tällä hetkellä. Mitään aihetunnisteita ei näytetä julkisesti, ennen kuin hyväksyt ne.
listable: Voidaan ehdottaa
- no_tag_selected: Yhtään tagia ei muutettu, koska yhtään ei valittu
+ no_tag_selected: Tunnisteita ei muutettu, koska yhtään ei ollut valittuna
not_listable: Ei tulla ehdottamaan
not_trendable: Ei näy trendien alla
not_usable: Ei voida käyttää
peaked_on_and_decaying: Saavutti huipun %{date}, nyt hiipuu
title: Suositut aihetunnisteet
trendable: Voi näkyä trendien alla
- trending_rank: 'Nousussa #%{rank}'
+ trending_rank: 'Suosittua #%{rank}'
usable: Voidaan käyttää
usage_comparison: Käytetty %{today} kertaa tänään, verrattuna %{yesterday} eiliseen
used_by_over_week:
one: Yhden henkilön käyttämä viime viikon aikana
other: Käyttänyt %{count} henkilöä viimeisen viikon aikana
title: Trendit
- trending: Nousussa
+ trending: Suosittua
warning_presets:
add_new: Lisää uusi
delete: Poista
edit_preset: Muokkaa varoituksen esiasetusta
empty: Et ole vielä määrittänyt yhtäkään varoitusten esiasetusta.
- title: Hallinnoi varoitusten esiasetuksia
+ title: Hallitse varoitusten esiasetuksia
webhooks:
add_new: Lisää päätepiste
delete: Poista
- description_html: "Webhook mahdollistaa Mastodonin työntää reaaliaikaisia ilmoituksia valituista tapahtumista omaan sovellukseesi, joten sovelluksesi voi laukaista automaattisesti reaktioita."
+ description_html: "Webhookin avulla Mastodon voi puskea sovellukseesi reaaliaikaisia ilmoituksia valituista tapahtumista, jotta sovelluksesi voi laukaista reaktioita automaattisesti."
disable: Poista käytöstä
- disabled: Ei käytössä
+ disabled: Pois käytöstä
edit: Muokkaa päätepistettä
- empty: Sinulla ei ole vielä määritetty webhook-päätepisteitä.
+ empty: Et ole vielä määrittänyt webhook-päätepisteitä.
enable: Ota käyttöön
enabled: Aktiivinen
enabled_events:
@@ -965,16 +966,16 @@ fi:
admin_mailer:
new_appeal:
actions:
- delete_statuses: poistaa heidän viestit
+ delete_statuses: poistaa hänen julkaisunsa
disable: jäädyttää heidän tilinsä
- mark_statuses_as_sensitive: merkitä heidän viestinsä arkaluonteisiksi
+ mark_statuses_as_sensitive: merkitä hänen julkaisunsa arkaluonteisiksi
none: varoitus
sensitive: merkitä heidän tilinsä arkaluonteiseksi
- silence: rajoittaa heidän tilinsä
- suspend: jäädyttää heidän tilinsä
- body: "%{target} on valittanut valvojan päätöksestä %{action_taken_by} aika %{date}, joka oli %{type}. He kirjoittivat:"
- next_steps: Voit hyväksyä vetoomuksen ja kumota päätöksen tai jättää sen huomiotta.
- subject: "%{username} valittaa valvojan päätöksestä, joka koskee instanssia %{instance}"
+ silence: rajoittaa hänen tiliään
+ suspend: jäädyttää hänen tilinsä
+ body: "%{target} valittaa valvojan %{action_taken_by} päätöksestä %{date}, joka oli %{type}. Hän kirjoitti:"
+ next_steps: Voit hyväksyä valituksen, jolloin valvontapäätös kumoutuu, tai sivuuttaa sen.
+ subject: "%{username} valittaa valvontapäätöksestä, joka koskee instanssia %{instance}"
new_critical_software_updates:
body: Mastodonin uusia kriittisen tärkeitä versioita on julkaistu, joten saatat haluta päivittää niin pian kuin mahdollista!
subject: Kriittisiä Mastodon-päivityksiä on saatavilla instanssille %{instance}!
@@ -983,7 +984,7 @@ fi:
subject: Uusi tili tarkastettavana instanssissa %{instance} (%{username})
new_report:
body: "%{reporter} on raportoinut kohteen %{target}"
- body_remote: Joku osoitteesta %{domain} on raportoinut kohteen %{target}
+ body_remote: Joku palvelimelta %{domain} raportoi käyttäjän %{target}
subject: Uusi raportti instanssista %{instance} (nro %{id})
new_software_updates:
body: Uusia Mastodon-versioita on julkaistu, joten saatat haluta päivittää!
@@ -993,10 +994,10 @@ fi:
new_trending_links:
title: Suositut linkit
new_trending_statuses:
- title: Suositut viestit
+ title: Suositut julkaisut
new_trending_tags:
- no_approved_tags: Tällä hetkellä ei ole hyväksyttyjä trendikkäitä aihetunnisteita.
- requirements: 'Mikä tahansa näistä ehdokkaista voisi ylittää #%{rank} hyväksytyn trendikkään aihetunnisteen, joka on tällä hetkellä #%{lowest_tag_name} arvosanalla %{lowest_tag_score}.'
+ no_approved_tags: Tällä hetkellä ei ole hyväksyttyjä suosittuja aihetunnisteita.
+ requirements: 'Mikä tahansa näistä ehdokkaista voisi ylittää #%{rank} hyväksytyn suositun aihetunnisteen, joka on tällä hetkellä #%{lowest_tag_name} %{lowest_tag_score} pisteellä.'
title: Suositut aihetunnisteet
subject: Uusia trendejä tarkistettavaksi instanssissa %{instance}
aliases:
@@ -1004,14 +1005,14 @@ fi:
created_msg: Uusi alias luotiin onnistuneesti. Voit nyt aloittaa siirron vanhasta tilistä.
deleted_msg: Alias poistettiin onnistuneesti. Siirtyminen tuolta tililtä tähän ei ole enää mahdollista.
empty: Sinulla ei ole aliaksia.
- hint_html: Jos haluat siirtyä toisesta tilistä tähän tiliin, voit luoda aliasin, joka on pakollinen, ennen kuin voit siirtää seuraajia vanhasta tilistä tähän tiliin. Tämä toiminto on itsessään vaaraton ja palautuva. Tilin siirtyminen aloitetaan vanhalta tililtä.
+ hint_html: Jos haluat muuttaa toiselta tililtä tälle tilille, voit luoda tässä aliaksen, mitä vaaditaan ennen kuin voit edetä siirtämään seuraajat vanhalta tililtä tälle tilille. Tänä toiminto on itsessään vaaraton ja kumottavissa. Tilin muuttaminen aloitetaan vanhalta tililtä.
remove: Poista aliaksen linkitys
appearance:
advanced_web_interface: Edistynyt selainkäyttöliittymä
- advanced_web_interface_hint: 'Jos haluat käyttää koko näytön leveyttä, edistyneen web-käyttöliittymän avulla voit määrittää useita eri sarakkeita näyttämään niin paljon tietoa samanaikaisesti kuin haluat: Koti, ilmoitukset, yhdistetty aikajana, mikä tahansa määrä luetteloita ja aihetunnisteita.'
+ advanced_web_interface_hint: 'Jos haluat hyödyntää näytön koko leveyttä, edistyneen selainkäyttöliittymän avulla voit määrittää useita erilaisia sarakkeita, niin näet kerralla niin paljon tietoa kuin haluat: kotisyöte, ilmoitukset, yleinen aikajana, mikä tahansa määrä listoja ja aihetunnisteita.'
animations_and_accessibility: Animaatiot ja saavutettavuus
confirmation_dialogs: Vahvistusvalinnat
- discovery: Löydöt
+ discovery: Löytäminen
localization:
body: Mastodonin ovat kääntäneet vapaaehtoiset.
guide_link: https://crowdin.com/project/mastodon
@@ -1042,7 +1043,7 @@ fi:
confirmations:
wrong_email_hint: Jos sähköpostiosoite ei ole oikein, voit muuttaa sen tilin asetuksista.
delete_account: Poista tili
- delete_account_html: Jos haluat poistaa tilisi, paina tästä. Poisto on vahvistettava.
+ delete_account_html: Jos haluat poistaa tilisi, voit edetä tästä. Sinua pyydetään vahvistamaan poisto.
description:
prefix_invited_by_user: "@%{name} kutsuu sinut liittymään tälle Mastodonin palvelimelle!"
prefix_sign_up: Liity Mastodoniin tänään!
@@ -1051,13 +1052,13 @@ fi:
dont_have_your_security_key: Eikö sinulla ole suojausavainta?
forgot_password: Unohditko salasanasi?
invalid_reset_password_token: Salasanan palautustunnus on virheellinen tai vanhentunut. Pyydä uusi.
- link_to_otp: Syötä puhelimesi kaksivaiheinen koodi tai palautuskoodi
+ link_to_otp: Syötä puhelimesi kaksivaiheisen todennuksen koodi tai palautuskoodi
link_to_webauth: Käytä suojausavaintasi
log_in_with: Kirjaudu käyttäen
login: Kirjaudu sisään
logout: Kirjaudu ulos
migrate_account: Muuta toiseen tiliin
- migrate_account_html: Jos haluat ohjata tämän tilin toiseen tiliin, voit asettaa toisen tilin tästä.
+ migrate_account_html: Jos haluat ohjata tämän tilin toiseen, voit asettaa toisen tilin tästä.
or_log_in_with: Tai käytä kirjautumiseen
privacy_policy_agreement_html: Olen lukenut ja hyväksynyt tietosuojakäytännön
progress:
@@ -1076,8 +1077,8 @@ fi:
accept: Hyväksy
back: Takaisin
invited_by: 'Seuraavalta käyttäjältä vastaanottamasi kutsun ansiosta voit liittyä palvelimelle %{domain}:'
- preamble: "%{domain} valvojat määrittävät ja valvovat sääntöjä."
- preamble_invited: Ennen kuin jatkat, huomioi palvelimen %{domain} valvojien asettamat perussäännöt.
+ preamble: Palvelimen %{domain} valvojat määrittävät ja valvovat sääntöjä.
+ preamble_invited: Ennen kuin jatkat, ota huomioon palvelimen %{domain} valvojien asettamat perussäännöt.
title: Joitakin perussääntöjä.
title_invited: Sinut on kutsuttu.
security: Tunnukset
@@ -1086,21 +1087,22 @@ fi:
email_below_hint_html: Tarkista roskapostikansiosi tai pyydä uusi viesti. Voit korjata sähköpostiosoitteesi, jos se oli väärin.
email_settings_hint_html: Napsauta lähettämäämme linkkiä vahvistaaksesi osoitteen %{email}. Odotamme täällä.
link_not_received: Etkö saanut linkkiä?
- new_confirmation_instructions_sent: Saat uuden vahvistuslinkin sisältävän sähköpostiviestin muutaman minuutin sisällä!
- title: Tarkista saamasi viestit
+ new_confirmation_instructions_sent: Saat uuden vahvistuslinkin sisältävän sähköpostiviestin muutamassa minuutissa!
+ title: Tarkista sähköpostilaatikkosi
sign_in:
- preamble_html: Kirjaudu %{domain}-tunnuksellasi. Jos tilisi sijaitsee eri palvelimella, et voi kirjautua täällä.
+ preamble_html: Kirjaudu %{domain}-tunnuksellasi. Jos tilisi sijaitsee eri palvelimella, et voi kirjautua tässä.
title: Kirjaudu palvelimelle %{domain}
sign_up:
- manual_review: Palvelimen %{domain} ylläpito tarkastaa rekisteröitymiset käsin. Helpottaaksesi rekisteröitymisesi käsittelyä, kerro hieman itsestäsi ja miksi haluat luoda käyttäjätilin palvelimelle %{domain}.
+ manual_review: Palvelimen %{domain} valvojat tarkistavat rekisteröitymiset käsin. Helpottaaksesi rekisteröitymisesi käsittelyä kerro hieman itsestäsi ja miksi haluat luoda käyttäjätilin palvelimelle %{domain}.
preamble: Kun sinulla on tili tällä Mastodon-palvelimella, voit seurata kaikkia muita verkossa olevia henkilöitä riippumatta siitä, missä heidän tilinsä on.
title: Otetaan sinulle käyttöön %{domain}.
status:
account_status: Tilin tila
confirming: Odotetaan sähköpostivahvistuksen valmistumista.
functional: Tilisi on täysin toiminnassa.
- pending: Hakemuksesi odottaa henkilökuntamme tarkastusta. Tämä voi kestää jonkin aikaa. Saat sähköpostiviestin, jos hakemuksesi on hyväksytty.
- redirecting_to: Tilisi ei ole aktiivinen, koska se ohjaa tällä hetkellä kohteeseen %{acct}.
+ pending: Hakemuksesi odottaa henkilökuntamme tarkastusta. Tämä voi kestää jonkin aikaa. Saat sähköpostiviestin, jos hakemuksesi hyväksytään.
+ redirecting_to: Tilisi ei ole aktiivinen, koska se ohjaa tällä hetkellä tilille %{acct}.
+ self_destruct: Koska %{domain} sulkeutuu, voit käyttää tiliäsi vain rajoitetusti.
view_strikes: Näytä tiliäsi koskevia aiempia varoituksia
too_fast: Lomake lähetettiin liian nopeasti, yritä uudelleen.
use_security_key: Käytä suojausavainta
@@ -1138,9 +1140,9 @@ fi:
proceed: Poista tili
success_msg: Tilin poisto onnistui
warning:
- before: 'Ennen kuin jatkat, lue nämä huomautukset huolellisesti:'
+ before: 'Ennen kuin etenet, lue nämä huomautukset huolellisesti:'
caches: Muiden palvelimien välimuistiin tallentamaa sisältöä voi vielä löytyä
- data_removal: Viestit ja muut tiedot poistetaan pysyvästi
+ data_removal: Julkaisusi ja muut tietosi poistetaan pysyvästi
email_change_html: Voit muuttaa sähköpostiosoitettasi poistamatta tiliäsi
email_contact_html: Jos ei saavu perille, voit pyytää apua sähköpostilla %{email}
email_reconfirmation_html: Jos et saa vahvistuksen sähköpostia, niin voit pyytää sitä uudelleen
@@ -1150,7 +1152,7 @@ fi:
username_unavailable: Käyttäjänimesi ei tule saataville enää uudestaan
disputes:
strikes:
- action_taken: Toteutetut toimet
+ action_taken: Tehty toimi
appeal: Vetoomus
appeal_approved: Tähän valitukseen on haettu muutosta, eikä se ole enää voimassa
appeal_rejected: Valitus on hylätty
@@ -1164,17 +1166,17 @@ fi:
description_html: Nämä ovat tiliäsi koskevia toimia ja varoituksia, jotka instanssin %{instance} henkilökunta on lähettänyt sinulle.
recipient: Osoitettu
reject_appeal: Hylkää valitus
- status: 'Viesti #%{id}'
- status_removed: Viesti on jo poistettu järjestelmästä
+ status: 'Julkaisu #%{id}'
+ status_removed: Julkaisu on jo poistettu järjestelmästä
title: "%{action} alkaen %{date}"
title_actions:
- delete_statuses: Viestin poisto
+ delete_statuses: Julkaisun poisto
disable: Tilin jäädyttäminen
- mark_statuses_as_sensitive: Viestien merkitseminen arkaluonteisiksi
+ mark_statuses_as_sensitive: Julkaisujen merkitseminen arkaluonteisiksi
none: Varoitus
sensitive: Tilin merkitseminen arkaluonteiseksi
silence: Tilin rajoittaminen
- suspend: Tilin jäädyttäminen
+ suspend: Tilin jäädytys
your_appeal_approved: Valituksesi on hyväksytty
your_appeal_pending: Olet lähettänyt valituksen
your_appeal_rejected: Valituksesi on hylätty
@@ -1182,8 +1184,8 @@ fi:
invalid_domain: ei ole kelvollinen toimialueen nimi
edit_profile:
basic_information: Perustiedot
- hint_html: "Mukauta mitä ihmiset näkevät julkisessa profiilissasi ja sinun julkaisujen vieressä. Ihmiset todennäköisesti seuraavat ja kirjoittavat sinulle, kun sinulla on täytetty profiili ja profiilikuva."
- other: Muu
+ hint_html: "Mukauta, mitä ihmiset näkevät julkisessa profiilissasi ja julkaisujesi vieressä. Ihmiset seuraavat sinua takaisin ja ovat kanssasi vuorovaikutuksessa todennäköisemmin, kun sinulla on täytetty profiili ja profiilikuva."
+ other: Muut
errors:
'400': Lähettämäsi pyyntö oli virheellinen tai muotoiltu virheellisesti.
'403': Sinulla ei ole lupaa nähdä tätä sivua.
@@ -1198,7 +1200,7 @@ fi:
content: Valitettavasti jokin meni pieleen meidän päässämme.
title: Sivu ei ole oikein
'503': Sivua ei voitu näyttää palvelimen väliaikaisen vian vuoksi.
- noscript_html: Käyttääksesi Mastodon-verkkopalvelua, ota JavaScript käyttöön. Vaihtoehtoisesti voit kokeilla myös jotakin juuri käyttämällesi alustalle kehitettyä Mastodon-sovellusta.
+ noscript_html: Käyttääksesi Mastodonin verkkosovellusta, ota JavaScript käyttöön. Vaihtoehtoisesti voit kokeilla käyttämällesi alustalle kehitettyjä Mastodonin natiivisovelluksia.
existing_username_validator:
not_found: paikallista käyttäjää ei löydy kyseisellä käyttäjänimellä
not_found_multiple: "%{usernames} ei löytynyt"
@@ -1206,7 +1208,7 @@ fi:
archive_takeout:
date: Päiväys
download: Lataa arkisto
- hint_html: Voit pyytää arkistoa omista viesteistä ja mediasta. Viedyt tiedot ovat ActivityPub-muodossa, ja ne voi lukea millä tahansa yhteensopivalla ohjelmalla. Voit pyytää arkistoa viikon välein.
+ hint_html: Voit pyytää arkistoa omista julkaisuista ja mediasta. Viedyt tiedot ovat ActivityPub-muodossa, ja ne voi lukea millä tahansa yhteensopivalla ohjelmalla. Voit pyytää arkistoa 7 päivän välein.
in_progress: Arkistoa kootaan...
request: Pyydä arkisto
size: Koko
@@ -1220,26 +1222,26 @@ fi:
featured_tags:
add_new: Lisää uusi
errors:
- limit: Olet jo nostanut esille enimmäismäärän aihetunnisteita
- hint_html: "Mitä ovat näkyvillä olevat hashtagit eli aihetunnisteet? Ne ovat näkyvissä julkisessa profiilissasi ja niiden avulla ihmiset voivat selata julkisia viestejäsi nimenomaan näiden aihetunnisteiden alla. Ne auttavat esimerkiksi luovan työn tai pitkäaikaisten projektien seurannassa."
+ limit: Pidät jo esillä aihetunnisteiden enimmäismäärää
+ hint_html: "Pidä tärkeimpiä aihetunnisteitasi esillä profiilissasi. Erinomainen työkalu, jolla pidät kirjaa luovista teoksistasi ja pitkäaikaisista projekteistasi. Esillä pitämäsi aihetunnisteet ovat näyttävällä paikalla profiilissasi ja mahdollistavat nopean pääsyn omiin julkaisuihisi."
filters:
contexts:
account: Profiilit
- home: Kotiaikajana
+ home: Kotisyöte ja listat
notifications: Ilmoitukset
public: Julkiset aikajanat
thread: Keskustelut
edit:
add_keyword: Lisää avainsana
keywords: Avainsanat
- statuses: Yksittäiset viestit
- statuses_hint_html: Tämä suodatin koskee yksittäisten viestien valintaa riippumatta siitä, vastaavatko ne alla olevia avainsanoja. Tarkista tai poista viestit suodattimesta.
+ statuses: Yksittäiset julkaisut
+ statuses_hint_html: Tämä suodatin koskee yksittäisten julkaisujen valintaa riippumatta siitä, vastaavatko ne alla olevia avainsanoja. Tarkista tai poista julkaisut suodattimesta.
title: Muokkaa suodatinta
errors:
deprecated_api_multiple_keywords: Näitä parametreja ei voi muuttaa tästä sovelluksesta, koska ne koskevat useampaa kuin yhtä suodattimen avainsanaa. Käytä uudempaa sovellusta tai selainkäyttöliittymää.
invalid_context: Ei sisältöä tai se on virheellinen
index:
- contexts: Suodattimet %{contexts}
+ contexts: Suodattaa kontektissa %{contexts}
delete: Poista
empty: Sinulla ei ole suodattimia.
expires_in: Vanhenee %{distance}
@@ -1248,11 +1250,11 @@ fi:
one: "%{count} avainsana"
other: "%{count} avainsanaa"
statuses:
- one: "%{count} viesti"
- other: "%{count} viestiä"
+ one: "%{count} julkaisu"
+ other: "%{count} julkaisua"
statuses_long:
- one: "%{count} yksittäinen viesti piilotettu"
- other: "%{count} yksittäistä viestiä piilotettu"
+ one: "%{count} yksittäinen julkaisu piilotettu"
+ other: "%{count} yksittäistä julkaisua piilotettu"
title: Suodattimet
new:
save: Tallenna uusi suodatin
@@ -1262,8 +1264,8 @@ fi:
batch:
remove: Poista suodattimista
index:
- hint: Tämä suodatin koskee yksittäisten viestien valintaa muista kriteereistä riippumatta. Voit lisätä lisää viestejä tähän suodattimeen web-käyttöliittymästä.
- title: Suodatetut viestit
+ hint: Tämä suodatin koskee yksittäisten julkaisujen valintaa muista kriteereistä riippumatta. Voit lisätä lisää julkaisuja tähän suodattimeen selainkäyttöliittymästä.
+ title: Suodatetut julkaisut
generic:
all: Kaikki
all_items_on_page_selected_html:
@@ -1271,7 +1273,7 @@ fi:
other: Kaikki %{count} kohdetta tällä sivulla on valittu.
all_matching_items_selected_html:
one: "%{count} kohde, joka vastaa hakuasi."
- other: Kaikki %{count} kohdetta, jotka vastaavat hakuasi.
+ other: Kaikki %{count} hakuasi vastaavaa kohdetta.
cancel: Peruuta
changes_saved_msg: Muutosten tallennus onnistui!
confirm: Vahvista
@@ -1279,11 +1281,11 @@ fi:
delete: Poista
deselect: Poista kaikki valinnat
none: Ei mitään
- order_by: Järjestä
+ order_by: Järjestys
save_changes: Tallenna muutokset
select_all_matching_items:
one: Valitse %{count} kohde, joka vastaa hakuasi.
- other: Valitse kaikki %{count} kohdetta, jotka vastaavat hakuasi.
+ other: Valitse kaikki %{count} hakuasi vastaavaa kohdetta.
today: tänään
validation_errors:
one: Kaikki ei ole aivan oikein! Tarkasta alla oleva virhe
@@ -1304,20 +1306,20 @@ fi:
overwrite: Korvaa
overwrite_long: Korvaa nykyiset tietueet uusilla
overwrite_preambles:
- blocking_html: Olet aikeissa korvata estoluettelon kaikkiaan %{total_items} tilillä tiedostoon %{filename} perustuen.
- bookmarks_html: Olet aikeissa korvata kirjanmerkit kaikkiaan %{total_items} julkaisulla tiedostosta %{filename}.
- domain_blocking_html: Olet aikeissa korvata verkkotunnusestot kaikkiaan %{total_items} verkkotunnuksella tiedostoon %{filename} perustuen.
- following_html: Olet aikeissa seurata kaikkiaan %{total_items} tiliä tiedostoon %{filename} perustuen. Aiot lisäksi lopettaa kaikkien muiden seuraamisen.
- lists_html: Olet korvaamassa listojasi tiedoston %{filename} sisällöllä. Uusiin listoihin lisätään kaikkiaan %{total_items} tiliä.
- muting_html: Olet korvaamassa mykistettyjä tilejäsi kaikkiaan %{total_items} tilillä tiedostoon %{filename} perustuen.
+ blocking_html: Olet aikeissa korvata estoluettelosi kaikkiaan %{total_items} tilillä tiedostosta %{filename}.
+ bookmarks_html: Olet aikeissa korvata kirjanmerkkisi kaikkiaan %{total_items} julkaisulla tiedostosta %{filename}.
+ domain_blocking_html: Olet aikeissa korvata verkkotunnusten estoluettelosi kaikkiaan %{total_items} verkkotunnuksella tiedostosta %{filename}.
+ following_html: Olet aikeissa seurata kaikkiaan %{total_items} tiliä tiedostosta %{filename} ja lopettaa kaikkien muiden seuraamisen.
+ lists_html: Olet aikeissa korvata listojasi tiedoston %{filename} sisällöllä. Uusiin listoihin lisätään kaikkiaan %{total_items} tiliä.
+ muting_html: Olet aikeissa korvata mykistettyjen tilien luettelosi kaikkiaan %{total_items} tilillä tiedostosta %{filename}.
preambles:
- blocking_html: Olet estämässä yhteensä %{total_items} tiliä tiedostoon %{filename} perustuen.
- bookmarks_html: Olet lisäämässä %{total_items} julkaisua tiedostosta %{filename}kirjanmerkkeihisi.
- domain_blocking_html: Olet estämässä yhteensä %{total_items} verkkotunnusta tiedoston %{filename} nojalla.
- following_html: Olet aikeissa seurata kaikkiaan %{total_items} tiliä tiedostoon %{filename} perustuen.
- lists_html: Olet lisäämässä listoihisi %{total_items} tiliä tiedostosta %{filename}. Uudet listat luodaan, jos sopivaa kohdelistaa ei ole olemassa.
- muting_html: Olet hiljentämässä yhteensä %{total_items} tiliä tiedostosta %{filename}.
- preface: Voit tuoda toisesta instanssista viemiäsi tietoja, kuten esimerkiksi seuraamiesi tai estämiesi henkilöiden listan.
+ blocking_html: Olet aikeissa estää kaikkiaan %{total_items} tiliä tiedostosta %{filename}.
+ bookmarks_html: Olet lisäämässä kaikkiaan %{total_items} julkaisua tiedostosta %{filename}kirjanmerkkeihisi.
+ domain_blocking_html: Olet aikeissa estää kaikkiaan %{total_items} verkkotunnusta tiedostosta %{filename}.
+ following_html: Olet aikeissa seurata kaikkiaan %{total_items} tiliä tiedostosta %{filename}.
+ lists_html: Olet lisäämässä listoihisi kaikkiaan %{total_items} tiliä tiedostosta %{filename}. Uusia listoja luodaan, jos sopivaa kohdelistaa ei ole olemassa.
+ muting_html: Olet aikeissa mykistää kaikkiaan %{total_items} tiliä tiedostosta %{filename}.
+ preface: Voit tuoda toiselta palvelimelta viemiäsi tietoja, kuten seuraamiesi tai estämiesi henkilöiden luettelon.
recent_imports: Viimeksi tuotu
states:
finished: Valmis
@@ -1332,19 +1334,19 @@ fi:
bookmarks: Tuodaan kirjanmerkkejä
domain_blocking: Tuodaan estettyjä verkkotunnuksia
following: Tuodaan seurattuja tilejä
- lists: Listojen tuonti
- muting: Tuodaan hiljennettyjä tilejä
+ lists: Tuodaan listoja
+ muting: Tuodaan mykistettyjä tilejä
type: Tuonnin tyyppi
type_groups:
constructive: Seuratut ja kirjanmerkit
- destructive: Estot ja hiljennykset
+ destructive: Estot ja mykistykset
types:
- blocking: Estettyjen lista
+ blocking: Estoluettelo
bookmarks: Kirjanmerkit
- domain_blocking: Verkkoalueen estolista
- following: Seurattujen lista
+ domain_blocking: Verkkotunnusten estoluettelo
+ following: Seurattujen luettelo
lists: Listat
- muting: Mykistettyjen lista
+ muting: Mykistettyjen luettelo
upload: Lähetä
invites:
delete: Poista käytöstä
@@ -1373,7 +1375,7 @@ fi:
limit: Sinulla on enimmäismäärä listoja
login_activities:
authentication_methods:
- otp: kaksivaiheinen todennussovellus
+ otp: kaksivaiheisen todennuksen sovellus
password: salasana
sign_in_token: sähköpostin turvakoodi
webauthn: suojausavaimet
@@ -1386,16 +1388,16 @@ fi:
unsubscribe:
action: Kyllä, peru tilaus
complete: Tilaus lopetettiin
- confirmation_html: Olethan varma, että haluat lopettaa %{type} -aiheisten Mastodonin sähköposti-ilmoitusten vastaanoton palvelimelta %{domain} osoitteeseesi %{email}? Voit toki milloin tahansa ottaa jälleen käyttöön muun muassa nämä viestit sähköposti-ilmoitusasetusten kautta.
+ confirmation_html: Haluatko varmasti lopettaa Mastodonin sähköposti-ilmoitusten vastaanottamisen aiheesta %{type} palvelimelta %{domain} osoitteeseesi %{email}? Voit tilata ilmoitusviestejä milloin tahansa uudelleen sähköposti-ilmoitusten asetuksista.
emails:
notification_emails:
- favourite: sähköpostit ilmoituksille
- follow: seuraa sähköpostin ilmoituksia
- follow_request: seuraa pyyntöjä sähköpostiin
- mention: mainitse sähköpostin ilmoitukset
- reblog: tehosta sähköpostien ilmoituksia
- resubscribe_html: Jos olet perunut ilmoitusviestien vastaanottamisen suotta, pääset jälleentilaamaan ilmoitusviestejä sähköposti-ilmoitusasetusten kautta.
- success_html: Sinulle ei vastedes lähetetä %{type} -aihepiirin Mastodon-sähköposti-ilmoituksia palvelimelta %{domain} osoitteeseen %{email}.
+ favourite: sähköposti-ilmoituksia suosikkeihin lisäämisistä
+ follow: sähköposti-ilmoituksia seuraamisista
+ follow_request: sähköposti-ilmoituksia seuraamispyynnöistä
+ mention: sähköposti-ilmoituksia maininnoista
+ reblog: sähköposti-ilmoituksia tehostuksista
+ resubscribe_html: Jos olet perunut tilauksen erehdyksessä, voit tilata ilmoitusviestejä uudelleen sähköposti-ilmoitusten asetuksista.
+ success_html: Sinulle ei enää lähetetä Mastodonin %{type} palvelimelta %{domain} osoitteeseen %{email}.
title: Lopeta tilaus
media_attachments:
validations:
@@ -1403,9 +1405,9 @@ fi:
not_ready: Ei voi liittää tiedostoja, joiden käsittely on kesken. Yritä hetken kuluttua uudelleen!
too_many: Tiedostoja voi liittää enintään 4
migrations:
- acct: uuden tilin käyttäjätunnus@verkkotunnus
+ acct: Muuttanut tunnukselle
cancel: Peruuta uudelleenohjaus
- cancel_explanation: Uudelleenohjauksen peruuttaminen aktivoi uudelleen nykyisen tilisi, mutta ei palauta seuraajia, jotka on siirretty kyseiselle tilille.
+ cancel_explanation: Uudelleenohjauksen peruuttaminen aktivoi nykyisen tilisi uudelleen mutta ei palauta seuraajia, jotka on siirretty kyseiselle tilille.
cancelled_msg: Uudelleenohjaus peruttu onnistuneesti.
errors:
already_moved: on sama tili, jonka olet jo siirtänyt
@@ -1414,8 +1416,8 @@ fi:
not_found: ei voitu löytää
on_cooldown: Sinä olet jäähyllä
followers_count: Seuraajat muuton aikana
- incoming_migrations: Siirtyminen toiselta tililtä
- incoming_migrations_html: Siirtääksesi toisesta tilistä tähän tiliin, sinun täytyy ensin luoda tilin alias.
+ incoming_migrations: Muutto toiselta tililtä
+ incoming_migrations_html: Muuttaaksesi toisesta tilistä tähän, sinun täytyy ensin luoda tilin alias.
moved_msg: Tilisi ohjaa nyt kohteeseen %{acct} ja seuraajiasi siirretään.
not_redirecting: Tilisi ei ohjaa tällä hetkellä mihinkään muuhun tiliin.
on_cooldown: Olet siirtänyt tilisi äskettäin. Tämä toiminto tulee saataville uudelleen %{count} päivän kuluttua.
@@ -1426,18 +1428,18 @@ fi:
set_redirect: Aseta uudelleenohjaus
warning:
backreference_required: Uusi tili on ensin määritettävä viittaamaan tähän tiliin
- before: 'Ennen jatkamista, lue nämä huomautukset huolellisesti:'
- cooldown: Muuton jälkeen on odotusaika, jonka aikana et pysty enää liikkumaan
- disabled_account: Nykyinen tilisi ei ole täysin käytettävissä jälkikäteen. Sinulla on kuitenkin pääsy tietojen vientiin ja uudelleenaktivointiin.
+ before: 'Ennen kuin etenet, lue nämä huomautukset huolellisesti:'
+ cooldown: Muuton jälkeen on odotusaika, jonka aikana et pysty enää muuttamaan
+ disabled_account: Nykyinen tilisi ei ole täysin käytettävissä tämän jälkeen. Sinulla on kuitenkin pääsy tietojen vientiin ja uudelleenaktivointiin.
followers: Tämä toiminto siirtää kaikki seuraajat nykyisestä tilistä uudelle tilille
- only_redirect_html: Vaihtoehtoisesti voit asettaa vain uudelleenohjauksen profiiliisi.
+ only_redirect_html: Vaihtoehtoisesti voit asettaa vain ohjauksen profiiliisi.
other_data: Muita tietoja ei siirretä automaattisesti
- redirect: Nykyinen tilisi profiili päivitetään, ohjataan uudelleen ja jätetään pois hausta
+ redirect: Nykyisen tilisi profiili päivitetään ohjaushuomautuksella ja suljetaan pois hauista
moderation:
- title: Moderointi
+ title: Valvonta
move_handler:
carry_blocks_over_text: Tämä käyttäjä siirtyi paikasta %{acct}, jonka olit estänyt.
- carry_mutes_over_text: Tämä käyttäjä siirtyi paikasta %{acct}, jonka mykistit.
+ carry_mutes_over_text: Tämä käyttäjä siirtyi tililtä %{acct}, jonka olet mykistänyt.
copy_account_note_text: 'Tämä käyttäjä siirtyi paikasta %{acct}, tässä olivat aiemmat muistiinpanosi niistä:'
navigation:
toggle_menu: Avaa/sulje valikko
@@ -1448,15 +1450,15 @@ fi:
sign_up:
subject: "%{name} rekisteröityi"
favourite:
- body: "%{name} tykkäsi tilastasi:"
- subject: "%{name} tykkäsi tilastasi"
- title: Uusi tykkäys
+ body: "%{name} lisäsi julkaisusi suosikkeihinsa:"
+ subject: "%{name} lisäsi julkaisusi suosikkeihinsa"
+ title: Uusi suosikkeihin lisäys
follow:
body: "%{name} seuraa nyt sinua!"
subject: "%{name} seuraa nyt sinua"
title: Uusi seuraaja
follow_request:
- action: Hallinnoi seuraamispyyntöjä
+ action: Hallitse seuraamispyyntöjä
body: "%{name} haluaa seurata sinua"
subject: 'Odottava seuraamispyyntö: %{name}'
title: Uusi seuraamispyyntö
@@ -1468,13 +1470,13 @@ fi:
poll:
subject: Äänestys käyttäjältä %{name} on päättynyt
reblog:
- body: "%{name} tehosti viestiäsi:"
- subject: "%{name} tehosti viestiäsi"
+ body: "%{name} tehosti julkaisuasi:"
+ subject: "%{name} tehosti julkaisuasi"
title: Uusi tehostus
status:
subject: "%{name} julkaisi juuri"
update:
- subject: "%{name} muokkasi viestiä"
+ subject: "%{name} muokkasi julkaisua"
notifications:
administration_emails: Ylläpitäjän sähköposti-ilmoitukset
email_events: Sähköposti-ilmoitusten tapahtumat
@@ -1492,7 +1494,7 @@ fi:
trillion: B
otp_authentication:
code_hint: Anna todennussovelluksen luoma koodi vahvistaaksesi
- description_html: Jos otat käyttöön kaksivaiheisen todentamisen, käyttämällä todennussovellusta, kirjautumiseen vaaditaan puhelin, jolla voidaan luoda kirjautumistunnuksia.
+ description_html: Jos otat kaksivaiheisen todennuksen käyttöön käyttämällä todennussovellusta, kirjautumiseen vaaditaan puhelin, jolla voidaan luoda kirjautumistunnuksia.
enable: Ota käyttöön
instructions_html: "Lue tämä QR-koodi puhelimen Google Authenticator- tai vastaavalla TOTP-sovelluksella. Sen jälkeen sovellus luo tunnuksia, joita tarvitset kun kirjaudut sisään."
manual_instructions: 'Jos et voi lukea QR-koodia ja haluat syöttää sen käsin, tässä on salainen koodi tekstinä:'
@@ -1518,16 +1520,16 @@ fi:
too_many_options: ei voi sisältää enempää kuin %{max} kohdetta
preferences:
other: Muut
- posting_defaults: Viestien oletusasetukset
+ posting_defaults: Julkaisun oletusasetukset
public_timelines: Julkiset aikajanat
privacy:
- hint_html: "Määritä, kuinka haluat profiilisi ja julkaisujesi löytyvän. Mastodonissa on monia ominaisuuksia, joiden käyttöönotto voi auttaa sinua saavuttamaan laajemman yleisön. Käytä hetki aikaa tarkistaaksesi, soveltuvatko nämä vaihtoehdot tarpeisiisi."
+ hint_html: "Määritä, kuinka haluat profiilisi ja julkaisujesi löytyvän. Mastodonissa on monia ominaisuuksia, joiden käyttöönotto voi auttaa sinua tavoittamaan laajemman yleisön. Käytä hetki tarkistaaksesi, sopivatko nämä asetukset käyttöösi."
privacy: Yksityisyys
- privacy_hint_html: Määritä miten paljon muita avustavia tietoja haluat paljastaa. Käyttäjät löytävät kiinnostavia profiileja sekä hienoja sovelluksia selaillen toisten seuraamia käyttäjiä, ja näkemällä, millä sovelluksilla nämä julkaisevat. Saatat kuitenkin haluta piilottaa nämä tiedot.
+ privacy_hint_html: Määritä, kuinka paljon muita avustavia tietoja haluat paljastaa. Käyttäjät löytävät kiinnostavia profiileja ja hienoja sovelluksia, kun he selaavat toisten seuraamia käyttäjiä ja kun he näkevät, millä sovelluksilla nämä julkaisevat. Saatat kuitenkin haluta piilottaa nämä tiedot.
reach: Tavoittavuus
- reach_hint_html: Päätä, haluatko tulla uusien käyttäjien löytämäksi ja seuraamaksi. Haluatko viestiesi näkyvän Selaa-sivulla? Haluatko käyttäjien näkevän sinut heidän seuraussuosituksissaan? Haluatko hyväksyä uudet seuraajat automaattisesti vai haluatko hyväksyä jokaisen erikseen?
- search: Haku
- search_hint_html: Määritä, kuinka haluat tulla löydetyksi. Haluatko, että ihmiset löytävät sinut julkisten julkaisujesi perusteella? Haluatko, että ihmiset Mastodonin ulkopuolella löytävät profiilisi tehdessään hakuja verkossa? Huomioithan, ettei täyttä poisjättäytymistä kaikista hakukoneista voida taata julkisille tiedoille.
+ reach_hint_html: Määritä, haluatko tulla uusien käyttäjien löytämäksi ja seuraamaksi. Haluatko julkaisujesi näkyvän Selaa-sivulla? Haluatko muiden käyttäjien näkevän sinut seuraamissuosituksissaan? Haluatko hyväksyä kaikki uudet seuraajat automaattisesti vai päättää jokaisesta erikseen?
+ search: Hae
+ search_hint_html: Määritä, kuinka haluat tulla löydetyksi. Haluatko, että ihmiset löytävät sinut julkisten julkaisujesi perusteella? Haluatko, että ihmiset Mastodonin ulkopuolella löytävät profiilisi tehdessään hakuja verkossa? Otathan huomioon, ettei julkisten tietojen täyttä kaikista hakukoneista poisjäämistä voi taata.
title: Yksityisyys ja tavoittavuus
privacy_policy:
title: Tietosuojakäytäntö
@@ -1547,10 +1549,10 @@ fi:
following: Seuratut
invited: Kutsutut
last_active: Viimeksi aktiivinen
- most_recent: Viimeisin
- moved: Muuttanut
+ most_recent: Viimeisimmät
+ moved: Muuttaneet
mutual: Molemmat
- primary: Ensisijainen
+ primary: Ensisijaiset
relationship: Suhde
remove_selected_domains: Poista kaikki seuraajat valituista verkkotunnuksista
remove_selected_followers: Poista valitut seuraajat
@@ -1564,12 +1566,15 @@ fi:
rss:
content_warning: 'Sisältövaroitus:'
descriptions:
- account: Julkiset viestit lähettäjältä @%{acct}
- tag: 'Julkiset viestit merkitty #%{hashtag}'
+ account: Julkiset julkaisut tililtä @%{acct}
+ tag: 'Julkiset julkaisut aihetunnisteella #%{hashtag}'
scheduled_statuses:
- over_daily_limit: Olet ylittänyt %{limit} ajoitetun viestin rajan tälle päivälle
- over_total_limit: Olet ylittänyt %{limit} ajoitetun viestin rajan
- too_soon: Ajoitetun päivämäärän on oltava tulevaisuudessa
+ over_daily_limit: Olet ylittänyt %{limit} ajoitetun julkaisun rajan tälle päivälle
+ over_total_limit: Olet ylittänyt %{limit} ajoitetun julkaisun rajan
+ too_soon: Ajoitetun päiväyksen pitää olla tulevaisuudessa
+ self_destruct:
+ lead_html: Valitettavasti %{domain} sulkeutuu pysyvästi. Jos sinulla on siellä tili, et voi jatkaa sen käyttöä mutta voit yhä pyytää varmuuskopiota tiedoistasi.
+ title: Tämä palvelin sulkeutuu
sessions:
activity: Viimeisin toiminta
browser: Selain
@@ -1595,7 +1600,7 @@ fi:
weibo: Weibo
current_session: Nykyinen istunto
description: "%{browser} alustalla %{platform}"
- explanation: Nämä verkkoselaimet ovat tällä hetkellä kirjautuneet Mastodon-tilillesi.
+ explanation: Nämä verkkoselaimet ovat tällä hetkellä kirjautuneena Mastodon-tilillesi.
ip: IP-osoite
platforms:
adobe_air: Adobe AIR
@@ -1623,20 +1628,20 @@ fi:
authorized_apps: Valtuutetut sovellukset
back: Takaisin Mastodoniin
delete: Tilin poisto
- development: Kehittäminen
+ development: Kehitys
edit_profile: Muokkaa profiilia
export: Vie tietoja
- featured_tags: Esitellyt aihetunnisteet
+ featured_tags: Esillä pidettävät aihetunnisteet
import: Tuo
- import_and_export: Tuo ja vie
+ import_and_export: Tuonti ja vienti
migrate: Tilin muutto muualle
notifications: Ilmoitukset
preferences: Ominaisuudet
- profile: Profiili
- relationships: Seurattavat ja seuraajat
- statuses_cleanup: Automaattinen viestin poisto
- strikes: Valvojan varoitukset
- two_factor_authentication: Kaksivaiheinen todentaminen
+ profile: Julkinen profiili
+ relationships: Seuratut ja seuraajat
+ statuses_cleanup: Autom. julkaisujen poisto
+ strikes: Valvontavaroitukset
+ two_factor_authentication: Kaksivaiheinen todennus
webauthn_authentication: Suojausavaimet
statuses:
attached:
@@ -1650,21 +1655,21 @@ fi:
video:
one: "%{count} video"
other: "%{count} videota"
- boosted_from_html: Tehostus lähteestä %{acct_link}
+ boosted_from_html: Tehosti lähteestä %{acct_link}
content_warning: 'Sisältövaroitus: %{warning}'
default_language: Sama kuin käyttöliittymän kieli
disallowed_hashtags:
- one: 'sisälsi aihetunnisteen jota ei sallita: %{tags}'
- other: 'sisälsi aihetunnisteet joita ei sallita: %{tags}'
+ one: 'sisälsi kielletyn aihetunnisteen: %{tags}'
+ other: 'sisälsi kiellettyjä aihetunnisteita: %{tags}'
edited_at_html: Muokattu %{date}
errors:
- in_reply_not_found: Viesti, johon yrität vastata, ei näytä olevan olemassa.
+ in_reply_not_found: Julkaisua, johon yrität vastata, ei näytä olevan olemassa.
open_in_web: Avaa selaimessa
over_character_limit: merkkimäärän rajoitus %{max} ylitetty
pin_errors:
- direct: Viestejä, jotka ovat näkyvissä vain mainituille käyttäjille, ei voi kiinnittää
- limit: Olet jo kiinnittänyt suurimman mahdollisen määrän viestejä
- ownership: Muiden viestejä ei voi kiinnittää
+ direct: Vain mainituille käyttäjille näkyviä julkaisuja ei voi kiinnittää
+ limit: Olet jo kiinnittänyt enimmäismäärän julkaisuja
+ ownership: Muiden julkaisuja ei voi kiinnittää
reblog: Tehostusta ei voi kiinnittää
poll:
total_people:
@@ -1681,33 +1686,33 @@ fi:
title: "%{name}: ”%{quote}”"
visibilities:
direct: Suoraan
- private: Vain seuraajille
+ private: Vain seuraajat
private_long: Näytä vain seuraajille
public: Julkinen
public_long: Kaikki voivat nähdä
- unlisted: Listaamaton julkinen
+ unlisted: Listaamaton
unlisted_long: Kaikki voivat nähdä, mutta ei näytetä julkisilla aikajanoilla
statuses_cleanup:
- enabled: Poista vanhat viestit automaattisesti
- enabled_hint: Poistaa viestit automaattisesti, kun ne saavuttavat tietyn ikärajan, elleivät ne täsmää yhtä alla olevista poikkeuksista
+ enabled: Poista vanhat julkaisut automaattisesti
+ enabled_hint: Poistaa julkaisusi automaattisesti, kun ne saavuttavat valitun ikärajan, ellei jokin alla olevista poikkeuksista tule kyseeseen
exceptions: Poikkeukset
- explanation: Koska viestien poistaminen on kallista toimintaa, sitä tehdään hitaasti ajan mittaan, kun palvelin ei ole muutoin kiireinen. Viestejäsi voidaankin siis poistaa myös viiveellä verrattuna niille määrittämääsi aikarajaan.
+ explanation: Koska julkaisujen poistaminen on raskas toimi, se tapahtuu hitaasti ajan mittaan, kun palvelin ei ole muutoin ruuhkainen. Siksi viestejäsi voi poistua vasta tovi sen jälkeen, kun ne ovat saavuttaneet ikärajan.
ignore_favs: Ohita suosikit
ignore_reblogs: Ohita tehostukset
- interaction_exceptions: Poikkeukset, jotka perustuvat vuorovaikutukseen
- interaction_exceptions_explanation: Huomaa, että ei ole takeita viestien poistamiselle, jos ne alittavat suosikki- tai tehostusrajan sen jälkeen, kun ne on kerran ylitetty.
+ interaction_exceptions: Vuorovaikutuksiin perustuvat poikkeukset
+ interaction_exceptions_explanation: Huomaa, ettei julkaisujen poistumisesta ole varmuutta, jos ne alittavat suosikki- tai tehostusrajan sen jälkeen kun ne on kerran ylitetty.
keep_direct: Säilytä yksityisviestit
- keep_direct_hint: Ei poista mitään sinun suoria viestejä
- keep_media: Säilytä viestit, joissa on liitetiedostoja
- keep_media_hint: Ei poista viestejä, joissa on liitteitä
- keep_pinned: Pidä kiinnitettyt viestit
- keep_pinned_hint: Ei poista mitään kiinnitettyä viestiä
+ keep_direct_hint: Ei poista yksityisviestejäsi
+ keep_media: Säilytä julkaisut, joissa on medialiitteitä
+ keep_media_hint: Ei poista julkaisujasi, joissa on medialiitteitä
+ keep_pinned: Säilytä kiinnitetyt julkaisut
+ keep_pinned_hint: Ei poista kiinnitettyjä julkaisujasi
keep_polls: Säilytä äänestykset
- keep_polls_hint: Ei poista yhtäkään äänestystä
- keep_self_bookmark: Säilytä kirjanmerkkeihin lisäämäsi viestit
- keep_self_bookmark_hint: Ei poista viestejäsi, jos olet lisännyt ne kirjanmerkkeihin
- keep_self_fav: Säilyttää viestit suosikeissa
- keep_self_fav_hint: Ei poista omia viestejäsi, jos olet lisännyt ne suosikkeihin
+ keep_polls_hint: Ei poista äänestyksiäsi
+ keep_self_bookmark: Säilytä kirjanmerkkeihin lisäämäsi julkaisut
+ keep_self_bookmark_hint: Ei poista julkaisujasi, jos olet lisännyt ne kirjanmerkkeihin
+ keep_self_fav: Säilytä suosikkeihin lisäämäsi julkaisut
+ keep_self_fav_hint: Ei poista julkaisujasi, jos olet lisännyt ne suosikkeihisi
min_age:
'1209600': 2 viikkoa
'15778476': 6 kuukautta
@@ -1718,12 +1723,12 @@ fi:
'63113904': 2 vuotta
'7889238': 3 kuukautta
min_age_label: Ikäraja
- min_favs: Pidä viestit suosikeissa vähintään
- min_favs_hint: Toiminto ei poista julkaisujasi, joista on tykätty vähintään tässä kohtaa määritellyn monesti. Jätä kenttä tyhjäksi, jos haluat poistaa julkaisut tykkäyksistä huolimatta
- min_reblogs: Pidä viestit tehostettuna vähintään
- min_reblogs_hint: Ei poista yhtään viestiäsi, jota on tehostettu vähintään näin monta kertaa. Jätä tyhjäksi poistaaksesi viestejä riippumatta niiden tehosteiden määrästä
+ min_favs: Säilytä julkaisut, joilla on suosikiksi lisäyksiä vähintään
+ min_favs_hint: Ei poista julkaisujasi, joita on lisätty suosikeihin vähintään näin monta kertaa. Jätä tyhjäksi, jos haluat poistaa julkaisuja riippumatta suosikkeihin lisäysmääristä
+ min_reblogs: Säilytä julkaisut, joilla on tehostuksia vähintään
+ min_reblogs_hint: Ei poista julkaisujasi, joita on tehostettu vähintään näin monta kertaa. Jätä tyhjäksi, jos haluat poistaa julkaisuja riippumatta niiden tehostusten määrästä
stream_entries:
- sensitive_content: Arkaluontoista sisältöä
+ sensitive_content: Arkaluonteista sisältöä
strikes:
errors:
too_late: On liian myöhäistä vedota tähän varoitukseen
@@ -1745,16 +1750,16 @@ fi:
too_many_requests: Käännöspalvelulle on hiljattain esitetty liian monta pyyntöä.
two_factor_authentication:
add: Lisää
- disable: Poista käytöstä
+ disable: Poista 2FA käytöstä
disabled_success: Kaksivaiheinen todennus on poistettu käytöstä
edit: Muokkaa
- enabled: Kaksivaiheinen todentaminen käytössä
- enabled_success: Kaksivaiheisen todentamisen käyttöönotto onnistui
+ enabled: Kaksivaiheinen todennus käytössä
+ enabled_success: Kaksivaiheisen todennuksen käyttöönotto onnistui
generate_recovery_codes: Luo palautuskoodit
- lost_recovery_codes: Palautuskoodien avulla voit käyttää tiliä, jos menetät puhelimesi. Jos olet hukannut palautuskoodit, voit luoda uudet tästä. Vanhat palautuskoodit poistetaan käytöstä.
- methods: Kaksivaiheisen tunnistautumisen menetelmät
+ lost_recovery_codes: Palautuskoodien avulla voit käyttää tiliä, jos menetät puhelimesi. Jos olet hukannut palautuskoodisi, voit luoda uudet tästä. Vanhat palautuskoodit poistetaan käytöstä.
+ methods: Kaksivaiheisen todennuksen menetelmät
otp: Todennussovellus
- recovery_codes: Varapalautuskoodit
+ recovery_codes: Ota palautuskoodit talteen
recovery_codes_regenerated: Uusien palautuskoodien luonti onnistui
recovery_instructions_html: Jos menetät puhelimesi, voit kirjautua tilillesi jollakin alla olevista palautuskoodeista. Pidä palautuskoodit hyvässä tallessa. Voit esimerkiksi tulostaa ne ja säilyttää muiden tärkeiden papereiden joukossa.
webauthn: Suojausavaimet
@@ -1776,7 +1781,7 @@ fi:
change_password: vaihda salasanasi
details: 'Tässä on tiedot kirjautumisesta:'
explanation: Olemme havainneet kirjautumisen tilillesi uudesta IP-osoitteesta.
- further_actions_html: Jos tämä et ollut sinä, suosittelemme että %{action} välittömästi ja ota kaksivaiheinen todennus käyttöön säilyttääksesi tilisi turvallisena.
+ further_actions_html: Jos tämä et ollut sinä, suosittelemme, että %{action} heti ja otat käyttöön kaksivaiheisen todennuksen pitääksesi tilisi turvassa.
subject: Tiliäsi on käytetty uudesta IP-osoitteesta
title: Uusi kirjautuminen
warning:
@@ -1786,38 +1791,38 @@ fi:
spam: Roskaposti
violation: Sisältö rikkoo seuraavia yhteisön sääntöjä
explanation:
- delete_statuses: Joitakin viesteistäsi on havaittu rikkovan yhtä tai useampaa yhteisön sääntöä ja instanssin %{instance} valvojat ovat poistaneet ne.
+ delete_statuses: Joidenkin julkaisuistasi on havaittu rikkovan ainakin yhtä yhteisön sääntöä, joten instanssin %{instance} valvojat ovat poistaneet ne.
disable: Et voi enää käyttää tiliäsi, mutta profiilisi ja muut tiedot pysyvät muuttumattomina. Voit pyytää varmuuskopiota tiedoistasi, vaihtaa tilin asetuksia tai poistaa tilisi.
- mark_statuses_as_sensitive: Instanssin %{instance} valvojat ovat merkinneet osan julkaisuistasi arkaluonteisiksi. Tämä tarkoittaa sitä, että ihmisten täytyy napauttaa viestiä ennen kuin esikatselu näytetään. Voit merkitä median itse arkaluonteiseksi kun julkaiset tulevaisuudessa.
+ mark_statuses_as_sensitive: Palvelimen %{instance} valvojat ovat merkinneet osan julkaisuistasi arkaluonteisiksi. Tämä tarkoittaa sitä, että ihmisten täytyy napauttaa mediaa ennen kuin sen esikatselu näytetään. Voit merkitä median itse arkaluonteiseksi, kun julkaiset tulevaisuudessa.
sensitive: Tästä lähtien kaikki ladatut mediatiedostot merkitään arkaluonteisiksi ja piilotetaan napsautusvaroituksen taakse.
- silence: Voit edelleen käyttää tiliäsi, mutta vain sinua jo seuraavat ihmiset näkevät viestisi tällä palvelimella ja sinut voidaan sulkea pois erilaisista hakuominaisuuksista. Toiset voivat kuitenkin edelleen seurata sinua manuaalisesti.
- suspend: Et voi enää käyttää tiliäsi ja profiilisi ja muut tiedot eivät ole enää käytettävissä. Voit silti kirjautua sisään pyytääksesi varmuuskopiota tiedoistasi, kunnes tiedot on poistettu kokonaan noin 30 päivän kuluttua. Säilytämme joitakin perustietoja, jotka estävät sinua kiertämästä keskeyttämistä.
+ silence: Voit edelleen käyttää tiliäsi, mutta vain sinua jo seuraavat käyttäjät näkevät julkaisusi tällä palvelimella ja sinut voidaan sulkea pois eri löytämisominaisuuksista. Toiset voivat kuitenkin edelleen seurata sinua manuaalisesti.
+ suspend: Et voi enää käyttää tiliäsi, eivätkä profiilisi ja muut tiedot ole enää käytettävissä. Voit silti kirjautua sisään pyytääksesi tietojesi varmuuskopiota, kunnes tiedot on poistettu kokonaan noin 30 päivän kuluttua. Säilytämme kuitenkin joitain perustietoja, jotka estävät sinua kiertämästä jäädytystä.
reason: 'Syy:'
- statuses: 'Viestejä lainattu:'
+ statuses: 'Julkaisuja lainattu:'
subject:
- delete_statuses: Viestisi %{acct} on poistettu
+ delete_statuses: Julkaisusi tilillä %{acct} on poistettu
disable: Tilisi %{acct} on jäädytetty
- mark_statuses_as_sensitive: Viestisi %{acct} on merkitty arkaluonteisiksi
+ mark_statuses_as_sensitive: Julkaisusi tilillä %{acct} on merkitty arkaluonteisiksi
none: Varoitus %{acct}
- sensitive: Sinun viestisi %{acct} merkitään arkaluonteisiksi tästä lähtien
- silence: Tilisi %{acct} on rajoitettu
+ sensitive: Julkaisusi tilillä %{acct} merkitään arkaluonteisiksi tästä lähtien
+ silence: Tiliäsi %{acct} on rajoitettu
suspend: Tilisi %{acct} on jäädytetty
title:
- delete_statuses: Viestit poistettu
+ delete_statuses: Julkaisut poistettu
disable: Tili jäädytetty
- mark_statuses_as_sensitive: Viestit on merkitty arkaluonteisiksi
+ mark_statuses_as_sensitive: Julkaisut merkitty arkaluonteisiksi
none: Varoitus
- sensitive: Tili on merkitty arkaluonteiseksi
- silence: Rajoitettu tili
- suspend: Tilin käyttäminen jäädytetty
+ sensitive: Tili merkitty arkaluonteiseksi
+ silence: Tiliä rajoitettu
+ suspend: Tili jäädytetty
welcome:
edit_profile_action: Määritä profiili
- edit_profile_step: Voit mukauttaa profiiliasi mm. profiilikuvalla ja uudella näyttönimellä. Voit myös valita haluatko tarkastaa ja hyväksyä uudet seuraajat itse.
+ edit_profile_step: Voit mukauttaa profiiliasi muun muassa profiilikuvalla ja uudella näyttönimellä. Voit myös valita, haluatko tarkastaa ja hyväksyä uudet seuraajat itse.
explanation: Näillä vinkeillä pääset alkuun
final_action: Ala julkaista
- final_step: 'Aloita julkaiseminen! Vaikkei sinulla ole seuraajia, voivat muut nähdä julkiset julkaisusi esimerkiksi paikallisella aikajanalla ja aihetunnisteilla. Kannattaa myös esittäytyä käyttämällä aihetunnistetta #introductions.'
+ final_step: 'Ala julkaista! Vaikkei sinulla olisi seuraajia, voivat muut nähdä julkisia julkaisujasi esimerkiksi paikallisella aikajanalla tai aihetunnisteissa. Kannattaa myös esitellä itsensä aihetunnisteella #esittely.'
full_handle: Koko käyttäjätunnuksesi
- full_handle_hint: Kerro tämä kavereillesi, niin he voivat lähettää sinulle viestejä tai löytää sinut muiden palvelimien kautta.
+ full_handle_hint: Kerro tämä kavereillesi, niin he voivat lähettää sinulle viestejä tai seurata sinua toiselta palvelimelta.
subject: Tervetuloa Mastodoniin
title: Tervetuloa mukaan, %{name}!
users:
@@ -1828,26 +1833,26 @@ fi:
seamless_external_login: Olet kirjautunut ulkoisen palvelun kautta, joten salasana- ja sähköpostiasetukset eivät ole käytettävissä.
signed_in_as: 'Kirjautunut tilillä:'
verification:
- extra_instructions_html: Vinkki: Tämä linkitys verkkosivustollasi voidaan toteuttaa myös näkymättömänä. Tärkeä osuus on rel="me"
-määre, jolla ehkäistään valeprofiilikäyttötarkoituksia sivustoilla, joiden sisältö perustuu käyttäjiensä julkaisuihin. Voit siis käyttää linkkiviittauselementtiä link
HTML-lähdekoodin otsakeosassa (head) sen sijaan, että käyttäisit näkyvää hyperlinkkielementtiä a
. HTML-lähdekoodin tulee tuolta osin kuitenkin olla JavaScriptistä riippumatonta.
+ extra_instructions_html: Vinkki: Verkkosivustollasi oleva linkki voi olla myös näkymätön. Olennainen osuus on rel="me"
, joka estää toiseksi henkilöksi tekeytymisen verkkosivustoilla, joilla on käyttäjien luomaa sisältöä. Voit käyttää jopa link
-elementtiä sivun head
-osassa elementin a
sijaan, mutta HTML:n pitää olla käytettävissä ilman JavaScript-koodin suorittamista.
here_is_how: Näin voit tehdä sen
- hint_html: "Mastodonissa henkilöllisyyden vahventaminen on jokaisen käyttäjän ulottuvilla. Tämä perustuu avoimiin standardeihin, maksuttomasti nyt ja aina. Kaikki mitä tarvitset on henkilökohtainen verkkosivusto, jonka avulla sinut voidaan tunnistaa. Kun Mastodon-profiilistasi on linkki kyseiselle verkkosivustollesi, ja sieltä löytyy vastaviittaus tai -linkitys profiiliisi, näkyy profiilissasi vahvistustunniste."
- instructions_html: Kopioi ja liitä alla oleva koodi verkkosivusi HTML-lähdekoodiin. Lisää sitten verkkosivustosi osoite johonkin ylimääräisistä kentistä profiiliasetuksissa, "Muokkaa profiilia" -välilehdestä, ja tallenna muutokset.
+ hint_html: "Henkilöllisyyden vahvistaminen on Mastodonissa jokaisen käyttäjän ulottuvilla. Se perustuu avoimiin standardeihin ja on maksutonta nyt ja aina. Tarvitset vain henkilökohtaisen verkkosivuston, jonka perusteella sinut voidaan tunnistaa. Kun teet linkin tuolle verkkosivulle profiilistasi, tarkistamme, että verkkosivustolla on linkki takaisin profiiliisi, ja näytämme profiilissasi visuaalisen ilmaisimen."
+ instructions_html: Kopioi ja liitä alla oleva koodi verkkosivustosi HTML-lähdekoodiin. Lisää sitten verkkosivustosi osoite johonkin profiilisi lisäkentistä ”Muokkaa profiilia” -välilehdellä ja tallenna muutokset.
verification: Vahvistus
verified_links: Vahvistetut linkkisi
webauthn_credentials:
add: Lisää uusi suojausavain
create:
- error: Suojausavaimen lisäämisessä tapahtui ongelma. Yritä uudelleen.
- success: Sinun suojausavaimen lisääminen onnistui.
+ error: Suojausavaimen lisäämisessä oli ongelma. Yritä uudelleen.
+ success: Suojausavaimesi lisääminen onnistui.
delete: Poista
delete_confirmation: Haluatko varmasti poistaa tämän suojausavaimen?
description_html: Jos otat suojausavaimen todennuksen käyttöön, kirjautuminen edellyttää jonkin suojausavaimen käyttämistä.
destroy:
- error: Suojausavaimen poistamisessa tapahtui ongelma. Yritä uudelleen.
- success: Sinun suojausavaimen poistaminen onnistui.
+ error: Suojausavaimen poistamisessa oli ongelma. Yritä uudelleen.
+ success: Suojausavaimesi poistaminen onnistui.
invalid_credential: Virheellinen suojausavain
- nickname_hint: Anna nimimerkki uudelle suojausavaimelle
- not_enabled: Et ole vielä ottanut käyttöön WebAuthn-ohjelmaa
+ nickname_hint: Anna uuden suojausaivaimesi lempinimi
+ not_enabled: Et ole vielä ottanut WebAuthn-ohjelmaa käyttöön
not_supported: Tämä selain ei tue suojausavaimia
- otp_required: Jos haluat käyttää suojausavaimia, ota ensin käyttöön kaksivaiheinen todennus.
+ otp_required: Jos haluat käyttää suojausavaimia, ota ensin kaksivaiheinen todennus käyttöön.
registered_on: Rekisteröity %{date}
diff --git a/config/locales/fo.yml b/config/locales/fo.yml
index 3c7fe4d9973729..bd716fa3846fc3 100644
--- a/config/locales/fo.yml
+++ b/config/locales/fo.yml
@@ -534,6 +534,7 @@ fo:
total_reported: Meldingar um tey
total_storage: Viðheftir miðlar
totals_time_period_hint_html: Við í samanteljingunum niðanfyri eru dátur frá byrjan av.
+ unknown_instance: Í løtuni er hetta navnaøkið ikki skrásett á hesum ambætaranum.
invites:
deactivate_all: Ger allar óvirknar
filter:
@@ -1101,6 +1102,7 @@ fo:
functional: Konta tín er fult virkin.
pending: Umsókn tín verður eftirkannað av okkara starvsfeløgum. Tað kann taka eina løtu. Tú móttekur eitt teldubræv, um umsóknin er góðkend.
redirecting_to: Konta tín er óvirkin, tí í løtuni verður hon víðaribeind til %{acct}.
+ self_destruct: Av tí at %{domain} er í ferð við at lukka, fært tú einans avmarkaða atgongd til tína kontu.
view_strikes: Vís eldri atsóknir móti tíni kontu
too_fast: Oyðublaðið innsent ov skjótt, royn aftur.
use_security_key: Brúka trygdarlykil
@@ -1570,6 +1572,9 @@ fo:
over_daily_limit: Tú er komin at markinum, sum er %{limit} skrálagdir postar, í dag
over_total_limit: Tú er komin at markinum, sum er %{limit} skrálagdir postar
too_soon: Ætlanardagfestingin má vera í framtíðini
+ self_destruct:
+ lead_html: Tíverri, %{domain} er í ferð við at blíva lukkað niður med alla. Um tú hevði eina kontu har, so ber ikki til framhaldandi at brúka hana, men tú kann framvegis biðja um trygdaravrit av tínum dátum.
+ title: Hesin ambætarin er í ferð við at lukka
sessions:
activity: Seinasta virksemi
browser: Kagi
diff --git a/config/locales/fr-QC.yml b/config/locales/fr-QC.yml
index b9605f3a6ae9b9..15e0fa60963229 100644
--- a/config/locales/fr-QC.yml
+++ b/config/locales/fr-QC.yml
@@ -534,6 +534,7 @@ fr-QC:
total_reported: Signalements à leur sujet
total_storage: Attachements de média
totals_time_period_hint_html: Les totaux affichés ci-dessous incluent des données sans limite de temps.
+ unknown_instance: Il n’y a actuellement aucune trace de ce domaine sur ce serveur.
invites:
deactivate_all: Tout désactiver
filter:
@@ -1101,6 +1102,7 @@ fr-QC:
functional: Votre compte est entièrement opérationnel.
pending: Votre demande est en attente d'examen par notre personnel. Cela peut prendre un certain temps. Vous recevrez un courriel si votre demande est approuvée.
redirecting_to: Votre compte est inactif car il est actuellement redirigé vers %{acct}.
+ self_destruct: Comme %{domain} est en train de fermer, vous n’aurez qu’un accès limité à votre compte.
view_strikes: Voir les sanctions précédemment appliquées à votre compte
too_fast: Formulaire envoyé trop rapidement, veuillez réessayer.
use_security_key: Utiliser la clé de sécurité
@@ -1570,6 +1572,9 @@ fr-QC:
over_daily_limit: Vous avez dépassé la limite de %{limit} messages planifiés par jour
over_total_limit: Vous avez dépassé la limite de %{limit} messages planifiés
too_soon: La date planifiée doit être dans le futur
+ self_destruct:
+ lead_html: Malheureusement, %{domain} ferme définitivement. Si vous y aviez un compte, vous ne pourrez pas continuer à l’utiliser, mais vous pouvez toujours demander une sauvegarde de vos données.
+ title: Ce serveur est en cours de fermeture
sessions:
activity: Dernière activité
browser: Navigateur
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index 821ef39dbe054e..1616f76726560f 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -534,6 +534,7 @@ fr:
total_reported: Signalements à leur sujet
total_storage: Attachements de média
totals_time_period_hint_html: Les totaux affichés ci-dessous incluent des données sans limite de temps.
+ unknown_instance: Il n’y a actuellement aucune trace de ce domaine sur ce serveur.
invites:
deactivate_all: Tout désactiver
filter:
@@ -1101,6 +1102,7 @@ fr:
functional: Votre compte est entièrement opérationnel.
pending: Votre demande est en attente d'examen par notre personnel. Cela peut prendre un certain temps. Vous recevrez un courriel si votre demande est approuvée.
redirecting_to: Votre compte est inactif car il est actuellement redirigé vers %{acct}.
+ self_destruct: Comme %{domain} est en train de fermer, vous n’aurez qu’un accès limité à votre compte.
view_strikes: Voir les sanctions précédemment appliquées à votre compte
too_fast: Formulaire envoyé trop rapidement, veuillez réessayer.
use_security_key: Utiliser la clé de sécurité
@@ -1570,6 +1572,9 @@ fr:
over_daily_limit: Vous avez dépassé la limite de %{limit} messages planifiés par jour
over_total_limit: Vous avez dépassé la limite de %{limit} messages planifiés
too_soon: La date planifiée doit être dans le futur
+ self_destruct:
+ lead_html: Malheureusement, %{domain} ferme définitivement. Si vous y aviez un compte, vous ne pourrez pas continuer à l’utiliser, mais vous pouvez toujours demander une sauvegarde de vos données.
+ title: Ce serveur est en cours de fermeture
sessions:
activity: Dernière activité
browser: Navigateur
diff --git a/config/locales/fy.yml b/config/locales/fy.yml
index 41ad60cf69b880..a7ab89fc87c079 100644
--- a/config/locales/fy.yml
+++ b/config/locales/fy.yml
@@ -534,6 +534,7 @@ fy:
total_reported: Rapportaazjes oer harren
total_storage: Mediabylagen
totals_time_period_hint_html: De hjirûnder toande totalen befetsje gegevens sûnt it begjin.
+ unknown_instance: Der binne op dit stuit gjin gegevens fan dit domein op dizze server.
invites:
deactivate_all: Alles deaktivearje
filter:
@@ -1101,6 +1102,7 @@ fy:
functional: Jo account kin folslein brûkt wurde.
pending: Jo oanfraach moat noch beoardiele wurde troch ien fan ús meiwurkers. Dit kin miskien efkes duorje. Jo ûntfangt in e-mailberjocht wannear’t jo oanfraach goedkard is.
redirecting_to: Jo account is ynaktyf, omdat it op dit stuit trochferwezen wurdt nei %{acct}.
+ self_destruct: Omdat %{domain} sluten sil, krije jo mar beheind tagong ta jo account.
view_strikes: Besjoch de earder troch moderatoaren fêststelde skeiningen dy’t jo makke hawwe
too_fast: Formulier is te fluch yntsjinne. Probearje it nochris.
use_security_key: Befeiligingskaai brûke
@@ -1570,6 +1572,9 @@ fy:
over_daily_limit: Jo binne oer de limyt fan %{limit} yn te plannen berjochten foar hjoed
over_total_limit: Jo binne oer de limyt fan %{limit} yn te plannen berjochten
too_soon: De datum foar it ynplande berjocht moat yn de takomst lizze
+ self_destruct:
+ lead_html: Spitigernôch sil %{domain} permanint ôfslute. As jo dêr in account hiene, kinne jo dizze net mear brûke, mar jo kinne noch hieltyd in reservekopy fan jo gegevens opfreegje.
+ title: Deze server sil ôfslute
sessions:
activity: Lêst warber
browser: Browser
diff --git a/config/locales/gd.yml b/config/locales/gd.yml
index e620db3a78e0ae..b2ccdd4d9d7572 100644
--- a/config/locales/gd.yml
+++ b/config/locales/gd.yml
@@ -556,6 +556,7 @@ gd:
total_reported: Gearanan mun dèidhinn
total_storage: Ceanglachain mheadhanan
totals_time_period_hint_html: Gabhaidh na h-iomlanan gu h-ìosal a-staigh an dàta o chian nan cian.
+ unknown_instance: Chan eil clàr dhen àrainn seo air an fhrithealaiche seo.
invites:
deactivate_all: Cuir na h-uile à gnìomh
filter:
@@ -1137,6 +1138,7 @@ gd:
functional: Tha an cunntas agad ag obair gu slàn.
pending: Feumaidh an sgioba againn lèirmheas a dhèanamh air d’ iarrtas. Dh’fhaoidte gun doir seo greis. Gheibh thu post-d nuair a bhios sinn air aontachadh ri d’ iarrtas.
redirecting_to: Chan eil an cunntas gad gnìomhach on a tha e ’ga ath-stiùireadh gu %{acct}.
+ self_destruct: On a tha %{domain} gu bhith dùnadh, chan fhaigh thu ach inntrigeadh cuingichte dhan chunntas agad.
view_strikes: Seall na rabhaidhean a fhuair an cunntas agad roimhe
too_fast: Chaidh am foirm a chur a-null ro luath, feuch ris a-rithist.
use_security_key: Cleachd iuchair tèarainteachd
@@ -1622,6 +1624,9 @@ gd:
over_daily_limit: Chaidh thu thar na crìoch de %{limit} post(aichean) sgeidealaichte an-diugh
over_total_limit: Chaidh thu thar na crìoch de %{limit} post(aichean) sgeidealaichte
too_soon: Feumaidh ceann-latha an sgeideil a bhith san àm ri teachd
+ self_destruct:
+ lead_html: Gu mì-fhortanach, thèid %{domain} a dhùnadh gu buan. Ma tha cunntas agad ann, chan urrainn dhut cumail a’ gol ’ga chleachdadh ach ’s urrainn dhut lethbhreac-glèidhidh dhen dàta agad iarraidh fhathast.
+ title: Tha am frithealaiche seo gu bhith dùnadh
sessions:
activity: A’ ghnìomhachd mu dheireadh
browser: Brabhsair
diff --git a/config/locales/gl.yml b/config/locales/gl.yml
index 14f78e46159287..f76c4dda12f1a2 100644
--- a/config/locales/gl.yml
+++ b/config/locales/gl.yml
@@ -534,6 +534,7 @@ gl:
total_reported: Denuncias sobre eles
total_storage: Adxuntos multimedia
totals_time_period_hint_html: Os totais aquí mostrados inclúen todo o historial de datos.
+ unknown_instance: Actualmente non temos constancia deste rexistro no servidor.
invites:
deactivate_all: Desactivar todo
filter:
@@ -1101,6 +1102,7 @@ gl:
functional: A túa conta está completamente operativa.
pending: A túa solicitude está pendente de revisión. Poderíanos levar algún tempo. Recibirás un correo se a solicitude está aprobada.
redirecting_to: A túa conta está inactiva porque está redirixida a %{acct}.
+ self_destruct: Como %{domain} vai fechar, tes acceso restrinxido á túa conta.
view_strikes: Ver avisos anteriores respecto da túa conta
too_fast: Formulario enviado demasiado rápido, inténtao outra vez.
use_security_key: Usa chave de seguridade
@@ -1570,6 +1572,9 @@ gl:
over_daily_limit: Excedeches o límite de %{limit} publicacións programadas para ese día
over_total_limit: Excedeches o límite de %{limit} publicacións programadas
too_soon: A data de programación debe estar no futuro
+ self_destruct:
+ lead_html: Desafortunadamente, %{domain} vai deixar de dar servizo. Se tes unha conta aquí non poderás seguir usándoa, mais podes solicitar un ficheiro cos teus datos.
+ title: Este servidor vai fechar
sessions:
activity: Última actividade
browser: Navegador
diff --git a/config/locales/he.yml b/config/locales/he.yml
index a7c702e9790431..33f57155f2d130 100644
--- a/config/locales/he.yml
+++ b/config/locales/he.yml
@@ -556,6 +556,7 @@ he:
total_reported: דוחות אודותיהם
total_storage: קבצי מדיה מצורפים
totals_time_period_hint_html: הסכומים המוצגים להלן כוללים מידע מכל הזמנים.
+ unknown_instance: אין כרגע תיעוד של שם המתחם הזה על שרת זה.
invites:
deactivate_all: להשבית הכל
filter:
@@ -1137,6 +1138,7 @@ he:
functional: החשבון שלכם פעיל לגמרי.
pending: בקשתך ממתינה לאישור על ידי הצוות שלנו. זה עשוי לקחת זמן מה. דוא"ל יישלח אליך אם בקשתך התקבלה.
redirecting_to: חשבונכם לא פעיל כעת מכיוון שמפנה ל%{acct}.
+ self_destruct: מכיוון שהשרת %{domain} בתהליכי סגירה, תהיה לך גישה מוגבלת בלבד לחשבונך.
view_strikes: צפיה בעברות קודמות שנרשמו נגד חשבונך
too_fast: הטופס הוגש מהר מדי, נסה/י שוב.
use_security_key: שימוש במפתח אבטחה
@@ -1622,6 +1624,9 @@ he:
over_daily_limit: חרגת מהמספר המקסימלי של הודעות מתוזמנות להיום, שהוא %{limit}
over_total_limit: חרגת מהמספר המקסימלי של הודעות מתוזמנות, שהוא %{limit}
too_soon: תאריך התזמון חייב להיות בעתיד
+ self_destruct:
+ lead_html: לרוע המזל, %{domain} עומד לרדת באופן סופי. אם היה לך חשבון כאן, לא תהיה אפשרות להמשיך להשתמש בו, אבל ניתן לבקש גיבוי של כל המידע שלך.
+ title: שרת זה בתהליכי סגירה
sessions:
activity: פעילות אחרונה
browser: דפדפן
diff --git a/config/locales/hr.yml b/config/locales/hr.yml
index d1e6728d427ef6..aa7ee760baf755 100644
--- a/config/locales/hr.yml
+++ b/config/locales/hr.yml
@@ -27,12 +27,17 @@ hr:
new_email: Nova e-pošta
submit: Promijeni e-poštu
title: Promjena e-pošte za %{username}
+ change_role:
+ changed_msg: Uloga uspješno dodijeljena!
+ label: Promjeni ulogu
confirm: Potvrdi
confirmed: Potvrđeno
confirming: Potvrđivanje
custom: Prilagođeno
delete: Izbriši podatke
deleted: Izbrisano
+ disable: Zamrzni
+ disable_two_factor_authentication: Onemogući 2FA
display_name: Prikazano ime
domain: Domena
edit: Uredi
diff --git a/config/locales/hu.yml b/config/locales/hu.yml
index f9eafb9081580d..67f5b693ac8e1c 100644
--- a/config/locales/hu.yml
+++ b/config/locales/hu.yml
@@ -534,6 +534,7 @@ hu:
total_reported: Bejelentés róluk
total_storage: Média csatolmány
totals_time_period_hint_html: Az alább mutatott összesítések minden eddigi adatot tartalmaznak.
+ unknown_instance: Jelenleg nincs rekord erről a domainről ezen a kiszolgálón.
invites:
deactivate_all: Összes deaktiválása
filter:
@@ -1101,6 +1102,7 @@ hu:
functional: A fiókod teljesen működőképes.
pending: A jelentkezésed engedélyezésre vár. Ez eltarthat egy ideig. Kapsz egy e-mailt, ha a kérelmedet jóváhagyták.
redirecting_to: A fiókod inaktív, mert jelenleg ide %{acct} van átirányítva.
+ self_destruct: Mivel a %{domain} bezár, csak korlátozott elérésed lesz a fiókodhoz.
view_strikes: Fiókod ellen felrótt korábbi vétségek megtekintése
too_fast: Túl gyorsan küldted el az űrlapot, próbáld később.
use_security_key: Biztonsági kulcs használata
@@ -1570,6 +1572,9 @@ hu:
over_daily_limit: Túllépted az időzített bejegyzésekre vonatkozó %{limit} db-os napi limitet
over_total_limit: Túllépted az időzített bejegyzésekre vonatkozó %{limit} db-os limitet
too_soon: Az időzített időpontnak a jövőben kell lennie
+ self_destruct:
+ lead_html: Sajnos a %{domain} végleg bezár. Ha volt itt fiókod, nem fogod tudni tovább használni, de kérheted majd az adataid biztonsági mentését.
+ title: A kiszolgáló bezár
sessions:
activity: Legutóbbi tevékenység
browser: Böngésző
diff --git a/config/locales/hy.yml b/config/locales/hy.yml
index f32fe33ab7bfd2..f3a6392ff09e0d 100644
--- a/config/locales/hy.yml
+++ b/config/locales/hy.yml
@@ -463,20 +463,40 @@ hy:
regenerate_token: Ստեղծել նոր հասանելիութեան կտրոն
your_token: Քո մուտքի բանալին
auth:
+ apply_for_account: Ուղարկել
delete_account: Ջնջել հաշիվը
description:
prefix_sign_up: Գրանցուի՛ր Մաստոդոնում հենց այսօր
+ didnt_get_confirmation: Չե՞ս ստացել հաստատման յղում
dont_have_your_security_key: Չունե՞ս անվտանգութեան բանալի։
forgot_password: Մոռացե՞լ ես գաղտնաբառդ
login: Մտնել
logout: Դուրս գալ
migrate_account: Տեղափոխուել այլ հաշիւ
or_log_in_with: Կամ մուտք գործել օգտագործելով՝
+ privacy_policy_agreement_html: Ես կարդացել եւ ընդունել եմ գաղնիութեան քաղաքականութիւնը
+ progress:
+ confirm: Փոստի հաստատում
+ details: Ձեր տուեալները
+ review: Վաւերացում
+ rules: Ընդունել կանոները
register: Գրանցվել
registration_closed: "%{instance}ը չի ընդունում նոր անդամներ"
reset_password: Վերականգնել գաղտանաբառը
+ rules:
+ accept: Հաստատել
+ back: Վերադառնալ
+ preamble: Կանոնները սահմանում եւ կիրառում են %{domain}-ի մոդերատորները։
+ title: Մի քանի հիմանական կանոններ։
security: Անվտանգություն
set_new_password: Սահմանել նոր գաղտնաբառ
+ sign_in:
+ preamble_html: Մուտքագրէք %{domain}-ի ձեր տուեալները։ Եթե ձեր հաշիւը ուրիշ սպասարկիչի վրայ է, այտեղ մտնել չի ստացուի։
+ title: Մտնել %{domain}
+ sign_up:
+ manual_review: Գրանցումները %{domain}-ում վաւերացնում են մոդերատորնրը։ Մեզ օգնելու համար մի փոքր պատմէք ձեր մասին եւ թե ինչու էք ուզում գրանցուել։
+ preamble: Այս հանգոյցում հաշիւ ունենալով դուք կարող էք հերտեւել դաշնեզերքի ցանկացած օգտատիրոջ, անկախ նրանից թե որտեղ է նրա հաշիւը տեղակայուած։
+ title: Ստեղծի՜ր հաշիւ %{domain}-ում
status:
account_status: Հաշուի կարգավիճակ
pending: Դիմումը պէտք է քննուի մեր անձնակազմի կողմից, ինչը կարող է մի փոքր ժամանակ խլել։ Դիմումի հաստատուելու դէպքում, կտեղեկացնենք նամակով։
@@ -685,6 +705,8 @@ hy:
other: Այլ
posting_defaults: Կանխադիր կարգաւորումներ
public_timelines: Հանրային հոսք
+ privacy:
+ search: Որոնել
privacy_policy:
title: Գաղտնիութեան քաղաքականութիւն
reactions:
diff --git a/config/locales/is.yml b/config/locales/is.yml
index c3608a7359b3ae..f5d89eca66c91e 100644
--- a/config/locales/is.yml
+++ b/config/locales/is.yml
@@ -534,6 +534,7 @@ is:
total_reported: Kærur um þá
total_storage: Myndaviðhengi
totals_time_period_hint_html: Samtölurnar sem birtar eru hér fyrir neðan innihalda gögn frá upphafi.
+ unknown_instance: Í augnablikinu er engin færsla um þetta lén á þessum netþjóni.
invites:
deactivate_all: Gera allt óvirkt
filter:
@@ -1105,6 +1106,7 @@ is:
functional: Notandaaðgangurinn þinn er með fulla virkni.
pending: Umsóknin þín bíður eftir að starfsfólkið okkar fari yfir hana. Það gæti tekið nokkurn tíma. Þú munt fá tölvupóst ef umsóknin er samþykkt.
redirecting_to: Notandaaðgangurinn þinn er óvirkur vegna þess að hann endurbeinist á %{acct}.
+ self_destruct: Þar sem %{domain} er að hætta starfsemi, muntu aðeins halda takmörkuðum aðgangi að aðgangnum þínum.
view_strikes: Skoða fyrri bönn notandaaðgangsins þíns
too_fast: Innfyllingarform sent inn of hratt, prófaðu aftur.
use_security_key: Nota öryggislykil
@@ -1574,6 +1576,9 @@ is:
over_daily_limit: Þú hefur farið fram úr hámarkinu með %{limit} áætlaðar færslur fyrir þennan dag
over_total_limit: Þú hefur farið fram úr hámarkinu með %{limit} áætlaðar færslur
too_soon: Áætluð dagsetning verður að vera í framtíðinni
+ self_destruct:
+ lead_html: Því miður, %{domain} er að hætta starfsemi endanlega. Ef þú varst með aðgang þar, muntu ekki geta haldið áfram að nota hann, en þú getur áfram beðið um afrit af gögnunum þínum.
+ title: Þessi netþjónn er að hætta starfsemi
sessions:
activity: Síðasta virkni
browser: Vafri
diff --git a/config/locales/it.yml b/config/locales/it.yml
index 2438e7e62a19ba..6e41389bc586d6 100644
--- a/config/locales/it.yml
+++ b/config/locales/it.yml
@@ -534,6 +534,7 @@ it:
total_reported: Segnalazioni su di loro
total_storage: Media allegati
totals_time_period_hint_html: I totali sotto visualizzati includono i dati per tutti i tempi.
+ unknown_instance: Al momento non c'è alcun documento di questo dominio su questo server.
invites:
deactivate_all: Disattiva tutto
filter:
@@ -1103,6 +1104,7 @@ it:
functional: Il tuo profilo è completamente operativo.
pending: La tua richiesta è in attesa di esame da parte del nostro staff. Potrebbe richiedere un po' di tempo. Riceverai una e-mail se la richiesta è approvata.
redirecting_to: Il tuo account è inattivo perché attualmente reindirizza a %{acct}.
+ self_destruct: Poiché %{domain} sta chiudendo, otterrai solo un accesso limitato al tuo account.
view_strikes: Visualizza le sanzioni precedenti prese nei confronti del tuo account
too_fast: Modulo inviato troppo velocemente, riprova.
use_security_key: Usa la chiave di sicurezza
@@ -1572,6 +1574,9 @@ it:
over_daily_limit: Hai superato il limite di %{limit} post programmati per questo giorno
over_total_limit: Hai superato il limite di %{limit} post programmati
too_soon: La data di pubblicazione deve essere nel futuro
+ self_destruct:
+ lead_html: Sfortunatamente, %{domain} sta chiudendo definitivamente. Se hai un account lì, non potrai continuare a usarlo, ma puoi ancora richiedere un backup dei tuoi dati.
+ title: Questo server sta chiudendo
sessions:
activity: Ultima attività
browser: Browser
diff --git a/config/locales/ja.yml b/config/locales/ja.yml
index b18405fb659335..9df32b09dd15a5 100644
--- a/config/locales/ja.yml
+++ b/config/locales/ja.yml
@@ -523,6 +523,7 @@ ja:
total_reported: 通報合計
total_storage: 添付されたメディア
totals_time_period_hint_html: 以下に表示される合計には、すべての時間のデータが含まれています。
+ unknown_instance: 今のところ、このドメインについては何も記録されていません。
invites:
deactivate_all: すべて無効化
filter:
@@ -770,12 +771,12 @@ ja:
critical_update: "※緊急 (速やかに適用してください)"
description: Mastodonサーバーはいつでも最新の状態を保ち、新しい機能や修正を利用できるようにしておくことをおすすめします。またセキュリティの問題が発生した場合は、速やかにMastodonをアップデートすることが大切です。Mastodonは30分おきにアップデートを確認し、通知設定に応じて新しいアップデートをメールで通知します。
documentation_link: もっと見る
- release_notes: 更新情報
+ release_notes: リリースノート
title: 利用可能なアップデート
type: アップデートの種別
types:
major: メジャーリリース
- minor: リリース
+ minor: マイナーリリース
patch: パッチ (バグ修正のみ)
version: バージョン
statuses:
@@ -1083,6 +1084,7 @@ ja:
functional: アカウントは完全に機能しています。
pending: あなたの申請は現在サーバー管理者による審査待ちです。これにはしばらくかかります。申請が承認されるとメールが届きます。
redirecting_to: アカウントは%{acct}に引っ越し設定されているため非アクティブになっています。
+ self_destruct: "%{domain} は閉鎖されるため、今後このアカウントでは限られた操作しかできません。"
view_strikes: 過去のストライクを表示
too_fast: フォームの送信が速すぎます。もう一度やり直してください。
use_security_key: セキュリティキーを使用
@@ -1544,6 +1546,9 @@ ja:
over_daily_limit: その日予約できる投稿数 %{limit}を超えています
over_total_limit: 予約できる投稿数 %{limit}を超えています
too_soon: より先の時間を指定してください
+ self_destruct:
+ lead_html: 残念ながら、%{domain} は恒久的に閉鎖されます。ここにお持ちだったアカウントを今後使うことはできませんが、これまでのデータのバックアップを要求することはまだ可能です。
+ title: このサーバーは閉鎖されます
sessions:
activity: 最後のアクティビティ
browser: ブラウザ
@@ -1653,7 +1658,7 @@ ja:
private_long: フォロワーにのみ表示されます
public: 公開
public_long: 誰でも見ることができ、かつ公開タイムラインに表示されます
- unlisted: 未収載
+ unlisted: 非収載
unlisted_long: 誰でも見ることができますが、公開タイムラインには表示されません
statuses_cleanup:
enabled: 古い投稿を自動的に削除する
diff --git a/config/locales/ko.yml b/config/locales/ko.yml
index da6d8596e0429c..eecac963e00f7a 100644
--- a/config/locales/ko.yml
+++ b/config/locales/ko.yml
@@ -47,7 +47,7 @@ ko:
label: 역할 변경
no_role: 역할 없음
title: "%{username}의 역할 변경"
- confirm: 확정
+ confirm: 신원 확인
confirmed: 확인됨
confirming: 확인 중
custom: 사용자 지정
@@ -269,7 +269,7 @@ ko:
reopen_report_html: "%{name} 님이 신고 %{target}을 다시 열었습니다"
resend_user_html: "%{name} 님이 %{target} 님에 대한 확인 메일을 다시 보냈습니다"
reset_password_user_html: "%{name} 님이 사용자 %{target}의 암호를 초기화했습니다"
- resolve_report_html: "%{name} 중재자가 %{target}번 신고를 해결로 변경하였습니다"
+ resolve_report_html: "%{name} 님이 %{target}번 신고를 해결로 변경하였습니다"
sensitive_account_html: "%{name} 님이 %{target}의 미디어를 민감함으로 표시했습니다"
silence_account_html: "%{name} 님이 %{target}의 계정을 제한시켰습니다"
suspend_account_html: "%{name} 님이 %{target}의 계정을 정지시켰습니다"
@@ -525,6 +525,7 @@ ko:
total_reported: 이들에 대한 신고
total_storage: 미디어 첨부
totals_time_period_hint_html: 아래에 표시된 총계에는 모든 시간에 대한 데이터가 포함됩니다.
+ unknown_instance: 현재 이 서버에서 해당 도메인에 대한 기록은 없습니다.
invites:
deactivate_all: 전부 비활성화
filter:
@@ -778,7 +779,7 @@ ko:
types:
major: 메이저 릴리스
minor: 마이너 릴리스
- patch: 패치 릴리스 — 버그픽스 그리고 변경점의 빠른 적용
+ patch: 패치 릴리스 — 버그픽스이며 변경을 적용하기 쉽습니다
version: 버전
statuses:
account: 작성자
@@ -881,9 +882,9 @@ ko:
only_allowed: 허용된 것만
pending_review: 심사 대기
preview_card_providers:
- allowed: 이 발행처의 링크는 유행록에 실릴 수 있음
+ allowed: 이 발행처의 링크는 유행 목록에 실릴 수 있음
description_html: 당신의 서버에서 많은 링크가 공유되고 있는 도메인들입니다. 링크의 도메인이 승인되기 전까지는 링크들은 공개적으로 트렌드에 게시되지 않습니다. 당신의 승인(또는 거절)은 서브도메인까지 확장됩니다.
- rejected: 이 발행처의 링크는 유행록에 실리지 않음
+ rejected: 이 발행처의 링크는 유행 목록에 실리지 않음
title: 발행처
rejected: 거부됨
statuses:
@@ -906,14 +907,14 @@ ko:
tag_servers_measure: 다른 서버들
tag_uses_measure: 총 사용
description_html: 현재 서버에서 볼 수 있는 게시물에서 많이 공유되고 있는 해시태그들입니다. 현재 사람들이 무슨 이야기를 하고 있는지 사용자들이 파악할 수 있도록 도움이 됩니다. 승인하지 않는 한 해시태그는 공개적으로 게시되지 않습니다.
- listable: 추천될 수 있습니다
+ listable: 추천될 수 있음
no_tag_selected: 아무 것도 선택 되지 않아 어떤 태그도 바뀌지 않았습니다
- not_listable: 추천될 수 없습니다
- not_trendable: 유행 목록에 나타나지 않습니다
- not_usable: 사용불가
+ not_listable: 추천하지 않음
+ not_trendable: 유행 목록에 나타내지 않음
+ not_usable: 이용할 수 없음
peaked_on_and_decaying: "%{date}에 고점을 찍고, 떨어지고 있습니다"
title: 유행하는 해시태그
- trendable: 유행 목록에 나타날 수 있습니다
+ trendable: 유행 목록에 나타날 수 있음
trending_rank: "#%{rank}위로 유행 중"
usable: 사용 가능
usage_comparison: 오늘은 %{today}회 쓰였고, 어제는 %{yesterday}회 쓰임
@@ -1085,6 +1086,7 @@ ko:
functional: 계정이 완벽히 작동합니다.
pending: 당신의 가입 신청은 스태프의 검사를 위해 대기 중입니다. 시간이 조금 걸릴 수 있습니다. 가입 신청이 승인되면 이메일을 받게 됩니다.
redirecting_to: 계정이 %{acct}로 리다이렉트 중이기 때문에 비활성 상태입니다.
+ self_destruct: "%{domain} 도메인 폐쇄가 진행중이기 때문에, 계정에는 제한된 접근만 할 수 있습니다."
view_strikes: 내 계정에 대한 과거 중재 기록 보기
too_fast: 너무 빠르게 양식이 제출되었습니다, 다시 시도하세요.
use_security_key: 보안 키 사용
@@ -1546,6 +1548,9 @@ ko:
over_daily_limit: 그 날짜에 대한 %{limit}개의 예약 게시물 제한을 초과합니다
over_total_limit: 예약 게시물 제한 %{limit}을 초과합니다
too_soon: 예약 날짜는 미래여야 합니다
+ self_destruct:
+ lead_html: 안타깝게도, %{domain} 도메인을 영구히 폐쇄합니다. 이곳의 계정을 가졌다면, 이제 이용할 수 없으며, 당분간 백업 데이터를 요청할 수 있습니다.
+ title: 이 서버는 폐쇄중입니다
sessions:
activity: 최근 활동
browser: 브라우저
diff --git a/config/locales/lv.yml b/config/locales/lv.yml
index 02a34fd8563231..28a1a33dcb6540 100644
--- a/config/locales/lv.yml
+++ b/config/locales/lv.yml
@@ -460,7 +460,7 @@ lv:
description_html: Tu gatavojies importēt domēna bloku sarakstu. Lūdzu, ļoti rūpīgi pārskati šo sarakstu, it īpaši, ja tu pats neesi to veidojis.
existing_relationships_warning: Esošās sekošanas attiecības
private_comment_description_html: 'Lai palīdzētu tev izsekot, no kurienes nāk importētie bloki, tiks izveidoti importētie bloki ar šādu privātu komentāru: %{comment}
'
- private_comment_template: Importēts no %{source} %{date}
+ private_comment_template: Importēt no %{source} %{date}
title: Importēt bloķētos domēnus
invalid_domain_block: 'Viens vai vairāki domēna bloķi tika izlaisti šādas kļūdas(-u) dēļ: %{error}'
new:
@@ -1107,7 +1107,7 @@ lv:
new_confirmation_instructions_sent: Pēc dažām minūtēm saņemsi jaunu e-pastu ar apstiprinājuma saiti!
title: Pārbaudi savu iesūtni
sign_in:
- preamble_html: Pierakstieties ar saviem %{domain} akreditācijas datiem. Ja jūsu konts ir mitināts citā serverī, jūs nevarēsit pieteikties šeit.
+ preamble_html: Piesakies ar saviem %{domain} akreditācijas datiem. Ja tavs konts ir mitināts citā serverī, tu nevarēsi pieteikties šeit.
title: Pierakstīties %{domain}
sign_up:
manual_review: Reģistrācijas domēnā %{domain} manuāli pārbauda mūsu moderatori. Lai palīdzētu mums apstrādāt tavu reģistrāciju, uzraksti mazliet par sevi un to, kāpēc vēlies kontu %{domain}.
diff --git a/config/locales/nl.yml b/config/locales/nl.yml
index 3e9d502ae9ad06..f107cbeca18c32 100644
--- a/config/locales/nl.yml
+++ b/config/locales/nl.yml
@@ -534,6 +534,7 @@ nl:
total_reported: Rapportages over hun
total_storage: Mediabijlagen
totals_time_period_hint_html: De hieronder getoonde totalen bevatten gegevens sinds het begin.
+ unknown_instance: Er zijn momenteel geen gegevens van dit domein op deze server.
invites:
deactivate_all: Alles deactiveren
filter:
@@ -1101,6 +1102,7 @@ nl:
functional: Jouw account kan in diens geheel gebruikt worden.
pending: Jouw aanvraag moet nog worden beoordeeld door een van onze medewerkers. Dit kan misschien eventjes duren. Je ontvangt een e-mail wanneer jouw aanvraag is goedgekeurd.
redirecting_to: Jouw account is inactief omdat het momenteel wordt doorverwezen naar %{acct}.
+ self_destruct: Omdat %{domain} gaat sluiten, krijgt u slechts beperkt toegang tot uw account.
view_strikes: Bekijk de eerder door moderatoren vastgestelde overtredingen die je hebt gemaakt
too_fast: Formulier is te snel ingediend. Probeer het nogmaals.
use_security_key: Beveiligingssleutel gebruiken
@@ -1570,6 +1572,9 @@ nl:
over_daily_limit: Je hebt de limiet van %{limit} in te plannen berichten voor vandaag overschreden
over_total_limit: Je hebt de limiet van %{limit} in te plannen berichten overschreden
too_soon: De datum voor het ingeplande bericht moet in de toekomst liggen
+ self_destruct:
+ lead_html: Helaas gaat %{domain} permanent afsluiten. Als u daar een account had, kunt u deze niet meer gebruiken, maar u kunt nog steeds een back-up van uw gegevens opvragen.
+ title: Deze server gaat afsluiten
sessions:
activity: Laatst actief
browser: Webbrowser
diff --git a/config/locales/nn.yml b/config/locales/nn.yml
index 9f34e5621654a9..1c187c1de1f285 100644
--- a/config/locales/nn.yml
+++ b/config/locales/nn.yml
@@ -570,7 +570,7 @@ nn:
enabled: Skrudd på
inbox_url: Overførings-URL
pending: Avventer overgangens godkjenning
- save_and_enable: Lagr og slå på
+ save_and_enable: Lagre og slå på
setup: Sett opp en overgangsforbindelse
signatures_not_enabled: Overgangar fungerer ikkje så lenge sikker- eller kvitlistingsmodus er aktivert
status: Status
@@ -1280,7 +1280,7 @@ nn:
deselect: Vel ingen
none: Ingen
order_by: Sorter etter
- save_changes: Lagr endringar
+ save_changes: Lagre endringar
select_all_matching_items:
one: Vel %{count} element som passar til søket ditt.
other: Vel %{count} element som passar til søket ditt.
diff --git a/config/locales/pl.yml b/config/locales/pl.yml
index 3f585863a4dd2f..08df6e7fc9f369 100644
--- a/config/locales/pl.yml
+++ b/config/locales/pl.yml
@@ -556,6 +556,7 @@ pl:
total_reported: Zgłoszenia dotyczące ich
total_storage: Załączniki multimedialne
totals_time_period_hint_html: Poniższe sumy zawierają dane od początku serwera.
+ unknown_instance: Obecnie ta domena jest nieznana na tym serwerze.
invites:
deactivate_all: Unieważnij wszystkie
filter:
@@ -1137,6 +1138,7 @@ pl:
functional: Twoje konto jest w pełni funkcjonalne.
pending: Twoje zgłoszenie czeka na zatwierdzenie przez nas. Może to trochę potrwać. Jeżeli zgłoszenie zostanie przyjęte, otrzymasz wiadomość e-mail.
redirecting_to: Twoje konto jest nieaktywne, ponieważ obecnie przekierowuje je na %{acct}.
+ self_destruct: "%{domain} jest zamykane, dostęp do konta będzie ograniczony."
view_strikes: Zobacz dawne ostrzeżenia nałożone na twoje konto
too_fast: Zbyt szybko przesłano formularz, spróbuj ponownie.
use_security_key: Użyj klucza bezpieczeństwa
@@ -1622,6 +1624,9 @@ pl:
over_daily_limit: Przekroczyłeś(-aś) limit %{limit} zaplanowanych wpisów na ten dzień
over_total_limit: Przekroczyłeś(-aś) limit %{limit} zaplanowanych wpisów
too_soon: Zaplanowana data musi wypadać w przyszłości
+ self_destruct:
+ lead_html: Niestety, %{domain} jest permanentnie zamykane. Konta z tego serwera nie będą dostępne, ale można jeszcze odzyskać kopię zapasową danych.
+ title: Ten serwer jest zamykany
sessions:
activity: Ostatnia aktywność
browser: Przeglądarka
diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml
index 114a486e82a4c9..da79c7555ce4f8 100644
--- a/config/locales/pt-BR.yml
+++ b/config/locales/pt-BR.yml
@@ -1101,6 +1101,7 @@ pt-BR:
functional: Sua conta está totalmente operacional.
pending: Sua solicitação está com revisão pendente por parte de nossa equipe. Você receberá um e-mail se ela for aprovada.
redirecting_to: Sua conta está inativa porque atualmente está redirecionando para %{acct}.
+ self_destruct: Como %{domain} está se encerrando, você só terá acesso limitado à sua conta.
view_strikes: Veja os avisos anteriores em relação à sua conta
too_fast: O formulário foi enviado muito rapidamente, tente novamente.
use_security_key: Usar chave de segurança
@@ -1570,6 +1571,9 @@ pt-BR:
over_daily_limit: Você excedeu o limite de %{limit} publicações agendadas para esse dia
over_total_limit: Você excedeu o limite de %{limit} publicações agendadas
too_soon: A data agendada precisa ser no futuro
+ self_destruct:
+ lead_html: Infelizmente, %{domain} está se encerrando de forma permanente. Se você tem uma conta lá, não poderá continuar a usá-la, mas ainda pode solicitar uma cópia dos seus dados.
+ title: Este servidor está sendo fechado
sessions:
activity: Última atividade
browser: Navegador
diff --git a/config/locales/pt-PT.yml b/config/locales/pt-PT.yml
index f4c363324cb872..62b497d70bf488 100644
--- a/config/locales/pt-PT.yml
+++ b/config/locales/pt-PT.yml
@@ -534,6 +534,7 @@ pt-PT:
total_reported: Denúncias sobre eles
total_storage: Anexos de media
totals_time_period_hint_html: Os totais exibidos abaixo incluem dados referentes ao tempo total.
+ unknown_instance: Atualmente não há registo deste domínio neste servidor.
invites:
deactivate_all: Desativar todos
filter:
@@ -1101,6 +1102,7 @@ pt-PT:
functional: A sua conta está totalmente operacional.
pending: A sua inscrição está pendente de revisão pela nossa equipa. Isso pode demorar algum tempo. Receberá um e-mail se a sua conta for aprovada.
redirecting_to: A sua conta está inativa porque está atualmente a ser redirecionada para %{acct}.
+ self_destruct: Como %{domain} vai fechar, só terá acesso limitado à sua conta.
view_strikes: Veja as reprimendas anteriores sobre a sua conta
too_fast: Formulário enviado demasiado rapidamente, tente novamente.
use_security_key: Usar chave de segurança
@@ -1570,6 +1572,9 @@ pt-PT:
over_daily_limit: Excedeste o limite de %{limit} publicações agendadas para esse dia
over_total_limit: Tu excedeste o limite de %{limit} publicações agendadas
too_soon: A data de agendamento tem de ser futura
+ self_destruct:
+ lead_html: Infelizmente, %{domain} vai fechar definitivamente. Se lá tinha conta, não pode continuar a usá-la, mas ainda pode pedir uma cópia dos seus dados.
+ title: Este servidor vai fechar
sessions:
activity: Última atividade
browser: Navegador
diff --git a/config/locales/si.yml b/config/locales/si.yml
index 45be8b76f2af8f..2c2a8ae8245229 100644
--- a/config/locales/si.yml
+++ b/config/locales/si.yml
@@ -1,76 +1,73 @@
---
si:
about:
- about_mastodon_html: 'අනාගත සමාජ ජාලය: දැන්වීම් නැත, ආයතනික නිරීක්ෂණ නැත, සදාචාරාත්මක සැලසුම් සහ විමධ්යගත කිරීම! Mastodon සමඟ ඔබේ දත්ත අයිති කරගන්න!'
- contact_missing: සකස් කර නැත
+ about_mastodon_html: 'අනාගත සමාජ ජාලය: දැන්වීම් නැත, සංස්ථානික අවේක්ෂණ නැත, යහපතට නිර්මිතයි සහ විමධ්යගතයි! මාස්ටඩන් සමඟ ඔබගේ දත්ත අයිතිව තබාගන්න!'
+ contact_missing: සකසා නැත
contact_unavailable: අ/නොවේ
- hosted_on: Mastodon %{domain}හි සත්කාරකත්වය දරයි
+ hosted_on: "%{domain} හරහා සත්කාරකත්වය ලබයි"
+ title: පිළිබඳව
accounts:
follow: අනුගමනය
followers:
one: අනුගාමිකයා
other: අනුගාමිකයින්
- following: අනුගමනය
+ following: අනුගමන
instance_actor_flash: මෙම ගිණුම සේවාදායකයම නියෝජනය කිරීමට භාවිතා කරන අතථ්ය නළුවෙකු වන අතර කිසිදු තනි පරිශීලකයෙකු නොවේ. එය ෆෙඩරේෂන් අරමුණු සඳහා භාවිතා කරන අතර අත්හිටුවිය යුතු නොවේ.
last_active: අවසාන ක්රියාකාරී
link_verified_on: මෙම සබැඳියේ හිමිකාරිත්වය %{date}හි පරීක්ෂා කරන ලදී
- nothing_here: මෙහි කිසිත් නැත!
- pin_errors:
- following: ඔබට අනුමත කිරීමට අවශ්ය පුද්ගලයා ඔබ දැනටමත් අනුගමනය කරමින් සිටිය යුතුය
+ nothing_here: මෙහි කිසිවක් නැත!
posts:
one: ලිපිය
other: ලිපි
posts_tab_heading: ලිපි
admin:
account_actions:
- action: ක්රියාව සිදු කරන්න
- title: "%{acct}මත මධ්යස්ථ ක්රියාව සිදු කරන්න"
+ action: ක්රියාමාර්ගයක් ගන්න
account_moderation_notes:
- create: සටහන හැරයන්න
- created_msg: මධ්යස්ථ සටහන සාර්ථකව සාදන ලදී!
- destroyed_msg: මධ්යස්ථ සටහන සාර්ථකව විනාශ විය!
+ create: සටහනක් තබන්න
accounts:
add_email_domain_block: වි-තැපැල් වසම අවහිර කරන්න
- approve: අනුමත කරන්න
+ approve: අනුමැතිය
approved_msg: "%{username}හි ලියාපදිංචි වීමේ යෙදුම සාර්ථකව අනුමත කරන ලදී"
are_you_sure: ඔබට විශ්වාසද?
- avatar: අවතාරය
+ avatar: ප්රතිරූපය
by_domain: වසම
change_email:
+ changed_msg: වි-තැපෑල සාර්ථකව වෙනස් විය!
current_email: වත්මන් වි-තැපෑල
label: වි-තැපෑල වෙනස් කරන්න
new_email: නව විද්යුත් තැපෑල
submit: වි-තැපෑල වෙනස් කරන්න
title: "%{username} සඳහා වි-තැපෑල වෙනස් කරන්න"
+ change_role:
+ changed_msg: භූමිකාව සාර්ථකව වෙනස් විය!
+ label: භූමිකාව වෙනස් කරන්න
+ no_role: නව භූමිකාව
+ title: "%{username} සඳහා භූමිකාව වෙනස් කරන්න"
confirm: සනාථ කරන්න
- confirmed: තහවුරු කර ඇත
+ confirmed: සනාථ කර ඇත
confirming: සනාථ කරමින්
custom: අභිරුචි
delete: දත්ත මකන්න
- deleted: මකා දමන ලදී
- demote: පහත් කරන්න
+ deleted: මකා ඇත
destroyed_msg: "%{username}හි දත්ත ඉක්මනින් මකා දැමීමට පෝලිම් කර ඇත"
- disable: කැටි කරන්න
disable_sign_in_token_auth: ඊමේල් ටෝකන් සත්යාපනය අක්රීය කරන්න
disable_two_factor_authentication: 2FA අබල කරන්න
- disabled: ශීත කළ
display_name: ප්රදර්ශන නාමය
domain: වසම
edit: සංස්කරණය
email: විද්යුත් තැපෑල
email_status: වි-තැපෑලෙහි තත්වය
- enable: කැටි කිරීම ඉවත් කරන්න
enable_sign_in_token_auth: විද්යුත් තැපෑල ටෝකන් සත්යාපනය සබල කරන්න
enabled: සබල කර ඇත
enabled_msg: "%{username}ගේ ගිණුම සාර්ථකව අත්හිටුවා ඇත"
followers: අනුගාමිකයින්
- follows: පහත සඳහන්
header: ශීර්ෂය
inbox_url: එන ලිපි URL
- invite_request_text: එක්වීම සඳහා
+ invite_request_text: එක්වීමට හේතුව
invited_by: විසින් ආරාධනා කරන ලදී
ip: අ.ජා. කෙ. (IP)
- joined: එක් වී ඇත
+ joined: එක් වූ දිනය
location:
all: සියල්ල
local: ස්ථානීය
@@ -84,12 +81,13 @@ si:
moderation:
active: සක්රීයයි
all: සියල්ල
- pending: පොරොත්තුවෙන්
+ disabled: අබලයි
+ pending: පොරොත්තු
suspended: අත්හිටුවන ලදි
- title: මධ්යස්ථභාවය
- moderation_notes: මධ්යස්ථ සටහන්
+ title: මැදිහත්කරණය
+ moderation_notes: මැදිහත්කරණ සටහන්
most_recent_activity: වඩාත්ම මෑත ක්රියාකාරිත්වය
- most_recent_ip: ඊට වඩා අ.ජා.කේ.(IP)
+ most_recent_ip: මෑත අ.ජා.කෙ. (IP)
no_account_selected: කිසිවක් තෝරා නොගත් බැවින් ගිණුම් කිසිවක් වෙනස් කර නැත
no_limits_imposed: සීමාවන් පනවා නැත
not_subscribed: දායක වී නැත
@@ -99,37 +97,36 @@ si:
previous_strikes_description_html:
one: මෙම ගිණුමට එක වර්ජනයක් ඇත.
other: මෙම ගිණුමේ වර්ජන %{count} ඇත.
- promote: ප්රවර්ධනය කරන්න
protocol: කෙටුම්පත
- public: ප්රසිද්ධ
+ public: ප්රසිද්ධ
push_subscription_expires: පුෂ් දායකත්වය කල් ඉකුත් වේ
- redownload: පැතිකඩ නැවුම්කරන්න
+ redownload: පැතිකඩ නැවුම් කරන්න
redownloaded_msg: මූලාරම්භයේ සිට %{username}හි පැතිකඩ සාර්ථකව නැවුම් කරන ලදී
reject: ප්රතික්ෂේප
rejected_msg: "%{username}හි ලියාපදිංචි වීමේ අයදුම්පත සාර්ථකව ප්රතික්ෂේප විය"
- remove_avatar: අවතාරය ඉවත් කරන්න
+ remove_avatar: ප්රතිරූපය ඉවත් කරන්න
remove_header: ශීර්ෂය ඉවත්කරන්න
removed_avatar_msg: "%{username}ගේ අවතාර රූපය සාර්ථකව ඉවත් කරන ලදී"
removed_header_msg: "%{username}හි ශීර්ෂ රූපය සාර්ථකව ඉවත් කරන ලදී"
resend_confirmation:
already_confirmed: මෙම පරිශීලකයා දැනටමත් තහවුරු කර ඇත
reset: නැවත සකසන්න
- reset_password: මුරපදය නැවතසකසන්න
+ reset_password: මුරපදය යළි සකසන්න
resubscribe: නැවත දායක වන්න
+ role: භූමිකාව
search: සොයන්න
search_same_email_domain: එකම විද්යුත් තැපැල් වසම සහිත වෙනත් පරිශීලකයන්
search_same_ip: එකම IP සහිත වෙනත් පරිශීලකයන්
+ security: ආරක්ෂාව
security_measures:
only_password: මුරපදය පමණි
password_and_2fa: මුරපදය සහ 2FA
- sensitive: සංවේදී
- sensitized: සංවේදී ලෙස සලකුණු කර ඇත
+ sensitized: සංවේදී බව සලකුණු කර ඇත
shared_inbox_url: බෙදාගත් එන ලිපි URL
show:
created_reports: වාර්තා හැදුවා
targeted_reports: වෙනත් අය විසින් වාර්තා කරන ලදී
- silence: සීමාව
- silenced: සීමාසහිත
+ silenced: සීමා සහිතයි
statuses: ලිපි
strikes: පෙර වැඩ වර්ජන
subscribe: දායක වන්න
@@ -147,26 +144,25 @@ si:
unsilenced_msg: "%{username}ගිණුමේ සීමාව සාර්ථකව ඉවත් කරන ලදී"
unsubscribe: දායක නොවන්න
unsuspended_msg: "%{username}ගිණුම සාර්ථකව අත්හිටුවන ලදී"
- username: පරිශීලක නාමය
+ username: පරිශ්රීලක නාමය
view_domain: වසම සඳහා සාරාංශය බලන්න
warn: අවවාද
web: වියමන
- whitelisted: ෆෙඩරේෂන් සඳහා අවසර ඇත
+ whitelisted: ඒකාබද්ධයට ඉඩ දී ඇත
action_logs:
action_types:
approve_appeal: අභියාචනය අනුමත කරන්න
approve_user: පරිශීලක අනුමත කරන්න
assigned_to_self_report: වාර්තාව පැවරීම
- change_email_user: පරිශීලකයින්ට වි-තැපෑල වෙනස් කරන්න
confirm_user: පරිශීලක තහවුරු කරන්න
create_account_warning: අවවාදයක් සාදන්න
create_announcement: නිවේදනය සාදන්න
create_custom_emoji: අභිරුචි ඉමොජි සාදන්න
- create_domain_allow: වසම් ඉඩදීමක් සාදන්න
- create_domain_block: වසම් අවහිරයක් සාදන්න
+ create_domain_allow: වසමකට ඉඩදීම සාදන්න
create_email_domain_block: ඊමේල් ඩොමේන් බ්ලොක් එකක් සාදන්න
create_ip_block: අ.ජා. කෙ. (IP) නීතියක් සාදන්න
create_unavailable_domain: ලබා ගත නොහැකි වසම සාදන්න
+ create_user_role: භූමිකාව සාදන්න
demote_user: පරිශීලකයා පහත් කරන්න
destroy_announcement: නිවේදනය මකන්න
destroy_custom_emoji: අභිරුචි ඉමොජි මකන්න
@@ -175,26 +171,24 @@ si:
destroy_email_domain_block: ඊමේල් ඩොමේන් බ්ලොක් එක මකන්න
destroy_instance: වසම පිරිසිදු කරන්න
destroy_ip_block: IP රීතිය මකන්න
- destroy_status: පළ කිරීම මකන්න
+ destroy_status: ලිපිය මකන්න
destroy_unavailable_domain: ලබා ගත නොහැකි වසම මකන්න
disable_2fa_user: 2FA අබල කරන්න
- disable_custom_emoji: අභිරුචි ඉමොජි අබල කරන්න
+ disable_custom_emoji: අභිරුචි ඉමෝජි අබල කරන්න
disable_sign_in_token_auth_user: පරිශීලකයා සඳහා ඊමේල් ටෝකන් සත්යාපනය අක්රීය කරන්න
- disable_user: පරිශීලනය කරන්න
- enable_custom_emoji: අභිරුචි ඉමොජි සබල කරන්න
+ enable_custom_emoji: අභිරුචි ඉමෝජි සබල කරන්න
enable_sign_in_token_auth_user: පරිශීලකයා සඳහා විද්යුත් තැපෑල ටෝකන් සත්යාපනය සක්රීය කරන්න
enable_user: පරිශීලක සබල කරන්න
memorialize_account: ගිණුම අනුස්මරණ කරන්න
- promote_user: පරිශීලක ප්රවර්ධනය කරන්න
reject_appeal: අභියාචනය ප්රතික්ෂේප කරන්න
reject_user: පරිශීලක ප්රතික්ෂේප කරන්න
- remove_avatar_user: Avatar ඉවත් කරන්න
- reopen_report: වාර්තාව නැවත විවෘත කරන්න
- reset_password_user: මුරපදය නැවතසකසන්න
+ remove_avatar_user: ප්රතිරූපය ඉවත් කරන්න
+ reopen_report: වාර්තාව නැවත අරින්න
+ reset_password_user: මුරපදය යළි සකසන්න
resolve_report: වාර්තාව විසඳන්න
sensitive_account: බල සංවේදී ගිණුම
silence_account: ගිණුම සීමා කරන්න
- suspend_account: සැලකිය යුතු
+ suspend_account: ගිණුම අත්හිටුවන්න
unassigned_report: වාර්තාව පැවරීම ඉවත් කරන්න
unblock_email_account: ඊමේල් ලිපිනය අවහිර කිරීම ඉවත් කරන්න
unsensitive_account: බල සංවේදී ගිණුම අහෝසි කරන්න
@@ -203,9 +197,8 @@ si:
update_announcement: නිවේදනය යාවත්කාල කරන්න
update_custom_emoji: අභිරුචි ඉමොජි යාවත්කාලීන කරන්න
update_domain_block: ඩොමේන් බ්ලොක් යාවත්කාලීන කරන්න
- update_status: පළ කිරීම යාවත්කාලීන කරන්න
+ update_status: ලිපිය යාවත්කාල කරන්න
actions:
- approve_appeal_html: "%{name} අනුමත මධ්යස්ථ තීරණ අභියාචනය %{target}සිට"
approve_user_html: "%{name} අනුමත ලියාපදිංචිය %{target}සිට"
assigned_to_self_report_html: "%{name} වාර්තාව %{target} තමන්ටම පවරා ඇත"
change_email_user_html: "%{name} පරිශීලක %{target}ගේ ඊමේල් ලිපිනය වෙනස් කළේය"
@@ -225,7 +218,6 @@ si:
destroy_email_domain_block_html: "%{name} අවහිර නොකළ විද්යුත් තැපැල් වසම %{target}"
destroy_instance_html: "%{name} පිරිසිදු කරන ලද වසම %{target}"
destroy_ip_block_html: IP %{target}සඳහා %{name} මකා දැමූ රීතිය
- destroy_status_html: "%{name} පෝස්ට් %{target}විසින් ඉවත් කරන ලදී"
destroy_unavailable_domain_html: "%{name} වසම %{target}වෙත බෙදා හැරීම නැවත ආරම්භ විය"
disable_2fa_user_html: "%{name} පරිශීලක %{target}සඳහා සාධක දෙකක අවශ්යතාවය අක්රීය කර ඇත"
disable_custom_emoji_html: "%{name} ආබාධිත ඉමොජි %{target}"
@@ -236,27 +228,25 @@ si:
enable_user_html: පරිශීලක %{target}සඳහා %{name} සක්රීය පුරනය වීම
memorialize_account_html: "%{name} %{target}ගේ ගිණුම සිහිවටන පිටුවක් බවට පත් කළේය"
promote_user_html: "%{name} උසස් පරිශීලක %{target}"
- reject_appeal_html: "%{name} %{target}සිට මධ්යස්ථ තීරණ අභියාචනය ප්රතික්ෂේප කරන ලදී"
reject_user_html: "%{name} %{target}සිට ලියාපදිංචි වීම ප්රතික්ෂේප විය"
remove_avatar_user_html: "%{name} %{target}ගේ අවතාරය ඉවත් කරන ලදී"
reopen_report_html: "%{name} නැවත විවෘත කළ වාර්තාව %{target}"
reset_password_user_html: "%{name} පරිශීලක %{target}හි මුරපදය යළි පිහිටුවන්න"
resolve_report_html: "%{name} විසඳන ලද වාර්තාව %{target}"
- sensitive_account_html: "%{name} %{target}හි මාධ්ය සංවේදී ලෙස සලකුණු කර ඇත"
+ sensitive_account_html: "%{target}ගේ මාධ්ය සංවේදී බව %{name} සලකුණු කර ඇත"
silence_account_html: "%{name} සීමිත %{target}ගිණුමක්"
suspend_account_html: "%{name} %{target}ගේ ගිණුම අත්හිටුවා ඇත"
unassigned_report_html: "%{name} පවරා නොදුන් වාර්තාව %{target}"
unblock_email_account_html: "%{name} %{target}ගේ ඊමේල් ලිපිනය අවහිර කිරීම ඉවත් කරන ලදී"
- unsensitive_account_html: "%{name} සලකුණු නොකළ %{target}ගේ මාධ්ය සංවේදී ලෙස"
+ unsensitive_account_html: "%{target}ගේ මාධ්ය සංවේදී බව %{name} ඉවත් කර ඇත"
unsilence_account_html: "%{target}ගිණුමේ %{name} undid සීමාව"
unsuspend_account_html: "%{name} අත්හිටුවන ලද %{target}ගිණුම"
update_announcement_html: "%{name} යාවත්කාලීන නිවේදනය %{target}"
update_custom_emoji_html: "%{name} යාවත්කාලීන කළ ඉමොජි %{target}"
update_domain_block_html: "%{target}සඳහා %{name} යාවත්කාලීන කරන ලද වසම් වාරණ"
- update_status_html: "%{name} %{target}යාවත්කාලීන කරන ලද පළ කිරීම"
empty: ලඝු-සටහන් හමු නොවිණි.
- filter_by_action: ක්රියාව අනුව පෙරන්න
- filter_by_user: පරිශීලක අනුව පෙරන්න
+ filter_by_action: ක්රියාමාර්ගය අනුව පෙරන්න
+ filter_by_user: පරිශ්රීලකයා අනුව පෙරන්න
title: විගණන සටහන
announcements:
destroyed_msg: නිවේදනය සාර්ථකව මකා ඇත!
@@ -279,22 +269,22 @@ si:
assign_category: කාණ්ඩය පැවරීම
by_domain: වසම
copied_msg: ඉමොජි වල දේශීය පිටපත සාර්ථකව සාදන ලදී
- copy: පිටපත්
+ copy: පිටපතක්
copy_failed_msg: එම ඉමොජියේ දේශීය පිටපතක් සෑදීමට නොහැකි විය
create_new_category: නව ප්රවර්ගයක් සාදන්න
created_msg: ඉමොජි සාර්ථකව නිර්මාණය කළා!
delete: මකන්න
destroyed_msg: Emojo සාර්ථකව විනාශ විය!
disable: අබල කරන්න
- disabled: අබල කර ඇත
+ disabled: අබලයි
disabled_msg: එම ඉමොජිය සාර්ථකව අබල කරන ලදී
- emoji: ඉමොජි
+ emoji: ඉමෝජි
enable: සබල කරන්න
- enabled: සබල කර ඇත
+ enabled: සබලයි
enabled_msg: එම ඉමොජි සාර්ථකව සබල කරන ලදී
image_hint: PNG හෝ GIF %{size}දක්වා
list: ලැයිස්තුව
- listed: ලැයිස්තුගත කර ඇත
+ listed: ලැයිස්තුගත
new:
title: නව අභිරුචි ඉමොජි එක් කරන්න
not_permitted: මෙම ක්රියාව සිදු කිරීමට ඔබට අවසර නැත
@@ -309,11 +299,11 @@ si:
updated_msg: ඉමොජි සාර්ථකව යාවත්කාලීන කරන ලදී!
upload: උඩුගත කරන්න
dashboard:
- active_users: ක්රියාකාරී පරිශීලකයන්
+ active_users: සක්රිය පරිශ්රීලකයින්
interactions: අන්තර්ක්රියා
- media_storage: මාධ්ය ගබඩාව
- new_users: නව පරිශීලකයන්
- opened_reports: වාර්තා විවෘත විය
+ media_storage: මාධ්ය ආචයනය
+ new_users: නව පරිශ්රීලකයින්
+ opened_reports: විවෘත වාර්තා
pending_appeals_html:
one: "%{count} අභියාචනයක් බලාපොරොත්තු වේ"
other: "%{count} අභියාචනා පොරොත්තු"
@@ -329,11 +319,11 @@ si:
resolved_reports: වාර්තා විසඳා ඇත
software: මෘදුකාංගය
sources: ලියාපදිංචි මූලාශ්ර
- space: අවකාශය භාවිතය
+ space: ඉඩ භාවිතය
title: උපකරණ පුවරුව
top_languages: ඉහළම ක්රියාකාරී භාෂා
top_servers: ඉහළම ක්රියාකාරී සේවාදායකයන්
- website: වෙබ් අඩවිය
+ website: අඩවිය
disputes:
appeals:
empty: අභියාචනා හමු නොවීය.
@@ -353,7 +343,6 @@ si:
existing_domain_block_html: ඔබ දැනටමත් %{name}මත දැඩි සීමාවන් පනවා ඇත, ඔබට එය අවහිර කිරීම ඉවත් කිරීමට අවශ්යයි.
new:
create: බ්ලොක් එකක් සාදන්න
- hint: ඩොමේන් බ්ලොක් එක දත්ත සමුදාය තුල ගිණුම් ඇතුලත් කිරීම් නිර්මාණය වීම වලක්වන්නේ නැත, නමුත් එම ගිණුම් වලට ප්රතික්රියාශීලීව සහ ස්වයංක්රීයව විශේෂිත මධ්යස්ථ ක්රම යොදනු ඇත.
severity:
noop: කිසිවක් නැත
suspend: අත්හිටුවන්න
@@ -361,7 +350,6 @@ si:
obfuscate: අපැහැදිලි වසම් නාමය
obfuscate_hint: වසම් සීමාවන් ලැයිස්තුව ප්රචාරණය කිරීම සබල කර ඇත්නම් ලැයිස්තුවේ වසම් නාමය අර්ධ වශයෙන් අපැහැදිලි කරන්න
private_comment: පුද්ගලික අදහස
- private_comment_hint: පරිපාලකයින් විසින් අභ්යන්තර භාවිතය සඳහා මෙම වසම් සීමාව ගැන අදහස් දක්වන්න.
public_comment: ප්රසිද්ධ අදහස
public_comment_hint: වසම් සීමාවන් ලැයිස්තුව ප්රචාරණය කිරීම සබල කර ඇත්නම්, සාමාන්ය ජනතාව සඳහා මෙම වසම් සීමාව ගැන අදහස් දක්වන්න.
reject_media: මාධ්ය ගොනු ප්රතික්ෂේප කරන්න
@@ -395,7 +383,7 @@ si:
status: තත්වය
suppress: අනුගමනය නිර්දේශය යටපත් කරන්න
suppressed: යටපත් කළා
- title: නිර්දේශ අනුගමනය කරන්න
+ title: අනුගමනයට නිර්දේශ
unsuppress: නිර්දේශ පිළිපැදීම ප්රතිසාධනය කරන්න
instances:
availability:
@@ -415,16 +403,16 @@ si:
by_domain: වසම
confirm_purge: ඔබට මෙම වසමෙන් දත්ත ස්ථිරවම මැකීමට අවශ්ය බව විශ්වාසද?
content_policies:
- comment: අභ්යන්තර සටහන
+ comment: අභ්යන්තර සටහන
description_html: ඔබට මෙම වසම සහ එහි ඕනෑම උප වසමකින් සියලුම ගිණුම් වලට අදාළ වන අන්තර්ගත ප්රතිපත්ති නිර්වචනය කළ හැක.
policies:
reject_media: මාධ්ය ප්රතික්ෂේප කරන්න
reject_reports: වාර්තා ප්රතික්ෂේප කරන්න
silence: සීමාව
suspend: අත්හිටුවන්න
- policy: ප්රතිපත්ති
+ policy: ප්රතිපත්තිය
reason: පොදු හේතුව
- title: අන්තර්ගත ප්රතිපත්ති
+ title: අන්තර්ගත ප්රතිපත්ති
dashboard:
instance_accounts_dimension: වැඩිපුරම අනුගමනය කරන ගිණුම්
instance_accounts_measure: ගබඩා කර ඇති ගිණුම්
@@ -443,7 +431,7 @@ si:
unavailable: ලබා ගත නොහැක
delivery_available: බෙදා හැරීම ලබා ගත හැකිය
delivery_error_days: බෙදා හැරීමේ දෝෂ සහිත දින
- delivery_error_hint: දින %{count} ක් සඳහා බෙදා හැරීම කළ නොහැකි නම්, එය ස්වයංක්රීයව බෙදා හැරිය නොහැකි ලෙස ලකුණු කරනු ලැබේ.
+ delivery_error_hint: දවස් %{count} කින් බාරදීමට නොහැකි වුවහොත්, බාරදීමට නොහැකි බව ස්වයංක්රීයව සලකුණු වේ.
destroyed_msg: "%{domain} සිට දත්ත දැන් ආසන්න මකාදැමීම සඳහා පෝලිම් කර ඇත."
empty: වසම් කිසිවක් හමු නොවීය.
known_accounts:
@@ -452,7 +440,7 @@ si:
moderation:
all: සියල්ල
limited: සීමා සහිතයි
- title: මධ්යස්ථභාවය
+ title: මැදිහත්කරණය
private_comment: පුද්ගලික අදහස
public_comment: ප්රසිද්ධ අදහස
purge: පිරිසිදු කරන්න
@@ -462,13 +450,12 @@ si:
total_followed_by_them: ඔවුන් විසින් අනුගමනය කරන ලදී
total_followed_by_us: අප විසින් අනුගමනය කරන ලදී
total_reported: ඔවුන් ගැන වාර්තා
- total_storage: මාධ්ය ඇමුණුම්
+ total_storage: මාධ්ය ඇමුණුම්
totals_time_period_hint_html: පහත දැක්වෙන එකතුවෙහි සියලු කාලය සඳහා දත්ත ඇතුළත් වේ.
invites:
deactivate_all: සියල්ල අක්රිය කරන්න
filter:
all: සියල්ල
- available: පවතින
expired: ඉකුත් වී ඇත
title: පෙරහන
title: ඇරයුම්
@@ -492,15 +479,13 @@ si:
relays:
add_new: නව රිලේ එක් කරන්න
delete: මකන්න
- description_html: "ෆෙඩරේෂන් රිලේ යනු එයට දායක වී ප්රකාශයට පත් කරන සේවාදායකයන් අතර විශාල ප්රසිද්ධ පළ කිරීම් හුවමාරු කරන අතරමැදි සේවාදායකයකි. එය කුඩා සහ මධ්යම සේවාදායකයන්ට fediverseවෙතින් අන්තර්ගතය සොයා ගැනීමට උදවු කළ හැකි අතර, එසේ නොමැති නම් දේශීය පරිශීලකයින්ට දුරස්ථ සේවාදායකයන් මත වෙනත් පුද්ගලයින් හස්තීයව අනුගමනය කිරීම අවශ්ය වේ."
disable: අබල කරන්න
- disabled: අබල කර ඇත
+ disabled: අබලයි
enable: සබල කරන්න
- enable_hint: සක්රිය කළ පසු, ඔබේ සේවාදායකය මෙම රිලේ වෙතින් සියලුම පොදු පළ කිරීම් සඳහා දායක වන අතර, මෙම සේවාදායකයේ පොදු පළ කිරීම් එයට යැවීම ආරම්භ කරනු ඇත.
enabled: සබල කර ඇත
inbox_url: රිලේ URL
pending: රිලේ අනුමැතිය සඳහා රැඳී සිටිමින්
- save_and_enable: සුරකින්න සහ සක්රිය කරන්න
+ save_and_enable: සුරකින්න හා සබල කරන්න
setup: රිලේ සම්බන්ධතාවයක් සකසන්න
signatures_not_enabled: ආරක්ෂිත මාදිලිය හෝ සීමිත ෆෙඩරේෂන් මාදිලිය සබල කර ඇති අතර රිලේ නිවැරදිව ක්රියා නොකරනු ඇත
status: තත්වය
@@ -516,40 +501,37 @@ si:
action_log: විගණන සටහන
action_taken_by: විසින් ගන්නා ලද පියවර
actions:
- delete_description_html: වාර්තා කරන ලද පළ කිරීම් මකා දැමෙනු ඇති අතර එම ගිණුමේම අනාගත උල්ලංඝනයන් තීව්ර කිරීමට ඔබට උදවු කිරීමට වර්ජනයක් වාර්තා කරනු ඇත.
- mark_as_sensitive_description_html: වාර්තා කරන ලද පළ කිරීම් වල මාධ්ය සංවේදී ලෙස සලකුණු කරනු ලබන අතර එම ගිණුම මගින් අනාගත උල්ලංඝනයන් උත්සන්න කිරීමට ඔබට උපකාර කිරීමට වර්ජනයක් වාර්තා කරනු ඇත.
other_description_html: ගිණුමේ හැසිරීම පාලනය කිරීම සහ වාර්තා කළ ගිණුමට සන්නිවේදනය අභිරුචිකරණය කිරීම සඳහා තවත් විකල්ප බලන්න.
resolve_description_html: වාර්තා කරන ලද ගිණුමට එරෙහිව කිසිදු ක්රියාමාර්ගයක් නොගනු ඇත, වැඩ වර්ජනයක් වාර්තා නොකෙරේ, වාර්තාව වසා දමනු ඇත.
actions_description_html: මෙම වාර්තාව විසඳීමට ගත යුතු ක්රියාමාර්ගය තීරණය කරන්න. ඔබ වාර්තා කරන ලද ගිණුමට එරෙහිව දණ්ඩනීය ක්රියාමාර්ගයක් ගන්නේ නම්, Spam කාණ්ඩය තෝරාගත් විට හැර, ඔවුන්ට විද්යුත් තැපෑලෙන් දැනුම්දීමක් යවනු ලැබේ.
add_to_report: වාර්තා කිරීමට තවත් එක් කරන්න
are_you_sure: ඔබට විශ්වාසද?
assign_to_self: මට පවරන්න
- assigned: පවරා ඇති උපපරිපාලක
by_target_domain: වාර්තා කළ ගිණුමෙහි වසම
- category: වර්ගය
+ cancel: අවලංගු
+ category: ප්රවර්ගය
category_description_html: මෙම ගිණුම සහ/හෝ අන්තර්ගතය වාර්තා කළ හේතුව වාර්තා කළ ගිණුම සමඟ සන්නිවේදනයේ සඳහන් කරනු ඇත
comment:
none: කිසිවක් නැත
comment_description_html: 'වැඩි විස්තර සැපයීම සඳහා, %{name} ලිවීය:'
created_at: වාර්තා කර ඇත
- delete_and_resolve: පළ කිරීම් මකන්න
- forwarded: යොමු කළා
- forwarded_to: "%{domain}වෙත යොමු කරන ලදී"
- mark_as_resolved: විසඳා ඇති ලෙස ලකුණු කරන්න
- mark_as_sensitive: සංවේදී ලෙස ලකුණු කරන්න
- mark_as_unresolved: නොවිසඳුනු ලෙස ලකුණු කරන්න
- no_one_assigned: කිසි කෙනෙක නැහැ
+ delete_and_resolve: ලිපි මකන්න
+ forwarded: හරවා යවා ඇත
+ forwarded_to: "%{domain} වෙත හරවා යැවිණි"
+ mark_as_resolved: විසඳූ බව යොදන්න
+ mark_as_sensitive: සංවේදී බව යොදන්න
+ mark_as_unresolved: නොවිසඳූ බව යොදන්න
+ no_one_assigned: කිසිවෙක් නැත
notes:
create: සටහන එකතු කරන්න
- create_and_resolve: සටහන සමඟ විසඳන්න
- create_and_unresolve: සටහනක් සමඟ නැවත විවෘත කරන්න
+ create_and_resolve: සටහනක් සමඟ විසඳන්න
+ create_and_unresolve: සටහනක් සමඟ නැවත අරින්න
delete: මකන්න
placeholder: ගෙන ඇති ක්රියාමාර්ග, හෝ වෙනත් අදාළ යාවත්කාලීන විස්තර කරන්න...
title: සටහන්
- notes_description_html: අනෙකුත් උපපරිපාලකයින්ට සහ ඔබේ අනාගතයට සටහන් බලන්න සහ තබන්න
quick_actions_description_html: 'වාර්තා කළ අන්තර්ගතය බැලීමට ඉක්මන් ක්රියාමාර්ගයක් ගන්න හෝ පහළට අනුචලනය කරන්න:'
remote_user_placeholder: "%{instance}සිට දුරස්ථ පරිශීලකයා"
- reopen: වාර්තාව නැවත විවෘත කරන්න
+ reopen: වාර්තාව නැවත අරින්න
report: "@%{id} වාර්තා කරන්න"
reported_account: වාර්තා කළ ගිණුම
reported_by: විසින් වාර්තා
@@ -562,17 +544,52 @@ si:
target_origin: වාර්තා කළ ගිණුමේ ආරම්භය
title: වාර්තා
unassign: පැවරීම ඉවත් කරන්න
+ unknown_action_msg: 'නොදන්නා ක්රියාමාර්ගයකි: %{action}'
unresolved: නොවිසඳී ඇත
updated_at: යාවත්කාලීන කරන ලදී
view_profile: පැතිකඩ බලන්න
+ roles:
+ categories:
+ administration: පරිපාලනය
+ devops: DevOps
+ invites: ඇරයුම්
+ moderation: මැදිහත්කරණය
+ special: විශේෂ
+ delete: මකන්න
+ permissions_count:
+ one: අවසර %{count}
+ other: අවසර %{count}
+ privileges:
+ administrator: පරිපාලක
+ delete_user_data: පරිශ්රීලක දත්ත මකන්න
+ invite_users: ආරාධනා කරන්න
+ manage_announcements: නිවේදනය කළමනාකරණය
+ manage_federation: ඒකාබද්ධ කළමනාකරණය
+ manage_invites: ආරාධනා කළමනාකරණය
+ manage_reports: වාර්තා කළමනාකරණය
+ manage_roles: භූමිකා කළමනාකරණය
+ manage_rules: නීති කළමනාකරණය
+ manage_settings: සැකසුම් කළමනාකරණය
+ manage_user_access: ප්රවේශය කළමනාකරණය
+ manage_users: පරිශ්රීලකයින් කළමනාකරණය
+ view_dashboard: උපකරණ පුවරුව බලන්න
+ view_devops: DevOps
+ title: භූමිකා
rules:
- add_new: නීතිය එකතු කරන්න
delete: මකන්න
description_html: බොහෝ දෙනා සේවා කොන්දේසි කියවා එකඟ වූ බව ප්රකාශ කරන අතර, සාමාන්යයෙන් මිනිසුන් ගැටලුවක් පැනනඟින තුරු කියවා නොගනිති. පැතලි බුලට් පොයින්ට් ලිස්ට් එකකින් ඒවා ලබා දීමෙන් බැලූ බැල්මට ඔබේ සේවාදායකයේ නීති බැලීම පහසු කරන්න. තනි නීති කෙටි හා සරලව තබා ගැනීමට උත්සාහ කරන්න, නමුත් ඒවා විවිධ අයිතම වලට බෙදීමට උත්සාහ නොකරන්න.
- edit: නීතිය සංස්කරණය කරන්න
+ edit: නීතිය සංස්කරණය
empty: තවමත් සේවාදායක රීති නිර්වචනය කර නොමැත.
title: සේවාදායකයේ නීති
settings:
+ about:
+ manage_rules: සේවාදායකයේ නීති කළමනාකරණය
+ title: පිළිබඳව
+ appearance:
+ title: පෙනුම
+ discovery:
+ profile_directory: පැතිකඩ නාමාවලිය
+ public_timelines: ප්රසිද්ධ කාලරේඛා
domain_blocks:
all: හැමෝටම
disabled: කාටවත් නෑ
@@ -582,28 +599,45 @@ si:
approved: ලියාපදිංචි වීමට අනුමැතිය අවශ්යයි
none: කිසිවෙකුට ලියාපදිංචි විය නොහැක
open: ඕනෑම කෙනෙකුට ලියාපදිංචි විය හැක
+ title: සේවාදායකයේ සැකසුම්
site_uploads:
delete: උඩුගත කළ ගොනුව මකන්න
destroyed_msg: අඩවිය උඩුගත කිරීම සාර්ථකව මකා ඇත!
+ software_updates:
+ documentation_link: තව දැනගන්න
+ release_notes: නිකුතු සටහන්
+ title: තිබෙන යාවත්කාල
+ type: වර්ගය
+ version: අනුවාදය
statuses:
- back_to_account: ගිණුම් පිටුවට ආපසු යන්න
- back_to_report: වාර්තා පිටුවට ආපසු යන්න
+ account: කර්තෘ
+ application: යෙදුම
+ back_to_account: ගිණුමේ පිටුවට ආපසු
+ back_to_report: වාර්තා පිටුවට ආපසු
batch:
remove_from_report: වාර්තාවෙන් ඉවත් කරන්න
report: වාර්තාව
- deleted: මකා දමන ලදී
+ deleted: මකා ඇත
+ favourites: ප්රියතමයන්
+ history: අනුවාද ඉතිහාසය
+ language: භාෂාව
media:
- title: මාධ්යය
- no_status_selected: කිසිවක් තෝරා නොගත් බැවින් තනතුරු කිසිවක් වෙනස් කර නැත
- title: ගිණුම් තනතුරු
- with_media: මාධ්ය දායකත්වය
+ title: මාධ්ය
+ metadata: පාරදත්ත
+ no_status_selected: කිසිවක් නොතේරූ බැවින් ලිපි කිසිවක් වෙනස් කර නැත
+ open: ලිපිය අරින්න
+ original_status: මුල් ලිපිය
+ status_changed: ලිපිය සංශෝධිතයි
+ title: ගිණුමේ ලිපි
+ trending: නැගී එන
+ with_media: මාධ්ය සමඟ
strikes:
actions:
- delete_statuses: "%{target}ගේ පළ කිරීම් %{name} මකා දමන ලදී"
+ delete_statuses: "%{target}ගේ ලිපි %{name} මකා ඇත"
disable: "%{name} %{target}ගේ ගිණුම නිශ්චල කළේය"
- mark_statuses_as_sensitive: "%{name} %{target}ගේ පළ කිරීම් සංවේදී ලෙස ලකුණු කර ඇත"
+ mark_statuses_as_sensitive: "%{target}ගේ ලිපි සංවේදී බව %{name} සලකුණු කර ඇත"
none: "%{name} %{target}අනතුරු ඇඟවීමක් යවා ඇත"
- sensitive: "%{name} %{target}ගේ ගිණුම සංවේදී ලෙස ලකුණු කර ඇත"
+ sensitive: "%{target}ගේ ගිණුම සංවේදී බව %{name} සලකුණු කර ඇත"
silence: "%{name} සීමිත %{target}ගිණුමක්"
suspend: "%{name} %{target}ගේ ගිණුම අත්හිටුවා ඇත"
appeal_approved: අභියාචනා කළා
@@ -611,28 +645,35 @@ si:
system_checks:
database_schema_check:
message_html: පොරොත්තු දත්ත සමුදා සංක්රමණයන් ඇත. යෙදුම අපේක්ෂිත පරිදි ක්රියා කරන බව සහතික කිරීමට කරුණාකර ඒවා ධාවනය කරන්න
+ elasticsearch_preset:
+ action: ප්රලේඛනය බලන්න
+ elasticsearch_preset_single_node:
+ action: ප්රලේඛනය බලන්න
elasticsearch_running_check:
message_html: Elasticsearch වෙත සම්බන්ධ වීමට නොහැකි විය. කරුණාකර එය ක්රියාත්මක වන බව පරීක්ෂා කරන්න, නැතහොත් සම්පූර්ණ පෙළ සෙවීම අක්රීය කරන්න
elasticsearch_version_check:
message_html: 'නොගැලපෙන ඉලාස්ටික් සෙවුම් අනුවාදය: %{value}'
version_comparison: Elasticsearch %{running_version} ක්රියාත්මක වන අතර %{required_version} අවශ්ය වේ
rules_check:
- action: සේවාදායක නීති කළමනාකරණය කරන්න
+ action: සේවාදායකයේ නීති කළමනාකරණය
message_html: ඔබ සේවාදායක රීති කිසිවක් නිර්වචනය කර නැත.
sidekiq_process_check:
message_html: "%{value} පෝලිම්(ය) සඳහා Sidekiq ක්රියාවලියක් ක්රියාත්මක නොවේ. කරුණාකර ඔබේ Sidekiq වින්යාසය සමාලෝචනය කරන්න"
+ software_version_critical_check:
+ action: තිබෙන යාවත්කාල බලන්න
+ software_version_patch_check:
+ action: තිබෙන යාවත්කාල බලන්න
tags:
review: තත්වය සමාලෝචනය
updated_msg: Hashtag සැකසුම් සාර්ථකව යාවත්කාලීන කරන ලදී
title: පරිපාලනය
trends:
- allow: ඉඩ දෙන්න
- approved: අනුමත කළා
+ allow: ඉඩදෙන්න
+ approved: අනුමතයි
disallow: අවසර නොදෙන්න
links:
- allow: සබැඳියට ඉඩ දෙන්න
+ allow: සබැඳියට ඉඩදෙන්න
allow_provider: ප්රකාශකයාට ඉඩ දෙන්න
- description_html: මේවා ඔබගේ සේවාදායකය විසින් පළ කිරීම් දකින ගිණුම් මගින් දැනට බොහෝ සෙයින් බෙදා ගන්නා සබැඳි වේ. එය ඔබගේ පරිශීලකයින්ට ලෝකයේ සිදුවෙමින් පවතින දේ සොයා ගැනීමට උදවු කළ හැක. ඔබ ප්රකාශකයා අනුමත කරන තුරු සබැඳි කිසිවක් ප්රසිද්ධියේ ප්රදර්ශනය නොවේ. ඔබට තනි සබැඳිවලට ඉඩ දීමට හෝ ප්රතික්ෂේප කිරීමටද හැකිය.
disallow: සබැඳියට ඉඩ නොදෙන්න
disallow_provider: ප්රකාශකයාට ඉඩ නොදෙන්න
shared_by_over_week:
@@ -640,7 +681,6 @@ si:
other: පසුගිය සතිය පුරා පුද්ගලයින් %{count} දෙනෙකු විසින් බෙදා ගන්නා ලදී
title: නැඟී එන සබැඳි
usage_comparison: ඊයේ %{yesterday} හා සසඳන විට අද %{today} වරක් බෙදා ගන්නා ලදී
- only_allowed: අවසර දී ඇත
pending_review: පොරොත්තු සමාලෝචනය
preview_card_providers:
allowed: මෙම ප්රකාශකයාගේ සබැඳි නැඹුරු විය හැක
@@ -649,16 +689,15 @@ si:
title: ප්රකාශකයන්
rejected: ප්රතික්ෂේප කළා
statuses:
- allow: පළ කිරීමට ඉඩ දෙන්න
+ allow: පළ කිරීමට ඉඩදෙන්න
allow_account: කතුවරයාට ඉඩ දෙන්න
- description_html: මේ වන විට ඔබේ සේවාදායකය දන්නා පෝස්ට් මේ වන විට බොහෝ බෙදාහරින සහ මේ මොහොතේ වැඩි කැමැත්තක් දක්වයි. එය ඔබගේ නව සහ නැවත පැමිණෙන පරිශීලකයින්ට අනුගමනය කිරීමට තවත් පුද්ගලයින් සොයා ගැනීමට උදවු කළ හැක. ඔබ කර්තෘ අනුමත කරන තෙක් පළ කිරීම් කිසිවක් ප්රසිද්ධියේ නොපෙන්වන අතර, කර්තෘ තම ගිණුම අන් අයට යෝජනා කිරීමට ඉඩ දෙයි. ඔබට තනි පළ කිරීම්වලට ඉඩ දීමට හෝ ප්රතික්ෂේප කිරීමටද හැකිය.
- disallow: පළ කිරීමට ඉඩ නොදෙන්න
+ disallow: ප්රකාශනයට ඉඩ නොදෙන්න
disallow_account: කතුවරයාට ඉඩ නොදෙන්න
not_discoverable: කර්තෘ සොයා ගත හැකි බව තෝරාගෙන නැත
shared_by:
one: එක් වරක් බෙදාගත් හෝ ප්රිය කරන ලදී
other: "%{friendly_count} වරක් බෙදාගෙන ප්රිය කරන ලදී"
- title: ප්රවණතා පළ කිරීම්
+ title: නැගී එන ලිපි
tags:
current_score: වත්මන් ලකුණු %{score}
dashboard:
@@ -667,9 +706,8 @@ si:
tag_servers_dimension: ඉහළම සේවාදායකයන්
tag_servers_measure: විවිධ සේවාදායකයන්
tag_uses_measure: සම්පූර්ණ භාවිතය
- description_html: මේවා දැනට ඔබගේ සේවාදායකය දකින බොහෝ පළ කිරීම් වල දිස්වන හැෂ් ටැග් වේ. මේ මොහොතේ මිනිසුන් වැඩිපුරම කතා කරන්නේ කුමක් දැයි සොයා ගැනීමට එය ඔබගේ පරිශීලකයින්ට උදවු කළ හැක. ඔබ ඒවා අනුමත කරන තුරු හෑෂ් ටැග් ප්රසිද්ධියේ නොපෙන්වයි.
- listable: යෝජනා කළ හැක
- not_listable: යෝජනා නොකරනු ඇත
+ listable: යෝජනා කළ හැකිය
+ not_listable: යෝජනා නොවනු ඇත
not_trendable: ප්රවණතා යටතේ දිස් නොවනු ඇත
not_usable: භාවිතා කළ නොහැක
peaked_on_and_decaying: "%{date}හි උච්චතම, දැන් දිරාපත් වෙමින් පවතී"
@@ -692,16 +730,15 @@ si:
webhooks:
add_new: අන්ත ලක්ෂ්යය එක් කරන්න
delete: මකන්න
- description_html: A webhook Mastodon හට තෝරාගත් සිදුවීම් පිළිබඳ තත්ය කාලීන දැනුම්දීම් ක් ඔබේම යෙදුමට තල්ලු කිරීමට හැකියාව ලබා දෙයි, එම නිසා ඔබේ යෙදුමට ස්වයංක්රීයව ප්රතික්රියා අවුලුවාලීමට හැකිය.
- disable: අක්රිය කරන්න
- disabled: ආබාධිතයි
+ disable: අබල කරන්න
+ disabled: අබලයි
edit: අන්ත ලක්ෂ්යය සංස්කරණය කරන්න
empty: ඔබට තවම වින්යාස කර ඇති කිසිදු webhook අන්ත ලක්ෂ්යයක් නොමැත.
enable: සබල කරන්න
- enabled: ක්රියාකාරී
+ enabled: ක්රියාත්මකයි
enabled_events:
- one: 1 සබල කළ සිදුවීමක්
- other: "%{count} සබල කළ සිදුවීම්"
+ one: සබල සිදුවීම් 1
+ other: සබල සිදුවීම් %{count}
events: සිදුවීම්
new: නව webhook
rotate_secret: රහස කරකවන්න
@@ -713,14 +750,10 @@ si:
actions:
delete_statuses: ඔවුන්ගේ පළ කිරීම් මකා දැමීමට
disable: ඔවුන්ගේ ගිණුම කැටි කිරීමට
- mark_statuses_as_sensitive: ඔවුන්ගේ තනතුරු සංවේදී ලෙස සලකුණු කිරීමට
none: අනතුරු ඇඟවීමක්
sensitive: ඔවුන්ගේ ගිණුම සංවේදී ලෙස සලකුණු කිරීමට
silence: ඔවුන්ගේ ගිණුම සීමා කිරීමට
suspend: ඔවුන්ගේ ගිණුම අත්හිටුවීමට
- body: "%{target} යනු %{type}ක් වූ %{date}සිට %{action_taken_by} කින් මධ්යස්ථ තීරණයක් අභියාචනා කරයි. ඔවුන් මෙසේ ලිවීය."
- next_steps: ඔබට මධ්යස්ථ තීරණය අවලංගු කිරීමට අභියාචනය අනුමත කළ හැකිය, නැතහොත් එය නොසලකා හරින්න.
- subject: "%{username} යනු %{instance}හි මධ්යස්ථ තීරණයකට අභියාචනා කරයි"
new_pending_account:
body: නව ගිණුමේ විස්තර පහතින්. ඔබට මෙම යෙදුම අනුමත කිරීමට හෝ ප්රතික්ෂේප කිරීමට හැකිය.
subject: නව ගිණුම සමාලෝචනය සඳහා %{instance} (%{username})
@@ -733,7 +766,7 @@ si:
new_trending_links:
title: නැඟී එන සබැඳි
new_trending_statuses:
- title: ප්රවණතා පළ කිරීම්
+ title: නැගී එන ලිපි
new_trending_tags:
no_approved_tags: දැනට අනුමත ප්රවණතා හැෂ් ටැග් නොමැත.
requirements: 'මෙම ඕනෑම අපේක්ෂකයෙකුට #%{rank} අනුමත ප්රවණතා හැෂ් ටැගය අභිබවා යා හැකිය, එය දැනට ලකුණු %{lowest_tag_score}ක් සමඟ #%{lowest_tag_name} වේ.'
@@ -747,37 +780,38 @@ si:
hint_html: ඔබට වෙනත් ගිණුමකින් මෙය වෙත මාරු වීමට අවශ්ය නම්, මෙහිදී ඔබට අන්වර්ථ නාමයක් සෑදිය හැක, එය පැරණි ගිණුමෙන් අනුගාමිකයින් මෙම ගිණුමට ගෙන යාමට පෙර අවශ්ය වේ. මෙම ක්රියාවම හානිකර නොවන සහ ආපසු හැරවිය හැකිවේ. ගිණුම් සංක්රමණය පැරණි ගිණුමෙන් ආරම්භ වේ.
remove: අන්වර්ථය විසන්ධි කරන්න
appearance:
- advanced_web_interface: උසස් වියමන අතුරුමුහුණත
+ advanced_web_interface: සංකීර්ණ අතුරු මුහුණත
advanced_web_interface_hint: 'ඔබට ඔබේ සම්පූර්ණ තිරයේ පළල භාවිතා කිරීමට අවශ්ය නම්, උසස් වෙබ් අතුරු මුහුණත ඔබට අවශ්ය පරිදි එකම වේලාවක බොහෝ තොරතුරු බැලීමට විවිධ තීරු වින්යාස කිරීමට ඉඩ දෙයි: නිවස, දැනුම්දීම්, ෆෙඩරේටඩ් කාලරාමුව, ඕනෑම ලැයිස්තු සහ හැෂ් ටැග්.'
animations_and_accessibility: සජීවිකරණ සහ ප්රවේශ්යතාව
confirmation_dialogs: තහවුරු කිරීමේ සංවාද
discovery: සොයාගැනීම
localization:
- body: Mastodon ස්වේච්ඡා සේවකයන් විසින් පරිවර්තනය කර ඇත.
+ body: මාස්ටඩන් ස්වේච්ඡාවෙන් පරිවර්තනය කර ඇත.
guide_link: https://crowdin.com/project/mastodon
- guide_link_text: සෑම කෙනෙකුටම දායක විය හැකිය.
- sensitive_content: සංවේදී අන්තර්ගතය
+ guide_link_text: පරිවර්තකයින්ට දායක වීමට හැකිය.
+ sensitive_content: සංවේදී අන්තර්ගත
application_mailer:
- notification_preferences: ඊමේල් මනාප වෙනස් කරන්න
+ notification_preferences: වි-තැපැල් අභිප්රේත වෙනස් කරන්න
salutation: "%{name},"
- settings: 'ඊමේල් මනාප වෙනස් කරන්න: %{link}'
+ settings: 'වි-තැපැල් අභිප්රේත වෙනස් කරන්න: %{link}'
view: 'දැක්ම:'
view_profile: පැතිකඩ බලන්න
- view_status: පළ කිරීම බලන්න
+ view_status: ලිපිය බලන්න
applications:
- created: යෙදුම සාර්ථකව නිර්මාණය කරන ලදී
+ created: යෙදුම සාර්ථකව සෑදිණි
destroyed: යෙදුම සාර්ථකව මකා ඇත
+ logout: නික්මෙන්න
regenerate_token: ප්රවේශ ටෝකනය නැවත උත්පාදනය කරන්න
token_regenerated: ප්රවේශ ටෝකනය සාර්ථකව ප්රතිජනනය කරන ලදී
warning: මෙම දත්ත සමඟ ඉතා ප්රවේශම් වන්න. එය කිසි විටෙක කිසිවෙකු සමඟ බෙදා නොගන්න!
your_token: ඔබේ ප්රවේශ ටෝකනය
auth:
+ apply_for_account: ගිණුමක් ඉල්ලන්න
delete_account: ගිණුම මකන්න
delete_account_html: ඔබට ඔබගේ ගිණුම මකා දැමීමට අවශ්ය නම්, ඔබට මෙතැනින් ඉදිරියට යා හැක. තහවුරු කිරීම සඳහා ඔබෙන් අසනු ඇත.
description:
- prefix_invited_by_user: "@%{name} ඔබට Mastodon හි මෙම සේවාදායකයට සම්බන්ධ වීමට ආරාධනා කරයි!"
+ prefix_invited_by_user: "@%{name} මෙම මාස්ටඩන් සේවාදායකයට ආරාධනා කර ඇත!"
prefix_sign_up: අදම මාස්ටඩන් හි ලියාපදිංචි වන්න!
- suffix: ගිණුමක් සමඟ, ඔබට ඕනෑම Mastodon සේවාදායකයකින් සහ තවත් බොහෝ දේ භාවිතා කරන්නන් සමඟ පුද්ගලයින් අනුගමනය කිරීමට, යාවත්කාලීන කිරීම් පළ කිරීමට සහ පණිවිඩ හුවමාරු කර ගැනීමට හැකි වනු ඇත!
dont_have_your_security_key: ඔබගේ ආරක්ෂක යතුර නොමැතිද?
forgot_password: මුරපදය අමතක වුනාද?
invalid_reset_password_token: මුරපද යළි පිහිටුවීමේ ටෝකනය අවලංගු හෝ කල් ඉකුත් වී ඇත. කරුණාකර අලුත් එකක් ඉල්ලන්න.
@@ -788,12 +822,25 @@ si:
logout: නික්මෙන්න
migrate_account: වෙනත් ගිණුමකට යන්න
migrate_account_html: ඔබට මෙම ගිණුම වෙනත් එකකට හරවා යැවීමට අවශ්ය නම්, ඔබට එය මෙහි වින්යාසගත කළ හැක.
- or_log_in_with: හෝ සමඟින් පිවිසෙන්න
+ progress:
+ details: ඔබගේ විස්තර
+ rules: නීති පිළිගන්න
+ providers:
+ cas: CAS
+ saml: SAML
register: ලියාපදිංචිය
registration_closed: "%{instance} නව සාමාජිකයින් පිළිගන්නේ නැත"
- reset_password: මුරපදය නැවත සකසන්න
- security: ආරක්ෂාව
+ reset_password: මුරපදය යළි සකසන්න
+ rules:
+ accept: පිළිගන්න
+ back: ආපසු
+ title_invited: ඔබට ආරාධනා කර ඇත.
+ security: ආරක්ෂාව
set_new_password: නව මුරපදය සකසන්න
+ setup:
+ title: ඔබගේ එනලිපි බලන්න
+ sign_in:
+ title: "%{domain} වෙත පිවිසෙන්න"
status:
account_status: ගිණුමේ තත්වය
confirming: විද්යුත් තැපෑල තහවුරු කිරීම සම්පූර්ණ කිරීම සඳහා රැඳී සිටිමින්.
@@ -802,11 +849,11 @@ si:
redirecting_to: එය දැනට %{acct}වෙත හරවා යවන බැවින් ඔබගේ ගිණුම අක්රියයි.
view_strikes: ඔබගේ ගිණුමට එරෙහිව පසුගිය වර්ජන බලන්න
too_fast: පෝරමය ඉතා වේගයෙන් ඉදිරිපත් කර ඇත, නැවත උත්සාහ කරන්න.
- use_security_key: ආරක්ෂක යතුර භාවිතා කරන්න
+ use_security_key: ආරක්ෂණ යතුර භාවිතා කරන්න
challenge:
confirm: ඉදිරියට
hint_html: "ඉඟිය: අපි ඉදිරි පැය සඳහා නැවත ඔබගේ මුරපදය ඔබෙන් නොඉල්ලමු."
- invalid_password: නොවන මුරපදයකි
+ invalid_password: මුරපදය වැරදිය
prompt: ඉදිරියට යාමට මුරපදය තහවුරු කරන්න
crypto:
errors:
@@ -814,20 +861,24 @@ si:
invalid_signature: වලංගු Ed25519 අත්සනක් නොවේ
date:
formats:
- default: "%b %d, %Y"
- with_month_name: "%B %d, %Y"
+ default: "%Y %b %d"
+ with_month_name: "%Y %B %d"
datetime:
distance_in_words:
about_x_hours: පැය %{count}
about_x_months: මාස %{count}
+ about_x_years: ව.%{count}
+ almost_x_years: ව.%{count}
half_a_minute: මේ දැන්
- less_than_x_minutes: මීටර් %{count}
+ less_than_x_minutes: විනාඩි %{count}
less_than_x_seconds: මේ දැන්
- x_minutes: මීටර් %{count}
+ over_x_years: ව.%{count}
+ x_days: ද.%{count}
+ x_minutes: විනාඩි %{count}
x_months: මාස %{count}
- x_seconds: "%{count}තත්"
+ x_seconds: තත්. %{count}
deletes:
- challenge_not_passed: ඔබ ඇතුළත් කළ තොරතුරු නිවැරදි නැත
+ challenge_not_passed: ඔබ ඇතුල් කරන ලද තොරතුරු වැරදියි
confirm_password: ඔබගේ අනන්යතාවය තහවුරු කිරීමට ඔබගේ වත්මන් මුරපදය ඇතුලත් කරන්න
confirm_username: ක්රියා පටිපාටිය තහවුරු කිරීමට ඔබගේ පරිශීලක නාමය ඇතුලත් කරන්න
proceed: ගිණුම මකන්න
@@ -835,7 +886,7 @@ si:
warning:
before: 'ඉදිරියට යාමට පෙර, කරුණාකර මෙම සටහන් හොඳින් කියවන්න:'
caches: වෙනත් සේවාදායකයන් විසින් හැඹිලිගත කර ඇති අන්තර්ගතය දිගටම පැවතිය හැක
- data_removal: ඔබගේ පළ කිරීම් සහ අනෙකුත් දත්ත ස්ථිරවම ඉවත් කරනු ලැබේ
+ data_removal: ඔබගේ ලිපි සහ අනෙකුත් දත්ත සදහටම ඉවත් කෙරෙනු ඇත
email_change_html: ඔබට ඔබගේ ගිණුම මකා කළ හැක
email_contact_html: එය තවමත් නොපැමිණියේ නම්, ඔබට උදව් සඳහා %{email} විද්යුත් තැපෑලෙන් යැවිය හැක
email_reconfirmation_html: ඔබට තහවුරු කිරීමේ විද්යුත් තැපෑල නොලැබුනේ නම්, ඔබට එය නැවත ඉල්ලා සිටිය හැක
@@ -859,13 +910,12 @@ si:
description_html: මේවා ඔබගේ ගිණුමට එරෙහිව ගන්නා ලද ක්රියා සහ %{instance}හි කාර්ය මණ්ඩලය විසින් ඔබට එවා ඇති අනතුරු ඇඟවීම් වේ.
recipient: වෙත යොමු කරන ලදී
reject_appeal: අභියාචනය ප්රතික්ෂේප කරන්න
- status: 'පළ කිරීම #%{id}'
- status_removed: පළ කිරීම දැනටමත් පද්ධතියෙන් ඉවත් කර ඇත
+ status: "#%{id} ලිපිය"
+ status_removed: ලිපිය දැනටමත් පද්ධතියෙන් ඉවත් කර ඇත
title: "%{action} සිට %{date}"
title_actions:
- delete_statuses: පසු ඉවත් කිරීම
+ delete_statuses: ලිපි ඉවත් කිරීම
disable: ගිණුම කැටි කිරීම
- mark_statuses_as_sensitive: තනතුරු සංවේදී ලෙස සලකුණු කිරීම
none: අවවාදයයි
sensitive: ගිණුම සංවේදී ලෙස සලකුණු කිරීම
silence: ගිණුම සීමා කිරීම
@@ -875,6 +925,9 @@ si:
your_appeal_rejected: ඔබගේ අභියාචනය ප්රතික්ෂේප කර ඇත
domain_validator:
invalid_domain: වලංගු ඩොමේන් නාමයක් නොවේ
+ edit_profile:
+ basic_information: මූලික තොරතුරු
+ other: වෙනත්
errors:
'400': ඔබ ඉදිරිපත් කළ ඉල්ලීම අවලංගු හෝ විකෘති විය.
'403': ඔබට මෙම පිටුව බැලීමට අවසර නැත.
@@ -884,42 +937,43 @@ si:
'422':
content: ආරක්ෂක සත්යාපනය අසාර්ථක විය. ඔබ කුකීස් අවහිර කරනවාද?
title: ආරක්ෂක සත්යාපනය අසාර්ථක විය
- '429': ඉල්ලීම් වැඩියි
+ '429': ඉල්ලීම් බොහෝය
'500':
content: අපට කණගාටුයි, නමුත් අපගේ පැත්තෙන් යමක් වැරදී ඇත.
- title: මෙම පිටුව නිවැරදි නොවේ
+ title: මෙම පිටුව වැරදියි
'503': තාවකාලික සේවාදායකයේ අසාර්ථක වීමක් හේතුවෙන් පිටුව සේවය කිරීමට නොහැකි විය.
- noscript_html: Mastodon වෙබ් යෙදුම භාවිතා කිරීමට, කරුණාකර JavaScript සක්රීය කරන්න. විකල්පයක් ලෙස, ඔබේ වේදිකාව සඳහා එකක් උත්සාහ කරන්න.
+ noscript_html: මාස්ටඩන් වියමන යෙදුම භාවිතා කිරීමට ජාවාස්ක්රිප්ට් සබල කරන්න. ඊට අමතරව, ඔබගේ වේදිකාව සඳහා වන නිසග යෙදුමක් අත්හදා බලන්න.
existing_username_validator:
not_found: එම පරිශීලක නාමය සහිත දේශීය පරිශීලකයෙකු සොයා ගැනීමට නොහැකි විය
not_found_multiple: "%{usernames}සොයා ගැනීමට නොහැකි විය"
exports:
archive_takeout:
date: දිනය
- download: ඔබගේ සුරක්ෂිතභාවය බාගන්න
- hint_html: ඔබට ඔබගේ පළ කිරීම් සහ උඩුගත කළ මාධ්යහි සංරක්ෂිතයක් ඉල්ලා සිටිය හැක. නිර්යාත කළ දත්ත ActivityPub ආකෘතියෙන්, ඕනෑම අනුකූල මෘදුකාංගයකට කියවිය හැකිය. ඔබට දින 7කට වරක් ලේඛනාගාරයක් ඉල්ලා සිටිය හැක.
+ download: ඔබගේ සංරක්ෂිතය බාගන්න
+ hint_html: ඔබට ලිපි සහ උඩුගත කළ මාධ්යවල සංරක්ෂණයක් ඉල්ලීමට හැකිය. නිර්යාත කළ දත්ත ActivityPub ආකෘතියට ගැළපෙන ඕනෑම මෘදුකාංගයකින් කියවීමට හැකිය. ඔබට දවස් 7 කට වරක් සංරක්ෂණයක් ඉල්ලීමට හැකිය.
in_progress: ඔබගේ සංරක්ෂිතය සම්පාදනය කරමින්...
request: ඔබගේ සංරක්ෂිතය ඉල්ලන්න
size: ප්රමාණය
blocks: ඔබ අවහිර කරන්න
- bookmarks: පොත් යොමු කරන්න
+ bookmarks: පොත්යොමු
+ csv: CSV
domain_blocks: වසම් අවහිර කිරීම්
- lists: ලැයිස්තුව
+ lists: ලැයිස්තු
mutes: ඔබ නිහඬ කරන්න
- storage: මාධ්ය ගබඩාව
+ storage: මාධ්ය ආචයනය
featured_tags:
add_new: අලුතින් එකතු කරන්න
- hint_html: "විශේෂාංගගත හැෂ් ටැග් මොනවාද? ඒවා ඔබේ පොදු පැතිකඩෙහි ප්රමුඛව ප්රදර්ශනය වන අතර එම හැෂ් ටැග් යටතේ ඔබේ පොදු පළ කිරීම් බ්රවුස් කිරීමට මිනිසුන්ට ඉඩ සලසයි. නිර්මාණාත්මක කෘති හෝ දිගු කාලීන ව්යාපෘති පිළිබඳ වාර්තාවක් තබා ගැනීම සඳහා ඔවුන් විශිෂ්ට මෙවලමක් වේ."
filters:
contexts:
account: පැතිකඩයන්
- home: නිවස සහ ලැයිස්තු
+ home: මුල සහ ලැයිස්තු
notifications: දැනුම්දීම්
- public: පොදු කාලරේඛා
+ public: ප්රසිද්ධ කාලරේඛා
thread: සංවාද
edit:
add_keyword: මූල පදය එක් කරන්න
keywords: මූල පද
+ statuses: තනි ලිපි
title: පෙරහන සංස්කරණය
errors:
deprecated_api_multiple_keywords: මෙම පරාමිති පෙරහන් මූල පද එකකට වඩා අදාළ වන බැවින් මෙම යෙදුමෙන් වෙනස් කළ නොහැක. වඩාත් මෑත යෙදුමක් හෝ වෙබ් අතුරු මුහුණතක් භාවිතා කරන්න.
@@ -927,21 +981,32 @@ si:
index:
contexts: "%{contexts}හි පෙරහන්"
delete: මකන්න
- empty: ඔබට පෙරහන් නොමැත.
- expires_in: "%{distance}කින් කල් ඉකුත් වේ"
- expires_on: "%{date}දින කල් ඉකුත් වේ"
+ empty: ඔබ සතුව පෙරහන් නැත.
+ expires_in: "%{distance} කින් ඉකුත් වේ"
+ expires_on: "%{date} දී ඉකුත් වේ"
keywords:
- one: "%{count} මූල පදය"
- other: "%{count} මූල පද"
+ one: මූල පද %{count}
+ other: මූල පද %{count}
+ statuses:
+ one: ලිපි %{count}
+ other: ලිපි %{count}
title: පෙරහන්
new:
save: නව පෙරහන සුරකින්න
title: නව පෙරහනක් එකතු කරන්න
+ statuses:
+ back_to_filter: පෙරහනට ආපසු
+ batch:
+ remove: පෙරහනෙන් ඉවතලන්න
+ index:
+ title: පෙරූ ලිපි
generic:
all: සියල්ල
- changes_saved_msg: වෙනස්කම් සාර්ථකව සුරකින ලදී!
+ cancel: අවලංගු
+ changes_saved_msg: වෙනස්කම් සාර්ථකව සුරැකිණි!
copy: පිටපතක්
delete: මකන්න
+ deselect: සියල්ල නොතෝරන්න
none: කිසිවක් නැත
order_by: විසින් ඇණවුම් කරන්න
save_changes: වෙනස්කම් සුරකින්න
@@ -951,24 +1016,33 @@ si:
other: යමක් තවමත් හරි නැත! කරුණාකර පහත දෝෂ %{count} ක් සමාලෝචනය කරන්න
imports:
errors:
+ empty: හිස් CSV ගොනුවකි
over_rows_processing_limit: පේළි %{count} කට වඩා අඩංගු වේ
+ too_large: ගොනුව ඉතා විශාලයි
+ imported: ආයාත විය
modes:
- merge: ඒකාබද්ධ කරන්න
+ merge: ඒකාබද්ධ
merge_long: පවතින වාර්තා තබා නව ඒවා එකතු කරන්න
overwrite: උඩින් ලියන්න
overwrite_long: වත්මන් වාර්තා නව ඒවා සමඟ ප්රතිස්ථාපනය කරන්න
preface: ඔබ අනුගමන කරන හෝ අවහිර කරන පුද්ගලයින්ගේ ලැයිස්තුවක් වැනි වෙනත් සේවාදායකයකින් ඔබ නිර්යාත කර ඇති දත්ත ඔබට ආයාත කළ හැක.
+ status: තත්වය
success: ඔබගේ දත්ත සාර්ථකව උඩුගත කර ඇති අතර නියමිත වේලාවට සැකසෙනු ඇත
+ titles:
+ lists: ලැයිස්තු ආයාත වෙමින්
+ type_groups:
+ constructive: අනුගමන හා පොත්යොමු
types:
- blocking: අවහිර කිරීමේ ලැයිස්තුව
- bookmarks: පොත් යොමු
- domain_blocking: වසම් අවහිර කිරීමේ ලැයිස්තුව
- following: පහත ලැයිස්තුව
+ blocking: අවහිර ලැයිස්තුව
+ bookmarks: පොත්යොමු
+ domain_blocking: වසම් අවහිර ලැයිස්තුව
+ following: අනුගමන ලැයිස්තුව
+ lists: ලැයිස්තු
muting: නිහඬ කිරීමේ ලැයිස්තුව
upload: උඩුගත කරන්න
invites:
- delete: අක්රිය කරන්න
- expired: කල් ඉකුත් වී ඇත
+ delete: අක්රිය කරන්න
+ expired: ඉකුත් වී ඇත
expires_in:
'1800': විනාඩි 30
'21600': පැය 6
@@ -987,7 +1061,7 @@ si:
table:
expires_at: කල් ඉකුත් වේ
uses: භාවිතා කරයි
- title: මිනිසුන්ට ආරාධනා කරන්න
+ title: ආරාධනා කරන්න
login_activities:
authentication_methods:
otp: ද්වි-සාධක සත්යාපන යෙදුම
@@ -1001,7 +1075,7 @@ si:
title: සත්යාපන ඉතිහාසය
media_attachments:
validations:
- images_and_video: දැනටමත් පින්තූර අඩංගු පළ කිරීමකට වීඩියෝවක් ඇමිණිය නොහැක
+ images_and_video: දැනටමත් රූප අඩංගු ලිපියකට දෘශ්යකයක් ඇමිණීමට නොහැකිය
not_ready: සැකසීම අවසන් නොකළ ගොනු ඇමිණිය නොහැක. මොහොතකින් නැවත උත්සාහ කරන්න!
too_many: ගොනු 4කට වඩා ඇමිණිය නොහැක
migrations:
@@ -1036,7 +1110,7 @@ si:
other_data: වෙනත් දත්ත කිසිවක් ස්වයංක්රීයව ගෙන නොයනු ඇත
redirect: ඔබගේ ජංගම ගිණුමේ පැතිකඩ යළි-යොමු කිරීමේ දැන්වීමක් සමඟ යාවත්කාලීන කෙරෙන අතර සෙවුම් වලින් බැහැර කරනු ලැබේ
moderation:
- title: මධ්යස්ථභාවය
+ title: මැදිහත්කරණය
move_handler:
carry_blocks_over_text: මෙම පරිශීලකයා ඔබ අවහිර කර තිබූ %{acct}සිට මාරු විය.
carry_mutes_over_text: මෙම පරිශීලකයා ඔබ නිශ්ශබ්ද කර තිබූ %{acct}වෙතින් මාරු විය.
@@ -1044,37 +1118,31 @@ si:
notification_mailer:
admin:
report:
- subject: "%{name} වාර්තාවක් ඉදිරිපත් කළේය"
+ subject: "%{name} වාර්තාවක් යොමු කර ඇත"
sign_up:
subject: "%{name} අත්සන් කර ඇත"
favourite:
- body: 'ඔබේ පළ කිරීම %{name}විසින් ප්රිය කරන ලදී:'
- subject: "%{name} ඔබගේ පළ කිරීම ප්රිය කරන ලදී"
- title: නව ප්රියතම
+ body: "%{name} ඔබගේ ලිපියට ප්රිය කළා:"
+ subject: "%{name} ඔබගේ ලිපියට ප්රිය කළා"
+ title: නව ප්රියතමය
follow:
body: "%{name} දැන් ඔබව අනුගමනය කරයි!"
subject: "%{name} දැන් ඔබව අනුගමනය කරයි"
title: නව අනුගාමිකයෙක්
follow_request:
- action: අනුගමනය කරන ඉල්ලීම් කළමනාකරණය කරන්න
+ action: අනුගමන ඉල්ලීම් කළමනාකරණය
body: "%{name} ඔබව අනුගමනය කිරීමට ඉල්ලා ඇත"
subject: 'පොරොත්තු අනුගාමිකයා: %{name}'
- title: නව අනුගමනය ඉල්ලීම
+ title: නව අනුගමන ඉල්ලීම
mention:
action: පිළිතුර
- body: 'ඔබව මෙහි %{name} කින් සඳහන් කර ඇත:'
- subject: ඔබව %{name}මගින් සඳහන් කර ඇත
+ body: "%{name} ඔබව මෙහි සඳහන් කර ඇත:"
+ subject: "%{name} ඔබව සඳහන් කර ඇත"
title: නව සඳැහුම
- poll:
- subject: "%{name} න් මත විමසුමක් අවසන් විය"
- reblog:
- body: 'ඔබේ පළ කිරීම %{name}කින් වැඩි කරන ලදී:'
- subject: "%{name} ඔබේ පළ කිරීම ඉහළ නැංවීය"
- title: නව තල්ලුවක්
status:
subject: "%{name} දැන් පළ කළා"
update:
- subject: "%{name} පළ කිරීමක් සංස්කරණය කළා"
+ subject: "%{name} ලිපිය සංශෝධනය කළා"
notifications:
email_events: ඊමේල් දැනුම්දීම් සඳහා සිදුවීම්
email_events_hint: 'ඔබට දැනුම්දීම් ලැබීමට අවශ්ය සිදුවීම් තෝරන්න:'
@@ -1084,11 +1152,8 @@ si:
decimal_units:
format: "%n%u"
units:
- billion: බී
million: ද.ල.
- quadrillion: ප්රශ්නය
thousand: ද.
- trillion: ටී
otp_authentication:
code_hint: තහවුරු කිරීමට ඔබගේ සත්යාපන යෙදුම මගින් ජනනය කරන ලද කේතය ඇතුළු කරන්න
description_html: ඔබ සත්යාපන යෙදුමක් භාවිතයෙන් ද්වි-සාධක සත්යාපනය සක්රීය කරන්නේ නම්, ලොගින් වීමේදී ඔබට ඔබගේ දුරකථනය සන්තකයේ තබා ගැනීමට අවශ්ය වනු ඇත, එය ඔබට ඇතුළු වීමට ටෝකන ජනනය කරයි.
@@ -1105,19 +1170,21 @@ si:
truncate: "…"
polls:
errors:
- already_voted: ඔබ දැනටමත් මෙම මත විමසුමට ඡන්දය දී ඇත
- duplicate_options: අනුපිටපත් අයිතම අඩංගු වේ
+ already_voted: ඔබ මෙම මත විමසුමට ඡන්දය දී ඇත
duration_too_long: අනාගතයට බොහෝ දුරයි
- duration_too_short: ඉතා ඉක්මනින් වේ
- expired: මත විමසුම දැනටමත් අවසන් වී ඇත
+ expired: මත විමසුම දැනටමත් නිමා වී ඇත
invalid_choice: තෝරාගත් ඡන්ද විකල්පය නොපවතී
- over_character_limit: එක් එක් අක්ෂර %{max} ට වඩා දිගු විය නොහැක
- too_few_options: එක් අයිතමයකට වඩා තිබිය යුතුය
- too_many_options: අයිතම %{max} කට වඩා අඩංගු විය නොහැක
+ self_vote: ඔබගේ මත විමසුමට ජන්දය දීමට නොහැකිය
+ too_few_options: එක් අථකයකට වඩා තිබිය යුතුය
+ too_many_options: අථක %{max} කට වඩා අඩංගු නොවිය යුතුය
preferences:
other: වෙනත්
- posting_defaults: පෙරනිමි පළ කිරීම
- public_timelines: පොදු කාලරේඛා
+ posting_defaults: සැමවිට පළ කරන ආකාරය
+ public_timelines: ප්රසිද්ධ කාලරේඛා
+ privacy:
+ search: සොයන්න
+ privacy_policy:
+ title: රහස්යතා ප්රතිපත්තිය
reactions:
errors:
limit_reached: විවිධ ප්රතික්රියා වල සීමාව ළඟා විය
@@ -1125,7 +1192,7 @@ si:
relationships:
activity: ගිණුමේ ක්රියාකාරකම්
dormant: නිදිමතයි
- follow_selected_followers: තෝරාගත් අනුගාමිකයින් අනුගමනය කරන්න
+ follow_selected_followers: තේරූ අනුගාමිකයින් අනුගමනය කරන්න
followers: අනුගාමිකයින්
following: අනුගමනය
invited: ආරාධනා කළා
@@ -1133,11 +1200,11 @@ si:
most_recent: මෑතකාලීන
moved: මාරු කළා
mutual: අන්යෝන්ය
- primary: ප්රාථමික
+ primary: ප්රාථමික
relationship: සම්බන්ධතාවය
- remove_selected_domains: තෝරාගත් වසම් වලින් සියලුම අනුගාමිකයින් ඉවත් කරන්න
- remove_selected_followers: තෝරාගත් අනුගාමිකයින් ඉවත් කරන්න
- remove_selected_follows: තෝරාගත් පරිශීලකයින් අනුගමනය නොකරන්න
+ remove_selected_domains: තේරූ වසම් වල සියලුම අනුගාමිකයින් ඉවත් කරන්න
+ remove_selected_followers: තේරූ අනුගාමිකයින් ඉවත් කරන්න
+ remove_selected_follows: තේරූ අය අනුගමනය නොකරන්න
status: ගිණුමේ තත්වය
remote_follow:
missing_resource: ඔබගේ ගිණුම සඳහා අවශ්ය යළි-යොමුවීම් URL එක සොයා ගැනීමට නොහැකි විය
@@ -1147,56 +1214,62 @@ si:
rss:
content_warning: 'අන්තර්ගත අනතුරු ඇඟවීම:'
descriptions:
- account: "@%{acct}සිට පොදු පළ කිරීම්"
- tag: "#%{hashtag}ටැග් කර ඇති පොදු පළ කිරීම්"
+ account: "@%{acct} වෙතින් ප්රසිද්ධ ලිපි"
scheduled_statuses:
- over_daily_limit: ඔබ අද දිනට නියමිත පළ කිරීම් %{limit} සීමාව ඉක්මවා ඇත
- over_total_limit: ඔබ නියමිත පළ කිරීම් %{limit} සීමාව ඉක්මවා ඇත
too_soon: නියමිත දිනය අනාගතයේ විය යුතුය
sessions:
activity: අවසාන ක්රියාකාරකම
browser: අතිරික්සුව
browsers:
alipay: අලිපේ
+ blackberry: බ්ලැක්බෙරි
chrome: ක්රෝම්
edge: මයික්රොසොෆ්ට් එඩ්ගේ
electron: ඉලෙක්ට්රෝන්
firefox: ෆයර්ෆොක්ස්
generic: නොදන්නා අතිරික්සුවකි
+ huawei_browser: හුආවේ අතිරික්සුව
ie: ඉන්ටර්නෙට් එක්ස්ප්ලෝරර්
micro_messenger: මයික්රොමැසෙන්ජර්
- nokia: Nokia S40 Ovi බ්රව්සරය
+ nokia: නොකියා S40 Ovi අතිරික්සුව
opera: ඔපෙරා
otter: ඔටර්
+ phantom_js: PhantomJS
qq: කියුකියු අතිරික්සුව
safari: සෆාරි
+ uc_browser: UC අතිරික්සුව
+ unknown_browser: නොදන්නා අතිරික්සුවකි
weibo: වෙයිබො
- current_session: වත්මන් සැසිය
- description: "%{browser} මත %{platform}"
- explanation: මේවා දැනට ඔබගේ Mastodon ගිණුමට ලොග් වී ඇති වෙබ් බ්රව්සර් වේ.
+ current_session: වත්මන් වාරය
+ description: "%{platform} හි %{browser}"
+ explanation: ඔබගේ මාස්ටඩන් ගිණුමට පිවිසීම සඳහා භාවිතා කර තිබෙන අතිරික්සු.
ip: අ.ජා. කෙ. (IP)
platforms:
adobe_air: ඇඩෝබි එයාර්
android: ඇන්ඩ්රොයිඩ්
+ blackberry: බ්ලැක්බෙරි
+ chrome_os: ChromeOS
firefox_os: ෆයර්ෆොක්ස් ඕඑස්
ios: අයිඕඑස්
+ kai_os: KaiOS
linux: ලිනක්ස්
mac: මැක්ඕඑස්
+ unknown_platform: නොදන්නා වේදිකාවකි
windows: වින්ඩෝස්
windows_mobile: වින්ඩෝස් මොබයිල්
windows_phone: වින්ඩෝස් පෝන්
revoke: අවලංගු කරන්න
- revoke_success: සැසිය සාර්ථකව අවලංගු කරන ලදී
- title: සැසිවාර
+ revoke_success: වාරය සාර්ථකව අවලංගු කෙරිණි
+ title: වාර
view_authentication_history: ඔබගේ ගිණුමේ සත්යාපන ඉතිහාසය බලන්න
settings:
account: ගිණුම
account_settings: ගිණුමේ සැකසුම්
aliases: ගිණුම් අන්වර්ථ නාමයන්
appearance: පෙනුම
- authorized_apps: අවසර ලත් යෙදුම්
- back: Mastodon වෙත නැවත යන්න
- delete: ගිණුම මකා දැමීම
+ authorized_apps: බලයලත් යෙදුම්
+ back: මාස්ටඩන් වෙත ආපසු
+ delete: ගිණුම මැකීම
development: සංවර්ධනය
edit_profile: පැතිකඩ සංස්කරණය
export: දත්ත නිර්යාතය
@@ -1205,13 +1278,12 @@ si:
import_and_export: ආයාත හා නිර්යාත
migrate: ගිණුම් සංක්රමණය
notifications: දැනුම්දීම්
- preferences: මනාප
- profile: පැතිකඩ
- relationships: අනුගාමිකයින් සහ අනුගාමිකයින්
- statuses_cleanup: ස්වයංක්රීය පළ කිරීම් මකාදැමීම
- strikes: මධ්යස්ථ වැඩ වර්ජන
+ preferences: අභිප්රේත
+ profile: ප්රසිද්ධ පැතිකඩ
+ relationships: අනුගමන හා අනුගාමික
+ statuses_cleanup: ස්වයංක්රීය ලිපි මැකීම
two_factor_authentication: ද්වි සාධක Aut
- webauthn_authentication: ආරක්ෂක යතුරු
+ webauthn_authentication: ආරක්ෂණ යතුරු
statuses:
attached:
audio:
@@ -1219,35 +1291,33 @@ si:
other: "%{count} ශ්රව්ය"
description: 'අමුණා ඇත: %{attached}'
image:
- one: "%{count} රූපය"
- other: පින්තූර %{count}
+ one: රූප %{count}
+ other: රූප %{count}
video:
- one: "%{count} වීඩියෝ"
- other: වීඩියෝ %{count}
- boosted_from_html: "%{acct_link}සිට වැඩි කරන ලදී"
+ one: දෘශ්යක %{count}
+ other: දෘශ්යක %{count}
content_warning: 'අන්තර්ගත අනතුරු ඇඟවීම: %{warning}'
- default_language: අතුරු මුහුණත් භාෂාවට සමානයි
+ default_language: අතුරු මුහුණතේ භාෂාවම
disallowed_hashtags:
one: 'අනුමත නොකළ හැෂ් ටැගයක් අඩංගු විය: %{tags}'
other: 'අනුමත නොකළ හැෂ් ටැග් අඩංගු විය: %{tags}'
edited_at_html: සංස්කරණය %{date}
errors:
- in_reply_not_found: ඔබ පිළිතුරු දීමට උත්සාහ කරන පළ කිරීම පවතින බවක් නොපෙනේ.
+ in_reply_not_found: ඔබ පිළිතුරු දීමට තැත් කරන ලිපිය නොපවතින බව පෙනෙයි.
open_in_web: වෙබයේ විවෘත කරන්න
over_character_limit: අක්ෂර සීමාව %{max} ඉක්මවා ඇත
pin_errors:
- direct: සඳහන් කළ පරිශීලකයින්ට පමණක් පෙනෙන පළ කිරීම් ඇමිණිය නොහැක
- limit: ඔබ දැනටමත් උපරිම පළ කිරීම් සංඛ්යාව අමුණා ඇත
- ownership: වෙනත් කෙනෙකුගේ පළ කිරීමක් ඇමිණිය නොහැක
- reblog: බූස්ට් එකක් ඇලවිය නොහැක
+ direct: සඳහන් කළ අයට පමණක් පෙනෙන ලිපි ඇමිණීමට නොහැකිය
+ limit: දැනටමත් මුදුනට ඇමිණිමට හැකි ලිපි සීමාවට ළඟා වී ඇත
+ ownership: වෙනත් අයගේ ලිපි ඇමිණීමට නොහැකිය
poll:
total_people:
- one: "%{count} පුද්ගලයෙක්"
- other: පුද්ගලයන් %{count}
+ one: පුද්ගලයින් %{count}
+ other: පුද්ගලයින් %{count}
total_votes:
- one: "%{count} ඡන්ද"
+ one: ඡන්ද %{count} යි
other: ඡන්ද %{count} යි
- vote: ඡන්දය දෙන්න
+ vote: ඡන්දය
show_more: තව පෙන්වන්න
show_newer: අලුත්ම පෙන්වන්න
show_older: පැරණි පෙන්වන්න
@@ -1255,46 +1325,40 @@ si:
title: '%{name}: "%{quote}"'
visibilities:
direct: සෘජු
- private: අනුගාමිකයින්-පමණි
+ private: අනුගාමිකයින් පමණි
private_long: අනුගාමිකයින්ට පමණක් පෙන්වන්න
public: ප්රසිද්ධ
public_long: හැමෝටම පේනවා
unlisted: ලැයිස්තුගත නොකළ
unlisted_long: සෑම කෙනෙකුටම දැකිය හැක, නමුත් පොදු කාලරාමුවෙහි ලැයිස්තුගත කර නොමැත
statuses_cleanup:
- enabled: පැරණි පළ කිරීම් ස්වයංක්රීයව මකන්න
- enabled_hint: ඔබේ පළ කිරීම් පහත ව්යතිරේකවලින් එකකට ගැලපෙන්නේ නම් මිස, ඒවා නිශ්චිත වයස් සීමාවකට ළඟා වූ පසු ස්වයංක්රීයව මකයි
- exceptions: ව්යතිරේක
- explanation: පළ කිරීම් මකා දැමීම මිල අධික මෙහෙයුමක් වන බැවින්, සේවාදායකය වෙනත් ආකාරයකින් කාර්යබහුල නොවන විට කාලයත් සමඟ මෙය සෙමින් සිදු කෙරේ. මෙම හේතුව නිසා, ඔබේ පළ කිරීම් වයස් සීමාවට ළඟා වූ පසු ටික වේලාවකට පසුව මකා දැමිය හැක.
- ignore_favs: ප්රියතමයන් නොසලකා හරින්න
- ignore_reblogs: වැඩි කිරීම් නොසලකා හරින්න
+ enabled: පරණ ලිපි ස්වයංක්රීයව මකන්න
+ exceptions: හැර දැමීම්
+ ignore_favs: ප්රියතමයන් නොසලකන්න
interaction_exceptions: අන්තර්ක්රියා මත පදනම් වූ ව්යතිරේක
- interaction_exceptions_explanation: පළ කිරීම් වරක් ඒවා ඉක්මවා ගිය පසු ප්රියතම හෝ බූස්ට් සීමාවට පහළින් ගියහොත් ඒවා මැකීමට සහතිකයක් නොමැති බව සලකන්න.
- keep_direct: සෘජු පණිවිඩ තබා ගන්න
- keep_direct_hint: ඔබගේ සෘජු පණිවිඩ කිසිවක් මකන්නේ නැත
- keep_media: මාධ්ය ඇමුණුම් සමඟ පළ කිරීම් තබා ගන්න
- keep_media_hint: මාධ්ය ඇමුණුම් ඇති ඔබේ පළ කිරීම් කිසිවක් මකන්නේ නැත
+ keep_direct: සෘජු පණිවිඩ තබාගන්න
+ keep_direct_hint: ඔබගේ සෘජු පණිවිඩ කිසිවක් නොමැකෙයි
+ keep_media: මාධ්ය ඇමුණුම් සහිත ලිපි තබාගන්න
+ keep_media_hint: මාධ්ය ඇමුණුම් සහිත ඔබගේ ලිපි කිසිවක් නොමැකෙයි
keep_pinned: ඇමිණූ ලිපි තබාගන්න
keep_pinned_hint: ඔබ ඇමිණූ ලිපි කිසිවක් නොමැකෙයි
- keep_polls: ඡන්ද තබා ගන්න
- keep_polls_hint: ඔබගේ ඡන්ද විමසීම් කිසිවක් මකන්නේ නැත
- keep_self_bookmark: ඔබ පිටු සලකුණු කළ පළ කිරීම් තබා ගන්න
- keep_self_bookmark_hint: ඔබ ඔබේම පළ කිරීම් පිටු සලකුණු කර ඇත්නම් ඒවා මකා නොදමන්න
- keep_self_fav: ඔබ කැමති පළ කිරීම් තබා ගන්න
- keep_self_fav_hint: ඔබ ඒවාට කැමති නම් ඔබේම පළ කිරීම් මකා නොදමන්න
+ keep_polls: මත විමසුම් තබාගන්න
+ keep_polls_hint: ඔබගේ මත විමසුම් නොමැකෙයි
+ keep_self_bookmark: ඔබ පොත්යොමු තැබූ ලිපි තබාගන්න
+ keep_self_bookmark_hint: ඔබගේම ලිපි වලට පොත්යොමු තබා ඇත්නම් ඒවා මකා නොදැමෙයි
+ keep_self_fav: ඔබ ප්රිය කළ ලිපි තබාගන්න
+ keep_self_fav_hint: ඔබගේම ලිපි වලට ප්රිය කර ඇත්නම් ඒවා මකා නොදැමෙයි
min_age:
- '1209600': සති 2 යි
- '15778476': මාස 6 යි
- '2629746': මාස 1 යි
- '31556952': වසර 1 යි
- '5259492': මාස 2 ක්
- '604800': 1 සතිය
- '63113904': අවුරුදු 2 ක්
- '7889238': මාස 3 යි
- min_age_label: වයස් සීමාව
- min_favs: අඩුම තරමින් පෝස්ට් ප්රිය කරන ලෙස තබා ගන්න
- min_reblogs: අඩුම තරමේ පෝස්ට් බූස්ට් කරගෙන තියාගන්න
- min_reblogs_hint: අඩුම තරමින් මෙම වාර ගණන වැඩි කර ඇති ඔබගේ පළ කිරීම් කිසිවක් මකා නොදමන්න. බූස්ට් ගණන නොතකා පළ කිරීම් මැකීමට හිස්ව තබන්න
+ '1209600': සති 2
+ '15778476': මාස 6
+ '2629746': මාස 1
+ '31556952': අවුරුදු 1
+ '5259492': මාස 2
+ '604800': සති 1
+ '63113904': අවුරුදු 2
+ '7889238': මාස 3
+ min_age_label: කාල සීමාව
+ min_favs: අවම වශයෙන් ප්රිය කළ ලිපි තබාගන්න
stream_entries:
sensitive_content: සංවේදී අන්තර්ගතයකි
strikes:
@@ -1303,22 +1367,26 @@ si:
tags:
does_not_match_previous_name: පෙර නමට නොගැලපේ
themes:
- contrast: Mastodon (ඉහළ වෙනස)
- default: මැස්ටෝඩන් (අඳුරු)
- mastodon-light: මැස්ටෝඩන් (ආලෝකය)
+ default: මාස්ටඩන් (අඳුරු)
+ mastodon-light: මාස්ටඩන් (දීප්ත)
+ time:
+ formats:
+ default: "%Y %b %d, %H:%M"
+ month: "%Y %b"
+ with_time_zone: "%Y %b %d, %H:%M %Z"
two_factor_authentication:
- add: එකතු කරන්න
+ add: එකතු
disable: 2FA අබල කරන්න
disabled_success: ද්වි-සාධක සත්යාපනය සාර්ථකව අබල කර ඇත
edit: සංස්කරණය
enabled: ද්වි-සාධක සත්යාපනය සක්රීය කර ඇත
enabled_success: ද්වි-සාධක සත්යාපනය සාර්ථකව සබල කර ඇත
- generate_recovery_codes: ප්රතිසාධන කේත ජනනය කරන්න
+ generate_recovery_codes: ප්රතිසාධන කේත උත්පාදනය කරන්න
lost_recovery_codes: ඔබගේ දුරකථනය නැති වුවහොත් ඔබගේ ගිණුමට ප්රවේශය නැවත ලබා ගැනීමට ප්රතිසාධන කේත ඔබට ඉඩ සලසයි. ඔබට ඔබේ ප්රතිසාධන කේත නැති වී ඇත්නම්, ඔබට ඒවා මෙහි නැවත උත්පාදනය කළ හැක. ඔබගේ පැරණි ප්රතිසාධන කේත අවලංගු වනු ඇත.
- methods: ද්වි සාධක ක්රම
+ methods: ද්වි සාධක ක්රම
otp: Authenticator යෙදුම
- recovery_codes: උපස්ථ ප්රතිසාධන කේත
- recovery_codes_regenerated: ප්රතිසාධන කේත සාර්ථකව ප්රතිජනනය කරන ලදී
+ recovery_codes: ප්රතිසාධන කේත උපස්ථය
+ recovery_codes_regenerated: ප්රතිසාධන කේත නැවත උත්පාදනය කෙරිණි
recovery_instructions_html: ඔබට කවදා හෝ ඔබගේ දුරකථනයට ප්රවේශය අහිමි වුවහොත්, ඔබගේ ගිණුමට ප්රවේශය නැවත ලබා ගැනීමට පහත ප්රතිසාධන කේත වලින් එකක් භාවිතා කළ හැක. ප්රතිසාධන කේත ආරක්ෂිතව තබා ගන්න. උදාහරණයක් ලෙස, ඔබට ඒවා මුද්රණය කර වෙනත් වැදගත් ලේඛන සමඟ ගබඩා කළ හැකිය.
webauthn: ආරක්ෂණ යතුරු
user_mailer:
@@ -1332,54 +1400,50 @@ si:
subject: "%{date} සිට ඔබගේ අභියාචනය ප්රතික්ෂේප කර ඇත"
title: අභියාචනය ප්රතික්ෂේප විය
backup_ready:
- explanation: ඔබ ඔබේ Mastodon ගිණුමේ සම්පූර්ණ උපස්ථයක් ඉල්ලා ඇත. එය දැන් බාගත කිරීම සඳහා සූදානම්!
+ explanation: ඔබගේ මාස්ටඩන් ගිණුමේ පූර්ණ උපස්ථයක් ඉල්ලා ඇත. එය දැන් බාගැනීමට හැකිය!
subject: ඔබගේ සංරක්ෂිතය බාගැනීමට සූදානම්ය
title: සංරක්ෂිත රැගෙන යාම
suspicious_sign_in:
- change_password: ඔබගේ මුරපදය වෙනස් කරන්න
- details: 'පුරනය වීමේ විස්තර මෙන්න:'
- explanation: අපි නව IP ලිපිනයකින් ඔබගේ ගිණුමට පුරනය වීමක් අනාවරණය කරගෙන ඇත.
- further_actions_html: මෙය ඔබ නොවේ නම්, අපි ඔබට වහාම %{action} ලෙස නිර්දේශ කර ඔබගේ ගිණුම සුරක්ෂිතව තබා ගැනීමට සාධක දෙකක සත්යාපනය සබල කරන්න.
- subject: ඔබගේ ගිණුම නව IP ලිපිනයකින් ප්රවේශ වී ඇත
- title: නව පුරනය වීමක්
+ change_password: මුරපදය වෙනස් කරන්න
+ details: 'ප්රවේශයට අදාළ විස්තර:'
+ explanation: ඔබගේ ගිණුමට නව අ.ජා.කෙ. (IP) ලිපිනයකින් ප්රවේශයක් අනාවරණය වී ඇත.
+ further_actions_html: මේ ඔබ නොවේ නම්, වහාම %{action}. ඔබගේ ගිණුම සුරක්ෂිතව තබා ගැනීමට ද්වි-සාධකය සබල කරන්න.
+ subject: ඔබගේ ගිණුමට නව අ.ජා.කෙ. (IP) ලිපිනයකින් ප්රවේශ වී ඇත
+ title: නව ප්රවේශයක්
warning:
appeal: අභියාචනයක් ඉදිරිපත් කරන්න
appeal_description: මෙය දෝෂයක් බව ඔබ විශ්වාස කරන්නේ නම්, ඔබට %{instance}හි කාර්ය මණ්ඩලයට අභියාචනයක් ඉදිරිපත් කළ හැක.
categories:
- spam: ආයාචිත තැපැල්
+ spam: ආයාචිත
violation: අන්තර්ගතය පහත ප්රජා මාර්ගෝපදේශ උල්ලංඝනය කරයි
explanation:
- delete_statuses: ඔබගේ සමහර පළ කිරීම් ප්රජා මාර්ගෝපදේශ එකක් හෝ කිහිපයක් උල්ලංඝනය කරන බව සොයා ගෙන ඇති අතර පසුව %{instance}හි උපපරිපාලකයින් විසින් ඉවත් කර ඇත.
disable: ඔබට තවදුරටත් ඔබගේ ගිණුම භාවිතා කළ නොහැක, නමුත් ඔබගේ පැතිකඩ සහ අනෙකුත් දත්ත නොවෙනස්ව පවතී. ඔබට ඔබගේ දත්තවල උපස්ථයක් ඉල්ලා සිටීමට, ගිණුම් සැකසීම් වෙනස් කිරීමට හෝ ඔබගේ ගිණුම මකා දැමීමට හැකිය.
- mark_statuses_as_sensitive: ඔබගේ සමහර පළ කිරීම් %{instance}හි පරිපාලකයින් විසින් සංවේදී ලෙස සලකුණු කර ඇත. මෙයින් අදහස් කරන්නේ පෙරදසුනක් දර්ශනය වීමට පෙර පුද්ගලයින්ට පළ කිරීම් වල මාධ්ය තට්ටු කිරීමට අවශ්ය වනු ඇති බවයි. අනාගතයේදී පළ කිරීමේදී ඔබට මාධ්ය සංවේදී ලෙස සලකුණු කළ හැක.
- sensitive: මෙතැන් සිට, ඔබගේ උඩුගත කරන ලද සියලුම මාධ්ය ගොනු සංවේදී ලෙස සලකුණු කර ක්ලික්-හරහා අනතුරු ඇඟවීමක් පිටුපස සඟවනු ඇත.
- silence: ඔබට තවමත් ඔබගේ ගිණුම භාවිතා කළ හැකි නමුත් දැනටමත් ඔබව අනුගමනය කරන පුද්ගලයින් පමණක් මෙම සේවාදායකයේ ඔබගේ පළ කිරීම් දකිනු ඇති අතර, විවිධ සොයාගැනීම් විශේෂාංග වලින් ඔබව බැහැර කරනු ලැබිය හැක. කෙසේ වෙතත්, අනෙක් අය තවමත් ඔබව අතින් අනුගමනය කළ හැක.
+ sensitive: මේ මොහොත් සිට ඔබ උඩුගත කරන සියලුම මාධ්ය ගොනු සංවේදී ලෙස සලකා අවවාදයක් පිටුපස සඟවනු ඇත.
suspend: ඔබට තවදුරටත් ඔබගේ ගිණුම භාවිතා කළ නොහැකි අතර, ඔබගේ පැතිකඩ සහ අනෙකුත් දත්ත තවදුරටත් ප්රවේශ විය නොහැක. දින 30කින් පමණ දත්ත සම්පූර්ණයෙන් ඉවත් කරන තෙක් ඔබට තවමත් ඔබේ දත්තවල උපස්ථයක් ඉල්ලා සිටීමට පුරනය විය හැක, නමුත් ඔබව අත්හිටුවීම මගහැර යාම වැළැක්වීමට අපි මූලික දත්ත කිහිපයක් රඳවා ගන්නෙමු.
reason: 'හේතුව:'
- statuses: 'උපුටා දක්වන ලද පළ කිරීම්:'
subject:
- delete_statuses: "%{acct} හි ඔබගේ පළ කිරීම් ඉවත් කර ඇත"
+ delete_statuses: "%{acct} හි ඔබගේ ලිපිය ඉවත් කර ඇත"
disable: ඔබගේ ගිණුම %{acct} කර ඇත
- mark_statuses_as_sensitive: "%{acct} හි ඔබගේ පළ කිරීම් සංවේදී ලෙස සලකුණු කර ඇත"
- none: "%{acct}සඳහා අනතුරු ඇඟවීම"
- sensitive: "%{acct} හි ඔබගේ පළ කිරීම් මෙතැන් සිට සංවේදී ලෙස සලකුණු කෙරේ"
+ mark_statuses_as_sensitive: ඔබගේ %{acct} ලිපි සංවේදී බව සලකුණු කර ඇත
+ none: "%{acct} සඳහා අවවාදය"
+ sensitive: ඔබගේ %{acct} ලිපිය මේ මොහොතේ සිට සංවේදී ලෙස සලකයි
silence: ඔබගේ ගිණුම %{acct} සීමා කර ඇත
suspend: ඔබගේ ගිණුම %{acct} අත්හිටුවා ඇත
title:
- delete_statuses: පළ කිරීම් ඉවත් කරන ලදී
+ delete_statuses: ලිපි ඉවත් කර ඇත
disable: ගිණුම නිශ්චල කර ඇත
- mark_statuses_as_sensitive: පළ කිරීම් සංවේදී ලෙස ලකුණු කර ඇත
+ mark_statuses_as_sensitive: ලිපි සංවේදී බව සලකුණු කර ඇත
none: අවවාදයයි
- sensitive: ගිණුම සංවේදී ලෙස ලකුණු කර ඇත
- silence: ගිණුම සීමා සහිතයි
+ sensitive: ගිණුම සංවේදී බව යොදා ඇත
+ silence: ගිණුම සීමා කර ඇත
suspend: ගිණුම අත්හිටුවා ඇත
welcome:
- edit_profile_action: සැකසුම් පැතිකඩ
+ edit_profile_action: පැතිකඩ පිහිටුවන්න
explanation: ඔබ ආරම්භ කිරීමට උපදෙස් කිහිපයක් මෙන්න
- final_action: පළ කිරීම ආරම්භ කරන්න
+ final_action: ලිපි පළ කරන්න
full_handle: ඔබේ සම්පූර්ණ හසුරුව
full_handle_hint: මෙය ඔබ ඔබේ මිතුරන්ට පවසනු ඇත, එවිට ඔවුන්ට වෙනත් සේවාදායකයකින් ඔබට පණිවිඩ යැවීමට හෝ අනුගමනය කිරීමට හැකිය.
- subject: Mastodon වෙත සාදරයෙන් පිළිගනිමු
+ subject: මාස්ටඩන් වෙත පිළිගනිමු
title: නැවට සාදරයෙන් පිළිගනිමු, %{name}!
users:
follow_limit_reached: ඔබට පුද්ගලයින් %{limit} කට වඩා අනුගමනය කළ නොහැක
@@ -1388,9 +1452,10 @@ si:
seamless_external_login: ඔබ බාහිර සේවාවක් හරහා ලොග් වී ඇත, එබැවින් මුරපදය සහ ඊමේල් සැකසුම් නොමැත.
signed_in_as: 'මෙසේ පුරනය වී ඇත:'
verification:
- verification: සත්යාපනය
+ here_is_how: කෙසේදැයි මෙන්න
+ verification: සත්යාපනය
webauthn_credentials:
- add: නව ආරක්ෂක යතුර එක් කරන්න
+ add: නව ආරක්ෂණ යතුර එක් කරන්න
create:
error: ඔබගේ ආරක්ෂක යතුර එක් කිරීමේ ගැටලුවක් ඇති විය. කරුණාකර නැවත උත්සාහ කරන්න.
success: ඔබගේ ආරක්ෂක යතුර සාර්ථකව එක් කරන ලදී.
@@ -1400,9 +1465,9 @@ si:
destroy:
error: ඔබගේ ආරක්ෂක යතුර මැකීමේ ගැටලුවක් ඇති විය. කරුණාකර නැවත උත්සාහ කරන්න.
success: ඔබගේ ආරක්ෂක යතුර සාර්ථකව මකා ඇත.
- invalid_credential: වලංගු නොවන ආරක්ෂක යතුර
+ invalid_credential: ආරක්ෂණ යතුර වලංගු නොවේ
nickname_hint: ඔබගේ නව ආරක්ෂක යතුරේ අන්වර්ථ නාමය ඇතුළත් කරන්න
not_enabled: ඔබ තවමත් WebAuthn සබල කර නැත
not_supported: මෙම බ්රවුසරය ආරක්ෂක යතුරු සඳහා සහය නොදක්වයි
otp_required: ආරක්ෂක යතුරු භාවිතා කිරීමට කරුණාකර පළමුව ද්වි-සාධක සත්යාපනය සක්රීය කරන්න.
- registered_on: "%{date}හි ලියාපදිංචි වී ඇත"
+ registered_on: "%{date} දී ලියාපදිංචි වී ඇත"
diff --git a/config/locales/simple_form.cy.yml b/config/locales/simple_form.cy.yml
index 70194a1e0cbe12..ddc1b1b9353c6b 100644
--- a/config/locales/simple_form.cy.yml
+++ b/config/locales/simple_form.cy.yml
@@ -292,7 +292,11 @@ cy:
reblog: Mae rhywun wedi hybu eich postiad
report: Cyflwynwyd adroddiad newydd
software_updates:
+ all: Rhoi gwybod am bob ddiweddariad
+ critical: Rhoi gwybod am ddiweddariadau critigol yn unig
label: Mae fersiwn Mastodon newydd ar gael
+ none: Byth rhoi gwybod am ddiweddariadau (nid argymhellir)
+ patch: Rhoi gwybod am ddiweddariadau trwsio byg
trending_tag: Mae pwnc llosg newydd angen adolygiad
rule:
text: Rheol
@@ -319,6 +323,7 @@ cy:
url: URL diweddbwynt
'no': Na
not_recommended: Heb ei argymell
+ overridden: Wedi'i gwrth-wneud
recommended: Argymhellwyd
required:
mark: "*"
diff --git a/config/locales/simple_form.en-GB.yml b/config/locales/simple_form.en-GB.yml
index 12af55af627cbc..f0c18d1128b676 100644
--- a/config/locales/simple_form.en-GB.yml
+++ b/config/locales/simple_form.en-GB.yml
@@ -330,5 +330,5 @@ en-GB:
text: required
title:
sessions:
- webauthn: Use one of your security keys to sign in
+ webauthn: Use one of your security keys to log in
'yes': 'Yes'
diff --git a/config/locales/simple_form.es-MX.yml b/config/locales/simple_form.es-MX.yml
index 0ed471a1f8d92b..932ed6c59aa7c3 100644
--- a/config/locales/simple_form.es-MX.yml
+++ b/config/locales/simple_form.es-MX.yml
@@ -323,7 +323,7 @@ es-MX:
url: URL de Endpoint
'no': 'No'
not_recommended: No recomendado
- overridden: Sobrescrito
+ overridden: Reemplazado
recommended: Recomendado
required:
mark: "*"
diff --git a/config/locales/simple_form.fi.yml b/config/locales/simple_form.fi.yml
index cc2f1141d95899..403162b8203525 100644
--- a/config/locales/simple_form.fi.yml
+++ b/config/locales/simple_form.fi.yml
@@ -3,90 +3,90 @@ fi:
simple_form:
hints:
account:
- discoverable: Julkisia viestejäsi ja profiiliasi voidaan pitää esillä tai suositella Mastodonin eri alueilla, ja profiiliasi voidaan myös ehdottaa suoraan toisille käyttäjille.
+ discoverable: Julkisia julkaisujasi ja profiiliasi voidaan pitää esillä tai suositella Mastodonin eri alueilla ja profiiliasi voidaan ehdottaa toisille käyttäjille.
display_name: Koko nimesi tai lempinimesi.
- fields: Kotisivusi, pronominit, ikä, mitä ikinä haluatkin.
- indexable: Julkiset viestit voivat näkyä hakutuloksissa Mastodonissa. Ihmiset, jotka ovat olleet vuorovaikutuksessa viestiesi kanssa, voivat etsiä niitä siitä riippumatta.
+ fields: Kotisivusi, pronominit, ikä, mitä ikinä haluat.
+ indexable: Julkiset julkaisusi voivat näkyä hakutuloksissa Mastodonissa. Ihmiset, jotka ovat olleet vuorovaikutuksessa julkaisujesi kanssa, voivat etsiä niitä asetuksesta riippumatta.
note: 'Voit @mainita muita käyttäjiä tai #aihetunnisteita.'
- show_collections: Käyttäjät eivät näe ketä seuraat ja ketkä seuraavat sinua. Käyttäjät, joita sinä seuraat, näkevät kuitenkin sinun seuraavan heitä.
- unlocked: Käyttäjät voivat seurata sinua pyytämättä hyväksyntää. Poista valinta, jos haluat tarkistaa ja hyväksyä tai hylätä vastaanottamasi seurantapyynnöt.
+ show_collections: Käyttäjät voivat selata seurattujasi ja seuraajiasi. Käyttäjät, joita seuraat, näkevät joka tapauksessa, että seuraat heitä.
+ unlocked: Käyttäjät voivat seurata sinua pyytämättä hyväksyntää. Poista valinta, jos haluat tarkistaa ja hyväksyä tai hylätä vastaanottamasi seuraamispyynnöt.
account_alias:
- acct: Määrittele käyttäjän käyttäjänimi@verkkotunnus, josta haluat siirtyä
+ acct: Määrittele sen tilin käyttäjänimi@verkkotunnus, josta haluat siirtyä
account_migration:
- acct: Määrittele käyttäjän käyttäjänimi@verkkotunnus, johon haluat siirtyä
+ acct: Määrittele sen tilin käyttäjänimi@verkkotunnus, johon haluat siirtyä
account_warning_preset:
text: Voit käyttää julkaisun syntaksia, kuten URL-osoitteita, aihetunnisteita ja mainintoja
title: Valinnainen. Ei näy vastaanottajalle
admin_account_action:
- include_statuses: Käyttäjä näkee mitkä viestit johtivat toimenpiteeseen tai varoitukseen
+ include_statuses: Käyttäjä näkee, mitkä julkaisut johtivat valvontatoimeen tai varoitukseen
send_email_notification: Käyttäjä saa selvityksen siitä, mitä hänen tililleen tapahtui
text_html: Valinnainen. Voit käyttää julkaisun syntaksia. Voit lisätä varoitusasetuksia säästääksesi aikaa
type_html: Valitse mitä teet käyttäjälle %{acct}
types:
disable: Estä käyttäjää käyttämästä tiliään, mutta älä poista tai piilota sen sisältöä.
none: Käytä tätä lähettääksesi varoituksen käyttäjälle käynnistämättä mitään muita toimintoja.
- sensitive: Pakota kaikki tämän käyttäjän mediatiedostot arkaluontoisiksi.
+ sensitive: Pakota kaikki tämän käyttäjän mediatiedostot arkaluonteisiksi.
silence: Estä käyttäjää lähettämästä viestejä julkisesti, piilota hänen viestinsä ja ilmoituksensa ihmisiltä, jotka eivät seuraa häntä. Sulkee kaikki tämän tilin raportit.
suspend: Estä kaikki vuorovaikutus tältä -tai tälle tilille ja poista sen kaikki sisältö. Päätös voidaan peruuttaa 30 päivän aikana. Sulkee kaikki raportit tätä tiliä vasten.
warning_preset_id: Valinnainen. Voit silti lisätä mukautetun tekstin esiasetuksen loppuun
announcement:
all_day: Kun valittu, vain valittu aikaväli näytetään
- ends_at: Valinnainen. Ilmoitus tullaan poistamaan automaattisesti tällä hetkellä
- scheduled_at: Jätä tyhjäksi julkaistaksesi ilmoituksen välittömästi
- starts_at: Valinnainen. Jos ilmoituksesi on sidottu tiettyyn aikaväliin
- text: Voit käyttää julkaisun syntaksia. Muista, kuinka paljon tilaa ilmoitus vie käyttäjän näytöltä
+ ends_at: Valinnainen. Tiedote poistetaan automaattisesti tällä hetkellä
+ scheduled_at: Jätä tyhjäksi julkaistaksesi tiedotteen heti
+ starts_at: Valinnainen. Jos tiedotteesi on sidottu tiettyyn aikaväliin
+ text: Voit käyttää julkaisun syntaksia. Ota huomioon, kuinka paljon tilaa tiedote vie käyttäjän näytöltä
appeal:
text: Voit valittaa varoituksesta vain kerran
defaults:
autofollow: Henkilöt, jotka rekisteröityvät kutsun kautta, seuraavat sinua automaattisesti
avatar: PNG, GIF tai JPG. Enintään %{size}. Skaalataan kokoon %{dimensions} px
bot: Tämä tili suorittaa enimmäkseen automaattisia toimintoja eikä sitä ehkä valvota
- context: Yksi tai useampi asiayhteys, jossa suodattimen pitäisi olla käytössä
+ context: Ainakin yksi konteksti, jossa suodattimen pitäisi olla voimassa
current_password: Turvallisuussyistä kirjoita nykyisen tilin salasana
- current_username: Vahvista kirjoittamalla nykyisen tilin käyttäjätunnus
+ current_username: Vahvista kirjoittamalla nykyisen tilin käyttäjänimi
digest: Lähetetään vain pitkän poissaolon jälkeen ja vain, jos olet saanut suoria viestejä poissaolosi aikana
email: Sinulle lähetetään vahvistussähköposti
header: PNG, GIF tai JPG. Enintään %{size}. Skaalataan kokoon %{dimensions} px
inbox_url: Kopioi URL-osoite haluamasi välittäjän etusivulta
irreversible: Suodatetut julkaisut katoavat lopullisesti, vaikka suodatin poistettaisiin myöhemmin
- locale: Käyttöliittymän, sähköpostien ja ilmoitusten kieli
+ locale: Käyttöliittymän, sähköpostien ja puskuilmoitusten kieli
password: Käytä vähintään 8 merkkiä
- phrase: Täytetään riippumatta julkaisun kirjainkoon tai sisällön varoituksesta
+ phrase: Täsmää riippumatta tekstin aakkoslajista tai julkaisun sisältövaroituksesta
scopes: Mihin sovellusliittymiin sovellus pääsee käsiksi. Jos valitset ylätason laajuuden, sinun ei tarvitse valita yksittäisiä.
- setting_aggregate_reblogs: Älä näytä uusia tehosteita viesteille, joita on äskettäin tehostettu (koskee vain äskettäin saatuja tehosteita)
- setting_always_send_emails: Yleensä sähköposti-ilmoituksia ei lähetetä, kun käytät aktiivisesti Mastodonia
- setting_default_sensitive: Arkaluontoinen media on oletuksena piilotettu ja se voidaan näyttää yhdellä napsautuksella
+ setting_aggregate_reblogs: Älä näytä uusia tehostuksia julkaisuille, joita on äskettäin tehostettu (koskee vain juuri vastaanotettuja tehostuksia)
+ setting_always_send_emails: Yleensä sähköposti-ilmoituksia ei lähetetä, kun käytät Mastodonia aktiivisesti
+ setting_default_sensitive: Arkaluonteinen media on oletuksena piilotettu, ja se voidaan näyttää yhdellä napsautuksella
setting_display_media_default: Piilota arkaluonteiseksi merkitty media
- setting_display_media_hide_all: Piilota aina kaikki media
- setting_display_media_show_all: Näytä aina arkaluonteiseksi merkitty media
- setting_use_blurhash: Liukuvärit perustuvat piilotettujen kuvien väreihin, mutta sumentavat yksityiskohdat
+ setting_display_media_hide_all: Piilota media aina
+ setting_display_media_show_all: Näytä media aina
+ setting_use_blurhash: Liukuvärit perustuvat piilotettujen kuvien väreihin mutta sumentavat yksityiskohdat
setting_use_pending_items: Piilota aikajanan päivitykset napsautuksen taakse syötteen automaattisen vierityksen sijaan
username: Voit käyttää kirjaimia, numeroita ja alaviivoja
- whole_word: Kun avainsana tai lause on vain aakkosnumeerinen, se otetaan käyttöön, jos se vastaa koko sanaa
+ whole_word: Kun avainsana tai -fraasi on kokonaan aakkosnumeerinen, se on voimassa vain, jos se vastaa koko sanaa
domain_allow:
domain: Tämä verkkotunnus voi noutaa tietoja tältä palvelimelta ja sieltä saapuvat tiedot käsitellään ja tallennetaan
email_domain_block:
- domain: Tämä voi olla se verkkotunnus, joka näkyy sähköpostiosoitteessa tai MX tietueessa jota se käyttää. Ne tarkistetaan rekisteröitymisen yhteydessä.
+ domain: Tämä voi olla verkkotunnus, joka näkyy sähköpostiosoitteessa tai sen käyttämässä MX-tietueessa. Ne tarkistetaan rekisteröitymisen yhteydessä.
with_dns_records: Annetun verkkotunnuksen DNS-tietueet yritetään ratkaista ja tulokset myös estetään
featured_tag:
name: 'Tässä muutamia hiljattain käyttämiäsi aihetunnisteita:'
filters:
- action: Valitse, mikä toiminto suoritetaan, kun viesti vastaa suodatinta
+ action: Valitse, mikä toiminto suoritetaan, kun julkaisu vastaa suodatinta
actions:
hide: Piilota suodatettu sisältö kokonaan ja käyttäydy ikään kuin sitä ei olisi olemassa
- warn: Piilota suodatettu sisältö varoituksen taakse, jossa mainitaan suodattimen otsikko
+ warn: Piilota suodatettu sisältö varoituksen taakse, jossa mainitaan suodattimen nimi
form_admin_settings:
activity_api_enabled: Paikallisesti julkaistujen julkaisujen, aktiivisten käyttäjien ja rekisteröitymisten viikoittainen määrä
backups_retention_period: Säilytä luodut arkistot määritetyn määrän päiviä.
- bootstrap_timeline_accounts: Nämä tilit kiinnitetään uusien käyttäjien suositusten yläpuolelle.
- closed_registrations_message: Näkyy, kun ilmoittautuminen on suljettu
- content_cache_retention_period: Viestit muilta palvelimilta poistetaan määritetyn määrän päiviä jälkeen, kun arvo on asetettu positiiviseksi. Tämä voi olla peruuttamatonta.
+ bootstrap_timeline_accounts: Nämä tilit kiinnitetään uusien käyttäjien seuraamissuositusten yläpuolelle.
+ closed_registrations_message: Näkyy, kun rekisteröityminen on suljettu
+ content_cache_retention_period: Kaikki julkaisut ja tehostukset muilta palvelimilta poistetaan, kun määritelty määrä päiviä on kulunut. Osaa julkaisuista voi olla mahdoton palauttaa. Kaikki julkaisuihin liittyvät kirjanmerkit, suosikit ja tehostukset menetetään, eikä niitä voi palauttaa.
custom_css: Voit käyttää mukautettuja tyylejä Mastodonin verkkoversiossa.
- mascot: Ohittaa kuvituksen edistyneessä käyttöliittymässä.
+ mascot: Ohittaa kuvituksen edistyneessä selainkäyttöliittymässä.
media_cache_retention_period: Ladatut mediatiedostot poistetaan määritetyn määrän päiviä jälkeen, kun arvo on positiivinen ja ladataan uudelleen pyynnöstä.
- peers_api_enabled: Lista verkkotunnuksista, joita tämä palvelin on kohdannut fediversessä. Täällä ei ole tietoja siitä, oletko liitossa tiettyjen palvelinten kanssa, vaan ainoastaan luettelo niistä verkkotunnuksista, joista palvelimesi on ylipäätään tietoinen. Tätä tietoa käytetään palveluissa, jotka keräävät liittotilastoja laajassa merkityksessä.
+ peers_api_enabled: Luettelo verkkotunnuksista, jotka tämä palvelin on kohdannut fediversumissa. Se ei kerro, oletko liitossa tietyn palvelimen kanssa, vaan että palvelimesi on ylipäätään tietoinen siitä. Tätä tietoa käytetään palveluissa, jotka keräävät tilastoja federoinnista yleisellä tasolla.
profile_directory: Profiilihakemisto lueteloi kaikki käyttäjät, jotka ovat ilmoittaneet olevansa löydettävissä.
- require_invite_text: Kun kirjautuminen vaatii manuaalisen hyväksynnän, tee ”Miksi haluat liittyä?” teksti syötetään pakolliseksi eikä vapaaehtoiseksi
+ require_invite_text: Kun rekisteröityminen vaatii manuaalisen hyväksynnän, tee ”Miksi haluat liittyä?” -tekstikentästä pakollinen vapaaehtoisen sijaan
site_contact_email: Kuinka ihmiset voivat tavoittaa sinut oikeudellisissa tai tukikysymyksissä.
site_contact_username: Miten ihmiset voivat tavoittaa sinut Mastodonissa.
site_extended_description: Kaikki lisätiedot, jotka voivat olla hyödyllisiä kävijöille ja käyttäjille. Voidaan jäsentää Markdown-syntaksilla.
@@ -96,23 +96,23 @@ fi:
status_page_url: URL-osoite sivulle, jonka kautta tämän palvelimen tila voidaan ongelmatilanteissa tarkastaa
theme: Teema, jonka uloskirjautuneet vierailijat ja uudet käyttäjät näkevät.
thumbnail: Noin 2:1 kuva näytetään palvelimen tietojen rinnalla.
- timeline_preview: Uloskirjautuneet vierailijat voivat selata uusimpia julkisia viestejä, jotka ovat saatavilla palvelimella.
+ timeline_preview: Uloskirjautuneet vierailijat voivat selata uusimpia julkisia julkaisuja, jotka ovat saatavilla palvelimella.
trendable_by_default: Ohita suositun sisällön manuaalinen tarkistus. Yksittäisiä kohteita voidaan edelleen poistaa jälkikäteen.
trends: Trendit osoittavat, mitkä julkaisut, aihetunnisteet ja uutiset ovat saamassa vetoa palvelimellasi.
- trends_as_landing_page: Näytä vierailijoille ja uloskirjautuneille käyttäjille suosittu sisältö palvelininstanssin kuvaustekstin sijaan. Edellytyksenä on, että suosittu sisältö -ominaisuus on käytössä.
+ trends_as_landing_page: Näytä vierailijoille ja uloskirjautuneille käyttäjille suosittua sisältöä palvelimen kuvauksen sijaan. Edellyttää, että trendit on otettu käyttöön.
form_challenge:
current_password: Olet menossa suojatulle alueelle
imports:
- data: Toisesta Mastodon-instanssista tuotu CSV-tiedosto
+ data: Toiselta Mastodon-palvelimelta tuotu CSV-tiedosto
invite_request:
text: Tämä auttaa meitä arvioimaan hakemustasi
ip_block:
comment: Valinnainen. Muista miksi lisäsit tämän säännön.
expires_in: IP-osoitteet ovat rajallinen resurssi, joskus niitä jaetaan ja vaihtavat usein omistajaa. Tästä syystä epämääräisiä IP-lohkoja ei suositella.
- ip: Kirjoita IPv4- tai IPv6-osoite. Voit estää kokonaisia alueita käyttämällä CIDR-syntaksia. Varo, että et lukitse itseäsi!
+ ip: Kirjoita IPv4- tai IPv6-osoite. Voit estää kokonaisia alueita käyttämällä CIDR-syntaksia. Varo, että et lukitse itseäsi ulos!
severities:
no_access: Estä pääsy kaikkiin resursseihin
- sign_up_block: Uudet kirjautumiset eivät ole mahdollisia
+ sign_up_block: Uudet rekisteröitymiset eivät ole mahdollisia
sign_up_requires_approval: Uudet rekisteröitymiset edellyttävät hyväksyntääsi
severity: Valitse, mitä tapahtuu tämän IP-osoitteen pyynnöille
rule:
@@ -122,56 +122,56 @@ fi:
webauthn: Jos kyseessä on USB-avain, muista laittaa se paikalleen ja tarvittaessa napauttaa sitä.
settings:
indexable: Profiilisi voi näkyä Googlen, Bingin ja muiden hakukoneiden hakutuloksissa.
- show_application: Voit siitä huolimatta aina nähdä, millä sovelluksella julkaisusi laadittiin.
+ show_application: Voit silti aina nähdä, mistä sovelluksesta julkaisusi lähetettiin.
tag:
name: Voit muuttaa esimerkiksi kirjaimia paremmin luettavaksi
user:
- chosen_languages: Kun valittu, vain valituilla kielillä julkaistut viestit näkyvät julkisilla aikajanoilla
+ chosen_languages: Kun valittu, vain valituilla kielillä kirjoitetut julkaisut näkyvät julkisilla aikajanoilla
role: Rooli määrää, mitkä käyttöoikeudet käyttäjällä on
user_role:
- color: Väri, jota käytetään roolin koko käyttöliittymässä, RGB heksamuodossa
+ color: Väri, jota käytetään roolille kaikkialla käyttöliittymässä, RGB-heksadesimaalimuodossa
highlighted: Tämä tekee roolista julkisesti näkyvän
- name: Roolin julkinen nimi, jos rooli on asetettu näytettäväksi mekkinä
+ name: Roolin julkinen nimi, jos rooli on asetettu näytettäväksi merkkinä
permissions_as_keys: Käyttäjillä, joilla on tämä rooli, on käyttöoikeus...
position: Korkeampi rooli ratkaisee konfliktit tietyissä tilanteissa. Tiettyjä toimintoja voidaan suorittaa vain rooleille, joiden prioriteetti on pienempi
webhook:
events: Valitse lähetettävät tapahtumat
- template: Luo oma JSON-hyötykuorma käyttäen muuttujainterpolointia. Jättäessäsi kentän tyhjäksi, käytetään vakio-JSON-kuormaa.
+ template: Luo oma JSON-hyötykuorma käyttäen muuttujien interpolointia. Jätä kenttä tyhjäksi käyttääksesi vakio-JSON-kuormaa.
url: Mihin tapahtumat lähetetään
labels:
account:
- discoverable: Sisällytä profiili ja julkaisut etsintäalgoritmeihin
+ discoverable: Pidä profiiliasi ja julkaisujasi esillä löytämisalgoritmeissa
fields:
name: Nimike
value: Sisältö
- indexable: Sisällytä julkiset viestit hakutuloksiin
+ indexable: Sisällytä julkiset julkaisut hakutuloksiin
show_collections: Näytä seuratut ja seuraajat profiilissa
unlocked: Hyväksy uudet seuraajat automaattisesti
account_alias:
- acct: Vanhan tilin käsittely
+ acct: Vanhan tilin käyttäjänimi
account_migration:
- acct: Uuden tilin käsittely
+ acct: Uuden tilin käyttäjänimi
account_warning_preset:
text: Esiasetettu teksti
- title: Otsikko
+ title: Nimi
admin_account_action:
include_statuses: Sisällytä raportoidut viestit sähköpostiin
send_email_notification: Ilmoita käyttäjälle sähköpostitse
text: Mukautettu varoitus
- type: Toimenpide
+ type: Toimi
types:
disable: Poista kirjautuminen käytöstä
none: Älä tee mitään
- sensitive: Arkaluontoinen
- silence: Hiljennä
- suspend: Poista käytöstä ja tuhoa käyttäjätunnuksen tiedot peruuttamattomasti
+ sensitive: Arkaluonteinen
+ silence: Rajoita
+ suspend: Jäädytä
warning_preset_id: Käytä varoitusmallia
announcement:
all_day: Koko päivän kestävä tapahtuma
ends_at: Tapahtuman loppu
- scheduled_at: Ajasta julkaisu
+ scheduled_at: Ajoita julkaisu
starts_at: Tapahtuman alku
- text: Ilmoitus
+ text: Tiedote
appeal:
text: Perustele, miksi tämä päätös olisi kumottava
defaults:
@@ -181,53 +181,53 @@ fi:
chosen_languages: Suodata kieliä
confirm_new_password: Vahvista uusi salasana
confirm_password: Vahvista salasana
- context: Suodata konteksteista
+ context: Suodattimen kontekstit
current_password: Nykyinen salasana
data: Tiedot
- display_name: Nimimerkki
+ display_name: Näyttönimi
email: Sähköpostiosoite
expires_in: Vanhenee
- fields: Profiilin metadata
- header: Otsakekuva
+ fields: Lisäkentät
+ header: Otsikkokuva
honeypot: "%{label} (älä täytä)"
inbox_url: Välittäjän postilaatikon URL-osoite
irreversible: Pudota piilottamisen sijaan
locale: Kieli
max_uses: Käyttökertoja enintään
new_password: Uusi salasana
- note: Kuvaus
+ note: Elämäkerta
otp_attempt: Kaksivaiheisen tunnistuksen koodi
password: Salasana
- phrase: Avainsana tai lause
- setting_advanced_layout: Ota käyttöön edistynyt selainkäyttöliittymä
- setting_aggregate_reblogs: Ryhmitä tehostukset aikajanalla
- setting_always_send_emails: Lähetä aina sähköposti-ilmoituksia
+ phrase: Avainsana tai -fraasi
+ setting_advanced_layout: Ota edistynyt selainkäyttöliittymä käyttöön
+ setting_aggregate_reblogs: Ryhmitä tehostukset aikajanoilla
+ setting_always_send_emails: Lähetä sähköposti-ilmoitukset aina
setting_auto_play_gif: Toista GIF-animaatiot automaattisesti
- setting_boost_modal: Kysy vahvistus ennen tehostusta
- setting_default_language: Viestien kieli
- setting_default_privacy: Viestin näkyvyys
- setting_default_sensitive: Merkitse media aina arkaluontoiseksi
- setting_delete_modal: Kysy vahvistusta ennen viestin poistamista
+ setting_boost_modal: Kysy vahvistusta ennen tehostusta
+ setting_default_language: Julkaisun kieli
+ setting_default_privacy: Julkaisun näkyvyys
+ setting_default_sensitive: Merkitse media aina arkaluonteiseksi
+ setting_delete_modal: Kysy vahvistusta ennen julkaisun poistamista
setting_disable_swiping: Poista pyyhkäisyt käytöstä
setting_display_media: Median näyttäminen
setting_display_media_default: Oletus
setting_display_media_hide_all: Piilota kaikki
setting_display_media_show_all: Näytä kaikki
- setting_expand_spoilers: Laajenna aina sisältövaroituksilla merkityt viestit
+ setting_expand_spoilers: Laajenna aina sisältövaroituksilla merkityt julkaisut
setting_hide_network: Piilota verkkosi
setting_reduce_motion: Vähennä animaatioiden liikettä
setting_system_font_ui: Käytä järjestelmän oletusfonttia
setting_theme: Sivuston teema
setting_trends: Näytä päivän trendit
- setting_unfollow_modal: Kysy vahvistusta, ennen kuin lopetat seuraamisen
+ setting_unfollow_modal: Kysy vahvistusta ennen seuraamisen lopettamista
setting_use_blurhash: Näytä värikkäät liukuvärit piilotetulle medialle
- setting_use_pending_items: Hidastila
+ setting_use_pending_items: Hidas tila
severity: Vakavuus
sign_in_token_attempt: Turvakoodi
- title: Otsikko
- type: Tietojen laji
+ title: Nimi
+ type: Tuontityyppi
username: Käyttäjänimi
- username_or_email: Käyttäjänimi tai sähköposti
+ username_or_email: Käyttäjänimi tai sähköpostiosoite
whole_word: Koko sana
email_domain_block:
with_dns_records: Sisällytä toimialueen MX tietueet ja IP-osoite
@@ -236,12 +236,12 @@ fi:
filters:
actions:
hide: Piilota kokonaan
- warn: Piilota varoituksella
+ warn: Piilota ja näytä varoitus
form_admin_settings:
- activity_api_enabled: Julkaise yhteenlasketut tilastot käyttäjätoiminnasta rajapinnassa
+ activity_api_enabled: Julkaise yhteenlasketut tilastot käyttäjätoiminnasta ohjelmointirajapinnassa
backups_retention_period: Käyttäjän arkiston säilytysaika
bootstrap_timeline_accounts: Suosittele aina näitä tilejä uusille käyttäjille
- closed_registrations_message: Mukautettu viesti, kun kirjautumisia ei ole saatavilla
+ closed_registrations_message: Mukautettu viesti, kun rekisteröityminen ei ole saatavilla
content_cache_retention_period: Sisällön välimuistin säilytysaika
custom_css: Mukautettu CSS
mascot: Mukautettu maskotti (legacy)
@@ -250,10 +250,10 @@ fi:
profile_directory: Ota profiilihakemisto käyttöön
registrations_mode: Kuka voi rekisteröityä
require_invite_text: Vaadi syy liittyä
- show_domain_blocks: Näytä domainestot
- show_domain_blocks_rationale: Näytä miksi verkkotunnukset on estetty
+ show_domain_blocks: Näytä verkkotunnusten estot
+ show_domain_blocks_rationale: Näytä, miksi verkkotunnukset on estetty
site_contact_email: Ota yhteyttä sähköpostilla
- site_contact_username: Kontaktin käyttäjänimi
+ site_contact_username: Yhteyshenkilön käyttäjänimi
site_extended_description: Laajennettu kuvaus
site_short_description: Palvelimen kuvaus
site_terms: Tietosuojakäytäntö
@@ -261,35 +261,35 @@ fi:
status_page_url: Tilasivun URL-osoite
theme: Oletusteema
thumbnail: Palvelimen pikkukuva
- timeline_preview: Salli todentamaton pääsy julkiselle aikajanalle
+ timeline_preview: Salli todentamaton pääsy julkisille aikajanoille
trendable_by_default: Salli trendit ilman ennakkotarkastusta
- trends: Trendit käyttöön
- trends_as_landing_page: Käytä suosittua sisältöä aloitussivuna
+ trends: Ota trendit käyttöön
+ trends_as_landing_page: Käytä trendejä aloitussivuna
interactions:
must_be_follower: Estä ilmoitukset käyttäjiltä, jotka eivät seuraa sinua
must_be_following: Estä ilmoitukset käyttäjiltä, joita et seuraa
- must_be_following_dm: Estä suorat viestit käyttäjiltä, joita et seuraa
+ must_be_following_dm: Estä yksityisviestit käyttäjiltä, joita et seuraa
invite:
comment: Kommentoi
invite_request:
text: Miksi haluat liittyä?
ip_block:
comment: Kommentti
- ip: IP
+ ip: IP-osoite
severities:
no_access: Estä pääsy
- sign_up_block: Estä kirjautumiset
+ sign_up_block: Estä rekisteröitymiset
sign_up_requires_approval: Rajoita rekisteröitymisiä
severity: Sääntö
notification_emails:
appeal: Joku valittaa valvojan päätöksestä
digest: Lähetä koosteviestejä sähköpostitse
- favourite: Lähetä sähköposti, kun joku tykkää tilastasi
- follow: Lähetä sähköposti, kun joku seuraa sinua
- follow_request: Lähetä sähköposti, kun joku pyytää seurata sinua
- mention: Lähetä sähköposti, kun sinut mainitaan
- pending_account: Uusi tili tarvitsee tarkastusta
- reblog: Lähetä sähköposti, kun joku tehosti viestiäsi
+ favourite: Joku lisäsi julkaisusi suosikkeihinsa
+ follow: Joku seurasi sinua
+ follow_request: Joku pyysi saada seurata sinua
+ mention: Joku mainitsi sinut
+ pending_account: Uusi tili tarvitsee tarkistusta
+ reblog: Joku tehosti julkaisuasi
report: Uusi raportti on lähetetty
software_updates:
all: Ilmoita kaikista päivityksistä
@@ -297,12 +297,12 @@ fi:
label: Uusi Mastodon-versio on saatavilla
none: Älä koskaan ilmoita päivityksistä (ei suositeltu)
patch: Ilmoita virhekorjauspäivityksistä
- trending_tag: Uusi trendi vaatii tarkastelua
+ trending_tag: Uusi trendi vaatii tarkistusta
rule:
text: Sääntö
settings:
indexable: Sisällytä profiilisivu hakukoneisiin
- show_application: Näytä, mistä sovelluksesta lähetit viestin
+ show_application: Näytä, mistä sovelluksesta lähetit julkaisun
tag:
listable: Salli tämän aihetunnisteen näkyä hauissa ja ehdotuksissa
name: Aihetunniste
@@ -313,7 +313,7 @@ fi:
time_zone: Aikavyöhyke
user_role:
color: Merkin väri
- highlighted: Näyttä rooli merkkinä käyttäjäprofiileissa
+ highlighted: Näytä rooli merkkinä käyttäjäprofiileissa
name: Nimi
permissions_as_keys: Oikeudet
position: Prioriteetti
diff --git a/config/locales/simple_form.fy.yml b/config/locales/simple_form.fy.yml
index 474d858382a468..f506b792522054 100644
--- a/config/locales/simple_form.fy.yml
+++ b/config/locales/simple_form.fy.yml
@@ -86,7 +86,7 @@ fy:
media_cache_retention_period: Mediabestannen dy’t fan oare servers download binne wurde nei it opjûne oantal dagen fuortsmiten en wurde op fersyk opnij download.
peers_api_enabled: In list mei domeinnammen, dêr’t dizze server yn fediverse kontakt hân mei hat. Hjir wurdt gjin data dield, oft jo mei in bepaalde server federearrest, mar alinnich, dat jo server dat wit. Dit wurdt foar tsjinsten brûkt, dy’t statistiken oer federaasje yn algemiene sin sammelet.
profile_directory: De brûkersgids befettet in list fan alle brûkers dy¥t derfoar keazen hawwe om ûntdekt wurde te kinnen.
- require_invite_text: Meitsje it ynfoljen fan "Wêrom wolle jo jo hjir registrearje?" ferplicht yn stee fan opsjoneel, wannear’t registraasjes hânmjittich goedkard wurde moatte
+ require_invite_text: Meitsje it ynfoljen fan ‘Wêrom wolle jo jo hjir registrearje?’ ferplicht yn stee fan opsjoneel, wannear’t registraasjes hânmjittich goedkard wurde moatte
site_contact_email: Hoe minsken jo berikke kinne foar juridyske fragen of stipe.
site_contact_username: Hoe minsken jo op Mastodon berikke kinne.
site_extended_description: Alle oanfoljende ynformaasje dy’t nuttich wêze kin foar besikers en jo brûkers. Kin opmakke wurde mei Markdown.
diff --git a/config/locales/simple_form.hy.yml b/config/locales/simple_form.hy.yml
index d2fab9e048305a..56aa1d66b1ce6a 100644
--- a/config/locales/simple_form.hy.yml
+++ b/config/locales/simple_form.hy.yml
@@ -44,6 +44,7 @@ hy:
setting_display_media_show_all: Մեդիա միշտ ցոյց տալ
setting_use_blurhash: Կտորները հիմնուում են թաքցուած վիզուալի վրայ՝ խամրեցնելով դետալները
setting_use_pending_items: Թաքցնել հոսքի թարմացումները կտտոի ետեւում՝ աւտօմատ թարմացուող հոսքի փոխարէն
+ username: Միայն լատինատառեր, թուեր եւ տակի գծիկ
whole_word: Եթէ բանալի բառը կամ արտայայտութիւնը պարունակում է միայն այբբենական նիշեր եւ թուեր, ապա այն կիրառուելու է ամբողջ բառի հետ համընկնելու դէպքում միայն
domain_allow:
domain: Այս տիրոյթը կարող է ստանալ տուեալներ այս սպասարկչից եւ ստացուող տուեալները կարող են օգտագործուել եւ պահուել
diff --git a/config/locales/simple_form.my.yml b/config/locales/simple_form.my.yml
index cf15616d244655..80b234c17c9e85 100644
--- a/config/locales/simple_form.my.yml
+++ b/config/locales/simple_form.my.yml
@@ -323,6 +323,7 @@ my:
url: URL ဆုံးမှတ်
'no': မလုပ်ပါ
not_recommended: ထောက်ခံထားမှုမရှိ
+ overridden: ပယ်ဖျက်
recommended: ထောက်ခံထားပြီး
required:
mark: "*"
diff --git a/config/locales/simple_form.si.yml b/config/locales/simple_form.si.yml
index 23e63ef42c059e..ededa85bcce76f 100644
--- a/config/locales/simple_form.si.yml
+++ b/config/locales/simple_form.si.yml
@@ -7,12 +7,10 @@ si:
account_migration:
acct: ඔබට යාමට අවශ්ය ගිණුමේ username@domain සඳහන් කරන්න
account_warning_preset:
- text: ඔබට URL, හෑෂ් ටැග් සහ සඳහන් කිරීම් වැනි පෝස්ට් සින්ටැක්ස් භාවිතා කළ හැක
+ text: ඔබට ඒ.ස.නි., පූරක අනන්යන සහ සැඳහුම් වැනි ලිපි පද ගැළපුම් භාවිතා කිරීමට හැකිය
title: විකල්ප. ලබන්නාට නොපෙනේ
admin_account_action:
- include_statuses: මධ්යස්ථ ක්රියාව හෝ අනතුරු ඇඟවීමට හේතු වී ඇත්තේ කුමන පළ කිරීම්දැයි පරිශීලකයා දකිනු ඇත
send_email_notification: පරිශීලකයාට ඔවුන්ගේ ගිණුම සමඟ සිදු වූ දේ පිළිබඳ පැහැදිලි කිරීමක් ලැබෙනු ඇත
- text_html: විකල්ප. ඔබට post syntax භාවිතා කළ හැක. කාලය ඉතිරි කර ගැනීම සඳහා ඔබට අනතුරු ඇඟවීමේ කළ හැක
type_html: "%{acct}සමඟ කළ යුතු දේ තෝරන්න"
types:
disable: පරිශීලකයාගේ ගිණුම භාවිතා කිරීමෙන් වළක්වන්න, නමුත් ඔවුන්ගේ අන්තර්ගතය මකා දැමීම හෝ සඟවන්න එපා.
@@ -24,7 +22,7 @@ si:
ends_at: විකල්ප. මෙම අවස්ථාවේදී නිවේදනය ස්වයංක්රීයව ප්රකාශනය කිරීමෙන් ඉවත් වනු ඇත
scheduled_at: නිවේදනය වහාම ප්රකාශයට පත් කිරීමට හිස්ව තබන්න
starts_at: විකල්ප. ඔබගේ නිවේදනය නිශ්චිත කාල පරාසයකට බැඳී ඇත්නම්
- text: ඔබට post syntax භාවිතා කළ හැක. කරුණාකර පරිශීලකයාගේ තිරය මත නිවේදනය ලබා ගන්නා ඉඩ ගැන සැලකිලිමත් වන්න
+ text: ඔබට ලිපි පද ගැළපුම් භාවිතා කිරීමට හැකිය. කරුණාකර නිවේදනයෙන් පරිශ්රීලකයින්ගේ තිරයේ ඉඩ කෙතරම් ඇහිරෙනවා ද පිළිබඳව සැලකිලිමත් වන්න
appeal:
text: ඔබට වර්ජනයකට අභියාචනා කළ හැක්කේ එක් වරක් පමණි
defaults:
@@ -38,17 +36,16 @@ si:
email: ඔබට තහවුරු කිරීමේ විද්යුත් තැපෑලක් එවනු ලැබේ
header: PNG, GIF හෝ JPG. වැඩිම %{size}. %{dimensions}px දක්වා අඩු කරනු ඇත
inbox_url: ඔබට භාවිතා කිරීමට අවශ්ය රිලේ හි මුල් පිටුවෙන් URL එක පිටපත් කරන්න
- irreversible: පෙරහන පසුව ඉවත් කළද, පෙරූ පළ කිරීම් ආපසු හැරවිය නොහැකි ලෙස අතුරුදහන් වනු ඇත
- locale: පරිශීලක අතුරුමුහුණතේ භාෂාව, ඊමේල් සහ තල්ලු දැනුම්දීම්
+ irreversible: පෙරහන පසුව ඉවත් කළ ද, පෙරූ ලිපි අප්රතිවර්ත්යව අතුරුදහන් වනු ඇත
+ locale: වි-තැපැල්, තල්ලු දැනුම්දීම් සහ පරිශ්රීලක අතුරුමුහුණතේ භාෂාව
password: අවම වශයෙන් අක්ෂර 8 ක් භාවිතා කරන්න
- phrase: පළ කිරීමක පෙළ හෝ අන්තර්ගත අනතුරු ඇඟවීම නොසලකා ගැලපේ
+ phrase: ලිපිවල පෙළ හෝ අන්තර්ගත අවවාද නොසලකා ගැළපෙනු ඇත
scopes: යෙදුමට ප්රවේශ වීමට ඉඩ දෙන්නේ කුමන API වලටද. ඔබ ඉහළ මට්ටමේ විෂය පථයක් තෝරා ගන්නේ නම්, ඔබට තනි ඒවා තෝරා ගැනීමට අවශ්ය නොවේ.
- setting_aggregate_reblogs: මෑතකදී බූස්ට් කරන ලද පළ කිරීම් සඳහා නව බූස්ට් පෙන්වන්න එපා (අලුතින් ලැබුණු බූස්ට් වලට පමණක් බලපායි)
- setting_always_send_emails: සාමාන්යයෙන් ඔබ Mastodon සක්රියව භාවිතා කරන විට විද්යුත් තැපැල් දැනුම්දීම් නොයවනු ඇත
+ setting_always_send_emails: ඔබ නිතර මාස්ටඩන් භාවිතා කරන විට වි-තැපැල් දැනුම්දීම් නොලැබෙයි
setting_default_sensitive: සංවේදී මාධ්ය පෙරනිමියෙන් සඟවා ඇති අතර ක්ලික් කිරීමකින් හෙළිදරව් කළ හැක
- setting_display_media_default: සංවේදී ලෙස සලකුණු කළ මාධ්ය සඟවන්න
- setting_display_media_hide_all: සෑම විටම මාධ්ය සඟවන්න
- setting_display_media_show_all: සෑම විටම මාධ්ය පෙන්වන්න
+ setting_display_media_default: සංවේදී බව සලකුණු කළ මාධ්ය සඟවන්න
+ setting_display_media_hide_all: සැමවිට මාධ්ය සඟවන්න
+ setting_display_media_show_all: සැමවිට මාධ්ය පෙන්වන්න
setting_use_blurhash: අනුක්රමණ සැඟවුණු දෘශ්යවල වර්ණ මත පදනම් වන නමුත් ඕනෑම විස්තරයක් අපැහැදිලි කරයි
setting_use_pending_items: සංග්රහය ස්වයංක්රීයව අනුචලනය කරනවා වෙනුවට ක්ලික් කිරීමක් පිටුපස කාලරේඛා යාවත්කාලීන සඟවන්න
whole_word: මූල පදය හෝ වාක්ය ඛණ්ඩය අක්ෂරාංක පමණක් වන විට, එය යෙදෙන්නේ එය සම්පූර්ණ වචනයට ගැලපේ නම් පමණි
@@ -58,14 +55,14 @@ si:
domain: මෙය විද්යුත් තැපැල් ලිපිනයේ හෝ එය භාවිතා කරන MX වාර්තාවේ පෙන්වන ඩොමේන් නාමය විය හැක. ලියාපදිංචි වූ පසු ඒවා පරීක්ෂා කරනු ලැබේ.
with_dns_records: ලබා දී ඇති වසමේ DNS වාර්තා විසඳීමට උත්සාහ කරන අතර ප්රතිඵල ද අවහිර කරනු ලැබේ
filters:
- action: පළ කිරීමක් පෙරහනට ගැළපෙන විට සිදු කළ යුතු ක්රියාව තෝරන්න
+ action: ලිපියක් පෙරහනට ගැළපෙන විට ඉටු විය යුතු ක්රියාමාර්ගය තෝරන්න
actions:
hide: පෙරහන් කළ අන්තර්ගතය සම්පූර්ණයෙන්ම සඟවන්න, එය නොපවතින ලෙස හැසිරෙන්න
warn: පෙරහන මාතෘකාව සඳහන් කරන අනතුරු ඇඟවීමක් පිටුපස පෙරූ අන්තර්ගතය සඟවන්න
form_challenge:
current_password: ඔබ ආරක්ෂිත ප්රදේශයකට ඇතුල් වේ
imports:
- data: CSV ගොනුව වෙනත් Mastodon සේවාදායකයකින් අපනයනය කරන ලදී
+ data: CSV ගොනුව වෙනත් මාස්ටඩන් සේවාදායකයකින් නිර්යාත කර ඇත
invite_request:
text: මෙය ඔබගේ අයදුම්පත සමාලෝචනය කිරීමට අපට උපකාරී වනු ඇත
ip_block:
@@ -84,7 +81,7 @@ si:
tag:
name: ඔබට අකුරු වල ආවරණය පමණක් වෙනස් කළ හැකිය, උදාහරණයක් ලෙස, එය වඩාත් කියවිය හැකි කිරීමට
user:
- chosen_languages: පරීක්ෂා කළ විට, තෝරාගත් භාෂාවලින් පළ කිරීම් පමණක් පොදු කාලරේඛා තුළ සංදර්ශන කෙරේ
+ chosen_languages: සබල නම්, තෝරාගත් භාෂාවල ලිපි පමණක් ප්රසිද්ධ කාල රේඛාවේ දිස්වේ
webhook:
events: යැවීමට සිදුවීම් තෝරන්න
url: සිදුවීම් යවනු ලබන ස්ථානය
@@ -93,22 +90,24 @@ si:
fields:
name: නම්පත
value: අන්තර්ගතය
+ show_collections: අනුගමන හා අනුගාමිකයින් පැතිකඩෙහි පෙන්වන්න
+ unlocked: නව අනුගාමිකයින් ස්වයංක්රීයව පිළිගන්න
account_alias:
acct: පැරණි ගිණුමේ හැසිරවීම
account_migration:
acct: නව ගිණුමේ හැසිරවීම
account_warning_preset:
text: පෙර සැකසූ පෙළ
- title: ශීර්ෂය
+ title: සිරැසිය
admin_account_action:
- include_statuses: විද්යුත් තැපෑලෙහි වාර්තා කරන ලද පළ කිරීම් ඇතුළත් කරන්න
+ include_statuses: වි-තැපෑලට වාර්තා කරන ලද ලිපි ද ඇතුළත් කරන්න
send_email_notification: විද්යුත් තැපෑලෙන් පරිශීලකයාට දැනුම් දෙන්න
text: අභිරුචි අනතුරු ඇඟවීම
type: ක්රියාමාර්ගය
types:
disable: කැටි කරන්න
none: අනතුරු ඇඟවීමක් යවන්න
- sensitive: පවතී
+ sensitive: සංවේදීතාව
silence: සීමාව
suspend: අත්හිටුවන්න
warning_preset_id: අනතුරු ඇඟවීමේ පෙරසිටුවක් භාවිතා කරන්න
@@ -121,14 +120,14 @@ si:
appeal:
text: මෙම තීරණය ආපසු හැරවිය යුත්තේ මන්දැයි පැහැදිලි කරන්න
defaults:
- autofollow: ඔබගේ ගිණුම අනුගමනය කිරීමට ආරාධනා කරන්න
- avatar: අවතාරය
- bot: මෙය ස්වයං ක්රමලේඛගත ගිණුමකි
- chosen_languages: භාෂා පෙරහන් කරන්න
- confirm_new_password: නව මුර පදය තහවුරු කරන්න
- confirm_password: මුරපදය තහවුරු කර ඇත
- context: සන්දර්භ පෙරහන් කරන්න
- current_password: වත්මන් මුර පදය
+ autofollow: ඔබගේ ගිණුම අනුගමනයයට ආරාධනා කරන්න
+ avatar: පැතිකඩ ඡායාරූපය
+ bot: මෙම ගිණුම ස්වයංක්රියයි
+ chosen_languages: භාෂා පෙරන්න
+ confirm_new_password: නව මුරපදය තහවුරු කරන්න
+ confirm_password: මුරපදය තහවුරු කරන්න
+ context: සන්දර්භ පෙරන්න
+ current_password: වත්මන් මුරපදය
data: දත්ත
display_name: ප්රදර්ශන නාමය
email: වි-තැපැල් ලිපිනය
@@ -138,39 +137,35 @@ si:
honeypot: "%{label} (පුරවන්න එපා)"
inbox_url: රිලේ එන ලිපි URL
irreversible: සැඟවීම වෙනුවට අතහරින්න
- locale: අතුරු මුහුණත භාෂාව
+ locale: අතුරු මුහුණතේ භාෂාව
max_uses: උපරිම භාවිත ගණන
new_password: නව මුරපදය
- note: ජෛව
otp_attempt: ද්වි සාධක කේතය
password: මුරපදය
phrase: මූල පදය හෝ වාක්ය ඛණ්ඩය
- setting_advanced_layout: උසස් වෙබ් අතුරු මුහුණත සබල කරන්න
- setting_aggregate_reblogs: කණ්ඩායම් කාලරේඛාව වැඩි කරයි
+ setting_advanced_layout: සංකීර්ණ අතුරු මුහුණත සබල කරන්න
setting_always_send_emails: සෑම විටම විද්යුත් තැපැල් දැනුම්දීම් යවන්න
setting_auto_play_gif: සජීවිකරණ GIF ස්වයංක්රීයව ධාවනය කරන්න
- setting_boost_modal: වැඩි කිරීමට පෙර තහවුරු කිරීමේ සංවාදය පෙන්වන්න
- setting_default_language: පළ කිරීමේ භාෂාව
- setting_default_privacy: පුද්ගලිකත්වය පළ කිරීම
- setting_default_sensitive: සෑම විටම මාධ්ය සංවේදී ලෙස සලකුණු කරන්න
- setting_delete_modal: පළ කිරීමක් මැකීමට පෙර තහවුරු කිරීමේ සංවාදය පෙන්වන්න
- setting_disable_swiping: ස්වයිප් චලන අක්රීය කරන්න
+ setting_default_language: ලිපිවල භාෂාව
+ setting_default_privacy: ලිපියේ රහස්යතාව
+ setting_default_sensitive: සෑමවිට මාධ්ය සංවේදී බව සලකුණු කරන්න
+ setting_delete_modal: ලිපියක් මැකීමට පෙර ඒ ගැන විමසන්න
setting_display_media: මාධ්ය සංදර්ශකය
- setting_display_media_default: පෙරනිමිය
+ setting_display_media_default: පෙරනිමි
setting_display_media_hide_all: සියල්ල සඟවන්න
setting_display_media_show_all: සියල්ල පෙන්වන්න
- setting_expand_spoilers: අන්තර්ගත අනතුරු ඇඟවීම් සමඟ සලකුණු කර ඇති පළ කිරීම් සැමවිටම පුළුල් කරන්න
+ setting_expand_spoilers: අන්තර්ගත අවවාද සහිත ලිපි සැමවිට දිගහරින්න
setting_hide_network: ඔබගේ ජාලය සඟවන්න
setting_reduce_motion: සජීවිකරණවල චලනය අඩු කරන්න
- setting_system_font_ui: පද්ධතියේ පෙරනිමි අකුරු භාවිතා කරන්න
+ setting_system_font_ui: පද්ධතියේ පෙරනිමි රුවකුරු භාවිතා කරන්න
setting_theme: අඩවියේ තේමාව
setting_trends: අද ප්රවණතා පෙන්වන්න
setting_unfollow_modal: යමෙකු අනුගමනය නොකිරීමට පෙර තහවුරු කිරීමේ සංවාදය පෙන්වන්න
setting_use_blurhash: සැඟවුණු මාධ්ය සඳහා වර්ණවත් අනුක්රමික පෙන්වන්න
- setting_use_pending_items: මන්දගාමී මාදිලිය
+ setting_use_pending_items: මන්දගාමී ප්රකාරය
severity: බරපතලකම
sign_in_token_attempt: ආරක්ෂණ කේතය
- title: ශීර්ෂය
+ title: සිරැසිය
type: ආයාත වර්ගය
username: පරිශීලක නාමය
username_or_email: පරි. නාමය හෝ වි-තැපෑල
@@ -181,12 +176,16 @@ si:
name: හෑෂ් ටැගය
filters:
actions:
- hide: සම්පූර්ණයෙන්ම සඟවන්න
- warn: අනතුරු ඇඟවීමක් සමඟ සඟවන්න
+ hide: මුළුමනින්ම සඟවන්න
+ warn: අවවාදයක් සහිතව සඟවන්න
+ form_admin_settings:
+ custom_css: අභිරුචි CSS
+ profile_directory: පැතිකඩ නාමාවලිය සබල කරන්න
+ site_terms: රහස්යතා ප්රතිපත්තිය
+ site_title: සේවාදායකයේ නම
+ theme: පෙරනිමි තේමාව
interactions:
- must_be_follower: අනුගාමිකයින් නොවන අයගේ දැනුම්දීම් අවහිර කරන්න
- must_be_following: ඔබ අනුගමනය නොකරන පුද්ගලයින්ගේ දැනුම්දීම් අවහිර කරන්න
- must_be_following_dm: ඔබ අනුගමනය නොකරන පුද්ගලයින්ගෙන් සෘජු පණිවිඩ අවහිර කරන්න
+ must_be_following_dm: ඔබ නොදන්නා අයගෙන් සෘජු පණිවිඩ ලැබීම අවහිර කරන්න
invite:
comment: අදහස
invite_request:
@@ -195,31 +194,34 @@ si:
comment: අදහස
ip: අ.ජා. කෙ. (IP)
severities:
- no_access: ප්රවේශය අවහිර කරන්න
+ no_access: ප්රවේශය අවහිර කරන්න
sign_up_requires_approval: ලියාපදිංචි වීම සීමා කරන්න
severity: නීතිය
notification_emails:
- appeal: යමෙක් උපපරිපාලක තීරණයකට අභියාචනා කරයි
digest: digest ඊමේල් යවන්න
- favourite: කවුරුහරි ඔබේ පළ කිරීම ප්රිය කළා
- follow: කවුරුහරි ඔබව අනුගමනය කළා
- follow_request: කවුරුහරි ඔබව අනුගමනය කරන ලෙස ඉල්ලා සිටියේය
- mention: කවුරුහරි ඔබව සඳහන් කළා
- pending_account: නව ගිණුම සමාලෝචනය අවශ්යයි
- reblog: කවුරුහරි ඔබේ පළ කිරීම වැඩි කළා
- report: නව වාර්තාවක් ඉදිරිපත් කෙරේ
- trending_tag: නව ප්රවණතාවයට සමාලෝචනයක් අවශ්ය වේ
+ favourite: යමෙක් ඔබගේ ලිපියට ප්රිය කළා
+ follow: යමෙක් ඔබව අනුගමනය කළා
+ mention: යමෙක් ඔබව සඳහන් කළා
+ report: නව වාර්තාවක් යොමු කර ඇත
rule:
text: නීතිය
tag:
listable: මෙම හැෂ් ටැගය සෙවීම් සහ යෝජනා වල දිස් වීමට ඉඩ දෙන්න
name: හෑෂ් ටැගය
trendable: මෙම හැෂ් ටැගය ප්රවණතා යටතේ දිස් වීමට ඉඩ දෙන්න
- usable: මෙම හැෂ් ටැගය භාවිතා කිරීමට පළ කිරීම් වලට ඉඩ දෙන්න
+ usable: ලිපි සඳහා මෙම පූරක අනන්යනය භාවිතයට ඉඩදෙන්න
+ user:
+ role: භූමිකාව
+ time_zone: වේලා කලාපය
+ user_role:
+ color: චිහ්නයේ පාට
+ name: නම
+ permissions_as_keys: අවසර
+ position: ප්රමුඛත්වය
webhook:
events: සබල කළ සිදුවීම්
url: අන්ත ලක්ෂ්ය URL
- 'no': නැත
+ 'no': නැහැ
recommended: නිර්දේශිත
required:
mark: "*"
diff --git a/config/locales/simple_form.zh-TW.yml b/config/locales/simple_form.zh-TW.yml
index 5108a974522bd3..be21f862f31352 100644
--- a/config/locales/simple_form.zh-TW.yml
+++ b/config/locales/simple_form.zh-TW.yml
@@ -5,7 +5,7 @@ zh-TW:
account:
discoverable: 公開嘟文及個人檔案可能於各 Mastodon 功能中被推薦,並且您的個人檔案可能被推薦至其他使用者。
display_name: 完整名稱或暱稱。
- fields: 烘培雞,自我認同代稱,年齡,及任何您想分享的。
+ fields: 烘培雞、自我認同代稱、年齡,及任何您想分享的。
indexable: 您的公開嘟文可能會顯示於 Mastodon 之搜尋結果中。曾與您嘟文互動過的人可能無論如何都能搜尋它們。
note: '您可以 @mention 其他人或者使用 #主題標籤。'
show_collections: 人們將能瀏覽您跟隨中及跟隨者帳號。您所跟隨之人能得知您正在跟隨其帳號。
@@ -30,8 +30,8 @@ zh-TW:
suspend: 禁止所有對該帳號任何互動,並且刪除其內容。三十天內可以撤銷此動作。關閉所有對此帳號之檢舉報告。
warning_preset_id: 選用。您仍可在預設的結尾新增自訂文字
announcement:
- all_day: 核取後,只會顯示出時間範圍中的日期部分
- ends_at: 可選的,公告會在該時間點自動取消發布
+ all_day: 當選取時,僅顯示出時間範圍中的日期部分
+ ends_at: 可選的,公告會於該時間點自動取消發布
scheduled_at: 空白則立即發布公告
starts_at: 可選的,讓公告在特定時間範圍內顯示
text: 您可以使用嘟文語法,但請小心別讓公告太鴨霸而佔據使用者的整個版面。
@@ -59,8 +59,8 @@ zh-TW:
setting_display_media_default: 隱藏標為敏感內容的媒體
setting_display_media_hide_all: 總是隱藏所有媒體
setting_display_media_show_all: 總是顯示標為敏感內容的媒體
- setting_use_blurhash: 彩色漸層圖樣是基於隱藏媒體內容顏色產生,所有細節會變得模糊
- setting_use_pending_items: 關閉自動捲動更新,時間軸只會在點擊後更新
+ setting_use_blurhash: 彩色漸層圖樣是基於隱藏媒體內容顏色產生,所有細節將變得模糊
+ setting_use_pending_items: 關閉自動捲動更新,時間軸僅於點擊後更新
username: 您可以使用字幕、數字與底線
whole_word: 如果關鍵字或詞組僅有字母與數字,則其將只在符合整個單字的時候才會套用
domain_allow:
@@ -116,7 +116,7 @@ zh-TW:
sign_up_requires_approval: 新註冊申請需要先經過您的審核
severity: 請選擇將如何處理來自這個 IP 位址的請求
rule:
- text: 說明使用者在此伺服器上需遵守的規則或條款。試著維持各項條款簡短而明瞭。
+ text: 說明使用者於此伺服器上需遵守的規則或條款。試著維持各項條款簡短而明瞭。
sessions:
otp: 請輸入產生自您手機 App 的兩階段驗證碼,或輸入其中一個備用驗證碼:
webauthn: 如果它是 USB 安全金鑰的話,請確認已正確插入,如有需要請觸擊。
@@ -126,7 +126,7 @@ zh-TW:
tag:
name: 您只能變更大小寫,例如,以使其更易讀。
user:
- chosen_languages: 當選取時,只有選取語言之嘟文會在公開時間軸中顯示
+ chosen_languages: 當選取時,只有選取語言之嘟文會於公開時間軸中顯示
role: 角色控制使用者有哪些權限
user_role:
color: 在整個使用者介面中用於角色的顏色,十六進位格式的 RGB
diff --git a/config/locales/sk.yml b/config/locales/sk.yml
index 78b9b87db34368..6e3fe0cd8987d9 100644
--- a/config/locales/sk.yml
+++ b/config/locales/sk.yml
@@ -228,6 +228,7 @@ sk:
create_account_warning_html: "%{name} poslal/a upozornenie užívateľovi %{target}"
create_announcement_html: "%{name} vytvoril/a nové oboznámenie %{target}"
create_custom_emoji_html: "%{name} nahral/a novú emotikonu %{target}"
+ create_domain_allow_html: "%{name} povolil/a federáciu s doménou %{target}"
create_domain_block_html: "%{name} zablokoval/a doménu %{target}"
create_email_domain_block_html: "%{name} zablokoval/a e-mailovú doménu %{target}"
create_user_role_html: "%{name} vytvoril/a rolu pre %{target}"
@@ -241,6 +242,7 @@ sk:
destroy_ip_block_html: "%{name} vymazal/a pravidlo pre IP %{target}"
destroy_status_html: "%{name} zmazal/a príspevok od %{target}"
destroy_user_role_html: "%{name} vymazal/a rolu pre %{target}"
+ enable_user_html: "%{name} povolil/a prihlásenie pre používateľa %{target}"
memorialize_account_html: "%{name} zmenil/a účet %{target} na pamätnú stránku"
reject_appeal_html: "%{name} zamietol/la námietku moderovacieho rozhodnutia od %{target}"
reopen_report_html: "%{name} znovu otvoril/a nahlásenie %{target}"
@@ -353,6 +355,7 @@ sk:
silence: Obmedz
suspend: Vylúč
title: Nové blokovanie domény
+ not_permitted: Nemáš povolenie na vykonanie tohto kroku
obfuscate: Zatemniť názov domény
private_comment: Súkromný komentár
private_comment_hint: Odôvodni toto doménové obmedzenie, pre vnútorné vyrozumenie moderátorov.
diff --git a/config/locales/sl.yml b/config/locales/sl.yml
index 35230ceddb33f0..00c696f6fd2f12 100644
--- a/config/locales/sl.yml
+++ b/config/locales/sl.yml
@@ -1,7 +1,7 @@
---
sl:
about:
- about_mastodon_html: 'Družbeno omrežje prihodnosti: brez oglasov, brez nadzora korporacij, etično oblikovanje in decentralizacija! Ohranite lastništvo nad svojimi podatki z Mastodonom!'
+ about_mastodon_html: 'Družbeno omrežje prihodnosti: brez oglasov, brez nadzora korporacij, etično oblikovano in decentralizirano! Ohranite lastništvo nad svojimi podatki z Mastodonom!'
contact_missing: Ni nastavljeno
contact_unavailable: Ni na voljo
hosted_on: Mastodon gostuje na %{domain}
diff --git a/config/locales/sq.yml b/config/locales/sq.yml
index 6cdfa268dbb27e..74810b147a5b8e 100644
--- a/config/locales/sq.yml
+++ b/config/locales/sq.yml
@@ -533,6 +533,7 @@ sq:
total_reported: Raportime rreth tyre
total_storage: Bashkëngjitje media
totals_time_period_hint_html: Vlerat e shfaqura më poshtë përfshijnë të dhënat për krejt kohën.
+ unknown_instance: Aktualisht në këtë shërbyes s’ka gjurmë të kësaj përkatësie.
invites:
deactivate_all: Çaktivizoji krejt
filter:
@@ -1095,6 +1096,7 @@ sq:
functional: Llogaria juaj është tërësisht funksionale.
pending: Aplikimi juaj është në pritje të shqyrtimit nga stafi ynë. Kjo mund të dojë ca kohë. Nëse aplikimi juaj miratohet, do të merrni një email.
redirecting_to: Llogaria juaj është joaktive, ngaqë aktualisht ridrejton te %{acct}.
+ self_destruct: Ngaqë %{domain} po mbyllet, do të keni vetëm hyrje të kufizuar te llogaria juaj.
view_strikes: Shihni paralajmërime të dikurshme kundër llogarisë tuaj
too_fast: Formulari u parashtrua shumë shpejt, riprovoni.
use_security_key: Përdor kyç sigurie
@@ -1564,6 +1566,9 @@ sq:
over_daily_limit: Keni tejkaluar kufirin e %{limit} mesazheve të planifikuara për atë ditë
over_total_limit: Keni tejkaluar kufirin prej %{limit} mesazhesh të planifikuara
too_soon: Data e planifikimit duhet të bjerë në të ardhmen
+ self_destruct:
+ lead_html: Mjerisht, %{domain} po mbyllet përgjithmonë. Nëse patët një llogari këtu, s’do të jeni në gjendje të vazhdoni ta përdorni, por mundeni ende të kërkoni një kopjeruajtje të të dhënave tuaja.
+ title: Ky shërbyes po mbyllet
sessions:
activity: Veprimtaria e fundit
browser: Shfletues
diff --git a/config/locales/sr-Latn.yml b/config/locales/sr-Latn.yml
index 82fbbff49e3065..37166bc03be398 100644
--- a/config/locales/sr-Latn.yml
+++ b/config/locales/sr-Latn.yml
@@ -545,6 +545,7 @@ sr-Latn:
total_reported: Prijave vezane za njih
total_storage: Multimedijalni prilozi
totals_time_period_hint_html: Ukupne vrednosti prikazane ispod uključuju podatke za sva vremena.
+ unknown_instance: Trenutno ne postoji zapis o ovom domenu na ovom serveru.
invites:
deactivate_all: Deaktiviraj sve
filter:
@@ -1119,6 +1120,7 @@ sr-Latn:
functional: Vaš nalog je potpuno operativan.
pending: Vaš zahtev je na čekanju za pregled od strane našeg osoblja. Ovo može potrajati neko vreme. Primićete imejl poruku ukoliko Vam zahtev bude odobren.
redirecting_to: Vaš nalog je neaktivan jer preusmerava na %{acct}.
+ self_destruct: Pošto se %{domain} zatvara, dobićete samo ograničen pristup svom nalogu.
view_strikes: Pogledajte prethodne prestupe upisane na Vaše ime
too_fast: Formular je podnet prebrzo, pokušajte ponovo.
use_security_key: Koristite sigurnosni ključ
@@ -1596,6 +1598,9 @@ sr-Latn:
over_daily_limit: Prekoračili ste granicu od %{limit} planiranih objava za danas
over_total_limit: Prekoračili ste granicu od %{limit} planiranih objava
too_soon: Planirani datum mora biti u budućnosti
+ self_destruct:
+ lead_html: Nažalost, %{domain} se trajno zatvara. Ako ste tamo imali nalog, nećete moći da nastavite da ga koristite, ali i dalje možete da zatražite rezervnu kopiju svojih podataka.
+ title: Ovaj server se zatvara
sessions:
activity: Poslednja aktivnost
browser: Veb čitač
diff --git a/config/locales/sr.yml b/config/locales/sr.yml
index ffddab8697deb3..ba269488e47454 100644
--- a/config/locales/sr.yml
+++ b/config/locales/sr.yml
@@ -545,6 +545,7 @@ sr:
total_reported: Пријаве везане за њих
total_storage: Мултимедијални прилози
totals_time_period_hint_html: Укупне вредности приказане испод укључују податке за сва времена.
+ unknown_instance: Тренутно не постоји запис о овом домену на овом серверу.
invites:
deactivate_all: Деактивирај све
filter:
@@ -1119,6 +1120,7 @@ sr:
functional: Ваш налог је потпуно оперативан.
pending: Ваш захтев је на чекању за преглед од стране нашег особља. Ово може потрајати неко време. Примићете имејл поруку уколико Вам захтев буде одобрен.
redirecting_to: Ваш налог је неактиван јер преусмерава на %{acct}.
+ self_destruct: Пошто се %{domain} затвара, добићете само ограничен приступ свом налогу.
view_strikes: Погледајте претходне преступе уписане на Ваше име
too_fast: Формулар је поднет пребрзо, покушајте поново.
use_security_key: Користите сигурносни кључ
@@ -1596,6 +1598,9 @@ sr:
over_daily_limit: Прекорачили сте границу од %{limit} планираних објава за данас
over_total_limit: Прекорачили сте границу од %{limit} планираних објава
too_soon: Планирани датум мора бити у будућности
+ self_destruct:
+ lead_html: Нажалост, %{domain} се трајно затвара. Ако сте тамо имали налог, нећете моћи да наставите да га користите, али и даље можете да затражите резервну копију својих података.
+ title: Овај сервер се затвара
sessions:
activity: Последња активност
browser: Веб читач
diff --git a/config/locales/sv.yml b/config/locales/sv.yml
index 3194d7a8c23395..72c5295b353be5 100644
--- a/config/locales/sv.yml
+++ b/config/locales/sv.yml
@@ -534,6 +534,7 @@ sv:
total_reported: Rapporter om dem
total_storage: Media-bilagor
totals_time_period_hint_html: Totalsummorna som visas nedan inkluderar data för all tid.
+ unknown_instance: Det finns för närvarande inga uppgifter om denna domän på denna server.
invites:
deactivate_all: Inaktivera alla
filter:
@@ -1101,6 +1102,7 @@ sv:
functional: Ditt konto fungerar som det ska.
pending: Din ansökan inväntar granskning. Detta kan ta tid. Du kommer att få ett e-postmeddelande om din ansökan godkänns.
redirecting_to: Ditt konto är inaktivt eftersom det för närvarande dirigeras om till %{acct}.
+ self_destruct: Eftersom %{domain} håller på att stängas ned, kommer du endast att ha begränsad tillgång till ditt konto.
view_strikes: Visa tidigare prickar på ditt konto
too_fast: Formuläret har skickats för snabbt, försök igen.
use_security_key: Använd säkerhetsnyckel
@@ -1570,6 +1572,9 @@ sv:
over_daily_limit: Du har överskridit dygnsgränsen på %{limit} schemalagda inlägg
over_total_limit: Du har överskridit gränsen på %{limit} schemalagda inlägg
too_soon: Schemaläggningsdatumet måste vara i framtiden
+ self_destruct:
+ lead_html: Tyvärr stänger %{domain} för gott. Om du hade ett konto där kommer du inte längre kunna använda det, men du kan fortfarande begära en säkerhetskopia av din data.
+ title: Denna server stänger ned
sessions:
activity: Senaste aktivitet
browser: Webbläsare
diff --git a/config/locales/th.yml b/config/locales/th.yml
index 781c3df29cb4c0..d8ab63730bec4a 100644
--- a/config/locales/th.yml
+++ b/config/locales/th.yml
@@ -523,6 +523,7 @@ th:
total_reported: รายงานเกี่ยวกับเขา
total_storage: ไฟล์แนบสื่อ
totals_time_period_hint_html: ยอดรวมที่แสดงด้านล่างรวมข้อมูลสำหรับเวลาทั้งหมด
+ unknown_instance: ไม่มีระเบียนของโดเมนนี้ในเซิร์ฟเวอร์นี้ในปัจจุบัน
invites:
deactivate_all: ปิดใช้งานทั้งหมด
filter:
@@ -1083,6 +1084,7 @@ th:
functional: บัญชีของคุณทำงานได้อย่างเต็มที่
pending: ใบสมัครของคุณกำลังรอดำเนินการตรวจทานโดยพนักงานของเรา นี่อาจใช้เวลาสักครู่ คุณจะได้รับอีเมลหากมีการอนุมัติใบสมัครของคุณ
redirecting_to: บัญชีของคุณไม่ได้ใช้งานเนื่องจากบัญชีกำลังเปลี่ยนเส้นทางไปยัง %{acct} ในปัจจุบัน
+ self_destruct: เนื่องจาก %{domain} กำลังปิดตัวลง คุณจะได้รับการเข้าถึงบัญชีของคุณแบบจำกัดเท่านั้น
view_strikes: ดูการดำเนินการที่ผ่านมาต่อบัญชีของคุณ
too_fast: ส่งแบบฟอร์มเร็วเกินไป ลองอีกครั้ง
use_security_key: ใช้กุญแจความปลอดภัย
@@ -1544,6 +1546,9 @@ th:
over_daily_limit: คุณมีโพสต์ที่จัดกำหนดการไว้เกินขีดจำกัดที่ %{limit} สำหรับวันนี้แล้ว
over_total_limit: คุณมีโพสต์ที่จัดกำหนดการไว้เกินขีดจำกัดที่ %{limit} แล้ว
too_soon: วันที่จัดกำหนดการต้องอยู่ในอนาคต
+ self_destruct:
+ lead_html: น่าเสียดาย %{domain} กำลังปิดตัวลงอย่างถาวร หากคุณมีบัญชีที่นั่น คุณจะไม่สามารถใช้บัญชีต่อไปได้ แต่คุณยังสามารถขอข้อมูลสำรองของข้อมูลของคุณ
+ title: เซิร์ฟเวอร์นี้กำลังปิดตัวลง
sessions:
activity: กิจกรรมล่าสุด
browser: เบราว์เซอร์
diff --git a/config/locales/tr.yml b/config/locales/tr.yml
index 862667f3ce782e..86d153528b9541 100644
--- a/config/locales/tr.yml
+++ b/config/locales/tr.yml
@@ -534,6 +534,7 @@ tr:
total_reported: Onlar hakkında şikayetler
total_storage: Medya ekleri
totals_time_period_hint_html: Aşağıdaki gösterilen toplamlar, gelmiş geçmiş tüm veriyi içeriyor.
+ unknown_instance: Bu sunucuda bu alan adının şu an bir kaydı yok.
invites:
deactivate_all: Tümünü devre dışı bırak
filter:
@@ -1101,6 +1102,7 @@ tr:
functional: Hesabınız tamamen kullanıma hazır.
pending: Başvurunuz personelimiz tarafından gözden geçirilmeyi beklemektedir. Bu biraz zaman alabilir. Başvurunuz onaylanırsa bir e-posta alacaksınız.
redirecting_to: Hesabınız aktif değil çünkü şu anda %{acct} adresine yönlendirilmektedir.
+ self_destruct: "%{domain} kapandığı için, hesabınıza sadece kısıtlı erişiminiz olacak."
view_strikes: Hesabınıza yönelik eski eylemleri görüntüleyin
too_fast: Form çok hızlı gönderildi, tekrar deneyin.
use_security_key: Güvenlik anahtarını kullan
@@ -1570,6 +1572,9 @@ tr:
over_daily_limit: Bugün için %{limit} zamanlanmış gönderi sınırını aştınız
over_total_limit: "%{limit} zamanlanmış gönderi sınırını aştınız"
too_soon: Programlanan tarih bugünden ileri bir tarihte olmalıdır
+ self_destruct:
+ lead_html: Maalesef %{domain} kalıcı olarak kapanıyor. Eğer orada hesabınız varsa, onu kullanmaya devam edemeyeceksiniz, ancak yine de verinizin bir yedeğini isteyebilirsiniz.
+ title: Bu sunucu kapanıyor
sessions:
activity: Son etkinlik
browser: Tarayıcı
diff --git a/config/locales/uk.yml b/config/locales/uk.yml
index 93cdc041747883..afa85ae67bb54a 100644
--- a/config/locales/uk.yml
+++ b/config/locales/uk.yml
@@ -556,6 +556,7 @@ uk:
total_reported: Звітів про них
total_storage: Мультимедійні вкладення
totals_time_period_hint_html: Нижче зображена статистика за все існування сервера.
+ unknown_instance: Наразі на цьому сервері немає записів цього домену.
invites:
deactivate_all: Деактивувати всі
filter:
@@ -1137,6 +1138,7 @@ uk:
functional: Ваш обліковий запис повністю робочий.
pending: Ваша заява очікує на розгляд нашим персоналом. Це може зайняти деякий час. Ви отримаєте електронний лист, якщо ваша заява буде схвалена.
redirecting_to: Ваш обліковий запис наразі неактивний, тому що він перенаправлений до %{acct}.
+ self_destruct: Оскільки %{domain} закривається, ви отримаєте тільки обмежений доступ до вашого облікового запису.
view_strikes: Переглянути попередні попередження вашому обліковому запису
too_fast: Форму подано занадто швидко, спробуйте ще раз.
use_security_key: Використовувати ключ безпеки
@@ -1622,6 +1624,9 @@ uk:
over_daily_limit: Ви перевищили ліміт в %{limit} запланованих дописів на сьогодні
over_total_limit: Ви перевищили ліміт в %{limit} запланованих дописів
too_soon: Запланована дата має бути в майбутньому
+ self_destruct:
+ lead_html: На жаль, %{domain} остаточно закривається. Якщо у вас є обліковий запис там, ви не зможете продовжити його використання, але ви все ще можете надіслати запит на резервну копію даних.
+ title: Сервер закривається
sessions:
activity: Остання активність
browser: Браузер
diff --git a/config/locales/vi.yml b/config/locales/vi.yml
index 73222a6047e24a..79ec13571d57c4 100644
--- a/config/locales/vi.yml
+++ b/config/locales/vi.yml
@@ -523,6 +523,7 @@ vi:
total_reported: Toàn bộ báo cáo
total_storage: Media
totals_time_period_hint_html: Tổng số được hiển thị bên dưới bao gồm dữ liệu cho mọi thời điểm.
+ unknown_instance: Hiện tại không có bản ghi tên miền này trên máy chủ này.
invites:
deactivate_all: Vô hiệu hóa tất cả
filter:
@@ -1083,6 +1084,7 @@ vi:
functional: Tài khoản của bạn đã được xác minh.
pending: Đơn đăng ký của bạn đang chờ phê duyệt. Điều này có thể mất một thời gian. Bạn sẽ nhận được email nếu đơn đăng ký của bạn được chấp thuận.
redirecting_to: Tài khoản của bạn không hoạt động vì hiện đang chuyển hướng đến %{acct}.
+ self_destruct: Vì %{domain} đang đóng cửa, bạn sẽ chỉ có quyền truy cập hạn chế vào tài khoản của mình.
view_strikes: Xem những lần cảnh cáo cũ
too_fast: Nghi vấn đăng ký spam, xin thử lại.
use_security_key: Dùng khóa bảo mật
@@ -1544,6 +1546,9 @@ vi:
over_daily_limit: Bạn đã vượt qua giới hạn được lên lịch đăng tút %{limit} hôm nay
over_total_limit: Bạn đã vượt quá giới hạn %{limit} của các tút được lên lịch
too_soon: Ngày lên lịch phải trong tương lai
+ self_destruct:
+ lead_html: Rất tiếc, %{domain}đã đóng cửa vĩnh viễn. Nếu bạn có tài khoản ở đó, bạn sẽ không thể tiếp tục sử dụng tài khoản đó nhưng bạn vẫn có thể yêu cầu bản sao lưu dữ liệu của mình.
+ title: Máy chủ đang đóng cửa
sessions:
activity: Gần đây nhất
browser: Ứng dụng
diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml
index 51baaf7a4e6479..6d3beddbcf025d 100644
--- a/config/locales/zh-CN.yml
+++ b/config/locales/zh-CN.yml
@@ -40,7 +40,7 @@ zh-CN:
current_email: 当前的电子邮箱
label: 更改电子邮箱
new_email: 新的电子邮箱
- submit: 更改电子邮件地址
+ submit: 更改电子邮箱
title: 更改 %{username} 的电子邮箱
change_role:
changed_msg: 已成功更改角色!
@@ -68,8 +68,8 @@ zh-CN:
enable_sign_in_token_auth: 启用电子邮件令牌认证
enabled: 已启用
enabled_msg: 成功解冻 %{username} 的账号
- followers: 关注者
- follows: 正在关注
+ followers: 粉丝
+ follows: 关注
header: 个人资料页横幅图片
inbox_url: 收件箱(Inbox)URL
invite_request_text: 加入理由
@@ -523,6 +523,7 @@ zh-CN:
total_reported: 关于对方的举报
total_storage: 媒体文件
totals_time_period_hint_html: 下方显示的总数来自全部历史数据。
+ unknown_instance: 此服务器上目前没有此域名的记录。
invites:
deactivate_all: 撤销所有邀请链接
filter:
@@ -1083,6 +1084,7 @@ zh-CN:
functional: 你的账号可以正常使用了。
pending: 工作人员正在审核你的申请。这需要花点时间。在申请被批准后,你将收到一封电子邮件。
redirecting_to: 你的账户无效,因为它已被设置为跳转到 %{acct}
+ self_destruct: 由于 %{domain} 即将关闭,你只能获得对你本人账号的有限访问权限。
view_strikes: 查看针对你账号的记录
too_fast: 表单提交过快,请重试。
use_security_key: 使用安全密钥
@@ -1544,6 +1546,9 @@ zh-CN:
over_daily_limit: 你已超出每日定时嘟文的上限(%{limit} 条)
over_total_limit: 你已超出定时嘟文的上限(%{limit} 条)
too_soon: 所定的时间必须在未来
+ self_destruct:
+ lead_html: 很遗憾,%{domain} 即将永久关闭。 如果你在其中设有账号,那么你将无法再继续使用,但你仍可以请求获得本人数据的备份。
+ title: 此服务器即将关闭
sessions:
activity: 最后一次活跃的时间
browser: 浏览器
diff --git a/config/locales/zh-HK.yml b/config/locales/zh-HK.yml
index 626cf22e71cd20..236b2d0cf93a1e 100644
--- a/config/locales/zh-HK.yml
+++ b/config/locales/zh-HK.yml
@@ -523,6 +523,7 @@ zh-HK:
total_reported: 關於他們的舉報
total_storage: 媒體附件
totals_time_period_hint_html: 下面顯示的總數包括所有時間的數據。
+ unknown_instance: 此伺服器目前沒有這個網域的紀錄。
invites:
deactivate_all: 全部停用
filter:
@@ -1083,6 +1084,7 @@ zh-HK:
functional: 你的帳號已完全投入使用。
pending: 管理員正在處理你的申請。可能會需要一點時間處理。我們將會在申請被批準的時候馬上寄電郵給你。
redirecting_to: 你的帳戶因為正在重新定向到 %{acct},所以暫時被停用。
+ self_destruct: 由於 %{domain} 即將停止服務,你只能有限存取你的帳號。
view_strikes: 查看針對你的帳戶的過往警告
too_fast: 你太快遞交了,請再試一次。
use_security_key: 使用安全密鑰裝置
@@ -1544,6 +1546,9 @@ zh-HK:
over_daily_limit: 你已經超越了當天排定發文的限額 (%{limit})
over_total_limit: 你已經超越了排定發文的限額 (%{limit})
too_soon: 不可以改變過去哦,嘟文只可以排定在未來
+ self_destruct:
+ lead_html: 很遺憾,%{domain} 即將永久停止服務。如果你在該處擁有帳號,你將無法繼續使用它,但你仍然可以要求備份你的數據。
+ title: 這個伺服器即將停止服務
sessions:
activity: 最近活動
browser: 瀏覽器
@@ -1706,6 +1711,7 @@ zh-HK:
default: "%Y年%-m月%d日 %H:%M"
month: "%b %Y"
time: "%H:%M"
+ with_time_zone: "%b %d, %Y, %H:%M %Z"
translation:
errors:
quota_exceeded: 已超出伺服器範圍的翻譯服務之使用配額。
diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml
index 33870c0bb229a5..28507b076a2dfc 100644
--- a/config/locales/zh-TW.yml
+++ b/config/locales/zh-TW.yml
@@ -390,7 +390,7 @@ zh-TW:
domain: 站點
edit: 更改封鎖的站台
existing_domain_block: 您已對 %{name} 施加更嚴格的限制。
- existing_domain_block_html: 您已對 %{name} 施加更嚴格的限制,您需要先 解除封鎖。
+ existing_domain_block_html: 您已對 %{name} 施加更嚴格的限制,您需要先解除封鎖。
export: 匯出
import: 匯入
new:
@@ -451,9 +451,7 @@ zh-TW:
title: 匯入網域黑名單
no_file: 尚未選擇檔案
follow_recommendations:
- description_html: |-
- 跟隨建議幫助新使用者們快速找到有趣的內容。當使用者沒有與其他帳號有足夠多的互動以建立個人化跟隨建議時,這些帳號將會被推薦。這些帳號將基於某選定語言之高互動和高本地跟隨者數量帳號而
- 每日重新更新。
+ description_html: "跟隨建議幫助新使用者們快速找到有趣的內容。當使用者沒有與其他帳號有足夠多的互動以建立個人化跟隨建議時,這些帳號將會被推薦。這些帳號將基於某選定語言之高互動和高本地跟隨者數量帳號而每日重新更新。"
language: 對於語言
status: 狀態
suppress: 取消跟隨建議
@@ -525,6 +523,7 @@ zh-TW:
total_reported: 關於他們的檢舉報告
total_storage: 多媒體附加檔案
totals_time_period_hint_html: 以下顯示之總和包含所有時間的資料。
+ unknown_instance: 此伺服器目前沒有這個網域的紀錄。
invites:
deactivate_all: 全部停用
filter:
@@ -553,7 +552,7 @@ zh-TW:
relays:
add_new: 新增中繼站
delete: 刪除
- description_html: "聯邦中繼站 是種中繼伺服器,會在訂閱並推送至此中繼站的伺服器之間交換大量的公開嘟文。中繼站也能協助小型或中型伺服器從聯邦宇宙中探索內容,而無須本地使用者手動跟隨遠端伺服器的其他使用者。"
+ description_html: "聯邦中繼站 是種中繼伺服器,會於訂閱並推送至此中繼站的伺服器之間交換大量的公開嘟文。中繼站也能協助小型或中型伺服器從聯邦宇宙中探索內容,而無須本地使用者手動跟隨遠端伺服器的其他使用者。"
disable: 停用
disabled: 停用
enable: 啟用
@@ -580,7 +579,7 @@ zh-TW:
mark_as_sensitive_description_html: 被檢舉的嘟文中的媒體將會被標記為敏感內容,並將會記錄一次警告,以協助您升級同一帳號未來的違規行為。
other_description_html: 檢視更多控制帳號行為以及自訂檢舉帳號通知之選項。
resolve_description_html: 被檢舉的帳號將不被採取任何行動,不會加以刪除線標記,並且此份報告將被關閉。
- silence_description_html: 此帳號僅會對已跟隨帳號之使用者或手動查詢可見,將大幅度限制觸及範圍。此設定可隨時被還原。關閉所有對此帳號之檢舉報告。
+ silence_description_html: 此帳號僅對已跟隨帳號之使用者或手動查詢可見,將大幅度限制觸及範圍。此設定可隨時被還原。關閉所有對此帳號之檢舉報告。
suspend_description_html: 此帳號及其所有內容將不可被存取並且最終被移除,並且無法與之進行互動。三十天內可以撤銷此動作。關閉所有對此帳號之檢舉報告。
actions_description_html: 決定應對此報告採取何種行動。若您對檢舉之帳號採取懲罰措施,則將對他們發送 e-mail 通知,如非選擇了 垃圾郵件 類別。
actions_description_remote_html: 決定將對此檢舉報告採取何種動作。這將僅作用於您的伺服器與此遠端帳號及其內容之通訊行為。
@@ -988,9 +987,9 @@ zh-TW:
aliases:
add_new: 建立別名
created_msg: 成功建立別名。您可以自舊帳號開始轉移。
- deleted_msg: 成功移除別名。您將無法再由舊帳號轉移到目前的帳號。
+ deleted_msg: 成功移除別名。您將無法再由舊帳號轉移至目前的帳號。
empty: 您目前沒有任何別名。
- hint_html: 如果想由其他帳號轉移至此帳號,您可以在此處新增別名,稍後系統將容許您將跟隨者由舊帳號轉移至此。此項作業是無害且可復原的。 帳號的遷移程序需要在舊帳號啟動。
+ hint_html: 如果想由其他帳號轉移至此帳號,您可以於此處新增別名,稍後系統將容許您將跟隨者由舊帳號轉移至此。此項作業是無害且可復原的。 帳號的遷移程序需要在舊帳號啟動。
remove: 取消連結別名
appearance:
advanced_web_interface: 進階網頁介面
@@ -999,7 +998,7 @@ zh-TW:
confirmation_dialogs: 確認對話框
discovery: 探索
localization:
- body: Mastodon 是由志願者翻譯的。
+ body: Mastodon 是由志願者所翻譯。
guide_link: https://crowdin.com/project/mastodon
guide_link_text: 每個人都能貢獻。
sensitive_content: 敏感內容
@@ -1042,8 +1041,8 @@ zh-TW:
log_in_with: 登入,使用
login: 登入
logout: 登出
- migrate_account: 轉移到另一個帳號
- migrate_account_html: 如果您希望引導他人跟隨另一個帳號,請 到這裡設定。
+ migrate_account: 轉移至另一個帳號
+ migrate_account_html: 如果您希望引導他人跟隨另一個帳號,請至這裡設定。
or_log_in_with: 或透過其他方式登入
privacy_policy_agreement_html: 我已閱讀且同意 隱私權政策
progress:
@@ -1072,10 +1071,10 @@ zh-TW:
email_below_hint_html: 請檢查您的垃圾郵件資料夾,或是請求另一個。如果是錯的,您可以更正您的電子郵件地址。
email_settings_hint_html: 請點擊我們寄給您連結以驗證 %{email}。我們將於此稍候。
link_not_received: 無法取得連結嗎?
- new_confirmation_instructions_sent: 您將會在幾分鐘之內收到新的包含確認連結的電子郵件!
+ new_confirmation_instructions_sent: 您將於幾分鐘之內收到新的包含確認連結的電子郵件!
title: 請檢查您的收件匣
sign_in:
- preamble_html: 請使用您於 %{domain} 的帳號密碼登入。若您的帳號託管於其他伺服器,您將無法在此登入。
+ preamble_html: 請使用您於 %{domain} 的帳號密碼登入。若您的帳號託管於其他伺服器,您將無法於此登入。
title: 登入 %{domain}
sign_up:
manual_review: "%{domain} 上的註冊由我們的管理員進行人工審核。為協助我們處理您的註冊,請寫一些關於您自己的資訊以及您想要在 %{domain} 上註冊帳號的原因。"
@@ -1084,9 +1083,10 @@ zh-TW:
status:
account_status: 帳號狀態
confirming: 等待電子郵件確認完成。
- functional: 您的帳號可以正常使用了。
+ functional: "您的帳號可以正常使用了。🎉"
pending: 管管們正在處理您的申請,這可能需要一點時間處理。我們將於申請通過後以電子郵件方式通知您。
redirecting_to: 您的帳號因目前重定向至 %{acct} 而被停用。
+ self_destruct: 由於 %{domain} 即將停止服務,您只能有限地存取您的帳號。
view_strikes: 檢視針對您帳號過去的警示
too_fast: 送出表單的速度太快跟不上,請稍後再試。
use_security_key: 使用安全金鑰
@@ -1296,7 +1296,7 @@ zh-TW:
following_html: 您將要 跟隨 自 %{filename} 中之 %{total_items} 個帳號。
lists_html: 您將自 %{filename} 新增 %{total_items} 個帳號至您的列表。若不存在列表用以新增帳號,則會建立新列表。
muting_html: 您將要 靜音 自 %{filename} 中之 %{total_items} 個帳號。
- preface: 您可以在此匯入您在其他伺服器所匯出的資料檔,包括跟隨的使用者、封鎖的使用者名單。
+ preface: 您能於此匯入您在其他伺服器所匯出的資料檔,包括跟隨中的使用者、封鎖的使用者名單等。
recent_imports: 最近匯入的
states:
finished: 已完成
@@ -1410,7 +1410,7 @@ zh-TW:
followers: 此動作將會將目前帳號的所有跟隨者轉移至新帳號
only_redirect_html: 或者,您也可以僅在您的個人檔案中設定重新導向。
other_data: 其他資料並不會自動轉移
- redirect: 您目前的帳號將會在個人檔案頁面新增重新導向公告,並會被排除在搜尋結果之外
+ redirect: 您目前的帳號將於個人檔案頁面新增重新導向公告,並會被排除在搜尋結果之外
moderation:
title: 站務
move_handler:
@@ -1499,9 +1499,7 @@ zh-TW:
posting_defaults: 嘟文預設值
public_timelines: 公開時間軸
privacy:
- hint_html: |-
- 自訂您希望如何讓您的個人檔案及嘟文被找到。
- 藉由啟用一系列 Mastodon 功能以幫助您觸及更廣的受眾。煩請花些時間確認您是否欲啟用這些設定。
+ hint_html: "自訂您希望如何讓您的個人檔案及嘟文被發現。藉由啟用一系列 Mastodon 功能以幫助您觸及更廣的受眾。煩請花些時間確認您是否欲啟用這些設定。"
privacy: 隱私權
privacy_hint_html: 控制您希望向其他人揭露之內容。人們透過瀏覽其他人的跟隨者與其發嘟之應用程式發現有趣的個人檔案和酷炫的 Mastodon 應用程式,但您能選擇將其隱藏。
reach: 觸及
@@ -1550,6 +1548,9 @@ zh-TW:
over_daily_limit: 您已經超過了本日排定發嘟的限額 (%{limit})
over_total_limit: 您已經超過排程發嘟的限額 (%{limit})
too_soon: 嘟文不可以改變過去哦,只能預定未來 (咦)
+ self_destruct:
+ lead_html: 很遺憾,%{domain} 即將永久停止服務。如果您於該伺服器擁有帳號,您將無法繼續使用它,但您仍然可以請求您的資料備份。
+ title: 這個伺服器即將停止服務
sessions:
activity: 最近活動
browser: 瀏覽器
@@ -1665,7 +1666,7 @@ zh-TW:
enabled: 自動刪除舊嘟文
enabled_hint: 一旦達到指定的保存期限,就會自動刪除您的嘟文,除非該嘟文符合下列例外
exceptions: 例外
- explanation: 因為刪除嘟文是耗費資源的操作,當伺服器不那麼忙碌時才會慢慢完成。因此,您的嘟文會在到達保存期限後一段時間才會被刪除。
+ explanation: 因為刪除嘟文是耗費資源的操作,當伺服器不那麼忙碌時才會慢慢完成。因此,您的嘟文將於到達保存期限後一段時間才會被刪除。
ignore_favs: 忽略最愛數
ignore_reblogs: 忽略轉嘟數
interaction_exceptions: 基於互動的例外規則
diff --git a/config/navigation.rb b/config/navigation.rb
index 4ea88fb4f2bfe0..e001544894a136 100644
--- a/config/navigation.rb
+++ b/config/navigation.rb
@@ -1,14 +1,16 @@
# frozen_string_literal: true
SimpleNavigation::Configuration.run do |navigation|
+ self_destruct = SelfDestructHelper.self_destruct?
+
navigation.items do |n|
n.item :web, safe_join([fa_icon('chevron-left fw'), t('settings.back')]), root_path
n.item :software_updates, safe_join([fa_icon('exclamation-circle fw'), t('admin.critical_update_pending')]), admin_software_updates_path, if: -> { ENV['UPDATE_CHECK_URL'] != '' && current_user.can?(:view_devops) && SoftwareUpdate.urgent_pending? }, html: { class: 'warning' }
- n.item :profile, safe_join([fa_icon('user fw'), t('settings.profile')]), settings_profile_path, if: -> { current_user.functional? }, highlights_on: %r{/settings/profile|/settings/featured_tags|/settings/verification|/settings/privacy}
+ n.item :profile, safe_join([fa_icon('user fw'), t('settings.profile')]), settings_profile_path, if: -> { current_user.functional? && !self_destruct }, highlights_on: %r{/settings/profile|/settings/featured_tags|/settings/verification|/settings/privacy}
- n.item :preferences, safe_join([fa_icon('cog fw'), t('settings.preferences')]), settings_preferences_path, if: -> { current_user.functional? } do |s|
+ n.item :preferences, safe_join([fa_icon('cog fw'), t('settings.preferences')]), settings_preferences_path, if: -> { current_user.functional? && !self_destruct } do |s|
s.item :appearance, safe_join([fa_icon('desktop fw'), t('settings.appearance')]), settings_preferences_appearance_path
s.item :notifications, safe_join([fa_icon('bell fw'), t('settings.notifications')]), settings_preferences_notifications_path
s.item :other, safe_join([fa_icon('cog fw'), t('preferences.other')]), settings_preferences_other_path
@@ -20,31 +22,31 @@
end
end
- n.item :relationships, safe_join([fa_icon('users fw'), t('settings.relationships')]), relationships_path, if: -> { current_user.functional? }
- n.item :filters, safe_join([fa_icon('filter fw'), t('filters.index.title')]), filters_path, highlights_on: %r{/filters}, if: -> { current_user.functional? }
- n.item :statuses_cleanup, safe_join([fa_icon('history fw'), t('settings.statuses_cleanup')]), statuses_cleanup_path, if: -> { current_user.functional_or_moved? }
+ n.item :relationships, safe_join([fa_icon('users fw'), t('settings.relationships')]), relationships_path, if: -> { current_user.functional? && !self_destruct }
+ n.item :filters, safe_join([fa_icon('filter fw'), t('filters.index.title')]), filters_path, highlights_on: %r{/filters}, if: -> { current_user.functional? && !self_destruct }
+ n.item :statuses_cleanup, safe_join([fa_icon('history fw'), t('settings.statuses_cleanup')]), statuses_cleanup_path, if: -> { current_user.functional_or_moved? && !self_destruct }
n.item :security, safe_join([fa_icon('lock fw'), t('settings.account')]), edit_user_registration_path do |s|
s.item :password, safe_join([fa_icon('lock fw'), t('settings.account_settings')]), edit_user_registration_path, highlights_on: %r{/auth/edit|/settings/delete|/settings/migration|/settings/aliases|/settings/login_activities|^/disputes}
s.item :two_factor_authentication, safe_join([fa_icon('mobile fw'), t('settings.two_factor_authentication')]), settings_two_factor_authentication_methods_path, highlights_on: %r{/settings/two_factor_authentication|/settings/otp_authentication|/settings/security_keys}
- s.item :authorized_apps, safe_join([fa_icon('list fw'), t('settings.authorized_apps')]), oauth_authorized_applications_path
+ s.item :authorized_apps, safe_join([fa_icon('list fw'), t('settings.authorized_apps')]), oauth_authorized_applications_path, if: -> { !self_destruct }
end
n.item :data, safe_join([fa_icon('cloud-download fw'), t('settings.import_and_export')]), settings_export_path do |s|
- s.item :import, safe_join([fa_icon('cloud-upload fw'), t('settings.import')]), settings_imports_path, if: -> { current_user.functional? }
+ s.item :import, safe_join([fa_icon('cloud-upload fw'), t('settings.import')]), settings_imports_path, if: -> { current_user.functional? && !self_destruct }
s.item :export, safe_join([fa_icon('cloud-download fw'), t('settings.export')]), settings_export_path
end
- n.item :invites, safe_join([fa_icon('user-plus fw'), t('invites.title')]), invites_path, if: -> { current_user.can?(:invite_users) && current_user.functional? }
- n.item :development, safe_join([fa_icon('code fw'), t('settings.development')]), settings_applications_path, if: -> { current_user.functional? }
+ n.item :invites, safe_join([fa_icon('user-plus fw'), t('invites.title')]), invites_path, if: -> { current_user.can?(:invite_users) && current_user.functional? && !self_destruct }
+ n.item :development, safe_join([fa_icon('code fw'), t('settings.development')]), settings_applications_path, if: -> { current_user.functional? && !self_destruct }
- n.item :trends, safe_join([fa_icon('fire fw'), t('admin.trends.title')]), admin_trends_statuses_path, if: -> { current_user.can?(:manage_taxonomies) } do |s|
+ n.item :trends, safe_join([fa_icon('fire fw'), t('admin.trends.title')]), admin_trends_statuses_path, if: -> { current_user.can?(:manage_taxonomies) && !self_destruct } do |s|
s.item :statuses, safe_join([fa_icon('comments-o fw'), t('admin.trends.statuses.title')]), admin_trends_statuses_path, highlights_on: %r{/admin/trends/statuses}
s.item :tags, safe_join([fa_icon('hashtag fw'), t('admin.trends.tags.title')]), admin_trends_tags_path, highlights_on: %r{/admin/tags|/admin/trends/tags}
s.item :links, safe_join([fa_icon('newspaper-o fw'), t('admin.trends.links.title')]), admin_trends_links_path, highlights_on: %r{/admin/trends/links}
end
- n.item :moderation, safe_join([fa_icon('gavel fw'), t('moderation.title')]), nil, if: -> { current_user.can?(:manage_reports, :view_audit_log, :manage_users, :manage_invites, :manage_taxonomies, :manage_federation, :manage_blocks) } do |s|
+ n.item :moderation, safe_join([fa_icon('gavel fw'), t('moderation.title')]), nil, if: -> { current_user.can?(:manage_reports, :view_audit_log, :manage_users, :manage_invites, :manage_taxonomies, :manage_federation, :manage_blocks) && !self_destruct } do |s|
s.item :reports, safe_join([fa_icon('flag fw'), t('admin.reports.title')]), admin_reports_path, highlights_on: %r{/admin/reports}, if: -> { current_user.can?(:manage_reports) }
s.item :accounts, safe_join([fa_icon('users fw'), t('admin.accounts.title')]), admin_accounts_path(origin: 'local'), highlights_on: %r{/admin/accounts|/admin/pending_accounts|/admin/disputes|/admin/users}, if: -> { current_user.can?(:manage_users) }
s.item :invites, safe_join([fa_icon('user-plus fw'), t('admin.invites.title')]), admin_invites_path, if: -> { current_user.can?(:manage_invites) }
@@ -55,7 +57,7 @@
s.item :action_logs, safe_join([fa_icon('bars fw'), t('admin.action_logs.title')]), admin_action_logs_path, if: -> { current_user.can?(:view_audit_log) }
end
- n.item :admin, safe_join([fa_icon('cogs fw'), t('admin.title')]), nil, if: -> { current_user.can?(:view_dashboard, :manage_settings, :manage_rules, :manage_announcements, :manage_custom_emojis, :manage_webhooks, :manage_federation) } do |s|
+ n.item :admin, safe_join([fa_icon('cogs fw'), t('admin.title')]), nil, if: -> { current_user.can?(:view_dashboard, :manage_settings, :manage_rules, :manage_announcements, :manage_custom_emojis, :manage_webhooks, :manage_federation) && !self_destruct } do |s|
s.item :dashboard, safe_join([fa_icon('tachometer fw'), t('admin.dashboard.title')]), admin_dashboard_path, if: -> { current_user.can?(:view_dashboard) }
s.item :settings, safe_join([fa_icon('cogs fw'), t('admin.settings.title')]), admin_settings_path, if: -> { current_user.can?(:manage_settings) }, highlights_on: %r{/admin/settings}
s.item :rules, safe_join([fa_icon('gavel fw'), t('admin.rules.title')]), admin_rules_path, highlights_on: %r{/admin/rules}, if: -> { current_user.can?(:manage_rules) }
diff --git a/config/routes.rb b/config/routes.rb
index 36f5967782ce8c..8c16d3c720ca81 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -85,10 +85,10 @@
devise_for :users, path: 'auth', format: false, controllers: {
omniauth_callbacks: 'auth/omniauth_callbacks',
- sessions: 'auth/sessions',
- registrations: 'auth/registrations',
- passwords: 'auth/passwords',
- confirmations: 'auth/confirmations',
+ sessions: 'auth/sessions',
+ registrations: 'auth/registrations',
+ passwords: 'auth/passwords',
+ confirmations: 'auth/confirmations',
}
get '/users/:username', to: redirect('/@%{username}'), constraints: lambda { |req| req.format.nil? || req.format.html? }
diff --git a/config/sidekiq.yml b/config/sidekiq.yml
index f1ba5651dd4e3e..3f9cbd9a7a5bef 100644
--- a/config/sidekiq.yml
+++ b/config/sidekiq.yml
@@ -7,6 +7,7 @@
- [mailers, 2]
- [pull]
- [scheduler]
+
:scheduler:
:listened_queues_only: true
:schedule:
diff --git a/config/webpack/rules/material_icons.js b/config/webpack/rules/material_icons.js
index f53445ef799e75..7ac1072b0aff84 100644
--- a/config/webpack/rules/material_icons.js
+++ b/config/webpack/rules/material_icons.js
@@ -1,12 +1,13 @@
module.exports = {
test: /\.svg$/,
- include: /node_modules\/@material-design-icons/,
+ include: /node_modules\/@material-symbols/,
issuer: /\.[jt]sx?$/,
use: [
{
loader: '@svgr/webpack',
options: {
svgo: false,
+ titleProp: true,
},
},
],
diff --git a/db/migrate/.rubocop.yml b/db/migrate/.rubocop.yml
new file mode 100644
index 00000000000000..4e23800dd14965
--- /dev/null
+++ b/db/migrate/.rubocop.yml
@@ -0,0 +1,4 @@
+inherit_from: ../../.rubocop.yml
+
+Naming/VariableNumber:
+ CheckSymbols: false
diff --git a/db/migrate/20190511134027_add_silenced_at_suspended_at_to_accounts.rb b/db/migrate/20190511134027_add_silenced_at_suspended_at_to_accounts.rb
index 7301e960d55da7..c9f0849557d532 100644
--- a/db/migrate/20190511134027_add_silenced_at_suspended_at_to_accounts.rb
+++ b/db/migrate/20190511134027_add_silenced_at_suspended_at_to_accounts.rb
@@ -19,7 +19,6 @@ def up
# Record suspend date of blocks and silences for users whose limitations match
# a domain block
DomainBlock.where(severity: [:silence, :suspend]).find_each do |block|
- scope = block.accounts
if block.suspend?
block.accounts.where(suspended: true).in_batches.update_all(suspended_at: block.created_at)
else
diff --git a/db/post_migrate/20190511152737_remove_suspended_silenced_account_fields.rb b/db/post_migrate/20190511152737_remove_suspended_silenced_account_fields.rb
index 615f35cd0d205c..7788431cd5af77 100644
--- a/db/post_migrate/20190511152737_remove_suspended_silenced_account_fields.rb
+++ b/db/post_migrate/20190511152737_remove_suspended_silenced_account_fields.rb
@@ -18,7 +18,6 @@ def up
# Record suspend date of blocks and silences for users whose limitations match
# a domain block
DomainBlock.where(severity: [:silence, :suspend]).find_each do |block|
- scope = block.accounts
if block.suspend?
block.accounts.where(suspended: true).in_batches.update_all(suspended_at: block.created_at)
else
diff --git a/docker-compose.yml b/docker-compose.yml
index d19f278f75fe0f..bcfa4c85f1bf3a 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -111,7 +111,7 @@ services:
test: ['CMD-SHELL', "ps aux | grep '[s]idekiq\ 6' || false"]
## Uncomment to enable federation with tor instances along with adding the following ENV variables
- ## http_proxy=http://privoxy:8118
+ ## http_hidden_proxy=http://privoxy:8118
## ALLOW_ACCESS_TO_HIDDEN_SERVICE=true
# tor:
# image: sirboops/tor
diff --git a/jest.config.js b/jest.config.js
index 0b928b63a97fd2..24dcf6afa4bb8d 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -19,6 +19,9 @@ const config = {
],
coverageDirectory: '/coverage',
moduleDirectories: ['/node_modules', '/app/javascript'],
+ moduleNameMapper: {
+ '\\.svg$': '/app/javascript/__mocks__/svg.js',
+ },
};
module.exports = config;
diff --git a/lib/active_record/batches.rb b/lib/active_record/batches.rb
index 91e50cc43dac09..7960b6e10de743 100644
--- a/lib/active_record/batches.rb
+++ b/lib/active_record/batches.rb
@@ -13,7 +13,7 @@ def pluck_each(*column_names)
column_names.unshift(primary_key)
- relation = relation.reorder(batch_order(order)).limit(batch_limit)
+ relation = relation.reorder(build_batch_orders(order).to_h).limit(batch_limit)
relation.skip_query_cache!
batch_relation = relation
diff --git a/lib/mastodon/cli/domains.rb b/lib/mastodon/cli/domains.rb
index d17b25368181b6..329f1716725b52 100644
--- a/lib/mastodon/cli/domains.rb
+++ b/lib/mastodon/cli/domains.rb
@@ -125,7 +125,7 @@ def crawl(start = nil)
failed = Concurrent::AtomicFixnum.new(0)
start_at = Time.now.to_f
seed = start ? [start] : Instance.pluck(:domain)
- blocked_domains = /\.?(#{DomainBlock.where(severity: 1).pluck(:domain).map { |domain| Regexp.escape(domain) }.join('|')})$/
+ blocked_domains = /\.?(#{Regexp.union(domain_block_suspended_domains).source})$/
progress = create_progress_bar
pool = Concurrent::ThreadPoolExecutor.new(min_threads: 0, max_threads: options[:concurrency], idletime: 10, auto_terminate: true, max_queue: 0)
@@ -189,6 +189,10 @@ def crawl(start = nil)
private
+ def domain_block_suspended_domains
+ DomainBlock.suspend.pluck(:domain)
+ end
+
def stats_to_summary(stats, processed, failed, start_at)
stats.compact!
diff --git a/lib/mastodon/cli/main.rb b/lib/mastodon/cli/main.rb
index 1594eadce81e6a..64f1646f491091 100644
--- a/lib/mastodon/cli/main.rb
+++ b/lib/mastodon/cli/main.rb
@@ -65,7 +65,6 @@ class Main < Base
desc 'maintenance SUBCOMMAND ...ARGS', 'Various maintenance utilities'
subcommand 'maintenance', Maintenance
- option :dry_run, type: :boolean
desc 'self-destruct', 'Erase the server from the federation'
long_desc <<~LONG_DESC
Erase the server from the federation by broadcasting account delete
@@ -92,55 +91,37 @@ def self_destruct
prompt = TTY::Prompt.new
- exit(1) unless prompt.ask('Type in the domain of the server to confirm:', required: true) == Rails.configuration.x.local_domain
-
- unless dry_run?
- prompt.warn('This operation WILL NOT be reversible. It can also take a long time.')
- prompt.warn('While the data won\'t be erased locally, the server will be in a BROKEN STATE afterwards.')
- prompt.warn('A running Sidekiq process is required. Do not shut it down until queues clear.')
-
- exit(1) if prompt.no?('Are you sure you want to proceed?')
- end
+ if SelfDestructHelper.self_destruct?
+ prompt.ok('Self-destruct mode is already enabled for this Mastodon server')
- inboxes = Account.inboxes
- processed = 0
+ pending_accounts = Account.local.without_suspended.count + Account.local.suspended.joins(:deletion_request).count
+ sidekiq_stats = Sidekiq::Stats.new
- Setting.registrations_mode = 'none' unless dry_run?
+ if pending_accounts.positive?
+ prompt.warn("#{pending_accounts} accounts are still pending deletion.")
+ elsif sidekiq_stats.enqueued.positive?
+ prompt.warn('Deletion notices are still being processed')
+ elsif sidekiq_stats.retry_size.positive?
+ prompt.warn('At least one delivery attempt for each deletion notice has been made, but some have failed and are scheduled for retry')
+ else
+ prompt.ok('Every deletion notice has been sent! You can safely delete all data and decomission your servers!')
+ end
- if inboxes.empty?
- Account.local.without_suspended.in_batches.update_all(suspended_at: Time.now.utc, suspension_origin: :local) unless dry_run?
- prompt.ok('It seems like your server has not federated with anything')
- prompt.ok('You can shut it down and delete it any time')
- return
+ exit(0)
end
- prompt.warn('Do NOT interrupt this process...')
-
- delete_account = lambda do |account|
- payload = ActiveModelSerializers::SerializableResource.new(
- account,
- serializer: ActivityPub::DeleteActorSerializer,
- adapter: ActivityPub::Adapter
- ).as_json
-
- json = Oj.dump(ActivityPub::LinkedDataSignature.new(payload).sign!(account))
-
- unless dry_run?
- ActivityPub::DeliveryWorker.push_bulk(inboxes, limit: 1_000) do |inbox_url|
- [json, account.id, inbox_url]
- end
-
- account.suspend!(block_email: false)
- end
+ exit(1) unless prompt.ask('Type in the domain of the server to confirm:', required: true) == Rails.configuration.x.local_domain
- processed += 1
- end
+ prompt.warn('This operation WILL NOT be reversible.')
+ prompt.warn('While the data won\'t be erased locally, the server will be in a BROKEN STATE afterwards.')
+ prompt.warn('The deletion process itself may take a long time, and will be handled by Sidekiq, so do not shut it down until it has finished (you will be able to re-run this command to see the state of the self-destruct process).')
- Account.local.without_suspended.find_each { |account| delete_account.call(account) }
- Account.local.suspended.joins(:deletion_request).find_each { |account| delete_account.call(account) }
+ exit(1) if prompt.no?('Are you sure you want to proceed?')
- prompt.ok("Queued #{inboxes.size * processed} items into Sidekiq for #{processed} accounts#{dry_run_mode_suffix}")
- prompt.ok('Wait until Sidekiq processes all items, then you can shut everything down and delete the data')
+ self_destruct_value = Rails.application.message_verifier('self-destruct').generate(Rails.configuration.x.local_domain)
+ prompt.ok('To switch Mastodon to self-destruct mode, add the following variable to your evironment (e.g. by adding a line to your `.env.production`) and restart all Mastodon processes:')
+ prompt.ok(" SELF_DESTRUCT=#{self_destruct_value}")
+ prompt.ok("\nYou can re-run this command to see the state of the self-destruct process.")
rescue TTY::Reader::InputInterrupt
exit(1)
end
diff --git a/lib/mastodon/cli/upgrade.rb b/lib/mastodon/cli/upgrade.rb
index 52b5540c40afdb..cf839868448762 100644
--- a/lib/mastodon/cli/upgrade.rb
+++ b/lib/mastodon/cli/upgrade.rb
@@ -125,27 +125,12 @@ def upgrade_storage_filesystem(progress, attachment, style)
progress.log("Moving #{previous_path} to #{upgraded_path}") if options[:verbose]
begin
- unless dry_run?
- FileUtils.mkdir_p(File.dirname(upgraded_path))
- FileUtils.mv(previous_path, upgraded_path)
-
- begin
- FileUtils.rmdir(File.dirname(previous_path), parents: true)
- rescue Errno::ENOTEMPTY
- # OK
- end
- end
+ move_previous_to_upgraded
rescue => e
progress.log(pastel.red("Error processing #{previous_path}: #{e}"))
success = false
- unless dry_run?
- begin
- FileUtils.rmdir(File.dirname(upgraded_path), parents: true)
- rescue Errno::ENOTEMPTY
- # OK
- end
- end
+ remove_directory
end
end
@@ -155,5 +140,28 @@ def upgrade_storage_filesystem(progress, attachment, style)
attachment.instance_write(:storage_schema_version, previous_storage_schema_version)
success
end
+
+ def move_previous_to_upgraded(previous_path, upgraded_path)
+ return if dry_run?
+
+ FileUtils.mkdir_p(File.dirname(upgraded_path))
+ FileUtils.mv(previous_path, upgraded_path)
+
+ begin
+ FileUtils.rmdir(File.dirname(previous_path), parents: true)
+ rescue Errno::ENOTEMPTY
+ # OK
+ end
+ end
+
+ def remove_directory(path)
+ return if dry_run?
+
+ begin
+ FileUtils.rmdir(File.dirname(path), parents: true)
+ rescue Errno::ENOTEMPTY
+ # OK
+ end
+ end
end
end
diff --git a/lib/mastodon/migration_helpers.rb b/lib/mastodon/migration_helpers.rb
index c382b5fbd5b839..a92a8767ce3957 100644
--- a/lib/mastodon/migration_helpers.rb
+++ b/lib/mastodon/migration_helpers.rb
@@ -37,7 +37,6 @@
# This is bad form, but there are enough differences that it's impractical to do
# otherwise:
-# rubocop:disable all
module Mastodon
module MigrationHelpers
@@ -989,5 +988,3 @@ def extract_foreign_key_action(specifier)
end
end
end
-
-# rubocop:enable all
diff --git a/lib/mastodon/redis_config.rb b/lib/mastodon/redis_config.rb
index 2dbe76f83cd204..e885712f896f3b 100644
--- a/lib/mastodon/redis_config.rb
+++ b/lib/mastodon/redis_config.rb
@@ -35,9 +35,11 @@ def setup_redis_env_url(prefix = nil, defaults = true)
url: ENV['CACHE_REDIS_URL'],
expires_in: 10.minutes,
namespace: cache_namespace,
- pool_size: Sidekiq.server? ? Sidekiq[:concurrency] : Integer(ENV['MAX_THREADS'] || 5),
- pool_timeout: 5,
connect_timeout: 5,
+ pool: {
+ size: Sidekiq.server? ? Sidekiq[:concurrency] : Integer(ENV['MAX_THREADS'] || 5),
+ timeout: 5,
+ },
}.freeze
REDIS_SIDEKIQ_PARAMS = {
diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb
index 0a11420756e154..b55873a3c926a8 100644
--- a/lib/mastodon/version.rb
+++ b/lib/mastodon/version.rb
@@ -9,7 +9,7 @@ def major
end
def minor
- 2
+ 3
end
def patch
@@ -17,7 +17,7 @@ def patch
end
def default_prerelease
- ''
+ 'alpha.0'
end
def prerelease
diff --git a/lib/tasks/mastodon.rake b/lib/tasks/mastodon.rake
index f68d1cf1f8fbeb..f2a90cd92e3a97 100644
--- a/lib/tasks/mastodon.rake
+++ b/lib/tasks/mastodon.rake
@@ -17,6 +17,8 @@ namespace :mastodon do
ENV.delete('SIDEKIQ_REDIS_URL')
begin
+ errors = false
+
prompt.say('Your instance is identified by its domain name. Changing it afterward will break things.')
env['LOCAL_DOMAIN'] = prompt.ask('Domain name:') do |q|
q.required true
@@ -95,7 +97,12 @@ namespace :mastodon do
rescue => e
prompt.error 'Database connection could not be established with this configuration, try again.'
prompt.error e.message
- break unless prompt.yes?('Try again?')
+ unless prompt.yes?('Try again?')
+ return prompt.warn 'Nothing saved. Bye!' unless prompt.yes?('Continue anyway?')
+
+ errors = true
+ break
+ end
end
end
@@ -135,7 +142,13 @@ namespace :mastodon do
rescue => e
prompt.error 'Redis connection could not be established with this configuration, try again.'
prompt.error e.message
- break unless prompt.yes?('Try again?')
+
+ unless prompt.yes?('Try again?')
+ return prompt.warn 'Nothing saved. Bye!' unless prompt.yes?('Continue anyway?')
+
+ errors = true
+ break
+ end
end
end
@@ -420,7 +433,13 @@ namespace :mastodon do
rescue => e
prompt.error 'E-mail could not be sent with this configuration, try again.'
prompt.error e.message
- break unless prompt.yes?('Try again?')
+
+ unless prompt.yes?('Try again?')
+ return prompt.warn 'Nothing saved. Bye!' unless prompt.yes?('Continue anyway?')
+
+ errors = true
+ break
+ end
end
end
@@ -466,6 +485,7 @@ namespace :mastodon do
prompt.ok 'Done!'
else
prompt.error 'That failed! Perhaps your configuration is not right'
+ errors = true
end
end
@@ -482,12 +502,17 @@ namespace :mastodon do
prompt.say 'Done!'
else
prompt.error 'That failed! Maybe you need swap space?'
+ errors = true
end
end
end
prompt.say "\n"
- prompt.ok 'All done! You can now power on the Mastodon server 🐘'
+ if errors
+ prompt.warn 'Your Mastodon server is set up, but there were some errors along the way, you may have to fix them.'
+ else
+ prompt.ok 'All done! You can now power on the Mastodon server 🐘'
+ end
prompt.say "\n"
if db_connection_works && prompt.yes?('Do you want to create an admin user straight away?')
diff --git a/package.json b/package.json
index 2b26f97a2f4005..40578504e822bb 100644
--- a/package.json
+++ b/package.json
@@ -44,8 +44,8 @@
"@formatjs/intl-pluralrules": "^5.2.2",
"@gamestdio/websocket": "^0.3.2",
"@github/webauthn-json": "^2.1.1",
- "@material-design-icons/svg": "^0.14.10",
- "@rails/ujs": "^7.0.6",
+ "@material-symbols/svg-600": "^0.13.1",
+ "@rails/ujs": "^7.1.1",
"@reduxjs/toolkit": "^1.9.5",
"@renchap/compression-webpack-plugin": "^6.1.4",
"@svgr/webpack": "^5.5.0",
@@ -81,6 +81,7 @@
"fuzzysort": "^2.0.4",
"glob": "^10.2.6",
"history": "^4.10.1",
+ "hoist-non-react-statics": "^3.3.2",
"http-link-header": "^1.1.1",
"immutable": "^4.3.0",
"imports-loader": "^1.2.0",
@@ -99,7 +100,7 @@
"pg-connection-string": "^2.6.0",
"postcss": "^8.4.24",
"postcss-loader": "^4.3.0",
- "prom-client": "^14.2.0",
+ "prom-client": "^15.0.0",
"prop-types": "^15.8.1",
"punycode": "^2.3.0",
"react": "^18.2.0",
@@ -114,8 +115,8 @@
"react-overlays": "^5.2.1",
"react-redux": "^8.0.4",
"react-redux-loading-bar": "^5.0.4",
- "react-router": "^4.3.1",
- "react-router-dom": "^4.1.1",
+ "react-router": "^5.3.4",
+ "react-router-dom": "^5.3.4",
"react-router-scroll-4": "^1.0.0-beta.1",
"react-select": "^5.7.3",
"react-sparklines": "^1.7.0",
@@ -161,6 +162,7 @@
"@types/emoji-mart": "^3.0.9",
"@types/escape-html": "^1.0.2",
"@types/express": "^4.17.17",
+ "@types/hoist-non-react-statics": "^3.3.1",
"@types/http-link-header": "^1.0.3",
"@types/intl": "^1.2.0",
"@types/jest": "^29.5.2",
@@ -175,8 +177,9 @@
"@types/react-dom": "^18.2.4",
"@types/react-helmet": "^6.1.6",
"@types/react-immutable-proptypes": "^2.1.0",
- "@types/react-motion": "^0.0.34",
+ "@types/react-motion": "^0.0.36",
"@types/react-overlays": "^3.1.0",
+ "@types/react-router": "^5.1.20",
"@types/react-router-dom": "^5.3.3",
"@types/react-select": "^5.0.1",
"@types/react-sparklines": "^1.7.2",
@@ -196,7 +199,7 @@
"eslint-config-prettier": "^9.0.0",
"eslint-import-resolver-typescript": "^3.5.5",
"eslint-plugin-formatjs": "^4.10.1",
- "eslint-plugin-import": "~2.28.0",
+ "eslint-plugin-import": "~2.29.0",
"eslint-plugin-jsdoc": "^46.1.0",
"eslint-plugin-jsx-a11y": "~6.7.1",
"eslint-plugin-prettier": "^5.0.0",
diff --git a/spec/config/initializers/rack_attack_spec.rb b/spec/config/initializers/rack_attack_spec.rb
index 7cd4ac76bbb3ab..c9ce9e27d023a9 100644
--- a/spec/config/initializers/rack_attack_spec.rb
+++ b/spec/config/initializers/rack_attack_spec.rb
@@ -16,37 +16,63 @@ def app
# https://github.com/rack/rack-attack/blob/v6.6.1/lib/rack/attack/cache.rb#L64-L66
# So we want to minimize `Time.now.to_i % period`
- travel_to Time.zone.at((Time.now.to_i / period.seconds).to_i * period.seconds)
+ travel_to Time.zone.at(counter_prefix * period.seconds)
end
context 'when the number of requests is lower than the limit' do
+ before do
+ below_limit.times { increment_counter }
+ end
+
it 'does not change the request status' do
- limit.times do
- request.call
- expect(response).to_not have_http_status(429)
- end
+ expect { request.call }.to change { throttle_count }.by(1)
+
+ expect(response).to_not have_http_status(429)
end
end
context 'when the number of requests is higher than the limit' do
+ before do
+ above_limit.times { increment_counter }
+ end
+
it 'returns http too many requests after limit and returns to normal status after period' do
- (limit * 2).times do |i|
- request.call
- expect(response).to have_http_status(429) if i > limit
- end
+ expect { request.call }.to change { throttle_count }.by(1)
+ expect(response).to have_http_status(429)
travel period
- request.call
+ expect { request.call }.to change { throttle_count }.by(1)
expect(response).to_not have_http_status(429)
end
end
+
+ def below_limit
+ limit - 1
+ end
+
+ def above_limit
+ limit * 2
+ end
+
+ def throttle_count
+ described_class.cache.read("#{counter_prefix}:#{throttle}:#{remote_ip}") || 0
+ end
+
+ def counter_prefix
+ (Time.now.to_i / period.seconds).to_i
+ end
+
+ def increment_counter
+ described_class.cache.count("#{throttle}:#{remote_ip}", period)
+ end
end
let(:remote_ip) { '1.2.3.5' }
describe 'throttle excessive sign-up requests by IP address' do
context 'when accessed through the website' do
+ let(:throttle) { 'throttle_sign_up_attempts/ip' }
let(:limit) { 25 }
let(:period) { 5.minutes }
let(:request) { -> { post path, headers: { 'REMOTE_ADDR' => remote_ip } } }
@@ -65,6 +91,7 @@ def app
end
context 'when accessed through the API' do
+ let(:throttle) { 'throttle_api_sign_up' }
let(:limit) { 5 }
let(:period) { 30.minutes }
let(:request) { -> { post path, headers: { 'REMOTE_ADDR' => remote_ip } } }
@@ -87,6 +114,7 @@ def app
end
describe 'throttle excessive sign-in requests by IP address' do
+ let(:throttle) { 'throttle_login_attempts/ip' }
let(:limit) { 25 }
let(:period) { 5.minutes }
let(:request) { -> { post path, headers: { 'REMOTE_ADDR' => remote_ip } } }
diff --git a/spec/controllers/accounts_controller_spec.rb b/spec/controllers/accounts_controller_spec.rb
index 5a8585b0697b99..cc9e3198b6fbdb 100644
--- a/spec/controllers/accounts_controller_spec.rb
+++ b/spec/controllers/accounts_controller_spec.rb
@@ -7,468 +7,319 @@
let(:account) { Fabricate(:account) }
- shared_examples 'cacheable response' do
- it 'does not set cookies' do
- expect(response.cookies).to be_empty
- expect(response.headers['Set-Cookies']).to be_nil
- end
-
- it 'does not set sessions' do
- expect(session).to be_empty
- end
+ shared_examples 'unapproved account check' do
+ before { account.user.update(approved: false) }
- it 'returns Vary header' do
- expect(response.headers['Vary']).to include 'Accept'
- end
+ it 'returns http not found' do
+ get :show, params: { username: account.username, format: format }
- it 'returns public Cache-Control header' do
- expect(response.headers['Cache-Control']).to include 'public'
+ expect(response).to have_http_status(404)
end
end
- describe 'GET #show' do
- let(:format) { 'html' }
-
- let!(:status) { Fabricate(:status, account: account) }
- let!(:status_reply) { Fabricate(:status, account: account, thread: Fabricate(:status)) }
- let!(:status_self_reply) { Fabricate(:status, account: account, thread: status) }
- let!(:status_media) { Fabricate(:status, account: account) }
- let!(:status_pinned) { Fabricate(:status, account: account) }
- let!(:status_private) { Fabricate(:status, account: account, visibility: :private) }
- let!(:status_direct) { Fabricate(:status, account: account, visibility: :direct) }
- let!(:status_reblog) { Fabricate(:status, account: account, reblog: Fabricate(:status)) }
-
+ shared_examples 'permanently suspended account check' do
before do
- status_media.media_attachments << Fabricate(:media_attachment, account: account, type: :image)
- account.pinned_statuses << status_pinned
- account.pinned_statuses << status_private
+ account.suspend!
+ account.deletion_request.destroy
end
- shared_examples 'preliminary checks' do
- context 'when account is not approved' do
- before do
- account.user.update(approved: false)
- end
+ it 'returns http gone' do
+ get :show, params: { username: account.username, format: format }
- it 'returns http not found' do
- get :show, params: { username: account.username, format: format }
- expect(response).to have_http_status(404)
- end
- end
+ expect(response).to have_http_status(410)
end
+ end
- context 'with HTML' do
- let(:format) { 'html' }
-
- it_behaves_like 'preliminary checks'
-
- context 'when account is permanently suspended' do
- before do
- account.suspend!
- account.deletion_request.destroy
- end
-
- it 'returns http gone' do
- get :show, params: { username: account.username, format: format }
- expect(response).to have_http_status(410)
- end
- end
-
- context 'when account is temporarily suspended' do
- before do
- account.suspend!
- end
-
- it 'returns http forbidden' do
- get :show, params: { username: account.username, format: format }
- expect(response).to have_http_status(403)
- end
- end
+ shared_examples 'temporarily suspended account check' do |code: 403|
+ before { account.suspend! }
- shared_examples 'common response characteristics' do
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
+ it 'returns appropriate http response code' do
+ get :show, params: { username: account.username, format: format }
- it 'returns Link header' do
- expect(response.headers['Link'].to_s).to include ActivityPub::TagManager.instance.uri_for(account)
- end
-
- it 'renders show template' do
- expect(response).to render_template(:show)
- end
- end
+ expect(response).to have_http_status(code)
+ end
+ end
- context 'with a normal account in an HTML request' do
- before do
- get :show, params: { username: account.username, format: format }
- end
+ describe 'GET #show' do
+ context 'with basic account status checks' do
+ context 'with HTML' do
+ let(:format) { 'html' }
- it_behaves_like 'common response characteristics'
+ it_behaves_like 'unapproved account check'
+ it_behaves_like 'permanently suspended account check'
+ it_behaves_like 'temporarily suspended account check'
end
- context 'with replies' do
- before do
- allow(controller).to receive(:replies_requested?).and_return(true)
- get :show, params: { username: account.username, format: format }
- end
+ context 'with JSON' do
+ let(:format) { 'json' }
- it_behaves_like 'common response characteristics'
+ it_behaves_like 'unapproved account check'
+ it_behaves_like 'permanently suspended account check'
+ it_behaves_like 'temporarily suspended account check', code: 200
end
- context 'with media' do
- before do
- allow(controller).to receive(:media_requested?).and_return(true)
- get :show, params: { username: account.username, format: format }
- end
+ context 'with RSS' do
+ let(:format) { 'rss' }
- it_behaves_like 'common response characteristics'
- end
-
- context 'with tag' do
- let(:tag) { Fabricate(:tag) }
-
- let!(:status_tag) { Fabricate(:status, account: account) }
-
- before do
- allow(controller).to receive(:tag_requested?).and_return(true)
- status_tag.tags << tag
- get :show, params: { username: account.username, format: format, tag: tag.to_param }
- end
-
- it_behaves_like 'common response characteristics'
+ it_behaves_like 'unapproved account check'
+ it_behaves_like 'permanently suspended account check'
+ it_behaves_like 'temporarily suspended account check'
end
end
- context 'with JSON' do
- let(:authorized_fetch_mode) { false }
- let(:format) { 'json' }
+ context 'with existing statuses' do
+ let!(:status) { Fabricate(:status, account: account) }
+ let!(:status_reply) { Fabricate(:status, account: account, thread: Fabricate(:status)) }
+ let!(:status_self_reply) { Fabricate(:status, account: account, thread: status) }
+ let!(:status_media) { Fabricate(:status, account: account) }
+ let!(:status_pinned) { Fabricate(:status, account: account) }
+ let!(:status_private) { Fabricate(:status, account: account, visibility: :private) }
+ let!(:status_direct) { Fabricate(:status, account: account, visibility: :direct) }
+ let!(:status_reblog) { Fabricate(:status, account: account, reblog: Fabricate(:status)) }
before do
- allow(controller).to receive(:authorized_fetch_mode?).and_return(authorized_fetch_mode)
+ status_media.media_attachments << Fabricate(:media_attachment, account: account, type: :image)
+ account.pinned_statuses << status_pinned
+ account.pinned_statuses << status_private
end
- it_behaves_like 'preliminary checks'
+ context 'with HTML' do
+ let(:format) { 'html' }
- context 'when account is suspended permanently' do
- before do
- account.suspend!
- account.deletion_request.destroy
- end
-
- it 'returns http gone' do
- get :show, params: { username: account.username, format: format }
- expect(response).to have_http_status(410)
- end
- end
-
- context 'when account is suspended temporarily' do
- before do
- account.suspend!
- end
+ shared_examples 'common HTML response' do
+ it 'returns a standard HTML response', :aggregate_failures do
+ expect(response).to have_http_status(200)
- it 'returns http success' do
- get :show, params: { username: account.username, format: format }
- expect(response).to have_http_status(200)
- end
- end
+ expect(response.headers['Link'].to_s).to include ActivityPub::TagManager.instance.uri_for(account)
- context 'with a normal account in a JSON request' do
- before do
- get :show, params: { username: account.username, format: format }
+ expect(response).to render_template(:show)
+ end
end
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
+ context 'with a normal account in an HTML request' do
+ before do
+ get :show, params: { username: account.username, format: format }
+ end
- it 'returns application/activity+json' do
- expect(response.media_type).to eq 'application/activity+json'
+ it_behaves_like 'common HTML response'
end
- it_behaves_like 'cacheable response'
+ context 'with replies' do
+ before do
+ allow(controller).to receive(:replies_requested?).and_return(true)
+ get :show, params: { username: account.username, format: format }
+ end
- it 'renders account' do
- json = body_as_json
- expect(json).to include(:id, :type, :preferredUsername, :inbox, :publicKey, :name, :summary)
+ it_behaves_like 'common HTML response'
end
- context 'with authorized fetch mode' do
- let(:authorized_fetch_mode) { true }
-
- it 'returns http unauthorized' do
- expect(response).to have_http_status(401)
+ context 'with media' do
+ before do
+ allow(controller).to receive(:media_requested?).and_return(true)
+ get :show, params: { username: account.username, format: format }
end
- end
- end
-
- context 'when signed in' do
- let(:user) { Fabricate(:user) }
- before do
- sign_in(user)
- get :show, params: { username: account.username, format: format }
+ it_behaves_like 'common HTML response'
end
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
+ context 'with tag' do
+ let(:tag) { Fabricate(:tag) }
- it 'returns application/activity+json' do
- expect(response.media_type).to eq 'application/activity+json'
- end
+ let!(:status_tag) { Fabricate(:status, account: account) }
- it 'returns private Cache-Control header' do
- expect(response.headers['Cache-Control']).to include 'private'
- end
+ before do
+ allow(controller).to receive(:tag_requested?).and_return(true)
+ status_tag.tags << tag
+ get :show, params: { username: account.username, format: format, tag: tag.to_param }
+ end
- it 'renders account' do
- json = body_as_json
- expect(json).to include(:id, :type, :preferredUsername, :inbox, :publicKey, :name, :summary)
+ it_behaves_like 'common HTML response'
end
end
- context 'with signature' do
- let(:remote_account) { Fabricate(:account, domain: 'example.com') }
+ context 'with JSON' do
+ let(:authorized_fetch_mode) { false }
+ let(:format) { 'json' }
before do
- allow(controller).to receive(:signed_request_actor).and_return(remote_account)
- get :show, params: { username: account.username, format: format }
- end
-
- it 'returns http success' do
- expect(response).to have_http_status(200)
+ allow(controller).to receive(:authorized_fetch_mode?).and_return(authorized_fetch_mode)
end
- it 'returns application/activity+json' do
- expect(response.media_type).to eq 'application/activity+json'
- end
-
- it_behaves_like 'cacheable response'
-
- it 'renders account' do
- json = body_as_json
- expect(json).to include(:id, :type, :preferredUsername, :inbox, :publicKey, :name, :summary)
- end
-
- context 'with authorized fetch mode' do
- let(:authorized_fetch_mode) { true }
+ context 'with a normal account in a JSON request' do
+ before do
+ get :show, params: { username: account.username, format: format }
+ end
- it 'returns http success' do
+ it 'returns a JSON version of the account', :aggregate_failures do
expect(response).to have_http_status(200)
- end
- it 'returns application/activity+json' do
expect(response.media_type).to eq 'application/activity+json'
- end
- it 'returns private Cache-Control header' do
- expect(response.headers['Cache-Control']).to include 'private'
+ expect(body_as_json).to include(:id, :type, :preferredUsername, :inbox, :publicKey, :name, :summary)
end
- it 'returns Vary header with Signature' do
- expect(response.headers['Vary']).to include 'Signature'
- end
-
- it 'renders account' do
- json = body_as_json
- expect(json).to include(:id, :type, :preferredUsername, :inbox, :publicKey, :name, :summary)
- end
- end
- end
- end
+ it_behaves_like 'cacheable response', expects_vary: 'Accept, Accept-Language, Cookie'
- context 'with RSS' do
- let(:format) { 'rss' }
+ context 'with authorized fetch mode' do
+ let(:authorized_fetch_mode) { true }
- it_behaves_like 'preliminary checks'
-
- context 'when account is permanently suspended' do
- before do
- account.suspend!
- account.deletion_request.destroy
- end
-
- it 'returns http gone' do
- get :show, params: { username: account.username, format: format }
- expect(response).to have_http_status(410)
- end
- end
-
- context 'when account is temporarily suspended' do
- before do
- account.suspend!
- end
-
- it 'returns http forbidden' do
- get :show, params: { username: account.username, format: format }
- expect(response).to have_http_status(403)
- end
- end
-
- shared_examples 'common response characteristics' do
- it 'returns http success' do
- expect(response).to have_http_status(200)
+ it 'returns http unauthorized' do
+ expect(response).to have_http_status(401)
+ end
+ end
end
- it_behaves_like 'cacheable response'
- end
+ context 'when signed in' do
+ let(:user) { Fabricate(:user) }
- context 'with a normal account in an RSS request' do
- before do
- get :show, params: { username: account.username, format: format }
- end
-
- it_behaves_like 'common response characteristics'
+ before do
+ sign_in(user)
+ get :show, params: { username: account.username, format: format }
+ end
- it 'renders public status' do
- expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status))
- end
+ it 'returns a private JSON version of the account', :aggregate_failures do
+ expect(response).to have_http_status(200)
- it 'renders self-reply' do
- expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_self_reply))
- end
+ expect(response.media_type).to eq 'application/activity+json'
- it 'renders status with media' do
- expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_media))
- end
+ expect(response.headers['Cache-Control']).to include 'private'
- it 'does not render reblog' do
- expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reblog.reblog))
+ expect(body_as_json).to include(:id, :type, :preferredUsername, :inbox, :publicKey, :name, :summary)
+ end
end
- it 'does not render private status' do
- expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_private))
- end
+ context 'with signature' do
+ let(:remote_account) { Fabricate(:account, domain: 'example.com') }
- it 'does not render direct status' do
- expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_direct))
- end
+ before do
+ allow(controller).to receive(:signed_request_actor).and_return(remote_account)
+ get :show, params: { username: account.username, format: format }
+ end
- it 'does not render reply to someone else' do
- expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reply))
- end
- end
+ it 'returns a JSON version of the account', :aggregate_failures do
+ expect(response).to have_http_status(200)
- context 'with replies' do
- before do
- allow(controller).to receive(:replies_requested?).and_return(true)
- get :show, params: { username: account.username, format: format }
- end
+ expect(response.media_type).to eq 'application/activity+json'
- it_behaves_like 'common response characteristics'
+ expect(body_as_json).to include(:id, :type, :preferredUsername, :inbox, :publicKey, :name, :summary)
+ end
- it 'renders public status' do
- expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status))
- end
+ it_behaves_like 'cacheable response', expects_vary: 'Accept, Accept-Language, Cookie'
- it 'renders self-reply' do
- expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_self_reply))
- end
+ context 'with authorized fetch mode' do
+ let(:authorized_fetch_mode) { true }
- it 'renders status with media' do
- expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_media))
- end
+ it 'returns a private signature JSON version of the account', :aggregate_failures do
+ expect(response).to have_http_status(200)
- it 'does not render reblog' do
- expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reblog.reblog))
- end
+ expect(response.media_type).to eq 'application/activity+json'
- it 'does not render private status' do
- expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_private))
- end
+ expect(response.headers['Cache-Control']).to include 'private'
- it 'does not render direct status' do
- expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_direct))
- end
+ expect(response.headers['Vary']).to include 'Signature'
- it 'renders reply to someone else' do
- expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_reply))
+ expect(body_as_json).to include(:id, :type, :preferredUsername, :inbox, :publicKey, :name, :summary)
+ end
+ end
end
end
- context 'with media' do
- before do
- allow(controller).to receive(:media_requested?).and_return(true)
- get :show, params: { username: account.username, format: format }
- end
-
- it_behaves_like 'common response characteristics'
+ context 'with RSS' do
+ let(:format) { 'rss' }
- it 'does not render public status' do
- expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status))
- end
-
- it 'does not render self-reply' do
- expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_self_reply))
- end
+ shared_examples 'common RSS response' do
+ it 'returns http success' do
+ expect(response).to have_http_status(200)
+ end
- it 'renders status with media' do
- expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_media))
+ it_behaves_like 'cacheable response', expects_vary: 'Accept, Accept-Language, Cookie'
end
- it 'does not render reblog' do
- expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reblog.reblog))
- end
+ context 'with a normal account in an RSS request' do
+ before do
+ get :show, params: { username: account.username, format: format }
+ end
- it 'does not render private status' do
- expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_private))
- end
+ it_behaves_like 'common RSS response'
- it 'does not render direct status' do
- expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_direct))
- end
-
- it 'does not render reply to someone else' do
- expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reply))
+ it 'responds with correct statuses', :aggregate_failures do
+ expect(response.body).to include_status_tag(status_media)
+ expect(response.body).to include_status_tag(status_self_reply)
+ expect(response.body).to include_status_tag(status)
+ expect(response.body).to_not include_status_tag(status_direct)
+ expect(response.body).to_not include_status_tag(status_private)
+ expect(response.body).to_not include_status_tag(status_reblog.reblog)
+ expect(response.body).to_not include_status_tag(status_reply)
+ end
end
- end
-
- context 'with tag' do
- let(:tag) { Fabricate(:tag) }
-
- let!(:status_tag) { Fabricate(:status, account: account) }
- before do
- allow(controller).to receive(:tag_requested?).and_return(true)
- status_tag.tags << tag
- get :show, params: { username: account.username, format: format, tag: tag.to_param }
- end
+ context 'with replies' do
+ before do
+ allow(controller).to receive(:replies_requested?).and_return(true)
+ get :show, params: { username: account.username, format: format }
+ end
- it_behaves_like 'common response characteristics'
+ it_behaves_like 'common RSS response'
- it 'does not render public status' do
- expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status))
+ it 'responds with correct statuses with replies', :aggregate_failures do
+ expect(response.body).to include_status_tag(status_media)
+ expect(response.body).to include_status_tag(status_reply)
+ expect(response.body).to include_status_tag(status_self_reply)
+ expect(response.body).to include_status_tag(status)
+ expect(response.body).to_not include_status_tag(status_direct)
+ expect(response.body).to_not include_status_tag(status_private)
+ expect(response.body).to_not include_status_tag(status_reblog.reblog)
+ end
end
- it 'does not render self-reply' do
- expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_self_reply))
- end
+ context 'with media' do
+ before do
+ allow(controller).to receive(:media_requested?).and_return(true)
+ get :show, params: { username: account.username, format: format }
+ end
- it 'does not render status with media' do
- expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_media))
- end
+ it_behaves_like 'common RSS response'
- it 'does not render reblog' do
- expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reblog.reblog))
+ it 'responds with correct statuses with media', :aggregate_failures do
+ expect(response.body).to include_status_tag(status_media)
+ expect(response.body).to_not include_status_tag(status_direct)
+ expect(response.body).to_not include_status_tag(status_private)
+ expect(response.body).to_not include_status_tag(status_reblog.reblog)
+ expect(response.body).to_not include_status_tag(status_reply)
+ expect(response.body).to_not include_status_tag(status_self_reply)
+ expect(response.body).to_not include_status_tag(status)
+ end
end
- it 'does not render private status' do
- expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_private))
- end
+ context 'with tag' do
+ let(:tag) { Fabricate(:tag) }
- it 'does not render direct status' do
- expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_direct))
- end
+ let!(:status_tag) { Fabricate(:status, account: account) }
- it 'does not render reply to someone else' do
- expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reply))
- end
+ before do
+ allow(controller).to receive(:tag_requested?).and_return(true)
+ status_tag.tags << tag
+ get :show, params: { username: account.username, format: format, tag: tag.to_param }
+ end
- it 'renders status with tag' do
- expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_tag))
+ it_behaves_like 'common RSS response'
+
+ it 'responds with correct statuses with a tag', :aggregate_failures do
+ expect(response.body).to include_status_tag(status_tag)
+ expect(response.body).to_not include_status_tag(status_direct)
+ expect(response.body).to_not include_status_tag(status_media)
+ expect(response.body).to_not include_status_tag(status_private)
+ expect(response.body).to_not include_status_tag(status_reblog.reblog)
+ expect(response.body).to_not include_status_tag(status_reply)
+ expect(response.body).to_not include_status_tag(status_self_reply)
+ expect(response.body).to_not include_status_tag(status)
+ end
end
end
end
end
+
+ def include_status_tag(status)
+ include ActivityPub::TagManager.instance.url_for(status)
+ end
end
diff --git a/spec/controllers/activitypub/collections_controller_spec.rb b/spec/controllers/activitypub/collections_controller_spec.rb
index e2802cf565ba55..cf484ff5a43ad9 100644
--- a/spec/controllers/activitypub/collections_controller_spec.rb
+++ b/spec/controllers/activitypub/collections_controller_spec.rb
@@ -7,22 +7,6 @@
let!(:private_pinned) { Fabricate(:status, account: account, text: 'secret private stuff', visibility: :private) }
let(:remote_account) { nil }
- shared_examples 'cacheable response' do
- it 'does not set cookies' do
- expect(response.cookies).to be_empty
- expect(response.headers['Set-Cookies']).to be_nil
- end
-
- it 'does not set sessions' do
- response
- expect(session).to be_empty
- end
-
- it 'returns public Cache-Control header' do
- expect(response.headers['Cache-Control']).to include 'public'
- end
- end
-
before do
allow(controller).to receive(:signed_request_actor).and_return(remote_account)
diff --git a/spec/controllers/activitypub/outboxes_controller_spec.rb b/spec/controllers/activitypub/outboxes_controller_spec.rb
index 6946fdfcffc721..53c4f0c09cca7c 100644
--- a/spec/controllers/activitypub/outboxes_controller_spec.rb
+++ b/spec/controllers/activitypub/outboxes_controller_spec.rb
@@ -5,22 +5,6 @@
RSpec.describe ActivityPub::OutboxesController do
let!(:account) { Fabricate(:account) }
- shared_examples 'cacheable response' do
- it 'does not set cookies' do
- expect(response.cookies).to be_empty
- expect(response.headers['Set-Cookies']).to be_nil
- end
-
- it 'does not set sessions' do
- response
- expect(session).to be_empty
- end
-
- it 'returns public Cache-Control header' do
- expect(response.headers['Cache-Control']).to include 'public'
- end
- end
-
before do
Fabricate(:status, account: account, visibility: :public)
Fabricate(:status, account: account, visibility: :unlisted)
diff --git a/spec/controllers/activitypub/replies_controller_spec.rb b/spec/controllers/activitypub/replies_controller_spec.rb
index c7b65f004deeb3..7e6e0ffb0d04a7 100644
--- a/spec/controllers/activitypub/replies_controller_spec.rb
+++ b/spec/controllers/activitypub/replies_controller_spec.rb
@@ -8,22 +8,6 @@
let(:remote_reply_id) { 'https://foobar.com/statuses/1234' }
let(:remote_querier) { nil }
- shared_examples 'cacheable response' do
- it 'does not set cookies' do
- expect(response.cookies).to be_empty
- expect(response.headers['Set-Cookies']).to be_nil
- end
-
- it 'does not set sessions' do
- response
- expect(session).to be_empty
- end
-
- it 'returns public Cache-Control header' do
- expect(response.headers['Cache-Control']).to include 'public'
- end
- end
-
shared_examples 'common behavior' do
context 'when status is private' do
let(:parent_visibility) { :private }
diff --git a/spec/controllers/admin/disputes/appeals_controller_spec.rb b/spec/controllers/admin/disputes/appeals_controller_spec.rb
index 3c3f23f5292b6a..3f4175a28177c9 100644
--- a/spec/controllers/admin/disputes/appeals_controller_spec.rb
+++ b/spec/controllers/admin/disputes/appeals_controller_spec.rb
@@ -15,6 +15,20 @@
let(:strike) { Fabricate(:account_warning, target_account: target_account, action: :suspend) }
let(:appeal) { Fabricate(:appeal, strike: strike, account: target_account) }
+ describe 'GET #index' do
+ let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
+
+ before { appeal }
+
+ it 'returns a page that lists details of appeals' do
+ get :index
+
+ expect(response).to have_http_status(:success)
+ expect(response.body).to include("#{strike.account.username}")
+ expect(response.body).to include("#{appeal.account.username}")
+ end
+ end
+
describe 'POST #approve' do
let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
diff --git a/spec/controllers/admin/domain_blocks_controller_spec.rb b/spec/controllers/admin/domain_blocks_controller_spec.rb
index 9be55906ed303f..13826be3665ad1 100644
--- a/spec/controllers/admin/domain_blocks_controller_spec.rb
+++ b/spec/controllers/admin/domain_blocks_controller_spec.rb
@@ -165,6 +165,17 @@
end
end
+ describe 'GET #edit' do
+ let(:domain_block) { Fabricate(:domain_block) }
+
+ it 'returns http success' do
+ get :edit, params: { id: domain_block.id }
+
+ expect(assigns(:domain_block)).to be_instance_of(DomainBlock)
+ expect(response).to have_http_status(200)
+ end
+ end
+
describe 'PUT #update' do
subject do
post :update, params: { :id => domain_block.id, :domain_block => { domain: 'example.com', severity: new_severity }, 'confirm' => '' }
diff --git a/spec/controllers/admin/export_domain_allows_controller_spec.rb b/spec/controllers/admin/export_domain_allows_controller_spec.rb
index 9d50c04aad1d31..e1e5ecc1f0d463 100644
--- a/spec/controllers/admin/export_domain_allows_controller_spec.rb
+++ b/spec/controllers/admin/export_domain_allows_controller_spec.rb
@@ -9,6 +9,14 @@
sign_in Fabricate(:user, role: UserRole.find_by(name: 'Admin')), scope: :user
end
+ describe 'GET #new' do
+ it 'returns http success' do
+ get :new
+
+ expect(response).to have_http_status(200)
+ end
+ end
+
describe 'GET #export' do
it 'renders instances' do
Fabricate(:domain_allow, domain: 'good.domain')
diff --git a/spec/controllers/admin/export_domain_blocks_controller_spec.rb b/spec/controllers/admin/export_domain_blocks_controller_spec.rb
index 1a630777364297..5a282c9572e678 100644
--- a/spec/controllers/admin/export_domain_blocks_controller_spec.rb
+++ b/spec/controllers/admin/export_domain_blocks_controller_spec.rb
@@ -9,6 +9,14 @@
sign_in Fabricate(:user, role: UserRole.find_by(name: 'Admin')), scope: :user
end
+ describe 'GET #new' do
+ it 'returns http success' do
+ get :new
+
+ expect(response).to have_http_status(200)
+ end
+ end
+
describe 'GET #export' do
it 'renders instances' do
Fabricate(:domain_block, domain: 'bad.domain', severity: 'silence', public_comment: 'bad server')
diff --git a/spec/controllers/admin/instances_controller_spec.rb b/spec/controllers/admin/instances_controller_spec.rb
index dd772d10366b79..5fed5d98d2a43d 100644
--- a/spec/controllers/admin/instances_controller_spec.rb
+++ b/spec/controllers/admin/instances_controller_spec.rb
@@ -34,6 +34,63 @@
end
end
+ describe 'GET #show' do
+ it 'shows an instance page' do
+ get :show, params: { id: account_popular_main.domain }
+
+ expect(response).to have_http_status(200)
+ end
+ end
+
+ describe 'POST #clear_delivery_errors' do
+ let(:tracker) { instance_double(DeliveryFailureTracker, clear_failures!: true) }
+
+ before { allow(DeliveryFailureTracker).to receive(:new).and_return(tracker) }
+
+ it 'clears instance delivery errors' do
+ post :clear_delivery_errors, params: { id: account_popular_main.domain }
+
+ expect(response).to redirect_to(admin_instance_path(account_popular_main.domain))
+ expect(tracker).to have_received(:clear_failures!)
+ end
+ end
+
+ describe 'POST #restart_delivery' do
+ let(:tracker) { instance_double(DeliveryFailureTracker, track_success!: true) }
+
+ before { allow(DeliveryFailureTracker).to receive(:new).and_return(tracker) }
+
+ context 'with an unavailable instance' do
+ before { Fabricate(:unavailable_domain, domain: account_popular_main.domain) }
+
+ it 'tracks success on the instance' do
+ post :restart_delivery, params: { id: account_popular_main.domain }
+
+ expect(response).to redirect_to(admin_instance_path(account_popular_main.domain))
+ expect(tracker).to have_received(:track_success!)
+ end
+ end
+
+ context 'with an available instance' do
+ it 'does not track success on the instance' do
+ post :restart_delivery, params: { id: account_popular_main.domain }
+
+ expect(response).to redirect_to(admin_instance_path(account_popular_main.domain))
+ expect(tracker).to_not have_received(:track_success!)
+ end
+ end
+ end
+
+ describe 'POST #stop_delivery' do
+ it 'clears instance delivery errors' do
+ expect do
+ post :stop_delivery, params: { id: account_popular_main.domain }
+ end.to change(UnavailableDomain, :count).by(1)
+
+ expect(response).to redirect_to(admin_instance_path(account_popular_main.domain))
+ end
+ end
+
describe 'DELETE #destroy' do
subject { delete :destroy, params: { id: Instance.first.id } }
diff --git a/spec/controllers/admin/settings/about_controller_spec.rb b/spec/controllers/admin/settings/about_controller_spec.rb
index 2ae26090b60041..f322cb44346b01 100644
--- a/spec/controllers/admin/settings/about_controller_spec.rb
+++ b/spec/controllers/admin/settings/about_controller_spec.rb
@@ -18,4 +18,12 @@
expect(response).to have_http_status(:success)
end
end
+
+ describe 'PUT #update' do
+ it 'updates the settings' do
+ put :update, params: { form_admin_settings: { site_extended_description: 'new site description' } }
+
+ expect(response).to redirect_to(admin_settings_about_path)
+ end
+ end
end
diff --git a/spec/controllers/admin/settings/appearance_controller_spec.rb b/spec/controllers/admin/settings/appearance_controller_spec.rb
index 65b29acc3e11f1..ea6f3b7833a834 100644
--- a/spec/controllers/admin/settings/appearance_controller_spec.rb
+++ b/spec/controllers/admin/settings/appearance_controller_spec.rb
@@ -18,4 +18,12 @@
expect(response).to have_http_status(:success)
end
end
+
+ describe 'PUT #update' do
+ it 'updates the settings' do
+ put :update, params: { form_admin_settings: { custom_css: 'html { display: inline; }' } }
+
+ expect(response).to redirect_to(admin_settings_appearance_path)
+ end
+ end
end
diff --git a/spec/controllers/admin/settings/content_retention_controller_spec.rb b/spec/controllers/admin/settings/content_retention_controller_spec.rb
index 53ce84d1893e05..fb6a3d28484dc2 100644
--- a/spec/controllers/admin/settings/content_retention_controller_spec.rb
+++ b/spec/controllers/admin/settings/content_retention_controller_spec.rb
@@ -18,4 +18,12 @@
expect(response).to have_http_status(:success)
end
end
+
+ describe 'PUT #update' do
+ it 'updates the settings' do
+ put :update, params: { form_admin_settings: { media_cache_retention_period: '2' } }
+
+ expect(response).to redirect_to(admin_settings_content_retention_path)
+ end
+ end
end
diff --git a/spec/controllers/admin/settings/discovery_controller_spec.rb b/spec/controllers/admin/settings/discovery_controller_spec.rb
index c7307ffc880382..33109e3c014ef5 100644
--- a/spec/controllers/admin/settings/discovery_controller_spec.rb
+++ b/spec/controllers/admin/settings/discovery_controller_spec.rb
@@ -18,4 +18,12 @@
expect(response).to have_http_status(:success)
end
end
+
+ describe 'PUT #update' do
+ it 'updates the settings' do
+ put :update, params: { form_admin_settings: { trends: '1' } }
+
+ expect(response).to redirect_to(admin_settings_discovery_path)
+ end
+ end
end
diff --git a/spec/controllers/admin/settings/registrations_controller_spec.rb b/spec/controllers/admin/settings/registrations_controller_spec.rb
index 3fc1f9d13217e3..e0765446037de8 100644
--- a/spec/controllers/admin/settings/registrations_controller_spec.rb
+++ b/spec/controllers/admin/settings/registrations_controller_spec.rb
@@ -18,4 +18,12 @@
expect(response).to have_http_status(:success)
end
end
+
+ describe 'PUT #update' do
+ it 'updates the settings' do
+ put :update, params: { form_admin_settings: { registrations_mode: 'open' } }
+
+ expect(response).to redirect_to(admin_settings_registrations_path)
+ end
+ end
end
diff --git a/spec/controllers/admin/tags_controller_spec.rb b/spec/controllers/admin/tags_controller_spec.rb
index 313298f14a3216..4e06adaca6780d 100644
--- a/spec/controllers/admin/tags_controller_spec.rb
+++ b/spec/controllers/admin/tags_controller_spec.rb
@@ -20,4 +20,26 @@
expect(response).to have_http_status(200)
end
end
+
+ describe 'PUT #update' do
+ let!(:tag) { Fabricate(:tag, listable: false) }
+
+ context 'with valid params' do
+ it 'updates the tag' do
+ put :update, params: { id: tag.id, tag: { listable: '1' } }
+
+ expect(response).to redirect_to(admin_tag_path(tag.id))
+ expect(tag.reload).to be_listable
+ end
+ end
+
+ context 'with invalid params' do
+ it 'does not update the tag' do
+ put :update, params: { id: tag.id, tag: { name: 'cant-change-name' } }
+
+ expect(response).to have_http_status(200)
+ expect(response).to render_template(:show)
+ end
+ end
+ end
end
diff --git a/spec/controllers/admin/webhooks_controller_spec.rb b/spec/controllers/admin/webhooks_controller_spec.rb
index 0ccfbbcc6e0450..17d85060256207 100644
--- a/spec/controllers/admin/webhooks_controller_spec.rb
+++ b/spec/controllers/admin/webhooks_controller_spec.rb
@@ -86,6 +86,24 @@
end
end
+ describe 'POST #enable' do
+ it 'enables the webhook' do
+ post :enable, params: { id: webhook.id }
+
+ expect(webhook.reload).to be_enabled
+ expect(response).to redirect_to(admin_webhook_path(webhook))
+ end
+ end
+
+ describe 'POST #disable' do
+ it 'disables the webhook' do
+ post :disable, params: { id: webhook.id }
+
+ expect(webhook.reload).to_not be_enabled
+ expect(response).to redirect_to(admin_webhook_path(webhook))
+ end
+ end
+
describe 'DELETE #destroy' do
it 'destroys the record' do
expect do
diff --git a/spec/controllers/api/oembed_controller_spec.rb b/spec/controllers/api/oembed_controller_spec.rb
index 70248c398217dd..5f0ca560d22864 100644
--- a/spec/controllers/api/oembed_controller_spec.rb
+++ b/spec/controllers/api/oembed_controller_spec.rb
@@ -14,11 +14,8 @@
get :show, params: { url: short_account_status_url(alice, status) }, format: :json
end
- it 'returns http success' do
+ it 'returns private cache control headers', :aggregate_failures do
expect(response).to have_http_status(200)
- end
-
- it 'returns private cache control headers' do
expect(response.headers['Cache-Control']).to include('private, no-store')
end
end
diff --git a/spec/controllers/api/v1/accounts/credentials_controller_spec.rb b/spec/controllers/api/v1/accounts/credentials_controller_spec.rb
index a677aaad0ed346..5bd2ee9aea02e4 100644
--- a/spec/controllers/api/v1/accounts/credentials_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/credentials_controller_spec.rb
@@ -41,11 +41,9 @@
}
end
- it 'returns http success' do
+ it 'updates account info', :aggregate_failures do
expect(response).to have_http_status(200)
- end
- it 'updates account info' do
user.reload
user.account.reload
@@ -55,9 +53,7 @@
expect(user.account.header).to exist
expect(user.setting_default_privacy).to eq('unlisted')
expect(user.setting_default_sensitive).to be(true)
- end
- it 'queues up an account update distribution' do
expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_async).with(user.account_id)
end
end
diff --git a/spec/controllers/api/v1/accounts/follower_accounts_controller_spec.rb b/spec/controllers/api/v1/accounts/follower_accounts_controller_spec.rb
index 7a387f326fb497..510a47566b371f 100644
--- a/spec/controllers/api/v1/accounts/follower_accounts_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/follower_accounts_controller_spec.rb
@@ -18,23 +18,19 @@
end
describe 'GET #index' do
- it 'returns http success' do
+ it 'returns accounts following the given account', :aggregate_failures do
get :index, params: { account_id: account.id, limit: 2 }
expect(response).to have_http_status(200)
- end
-
- it 'returns accounts following the given account' do
- get :index, params: { account_id: account.id, limit: 2 }
-
expect(body_as_json.size).to eq 2
expect([body_as_json[0][:id], body_as_json[1][:id]]).to contain_exactly(alice.id.to_s, bob.id.to_s)
end
- it 'does not return blocked users' do
+ it 'does not return blocked users', :aggregate_failures do
user.account.block!(bob)
get :index, params: { account_id: account.id, limit: 2 }
+ expect(response).to have_http_status(200)
expect(body_as_json.size).to eq 1
expect(body_as_json[0][:id]).to eq alice.id.to_s
end
diff --git a/spec/controllers/api/v1/accounts/following_accounts_controller_spec.rb b/spec/controllers/api/v1/accounts/following_accounts_controller_spec.rb
index b69b0bd395bd5c..a7d07a6bec9a01 100644
--- a/spec/controllers/api/v1/accounts/following_accounts_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/following_accounts_controller_spec.rb
@@ -18,23 +18,19 @@
end
describe 'GET #index' do
- it 'returns http success' do
+ it 'returns accounts followed by the given account', :aggregate_failures do
get :index, params: { account_id: account.id, limit: 2 }
expect(response).to have_http_status(200)
- end
-
- it 'returns accounts followed by the given account' do
- get :index, params: { account_id: account.id, limit: 2 }
-
expect(body_as_json.size).to eq 2
expect([body_as_json[0][:id], body_as_json[1][:id]]).to contain_exactly(alice.id.to_s, bob.id.to_s)
end
- it 'does not return blocked users' do
+ it 'does not return blocked users', :aggregate_failures do
user.account.block!(bob)
get :index, params: { account_id: account.id, limit: 2 }
+ expect(response).to have_http_status(200)
expect(body_as_json.size).to eq 1
expect(body_as_json[0][:id]).to eq alice.id.to_s
end
diff --git a/spec/controllers/api/v1/accounts/notes_controller_spec.rb b/spec/controllers/api/v1/accounts/notes_controller_spec.rb
index 4107105afd70bd..75599b32b2a069 100644
--- a/spec/controllers/api/v1/accounts/notes_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/notes_controller_spec.rb
@@ -19,30 +19,24 @@
post :create, params: { account_id: account.id, comment: comment }
end
- context 'when account note has reasonable length' do
+ context 'when account note has reasonable length', :aggregate_failures do
let(:comment) { 'foo' }
- it 'returns http success' do
- subject
- expect(response).to have_http_status(200)
- end
-
it 'updates account note' do
subject
+
+ expect(response).to have_http_status(200)
expect(AccountNote.find_by(account_id: user.account.id, target_account_id: account.id).comment).to eq comment
end
end
- context 'when account note exceeds allowed length' do
+ context 'when account note exceeds allowed length', :aggregate_failures do
let(:comment) { 'a' * 2_001 }
- it 'returns 422' do
- subject
- expect(response).to have_http_status(422)
- end
-
it 'does not create account note' do
subject
+
+ expect(response).to have_http_status(422)
expect(AccountNote.where(account_id: user.account.id, target_account_id: account.id)).to_not exist
end
end
diff --git a/spec/controllers/api/v1/accounts/pins_controller_spec.rb b/spec/controllers/api/v1/accounts/pins_controller_spec.rb
index b4aa9b7116edac..36f525e756bfe1 100644
--- a/spec/controllers/api/v1/accounts/pins_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/pins_controller_spec.rb
@@ -15,14 +15,11 @@
describe 'POST #create' do
subject { post :create, params: { account_id: kevin.account.id } }
- it 'returns 200' do
- expect(response).to have_http_status(200)
- end
-
- it 'creates account_pin' do
+ it 'creates account_pin', :aggregate_failures do
expect do
subject
end.to change { AccountPin.where(account: john.account, target_account: kevin.account).count }.by(1)
+ expect(response).to have_http_status(200)
end
end
@@ -33,14 +30,11 @@
Fabricate(:account_pin, account: john.account, target_account: kevin.account)
end
- it 'returns 200' do
- expect(response).to have_http_status(200)
- end
-
- it 'destroys account_pin' do
+ it 'destroys account_pin', :aggregate_failures do
expect do
subject
end.to change { AccountPin.where(account: john.account, target_account: kevin.account).count }.by(-1)
+ expect(response).to have_http_status(200)
end
end
end
diff --git a/spec/controllers/api/v1/accounts/relationships_controller_spec.rb b/spec/controllers/api/v1/accounts/relationships_controller_spec.rb
index 993ead636a99bc..5ba6f2a1f8de99 100644
--- a/spec/controllers/api/v1/accounts/relationships_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/relationships_controller_spec.rb
@@ -26,13 +26,10 @@
get :index, params: { id: simon.id }
end
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
-
- it 'returns JSON with correct data' do
+ it 'returns JSON with correct data', :aggregate_failures do
json = body_as_json
+ expect(response).to have_http_status(200)
expect(json).to be_a Enumerable
expect(json.first[:following]).to be true
expect(json.first[:followed_by]).to be false
@@ -51,11 +48,14 @@
context 'when there is returned JSON data' do
let(:json) { body_as_json }
- it 'returns an enumerable json' do
+ it 'returns an enumerable json with correct elements', :aggregate_failures do
expect(json).to be_a Enumerable
+
+ expect_simon_item_one
+ expect_lewis_item_two
end
- it 'returns a correct first element' do
+ def expect_simon_item_one
expect(json.first[:id]).to eq simon.id.to_s
expect(json.first[:following]).to be true
expect(json.first[:showing_reblogs]).to be true
@@ -65,7 +65,7 @@
expect(json.first[:domain_blocking]).to be false
end
- it 'returns a correct second element' do
+ def expect_lewis_item_two
expect(json.second[:id]).to eq lewis.id.to_s
expect(json.second[:following]).to be false
expect(json.second[:showing_reblogs]).to be false
diff --git a/spec/controllers/api/v1/accounts/statuses_controller_spec.rb b/spec/controllers/api/v1/accounts/statuses_controller_spec.rb
index cb62afcf936813..0e4fa930177c07 100644
--- a/spec/controllers/api/v1/accounts/statuses_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/statuses_controller_spec.rb
@@ -14,15 +14,10 @@
end
describe 'GET #index' do
- it 'returns http success' do
+ it 'returns expected headers', :aggregate_failures do
get :index, params: { account_id: user.account.id, limit: 1 }
expect(response).to have_http_status(200)
- end
-
- it 'returns expected headers' do
- get :index, params: { account_id: user.account.id, limit: 1 }
-
expect(response.headers['Link'].links.size).to eq(2)
end
@@ -44,14 +39,11 @@
get :index, params: { account_id: user.account.id, exclude_replies: true }
end
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
-
- it 'returns posts along with self replies' do
+ it 'returns posts along with self replies', :aggregate_failures do
json = body_as_json
post_ids = json.map { |item| item[:id].to_i }.sort
+ expect(response).to have_http_status(200)
expect(post_ids).to eq [status.id, status_self_reply.id]
end
end
diff --git a/spec/controllers/api/v1/accounts_controller_spec.rb b/spec/controllers/api/v1/accounts_controller_spec.rb
index 0daec691a5db77..9d0bb73c7cbd57 100644
--- a/spec/controllers/api/v1/accounts_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts_controller_spec.rb
@@ -25,15 +25,10 @@
context 'when given truthy agreement' do
let(:agreement) { 'true' }
- it 'returns http success' do
+ it 'creates a user', :aggregate_failures do
expect(response).to have_http_status(200)
- end
-
- it 'returns a new access token as JSON' do
expect(body_as_json[:access_token]).to_not be_blank
- end
- it 'creates a user' do
user = User.find_by(email: 'hello@world.tld')
expect(user).to_not be_nil
expect(user.created_by_application_id).to eq app.id
@@ -59,18 +54,14 @@
context 'with unlocked account' do
let(:locked) { false }
- it 'returns http success' do
+ it 'creates a following relation between user and target user', :aggregate_failures do
expect(response).to have_http_status(200)
- end
- it 'returns JSON with following=true and requested=false' do
json = body_as_json
expect(json[:following]).to be true
expect(json[:requested]).to be false
- end
- it 'creates a following relation between user and target user' do
expect(user.account.following?(other_account)).to be true
end
@@ -80,18 +71,14 @@
context 'with locked account' do
let(:locked) { true }
- it 'returns http success' do
+ it 'creates a follow request relation between user and target user', :aggregate_failures do
expect(response).to have_http_status(200)
- end
- it 'returns JSON with following=false and requested=true' do
json = body_as_json
expect(json[:following]).to be false
expect(json[:requested]).to be true
- end
- it 'creates a follow request relation between user and target user' do
expect(user.account.requested?(other_account)).to be true
end
@@ -148,11 +135,8 @@
post :unfollow, params: { id: other_account.id }
end
- it 'returns http success' do
+ it 'removes the following relation between user and target user', :aggregate_failures do
expect(response).to have_http_status(200)
- end
-
- it 'removes the following relation between user and target user' do
expect(user.account.following?(other_account)).to be false
end
@@ -168,11 +152,8 @@
post :remove_from_followers, params: { id: other_account.id }
end
- it 'returns http success' do
+ it 'removes the followed relation between user and target user', :aggregate_failures do
expect(response).to have_http_status(200)
- end
-
- it 'removes the followed relation between user and target user' do
expect(user.account.followed_by?(other_account)).to be false
end
@@ -188,15 +169,9 @@
post :block, params: { id: other_account.id }
end
- it 'returns http success' do
+ it 'creates a blocking relation', :aggregate_failures do
expect(response).to have_http_status(200)
- end
-
- it 'removes the following relation between user and target user' do
expect(user.account.following?(other_account)).to be false
- end
-
- it 'creates a blocking relation' do
expect(user.account.blocking?(other_account)).to be true
end
@@ -212,11 +187,8 @@
post :unblock, params: { id: other_account.id }
end
- it 'returns http success' do
+ it 'removes the blocking relation between user and target user', :aggregate_failures do
expect(response).to have_http_status(200)
- end
-
- it 'removes the blocking relation between user and target user' do
expect(user.account.blocking?(other_account)).to be false
end
@@ -232,19 +204,10 @@
post :mute, params: { id: other_account.id }
end
- it 'returns http success' do
+ it 'mutes notifications', :aggregate_failures do
expect(response).to have_http_status(200)
- end
-
- it 'does not remove the following relation between user and target user' do
expect(user.account.following?(other_account)).to be true
- end
-
- it 'creates a muting relation' do
expect(user.account.muting?(other_account)).to be true
- end
-
- it 'mutes notifications' do
expect(user.account.muting_notifications?(other_account)).to be true
end
@@ -260,19 +223,10 @@
post :mute, params: { id: other_account.id, notifications: false }
end
- it 'returns http success' do
+ it 'does not mute notifications', :aggregate_failures do
expect(response).to have_http_status(200)
- end
-
- it 'does not remove the following relation between user and target user' do
expect(user.account.following?(other_account)).to be true
- end
-
- it 'creates a muting relation' do
expect(user.account.muting?(other_account)).to be true
- end
-
- it 'does not mute notifications' do
expect(user.account.muting_notifications?(other_account)).to be false
end
@@ -288,19 +242,10 @@
post :mute, params: { id: other_account.id, duration: 300 }
end
- it 'returns http success' do
+ it 'mutes notifications', :aggregate_failures do
expect(response).to have_http_status(200)
- end
-
- it 'does not remove the following relation between user and target user' do
expect(user.account.following?(other_account)).to be true
- end
-
- it 'creates a muting relation' do
expect(user.account.muting?(other_account)).to be true
- end
-
- it 'mutes notifications' do
expect(user.account.muting_notifications?(other_account)).to be true
end
@@ -316,11 +261,8 @@
post :unmute, params: { id: other_account.id }
end
- it 'returns http success' do
+ it 'removes the muting relation between user and target user', :aggregate_failures do
expect(response).to have_http_status(200)
- end
-
- it 'removes the muting relation between user and target user' do
expect(user.account.muting?(other_account)).to be false
end
diff --git a/spec/controllers/api/v1/admin/accounts_controller_spec.rb b/spec/controllers/api/v1/admin/accounts_controller_spec.rb
deleted file mode 100644
index 36f6e398cbe09a..00000000000000
--- a/spec/controllers/api/v1/admin/accounts_controller_spec.rb
+++ /dev/null
@@ -1,198 +0,0 @@
-# frozen_string_literal: true
-
-require 'rails_helper'
-
-RSpec.describe Api::V1::Admin::AccountsController do
- render_views
-
- let(:role) { UserRole.find_by(name: 'Moderator') }
- let(:user) { Fabricate(:user, role: role) }
- let(:scopes) { 'admin:read admin:write' }
- let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
- let(:account) { Fabricate(:account) }
-
- before do
- allow(controller).to receive(:doorkeeper_token) { token }
- end
-
- describe 'GET #index' do
- let!(:remote_account) { Fabricate(:account, domain: 'example.org') }
- let!(:other_remote_account) { Fabricate(:account, domain: 'foo.bar') }
- let!(:suspended_account) { Fabricate(:account, suspended: true) }
- let!(:suspended_remote) { Fabricate(:account, domain: 'foo.bar', suspended: true) }
- let!(:disabled_account) { Fabricate(:user, disabled: true).account }
- let!(:pending_account) { Fabricate(:user, approved: false).account }
- let!(:admin_account) { user.account }
-
- let(:params) { {} }
-
- before do
- pending_account.user.update(approved: false)
- get :index, params: params
- end
-
- it_behaves_like 'forbidden for wrong scope', 'write:statuses'
- it_behaves_like 'forbidden for wrong role', ''
-
- [
- [{ active: 'true', local: 'true', staff: 'true' }, [:admin_account]],
- [{ by_domain: 'example.org', remote: 'true' }, [:remote_account]],
- [{ suspended: 'true' }, [:suspended_account]],
- [{ disabled: 'true' }, [:disabled_account]],
- [{ pending: 'true' }, [:pending_account]],
- ].each do |params, expected_results|
- context "when called with #{params.inspect}" do
- let(:params) { params }
-
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
-
- it "returns the correct accounts (#{expected_results.inspect})" do
- json = body_as_json
-
- expect(json.map { |a| a[:id].to_i }).to eq(expected_results.map { |symbol| send(symbol).id })
- end
- end
- end
- end
-
- describe 'GET #show' do
- before do
- get :show, params: { id: account.id }
- end
-
- it_behaves_like 'forbidden for wrong scope', 'write:statuses'
- it_behaves_like 'forbidden for wrong role', ''
-
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
- end
-
- describe 'POST #approve' do
- before do
- account.user.update(approved: false)
- post :approve, params: { id: account.id }
- end
-
- it_behaves_like 'forbidden for wrong scope', 'write:statuses'
- it_behaves_like 'forbidden for wrong role', ''
-
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
-
- it 'approves user' do
- expect(account.reload.user_approved?).to be true
- end
-
- it 'logs action' do
- log_item = Admin::ActionLog.last
-
- expect(log_item).to_not be_nil
- expect(log_item.action).to eq :approve
- expect(log_item.account_id).to eq user.account_id
- expect(log_item.target_id).to eq account.user.id
- end
- end
-
- describe 'POST #reject' do
- before do
- account.user.update(approved: false)
- post :reject, params: { id: account.id }
- end
-
- it_behaves_like 'forbidden for wrong scope', 'write:statuses'
- it_behaves_like 'forbidden for wrong role', ''
-
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
-
- it 'removes user' do
- expect(User.where(id: account.user.id).count).to eq 0
- end
-
- it 'logs action' do
- log_item = Admin::ActionLog.last
-
- expect(log_item).to_not be_nil
- expect(log_item.action).to eq :reject
- expect(log_item.account_id).to eq user.account_id
- expect(log_item.target_id).to eq account.user.id
- end
- end
-
- describe 'POST #enable' do
- before do
- account.user.update(disabled: true)
- post :enable, params: { id: account.id }
- end
-
- it_behaves_like 'forbidden for wrong scope', 'write:statuses'
- it_behaves_like 'forbidden for wrong role', ''
-
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
-
- it 'enables user' do
- expect(account.reload.user_disabled?).to be false
- end
- end
-
- describe 'POST #unsuspend' do
- before do
- account.suspend!
- post :unsuspend, params: { id: account.id }
- end
-
- it_behaves_like 'forbidden for wrong scope', 'write:statuses'
- it_behaves_like 'forbidden for wrong role', ''
-
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
-
- it 'unsuspends account' do
- expect(account.reload.suspended?).to be false
- end
- end
-
- describe 'POST #unsensitive' do
- before do
- account.touch(:sensitized_at)
- post :unsensitive, params: { id: account.id }
- end
-
- it_behaves_like 'forbidden for wrong scope', 'write:statuses'
- it_behaves_like 'forbidden for wrong role', ''
-
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
-
- it 'unsensitizes account' do
- expect(account.reload.sensitized?).to be false
- end
- end
-
- describe 'POST #unsilence' do
- before do
- account.touch(:silenced_at)
- post :unsilence, params: { id: account.id }
- end
-
- it_behaves_like 'forbidden for wrong scope', 'write:statuses'
- it_behaves_like 'forbidden for wrong role', ''
-
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
-
- it 'unsilences account' do
- expect(account.reload.silenced?).to be false
- end
- end
-end
diff --git a/spec/controllers/api/v1/admin/trends/links_controller_spec.rb b/spec/controllers/api/v1/admin/trends/links_controller_spec.rb
deleted file mode 100644
index d9aa06824db344..00000000000000
--- a/spec/controllers/api/v1/admin/trends/links_controller_spec.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-# frozen_string_literal: true
-
-require 'rails_helper'
-
-describe Api::V1::Admin::Trends::LinksController do
- render_views
-
- let(:role) { UserRole.find_by(name: 'Admin') }
- let(:user) { Fabricate(:user, role: role) }
- let(:scopes) { 'admin:read admin:write' }
- let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
- let(:account) { Fabricate(:account) }
- let(:preview_card) { Fabricate(:preview_card) }
-
- before do
- allow(controller).to receive(:doorkeeper_token) { token }
- end
-
- describe 'GET #index' do
- it 'returns http success' do
- get :index, params: { account_id: account.id, limit: 2 }
-
- expect(response).to have_http_status(200)
- end
- end
-
- describe 'POST #approve' do
- before do
- post :approve, params: { id: preview_card.id }
- end
-
- it_behaves_like 'forbidden for wrong scope', 'write:statuses'
- it_behaves_like 'forbidden for wrong role', ''
-
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
- end
-
- describe 'POST #reject' do
- before do
- post :reject, params: { id: preview_card.id }
- end
-
- it_behaves_like 'forbidden for wrong scope', 'write:statuses'
- it_behaves_like 'forbidden for wrong role', ''
-
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
- end
-end
diff --git a/spec/controllers/api/v1/announcements/reactions_controller_spec.rb b/spec/controllers/api/v1/announcements/reactions_controller_spec.rb
index 10aaa553f5a3ac..c1debc33fe22cc 100644
--- a/spec/controllers/api/v1/announcements/reactions_controller_spec.rb
+++ b/spec/controllers/api/v1/announcements/reactions_controller_spec.rb
@@ -25,11 +25,8 @@
put :update, params: { announcement_id: announcement.id, id: '😂' }
end
- it 'returns http success' do
+ it 'creates reaction', :aggregate_failures do
expect(response).to have_http_status(200)
- end
-
- it 'creates reaction' do
expect(announcement.announcement_reactions.find_by(name: '😂', account: user.account)).to_not be_nil
end
end
@@ -53,11 +50,8 @@
delete :destroy, params: { announcement_id: announcement.id, id: '😂' }
end
- it 'returns http success' do
+ it 'creates reaction', :aggregate_failures do
expect(response).to have_http_status(200)
- end
-
- it 'creates reaction' do
expect(announcement.announcement_reactions.find_by(name: '😂', account: user.account)).to be_nil
end
end
diff --git a/spec/controllers/api/v1/announcements_controller_spec.rb b/spec/controllers/api/v1/announcements_controller_spec.rb
index 15d94b45120906..95ce8fd9fc1b01 100644
--- a/spec/controllers/api/v1/announcements_controller_spec.rb
+++ b/spec/controllers/api/v1/announcements_controller_spec.rb
@@ -47,11 +47,8 @@
post :dismiss, params: { id: announcement.id }
end
- it 'returns http success' do
+ it 'dismisses announcement', :aggregate_failures do
expect(response).to have_http_status(200)
- end
-
- it 'dismisses announcement' do
expect(announcement.announcement_mutes.find_by(account: user.account)).to_not be_nil
end
end
diff --git a/spec/controllers/api/v1/blocks_controller_spec.rb b/spec/controllers/api/v1/blocks_controller_spec.rb
deleted file mode 100644
index eaafc1b4fa0eb4..00000000000000
--- a/spec/controllers/api/v1/blocks_controller_spec.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-# frozen_string_literal: true
-
-require 'rails_helper'
-
-RSpec.describe Api::V1::BlocksController do
- render_views
-
- let(:user) { Fabricate(:user) }
- let(:scopes) { 'read:blocks' }
- let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
-
- before { allow(controller).to receive(:doorkeeper_token) { token } }
-
- describe 'GET #index' do
- it 'limits according to limit parameter' do
- Array.new(2) { Fabricate(:block, account: user.account) }
- get :index, params: { limit: 1 }
- expect(body_as_json.size).to eq 1
- end
-
- it 'queries blocks in range according to max_id' do
- blocks = Array.new(2) { Fabricate(:block, account: user.account) }
-
- get :index, params: { max_id: blocks[1] }
-
- expect(body_as_json.size).to eq 1
- expect(body_as_json[0][:id]).to eq blocks[0].target_account_id.to_s
- end
-
- it 'queries blocks in range according to since_id' do
- blocks = Array.new(2) { Fabricate(:block, account: user.account) }
-
- get :index, params: { since_id: blocks[0] }
-
- expect(body_as_json.size).to eq 1
- expect(body_as_json[0][:id]).to eq blocks[1].target_account_id.to_s
- end
-
- it 'sets pagination header for next path' do
- blocks = Array.new(2) { Fabricate(:block, account: user.account) }
- get :index, params: { limit: 1, since_id: blocks[0] }
- expect(response.headers['Link'].find_link(%w(rel next)).href).to eq api_v1_blocks_url(limit: 1, max_id: blocks[1])
- end
-
- it 'sets pagination header for previous path' do
- block = Fabricate(:block, account: user.account)
- get :index
- expect(response.headers['Link'].find_link(%w(rel prev)).href).to eq api_v1_blocks_url(since_id: block)
- end
-
- it 'returns http success' do
- get :index
- expect(response).to have_http_status(200)
- end
-
- context 'with wrong scopes' do
- let(:scopes) { 'write:blocks' }
-
- it 'returns http forbidden' do
- get :index
- expect(response).to have_http_status(403)
- end
- end
- end
-end
diff --git a/spec/controllers/api/v1/conversations_controller_spec.rb b/spec/controllers/api/v1/conversations_controller_spec.rb
index 28d7c7f3ae8f71..50e2a62efd82c3 100644
--- a/spec/controllers/api/v1/conversations_controller_spec.rb
+++ b/spec/controllers/api/v1/conversations_controller_spec.rb
@@ -21,17 +21,14 @@
PostStatusService.new.call(user.account, text: 'Hey, nobody here', visibility: 'direct')
end
- it 'returns http success' do
- get :index
- expect(response).to have_http_status(200)
- end
-
- it 'returns pagination headers' do
+ it 'returns pagination headers', :aggregate_failures do
get :index, params: { limit: 1 }
+
+ expect(response).to have_http_status(200)
expect(response.headers['Link'].links.size).to eq(2)
end
- it 'returns conversations' do
+ it 'returns conversations', :aggregate_failures do
get :index
json = body_as_json
expect(json.size).to eq 2
diff --git a/spec/controllers/api/v1/favourites_controller_spec.rb b/spec/controllers/api/v1/favourites_controller_spec.rb
deleted file mode 100644
index c9ca046be0d598..00000000000000
--- a/spec/controllers/api/v1/favourites_controller_spec.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-# frozen_string_literal: true
-
-require 'rails_helper'
-
-RSpec.describe Api::V1::FavouritesController do
- render_views
-
- let(:user) { Fabricate(:user) }
- let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') }
-
- describe 'GET #index' do
- context 'without token' do
- it 'returns http unauthorized' do
- get :index
- expect(response).to have_http_status 401
- end
- end
-
- context 'with token' do
- context 'without read scope' do
- before do
- allow(controller).to receive(:doorkeeper_token) do
- Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: '')
- end
- end
-
- it 'returns http forbidden' do
- get :index
- expect(response).to have_http_status 403
- end
- end
-
- context 'without valid resource owner' do
- before do
- token = Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read')
- user.destroy!
-
- allow(controller).to receive(:doorkeeper_token) { token }
- end
-
- it 'returns http unprocessable entity' do
- get :index
- expect(response).to have_http_status 422
- end
- end
-
- context 'with read scope and valid resource owner' do
- before do
- allow(controller).to receive(:doorkeeper_token) do
- Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:favourites')
- end
- end
-
- it 'shows favourites owned by the user' do
- favourite_by_user = Fabricate(:favourite, account: user.account)
- favourite_by_others = Fabricate(:favourite)
-
- get :index
-
- expect(assigns(:statuses)).to contain_exactly(favourite_by_user.status)
- end
-
- it 'adds pagination headers if necessary' do
- favourite = Fabricate(:favourite, account: user.account)
-
- get :index, params: { limit: 1 }
-
- expect(response.headers['Link'].find_link(%w(rel next)).href).to eq "http://test.host/api/v1/favourites?limit=1&max_id=#{favourite.id}"
- expect(response.headers['Link'].find_link(%w(rel prev)).href).to eq "http://test.host/api/v1/favourites?limit=1&min_id=#{favourite.id}"
- end
-
- it 'does not add pagination headers if not necessary' do
- get :index
-
- expect(response.headers['Link']).to be_nil
- end
- end
- end
- end
-end
diff --git a/spec/controllers/api/v1/filters_controller_spec.rb b/spec/controllers/api/v1/filters_controller_spec.rb
index 8ccd2f4d6667b4..8d5408cf548c0a 100644
--- a/spec/controllers/api/v1/filters_controller_spec.rb
+++ b/spec/controllers/api/v1/filters_controller_spec.rb
@@ -31,12 +31,10 @@
post :create, params: { phrase: 'magic', context: %w(home), irreversible: irreversible, whole_word: whole_word }
end
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
-
- it 'creates a filter' do
+ it 'creates a filter', :aggregate_failures do
filter = user.account.custom_filters.first
+
+ expect(response).to have_http_status(200)
expect(filter).to_not be_nil
expect(filter.keywords.pluck(:keyword, :whole_word)).to eq [['magic', whole_word]]
expect(filter.context).to eq %w(home)
@@ -48,12 +46,10 @@
let(:irreversible) { false }
let(:whole_word) { true }
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
-
- it 'creates a filter' do
+ it 'creates a filter', :aggregate_failures do
filter = user.account.custom_filters.first
+
+ expect(response).to have_http_status(200)
expect(filter).to_not be_nil
expect(filter.keywords.pluck(:keyword, :whole_word)).to eq [['magic', whole_word]]
expect(filter.context).to eq %w(home)
@@ -83,11 +79,8 @@
put :update, params: { id: keyword.id, phrase: 'updated' }
end
- it 'returns http success' do
+ it 'updates the filter', :aggregate_failures do
expect(response).to have_http_status(200)
- end
-
- it 'updates the filter' do
expect(keyword.reload.phrase).to eq 'updated'
end
end
@@ -101,11 +94,8 @@
delete :destroy, params: { id: keyword.id }
end
- it 'returns http success' do
+ it 'removes the filter', :aggregate_failures do
expect(response).to have_http_status(200)
- end
-
- it 'removes the filter' do
expect { keyword.reload }.to raise_error ActiveRecord::RecordNotFound
end
end
diff --git a/spec/controllers/api/v1/followed_tags_controller_spec.rb b/spec/controllers/api/v1/followed_tags_controller_spec.rb
deleted file mode 100644
index c1a366d4e372f4..00000000000000
--- a/spec/controllers/api/v1/followed_tags_controller_spec.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# frozen_string_literal: true
-
-require 'rails_helper'
-
-RSpec.describe Api::V1::FollowedTagsController do
- render_views
-
- let(:user) { Fabricate(:user) }
- let(:scopes) { 'read:follows' }
- let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
-
- before { allow(controller).to receive(:doorkeeper_token) { token } }
-
- describe 'GET #index' do
- let!(:tag_follows) { Fabricate.times(5, :tag_follow, account: user.account) }
-
- before do
- get :index, params: { limit: 1 }
- end
-
- it 'returns http success' do
- expect(response).to have_http_status(:success)
- end
- end
-end
diff --git a/spec/controllers/api/v1/instances/translation_languages_controller_spec.rb b/spec/controllers/api/v1/instances/translation_languages_controller_spec.rb
index 88bcc403416449..f79687df66b7ad 100644
--- a/spec/controllers/api/v1/instances/translation_languages_controller_spec.rb
+++ b/spec/controllers/api/v1/instances/translation_languages_controller_spec.rb
@@ -5,7 +5,7 @@
describe Api::V1::Instances::TranslationLanguagesController do
describe 'GET #show' do
context 'when no translation service is configured' do
- it 'returns empty language matrix' do
+ it 'returns empty language matrix', :aggregate_failures do
get :show
expect(response).to have_http_status(200)
@@ -19,7 +19,7 @@
allow(TranslationService).to receive_messages(configured?: true, configured: service)
end
- it 'returns language matrix' do
+ it 'returns language matrix', :aggregate_failures do
get :show
expect(response).to have_http_status(200)
diff --git a/spec/controllers/api/v1/lists/accounts_controller_spec.rb b/spec/controllers/api/v1/lists/accounts_controller_spec.rb
deleted file mode 100644
index d4550dd769c585..00000000000000
--- a/spec/controllers/api/v1/lists/accounts_controller_spec.rb
+++ /dev/null
@@ -1,92 +0,0 @@
-# frozen_string_literal: true
-
-require 'rails_helper'
-
-describe Api::V1::Lists::AccountsController do
- render_views
-
- let(:user) { Fabricate(:user) }
- let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
- let(:list) { Fabricate(:list, account: user.account) }
-
- before do
- follow = Fabricate(:follow, account: user.account)
- list.accounts << follow.target_account
- allow(controller).to receive(:doorkeeper_token) { token }
- end
-
- describe 'GET #index' do
- let(:scopes) { 'read:lists' }
-
- it 'returns http success' do
- get :show, params: { list_id: list.id }
-
- expect(response).to have_http_status(200)
- end
- end
-
- describe 'POST #create' do
- let(:scopes) { 'write:lists' }
- let(:bob) { Fabricate(:account, username: 'bob') }
-
- context 'when the added account is followed' do
- before do
- user.account.follow!(bob)
- post :create, params: { list_id: list.id, account_ids: [bob.id] }
- end
-
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
-
- it 'adds account to the list' do
- expect(list.accounts.include?(bob)).to be true
- end
- end
-
- context 'when the added account has been sent a follow request' do
- before do
- user.account.follow_requests.create!(target_account: bob)
- post :create, params: { list_id: list.id, account_ids: [bob.id] }
- end
-
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
-
- it 'adds account to the list' do
- expect(list.accounts.include?(bob)).to be true
- end
- end
-
- context 'when the added account is not followed' do
- before do
- post :create, params: { list_id: list.id, account_ids: [bob.id] }
- end
-
- it 'returns http not found' do
- expect(response).to have_http_status(404)
- end
-
- it 'does not add the account to the list' do
- expect(list.accounts.include?(bob)).to be false
- end
- end
- end
-
- describe 'DELETE #destroy' do
- let(:scopes) { 'write:lists' }
-
- before do
- delete :destroy, params: { list_id: list.id, account_ids: [list.accounts.first.id] }
- end
-
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
-
- it 'removes account from the list' do
- expect(list.accounts.count).to eq 0
- end
- end
-end
diff --git a/spec/controllers/api/v1/markers_controller_spec.rb b/spec/controllers/api/v1/markers_controller_spec.rb
index 64e9dcafb6fa13..e954bbd1b6f30d 100644
--- a/spec/controllers/api/v1/markers_controller_spec.rb
+++ b/spec/controllers/api/v1/markers_controller_spec.rb
@@ -18,13 +18,10 @@
get :index, params: { timeline: %w(home notifications) }
end
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
-
- it 'returns markers' do
+ it 'returns markers', :aggregate_failures do
json = body_as_json
+ expect(response).to have_http_status(200)
expect(json.key?(:home)).to be true
expect(json[:home][:last_read_id]).to eq '123'
expect(json.key?(:notifications)).to be true
@@ -38,11 +35,8 @@
post :create, params: { home: { last_read_id: '69420' } }
end
- it 'returns http success' do
+ it 'creates a marker', :aggregate_failures do
expect(response).to have_http_status(200)
- end
-
- it 'creates a marker' do
expect(user.markers.first.timeline).to eq 'home'
expect(user.markers.first.last_read_id).to eq 69_420
end
@@ -54,11 +48,8 @@
post :create, params: { home: { last_read_id: '70120' } }
end
- it 'returns http success' do
+ it 'updates a marker', :aggregate_failures do
expect(response).to have_http_status(200)
- end
-
- it 'updates a marker' do
expect(user.markers.first.timeline).to eq 'home'
expect(user.markers.first.last_read_id).to eq 70_120
end
diff --git a/spec/controllers/api/v1/media_controller_spec.rb b/spec/controllers/api/v1/media_controller_spec.rb
deleted file mode 100644
index 94b2a0a98f8ee6..00000000000000
--- a/spec/controllers/api/v1/media_controller_spec.rb
+++ /dev/null
@@ -1,132 +0,0 @@
-# frozen_string_literal: true
-
-require 'rails_helper'
-
-RSpec.describe Api::V1::MediaController do
- render_views
-
- let(:user) { Fabricate(:user) }
- let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:media') }
-
- before do
- allow(controller).to receive(:doorkeeper_token) { token }
- end
-
- describe 'POST #create' do
- describe 'with paperclip errors' do
- context 'when imagemagick cant identify the file type' do
- it 'returns http 422' do
- allow_any_instance_of(Account).to receive_message_chain(:media_attachments, :create!).and_raise(Paperclip::Errors::NotIdentifiedByImageMagickError)
- post :create, params: { file: fixture_file_upload('attachment.jpg', 'image/jpeg') }
-
- expect(response).to have_http_status(422)
- end
- end
-
- context 'when there is a generic error' do
- it 'returns http 422' do
- allow_any_instance_of(Account).to receive_message_chain(:media_attachments, :create!).and_raise(Paperclip::Error)
- post :create, params: { file: fixture_file_upload('attachment.jpg', 'image/jpeg') }
-
- expect(response).to have_http_status(500)
- end
- end
- end
-
- context 'with image/jpeg' do
- before do
- post :create, params: { file: fixture_file_upload('attachment.jpg', 'image/jpeg') }
- end
-
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
-
- it 'creates a media attachment' do
- expect(MediaAttachment.first).to_not be_nil
- end
-
- it 'uploads a file' do
- expect(MediaAttachment.first).to have_attached_file(:file)
- end
-
- it 'returns media ID in JSON' do
- expect(body_as_json[:id]).to eq MediaAttachment.first.id.to_s
- end
- end
-
- context 'with image/gif' do
- before do
- post :create, params: { file: fixture_file_upload('attachment.gif', 'image/gif') }
- end
-
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
-
- it 'creates a media attachment' do
- expect(MediaAttachment.first).to_not be_nil
- end
-
- it 'uploads a file' do
- expect(MediaAttachment.first).to have_attached_file(:file)
- end
-
- it 'returns media ID in JSON' do
- expect(body_as_json[:id]).to eq MediaAttachment.first.id.to_s
- end
- end
-
- context 'with video/webm' do
- before do
- post :create, params: { file: fixture_file_upload('attachment.webm', 'video/webm') }
- end
-
- it do
- # returns http success
- expect(response).to have_http_status(200)
-
- # creates a media attachment
- expect(MediaAttachment.first).to_not be_nil
-
- # uploads a file
- expect(MediaAttachment.first).to have_attached_file(:file)
-
- # returns media ID in JSON
- expect(body_as_json[:id]).to eq MediaAttachment.first.id.to_s
- end
- end
- end
-
- describe 'PUT #update' do
- context 'when somebody else\'s' do
- let(:media) { Fabricate(:media_attachment, status: nil) }
-
- it 'returns http not found' do
- put :update, params: { id: media.id, description: 'Lorem ipsum!!!' }
- expect(response).to have_http_status(404)
- end
- end
-
- context 'when the author \'s' do
- let(:status) { nil }
- let(:media) { Fabricate(:media_attachment, status: status, account: user.account) }
-
- before do
- put :update, params: { id: media.id, description: 'Lorem ipsum!!!' }
- end
-
- it 'updates the description' do
- expect(media.reload.description).to eq 'Lorem ipsum!!!'
- end
-
- context 'when already attached to a status' do
- let(:status) { Fabricate(:status, account: user.account) }
-
- it 'returns http not found' do
- expect(response).to have_http_status(404)
- end
- end
- end
- end
-end
diff --git a/spec/controllers/api/v1/notifications_controller_spec.rb b/spec/controllers/api/v1/notifications_controller_spec.rb
deleted file mode 100644
index 6615848b8322a4..00000000000000
--- a/spec/controllers/api/v1/notifications_controller_spec.rb
+++ /dev/null
@@ -1,137 +0,0 @@
-# frozen_string_literal: true
-
-require 'rails_helper'
-
-RSpec.describe Api::V1::NotificationsController do
- render_views
-
- let(:user) { Fabricate(:user, account_attributes: { username: 'alice' }) }
- let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
- let(:other) { Fabricate(:user) }
- let(:third) { Fabricate(:user) }
-
- before do
- allow(controller).to receive(:doorkeeper_token) { token }
- end
-
- describe 'GET #show' do
- let(:scopes) { 'read:notifications' }
-
- it 'returns http success' do
- notification = Fabricate(:notification, account: user.account)
- get :show, params: { id: notification.id }
-
- expect(response).to have_http_status(200)
- end
- end
-
- describe 'POST #dismiss' do
- let(:scopes) { 'write:notifications' }
-
- it 'destroys the notification' do
- notification = Fabricate(:notification, account: user.account)
- post :dismiss, params: { id: notification.id }
-
- expect(response).to have_http_status(200)
- expect { notification.reload }.to raise_error(ActiveRecord::RecordNotFound)
- end
- end
-
- describe 'POST #clear' do
- let(:scopes) { 'write:notifications' }
-
- it 'clears notifications for the account' do
- notification = Fabricate(:notification, account: user.account)
- post :clear
-
- expect(notification.account.reload.notifications).to be_empty
- expect(response).to have_http_status(200)
- end
- end
-
- describe 'GET #index' do
- let(:scopes) { 'read:notifications' }
-
- before do
- first_status = PostStatusService.new.call(user.account, text: 'Test')
- @reblog_of_first_status = ReblogService.new.call(other.account, first_status)
- mentioning_status = PostStatusService.new.call(other.account, text: 'Hello @alice')
- @mention_from_status = mentioning_status.mentions.first
- @favourite = FavouriteService.new.call(other.account, first_status)
- @second_favourite = FavouriteService.new.call(third.account, first_status)
- @follow = FollowService.new.call(other.account, user.account)
- end
-
- describe 'with no options' do
- before do
- get :index
- end
-
- it 'returns expected notification types', :aggregate_failures do
- expect(response).to have_http_status(200)
-
- expect(body_json_types).to include 'reblog'
- expect(body_json_types).to include 'mention'
- expect(body_json_types).to include 'favourite'
- expect(body_json_types).to include 'follow'
- end
- end
-
- describe 'with account_id param' do
- before do
- get :index, params: { account_id: third.account.id }
- end
-
- it 'returns only notifications from specified user', :aggregate_failures do
- expect(response).to have_http_status(200)
-
- expect(body_json_account_ids.uniq).to eq [third.account.id.to_s]
- end
-
- def body_json_account_ids
- body_as_json.map { |x| x[:account][:id] }
- end
- end
-
- describe 'with invalid account_id param' do
- before do
- get :index, params: { account_id: 'foo' }
- end
-
- it 'returns nothing', :aggregate_failures do
- expect(response).to have_http_status(200)
-
- expect(body_as_json.size).to eq 0
- end
- end
-
- describe 'with exclude_types param' do
- before do
- get :index, params: { exclude_types: %w(mention) }
- end
-
- it 'returns everything but excluded type', :aggregate_failures do
- expect(response).to have_http_status(200)
-
- expect(body_as_json.size).to_not eq 0
- expect(body_json_types.uniq).to_not include 'mention'
- end
- end
-
- describe 'with types param' do
- before do
- get :index, params: { types: %w(mention) }
- end
-
- it 'returns only requested type', :aggregate_failures do
- expect(response).to have_http_status(200)
-
- expect(body_json_types.uniq).to eq ['mention']
- end
- end
-
- def body_json_types
- body_as_json.pluck(:type)
- end
- end
-end
diff --git a/spec/controllers/api/v1/polls/votes_controller_spec.rb b/spec/controllers/api/v1/polls/votes_controller_spec.rb
index 7abd2a1b171c1a..5de225a48796ed 100644
--- a/spec/controllers/api/v1/polls/votes_controller_spec.rb
+++ b/spec/controllers/api/v1/polls/votes_controller_spec.rb
@@ -18,18 +18,13 @@
post :create, params: { poll_id: poll.id, choices: %w(1) }
end
- it 'returns http success' do
+ it 'creates a vote', :aggregate_failures do
expect(response).to have_http_status(200)
- end
-
- it 'creates a vote' do
vote = poll.votes.where(account: user.account).first
expect(vote).to_not be_nil
expect(vote.choice).to eq 1
- end
- it 'updates poll tallies' do
expect(poll.reload.cached_tallies).to eq [0, 1]
end
end
diff --git a/spec/controllers/api/v1/reports_controller_spec.rb b/spec/controllers/api/v1/reports_controller_spec.rb
deleted file mode 100644
index f923ff07945ffe..00000000000000
--- a/spec/controllers/api/v1/reports_controller_spec.rb
+++ /dev/null
@@ -1,75 +0,0 @@
-# frozen_string_literal: true
-
-require 'rails_helper'
-
-RSpec.describe Api::V1::ReportsController do
- render_views
-
- let(:user) { Fabricate(:user) }
- let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
-
- before do
- allow(controller).to receive(:doorkeeper_token) { token }
- end
-
- describe 'POST #create' do
- let!(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
-
- let(:scopes) { 'write:reports' }
- let(:status) { Fabricate(:status) }
- let(:target_account) { status.account }
- let(:category) { nil }
- let(:forward) { nil }
- let(:rule_ids) { nil }
-
- before do
- post :create, params: { status_ids: [status.id], account_id: target_account.id, comment: 'reasons', category: category, rule_ids: rule_ids, forward: forward }
- end
-
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
-
- it 'creates a report' do
- expect(target_account.targeted_reports).to_not be_empty
- end
-
- it 'saves comment' do
- expect(target_account.targeted_reports.first.comment).to eq 'reasons'
- end
-
- it 'sends e-mails to admins' do
- expect(ActionMailer::Base.deliveries.first.to).to eq([admin.email])
- end
-
- context 'when a status does not belong to the reported account' do
- let(:target_account) { Fabricate(:account) }
-
- it 'returns http not found' do
- expect(response).to have_http_status(404)
- end
- end
-
- context 'when a category is chosen' do
- let(:category) { 'spam' }
-
- it 'saves category' do
- expect(target_account.targeted_reports.first.spam?).to be true
- end
- end
-
- context 'when violated rules are chosen' do
- let(:rule) { Fabricate(:rule) }
- let(:category) { 'violation' }
- let(:rule_ids) { [rule.id] }
-
- it 'saves category' do
- expect(target_account.targeted_reports.first.violation?).to be true
- end
-
- it 'saves rule_ids' do
- expect(target_account.targeted_reports.first.rule_ids).to contain_exactly(rule.id)
- end
- end
- end
-end
diff --git a/spec/controllers/api/v1/statuses/mutes_controller_spec.rb b/spec/controllers/api/v1/statuses/mutes_controller_spec.rb
index bffa9fe0d9c6a5..03274fe1cd2b5c 100644
--- a/spec/controllers/api/v1/statuses/mutes_controller_spec.rb
+++ b/spec/controllers/api/v1/statuses/mutes_controller_spec.rb
@@ -21,11 +21,8 @@
post :create, params: { status_id: status.id }
end
- it 'returns http success' do
+ it 'creates a conversation mute', :aggregate_failures do
expect(response).to have_http_status(200)
- end
-
- it 'creates a conversation mute' do
expect(ConversationMute.find_by(account: user.account, conversation_id: status.conversation_id)).to_not be_nil
end
end
@@ -38,11 +35,8 @@
post :destroy, params: { status_id: status.id }
end
- it 'returns http success' do
+ it 'destroys the conversation mute', :aggregate_failures do
expect(response).to have_http_status(200)
- end
-
- it 'destroys the conversation mute' do
expect(ConversationMute.find_by(account: user.account, conversation_id: status.conversation_id)).to be_nil
end
end
diff --git a/spec/controllers/api/v1/statuses/reblogged_by_accounts_controller_spec.rb b/spec/controllers/api/v1/statuses/reblogged_by_accounts_controller_spec.rb
index 756010af87e2d4..0d15cca75c3430 100644
--- a/spec/controllers/api/v1/statuses/reblogged_by_accounts_controller_spec.rb
+++ b/spec/controllers/api/v1/statuses/reblogged_by_accounts_controller_spec.rb
@@ -24,14 +24,12 @@
Fabricate(:status, account: bob, reblog_of_id: status.id)
end
- it 'returns http success' do
+ it 'returns accounts who reblogged the status', :aggregate_failures do
get :index, params: { status_id: status.id, limit: 2 }
+
expect(response).to have_http_status(200)
expect(response.headers['Link'].links.size).to eq(2)
- end
- it 'returns accounts who reblogged the status' do
- get :index, params: { status_id: status.id, limit: 2 }
expect(body_as_json.size).to eq 2
expect([body_as_json[0][:id], body_as_json[1][:id]]).to contain_exactly(alice.id.to_s, bob.id.to_s)
end
diff --git a/spec/controllers/api/v1/statuses/reblogs_controller_spec.rb b/spec/controllers/api/v1/statuses/reblogs_controller_spec.rb
index 16ce95dc22bc66..2f2b30b07d0539 100644
--- a/spec/controllers/api/v1/statuses/reblogs_controller_spec.rb
+++ b/spec/controllers/api/v1/statuses/reblogs_controller_spec.rb
@@ -28,19 +28,13 @@
end
context 'with public status' do
- it 'returns http success' do
+ it 'reblogs the status', :aggregate_failures do
expect(response).to have_http_status(200)
- end
- it 'updates the reblogs count' do
expect(status.reblogs.count).to eq 1
- end
- it 'updates the reblogged attribute' do
expect(user.account.reblogged?(status)).to be true
- end
- it 'returns json with updated attributes' do
hash_body = body_as_json
expect(hash_body[:reblog][:id]).to eq status.id.to_s
@@ -67,19 +61,13 @@
post :destroy, params: { status_id: status.id }
end
- it 'returns http success' do
+ it 'destroys the reblog', :aggregate_failures do
expect(response).to have_http_status(200)
- end
- it 'updates the reblogs count' do
expect(status.reblogs.count).to eq 0
- end
- it 'updates the reblogged attribute' do
expect(user.account.reblogged?(status)).to be false
- end
- it 'returns json with updated attributes' do
hash_body = body_as_json
expect(hash_body[:id]).to eq status.id.to_s
@@ -97,19 +85,13 @@
post :destroy, params: { status_id: status.id }
end
- it 'returns http success' do
+ it 'destroys the reblog', :aggregate_failures do
expect(response).to have_http_status(200)
- end
- it 'updates the reblogs count' do
expect(status.reblogs.count).to eq 0
- end
- it 'updates the reblogged attribute' do
expect(user.account.reblogged?(status)).to be false
- end
- it 'returns json with updated attributes' do
hash_body = body_as_json
expect(hash_body[:id]).to eq status.id.to_s
diff --git a/spec/controllers/api/v1/statuses/sources_controller_spec.rb b/spec/controllers/api/v1/statuses/sources_controller_spec.rb
deleted file mode 100644
index fbe6fa0be6cbc1..00000000000000
--- a/spec/controllers/api/v1/statuses/sources_controller_spec.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# frozen_string_literal: true
-
-require 'rails_helper'
-
-describe Api::V1::Statuses::SourcesController do
- render_views
-
- let(:user) { Fabricate(:user) }
- let(:app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') }
- let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses', application: app) }
-
- context 'with an oauth token' do
- before do
- allow(controller).to receive(:doorkeeper_token) { token }
- end
-
- describe 'GET #show' do
- let(:status) { Fabricate(:status, account: user.account) }
-
- before do
- get :show, params: { status_id: status.id }
- end
-
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
- end
- end
-end
diff --git a/spec/controllers/api/v1/statuses_controller_spec.rb b/spec/controllers/api/v1/statuses_controller_spec.rb
index c2bdba9ace3bf6..30bafe19ac30e5 100644
--- a/spec/controllers/api/v1/statuses_controller_spec.rb
+++ b/spec/controllers/api/v1/statuses_controller_spec.rb
@@ -30,14 +30,11 @@
user.account.custom_filters.create!(phrase: 'filter1', context: %w(home), action: :hide, keywords_attributes: [{ keyword: 'banned' }, { keyword: 'irrelevant' }])
end
- it 'returns http success' do
- get :show, params: { id: status.id }
- expect(response).to have_http_status(200)
- end
-
- it 'returns filter information' do
+ it 'returns filter information', :aggregate_failures do
get :show, params: { id: status.id }
json = body_as_json
+
+ expect(response).to have_http_status(200)
expect(json[:filtered][0]).to include({
filter: a_hash_including({
id: user.account.custom_filters.first.id.to_s,
@@ -57,14 +54,11 @@
filter.statuses.create!(status_id: status.id)
end
- it 'returns http success' do
- get :show, params: { id: status.id }
- expect(response).to have_http_status(200)
- end
-
- it 'returns filter information' do
+ it 'returns filter information', :aggregate_failures do
get :show, params: { id: status.id }
json = body_as_json
+
+ expect(response).to have_http_status(200)
expect(json[:filtered][0]).to include({
filter: a_hash_including({
id: user.account.custom_filters.first.id.to_s,
@@ -83,14 +77,11 @@
user.account.custom_filters.create!(phrase: 'filter1', context: %w(home), action: :hide, keywords_attributes: [{ keyword: 'banned' }, { keyword: 'irrelevant' }])
end
- it 'returns http success' do
- get :show, params: { id: status.id }
- expect(response).to have_http_status(200)
- end
-
- it 'returns filter information' do
+ it 'returns filter information', :aggregate_failures do
get :show, params: { id: status.id }
json = body_as_json
+
+ expect(response).to have_http_status(200)
expect(json[:reblog][:filtered][0]).to include({
filter: a_hash_including({
id: user.account.custom_filters.first.id.to_s,
@@ -125,11 +116,8 @@
post :create, params: { status: 'Hello world' }
end
- it 'returns http success' do
+ it 'returns rate limit headers', :aggregate_failures do
expect(response).to have_http_status(200)
- end
-
- it 'returns rate limit headers' do
expect(response.headers['X-RateLimit-Limit']).to eq RateLimiter::FAMILIES[:statuses][:limit].to_s
expect(response.headers['X-RateLimit-Remaining']).to eq (RateLimiter::FAMILIES[:statuses][:limit] - 1).to_s
end
@@ -143,11 +131,8 @@
post :create, params: { status: '@alice hm, @bob is really annoying lately', allowed_mentions: [alice.id] }
end
- it 'returns http unprocessable entity' do
+ it 'returns serialized extra accounts in body', :aggregate_failures do
expect(response).to have_http_status(422)
- end
-
- it 'returns serialized extra accounts in body' do
expect(body_as_json[:unexpected_accounts].map { |a| a.slice(:id, :acct) }).to eq [{ id: bob.id.to_s, acct: bob.acct }]
end
end
@@ -157,11 +142,8 @@
post :create, params: {}
end
- it 'returns http unprocessable entity' do
+ it 'returns rate limit headers', :aggregate_failures do
expect(response).to have_http_status(422)
- end
-
- it 'returns rate limit headers' do
expect(response.headers['X-RateLimit-Limit']).to eq RateLimiter::FAMILIES[:statuses][:limit].to_s
end
end
@@ -173,11 +155,8 @@
post :create, params: { status: 'Hello world' }
end
- it 'returns http too many requests' do
+ it 'returns rate limit headers', :aggregate_failures do
expect(response).to have_http_status(429)
- end
-
- it 'returns rate limit headers' do
expect(response.headers['X-RateLimit-Limit']).to eq RateLimiter::FAMILIES[:statuses][:limit].to_s
expect(response.headers['X-RateLimit-Remaining']).to eq '0'
end
@@ -192,11 +171,8 @@
post :destroy, params: { id: status.id }
end
- it 'returns http success' do
+ it 'removes the status', :aggregate_failures do
expect(response).to have_http_status(200)
- end
-
- it 'removes the status' do
expect(Status.find_by(id: status.id)).to be_nil
end
end
@@ -209,11 +185,8 @@
put :update, params: { id: status.id, status: 'I am updated' }
end
- it 'returns http success' do
+ it 'updates the status', :aggregate_failures do
expect(response).to have_http_status(200)
- end
-
- it 'updates the status' do
expect(status.reload.text).to eq 'I am updated'
end
end
diff --git a/spec/controllers/api/v1/timelines/tag_controller_spec.rb b/spec/controllers/api/v1/timelines/tag_controller_spec.rb
deleted file mode 100644
index 8896f02a77272e..00000000000000
--- a/spec/controllers/api/v1/timelines/tag_controller_spec.rb
+++ /dev/null
@@ -1,75 +0,0 @@
-# frozen_string_literal: true
-
-require 'rails_helper'
-
-describe Api::V1::Timelines::TagController do
- render_views
-
- let(:user) { Fabricate(:user) }
- let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses') }
-
- before do
- allow(controller).to receive(:doorkeeper_token) { token }
- end
-
- describe 'GET #show' do
- subject do
- get :show, params: { id: 'test' }
- end
-
- before do
- PostStatusService.new.call(user.account, text: 'It is a #test')
- end
-
- context 'when the instance allows public preview' do
- before do
- Setting.timeline_preview = true
- end
-
- context 'when the user is not authenticated' do
- let(:token) { nil }
-
- it 'returns http success', :aggregate_failures do
- subject
-
- expect(response).to have_http_status(200)
- expect(response.headers['Link'].links.size).to eq(2)
- end
- end
-
- context 'when the user is authenticated' do
- it 'returns http success', :aggregate_failures do
- subject
-
- expect(response).to have_http_status(200)
- expect(response.headers['Link'].links.size).to eq(2)
- end
- end
- end
-
- context 'when the instance does not allow public preview' do
- before do
- Form::AdminSettings.new(timeline_preview: false).save
- end
-
- context 'when the user is not authenticated' do
- let(:token) { nil }
-
- it 'returns http unauthorized' do
- subject
-
- expect(response).to have_http_status(401)
- end
- end
-
- context 'when the user is authenticated' do
- it 'returns http success', :aggregate_failures do
- subject
-
- expect(response).to have_http_status(200)
- expect(response.headers['Link'].links.size).to eq(2)
- end
- end
- end
- end
-end
diff --git a/spec/controllers/api/v2/admin/accounts_controller_spec.rb b/spec/controllers/api/v2/admin/accounts_controller_spec.rb
index 635f645915beef..18b3950140eb4f 100644
--- a/spec/controllers/api/v2/admin/accounts_controller_spec.rb
+++ b/spec/controllers/api/v2/admin/accounts_controller_spec.rb
@@ -44,14 +44,14 @@
context "when called with #{params.inspect}" do
let(:params) { params }
- it 'returns http success' do
+ it "returns the correct accounts (#{expected_results.inspect})" do
expect(response).to have_http_status(200)
- end
- it "returns the correct accounts (#{expected_results.inspect})" do
- json = body_as_json
+ expect(body_json_ids).to eq(expected_results.map { |symbol| send(symbol).id })
+ end
- expect(json.map { |a| a[:id].to_i }).to eq(expected_results.map { |symbol| send(symbol).id })
+ def body_json_ids
+ body_as_json.map { |a| a[:id].to_i }
end
end
end
diff --git a/spec/controllers/api/v2/filters/keywords_controller_spec.rb b/spec/controllers/api/v2/filters/keywords_controller_spec.rb
index 057a9c3d00390f..5321f787a1aedc 100644
--- a/spec/controllers/api/v2/filters/keywords_controller_spec.rb
+++ b/spec/controllers/api/v2/filters/keywords_controller_spec.rb
@@ -40,17 +40,13 @@
post :create, params: { filter_id: filter_id, keyword: 'magic', whole_word: false }
end
- it 'returns http success' do
+ it 'creates a filter', :aggregate_failures do
expect(response).to have_http_status(200)
- end
- it 'returns a keyword' do
json = body_as_json
expect(json[:keyword]).to eq 'magic'
expect(json[:whole_word]).to be false
- end
- it 'creates a keyword' do
filter = user.account.custom_filters.first
expect(filter).to_not be_nil
expect(filter.keywords.pluck(:keyword)).to eq ['magic']
@@ -73,11 +69,9 @@
get :show, params: { id: keyword.id }
end
- it 'returns http success' do
+ it 'responds with the keyword', :aggregate_failures do
expect(response).to have_http_status(200)
- end
- it 'returns expected data' do
json = body_as_json
expect(json[:keyword]).to eq 'foo'
expect(json[:whole_word]).to be false
@@ -100,11 +94,9 @@
get :update, params: { id: keyword.id, keyword: 'updated' }
end
- it 'returns http success' do
+ it 'updates the keyword', :aggregate_failures do
expect(response).to have_http_status(200)
- end
- it 'updates the keyword' do
expect(keyword.reload.keyword).to eq 'updated'
end
@@ -125,11 +117,9 @@
delete :destroy, params: { id: keyword.id }
end
- it 'returns http success' do
+ it 'destroys the keyword', :aggregate_failures do
expect(response).to have_http_status(200)
- end
- it 'removes the filter' do
expect { keyword.reload }.to raise_error ActiveRecord::RecordNotFound
end
diff --git a/spec/controllers/api/v2/filters/statuses_controller_spec.rb b/spec/controllers/api/v2/filters/statuses_controller_spec.rb
index 588532ffd22bea..5c2a623954f4be 100644
--- a/spec/controllers/api/v2/filters/statuses_controller_spec.rb
+++ b/spec/controllers/api/v2/filters/statuses_controller_spec.rb
@@ -41,16 +41,12 @@
post :create, params: { filter_id: filter_id, status_id: status.id }
end
- it 'returns http success' do
+ it 'creates a filter', :aggregate_failures do
expect(response).to have_http_status(200)
- end
- it 'returns a status filter' do
json = body_as_json
expect(json[:status_id]).to eq status.id.to_s
- end
- it 'creates a status filter' do
filter = user.account.custom_filters.first
expect(filter).to_not be_nil
expect(filter.statuses.pluck(:status_id)).to eq [status.id]
@@ -73,11 +69,9 @@
get :show, params: { id: status_filter.id }
end
- it 'returns http success' do
+ it 'responds with the filter', :aggregate_failures do
expect(response).to have_http_status(200)
- end
- it 'returns expected data' do
json = body_as_json
expect(json[:status_id]).to eq status_filter.status_id.to_s
end
@@ -99,11 +93,9 @@
delete :destroy, params: { id: status_filter.id }
end
- it 'returns http success' do
+ it 'destroys the filter', :aggregate_failures do
expect(response).to have_http_status(200)
- end
- it 'removes the filter' do
expect { status_filter.reload }.to raise_error ActiveRecord::RecordNotFound
end
diff --git a/spec/controllers/concerns/account_controller_concern_spec.rb b/spec/controllers/concerns/account_controller_concern_spec.rb
index d080475c32a835..56ffcfb047c844 100644
--- a/spec/controllers/concerns/account_controller_concern_spec.rb
+++ b/spec/controllers/concerns/account_controller_concern_spec.rb
@@ -62,7 +62,7 @@ def success
end
it 'sets link headers' do
- account = Fabricate(:account, username: 'username')
+ Fabricate(:account, username: 'username')
get 'success', params: { account_username: 'username' }
expect(response.headers['Link'].to_s).to eq '; rel="lrdd"; type="application/jrd+json", ; rel="alternate"; type="application/activity+json"'
end
diff --git a/spec/controllers/settings/imports_controller_spec.rb b/spec/controllers/settings/imports_controller_spec.rb
index 76e1e4ecb0c5db..35d2f081939006 100644
--- a/spec/controllers/settings/imports_controller_spec.rb
+++ b/spec/controllers/settings/imports_controller_spec.rb
@@ -252,6 +252,19 @@
include_examples 'export failed rows', "https://foo.com/1\nhttps://foo.com/2\n"
end
+
+ context 'with lists' do
+ let(:import_type) { 'lists' }
+
+ let!(:rows) do
+ [
+ { 'list_name' => 'Amigos', 'acct' => 'user@example.com' },
+ { 'list_name' => 'Frenemies', 'acct' => 'user@org.org' },
+ ].map { |data| Fabricate(:bulk_import_row, bulk_import: bulk_import, data: data) }
+ end
+
+ include_examples 'export failed rows', "Amigos,user@example.com\nFrenemies,user@org.org\n"
+ end
end
describe 'POST #create' do
diff --git a/spec/controllers/statuses_controller_spec.rb b/spec/controllers/statuses_controller_spec.rb
index bd98929c0267ea..8b715824b88cbc 100644
--- a/spec/controllers/statuses_controller_spec.rb
+++ b/spec/controllers/statuses_controller_spec.rb
@@ -5,25 +5,6 @@
describe StatusesController do
render_views
- shared_examples 'cacheable response' do
- it 'does not set cookies' do
- expect(response.cookies).to be_empty
- expect(response.headers['Set-Cookies']).to be_nil
- end
-
- it 'does not set sessions' do
- expect(session).to be_empty
- end
-
- it 'returns Vary header' do
- expect(response.headers['Vary']).to include 'Accept, Accept-Language, Cookie'
- end
-
- it 'returns public Cache-Control header' do
- expect(response.headers['Cache-Control']).to include 'public'
- end
- end
-
describe 'GET #show' do
let(:account) { Fabricate(:account) }
let(:status) { Fabricate(:status, account: account) }
@@ -88,7 +69,7 @@
context 'with JSON' do
let(:format) { 'json' }
- it_behaves_like 'cacheable response'
+ it_behaves_like 'cacheable response', expects_vary: 'Accept, Accept-Language, Cookie'
it 'renders ActivityPub Note object successfully', :aggregate_failures do
expect(response).to have_http_status(200)
@@ -371,7 +352,7 @@
context 'with JSON' do
let(:format) { 'json' }
- it_behaves_like 'cacheable response'
+ it_behaves_like 'cacheable response', expects_vary: 'Accept, Accept-Language, Cookie'
it 'renders ActivityPub Note object successfully', :aggregate_failures do
expect(response).to have_http_status(200)
diff --git a/spec/features/admin/accounts_spec.rb b/spec/features/admin/accounts_spec.rb
new file mode 100644
index 00000000000000..ad9c51485a76db
--- /dev/null
+++ b/spec/features/admin/accounts_spec.rb
@@ -0,0 +1,81 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe 'Admin::Accounts' do
+ let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
+
+ before do
+ sign_in current_user
+ end
+
+ describe 'Performing batch updates' do
+ let(:unapproved_user_account) { Fabricate(:account) }
+ let(:approved_user_account) { Fabricate(:account) }
+
+ before do
+ unapproved_user_account.user.update(approved: false)
+ approved_user_account.user.update(approved: true)
+
+ visit admin_accounts_path
+ end
+
+ context 'without selecting any accounts' do
+ it 'displays a notice about account selection' do
+ click_button button_for_suspend
+
+ expect(page).to have_content(selection_error_text)
+ end
+ end
+
+ context 'with action of `suspend`' do
+ it 'suspends the account' do
+ batch_checkbox_for(approved_user_account).check
+
+ click_button button_for_suspend
+
+ expect(approved_user_account.reload).to be_suspended
+ end
+ end
+
+ context 'with action of `approve`' do
+ it 'approves the account user' do
+ batch_checkbox_for(unapproved_user_account).check
+
+ click_button button_for_approve
+
+ expect(unapproved_user_account.reload.user).to be_approved
+ end
+ end
+
+ context 'with action of `reject`' do
+ it 'rejects and removes the account' do
+ batch_checkbox_for(unapproved_user_account).check
+
+ click_button button_for_reject
+
+ expect { unapproved_user_account.reload }.to raise_error(ActiveRecord::RecordNotFound)
+ end
+ end
+
+ def button_for_suspend
+ I18n.t('admin.accounts.perform_full_suspension')
+ end
+
+ def button_for_approve
+ I18n.t('admin.accounts.approve')
+ end
+
+ def button_for_reject
+ I18n.t('admin.accounts.reject')
+ end
+
+ def selection_error_text
+ I18n.t('admin.accounts.no_account_selected')
+ end
+
+ def batch_checkbox_for(account)
+ find("#form_account_batch_account_ids_#{account.id}")
+ end
+ end
+end
diff --git a/spec/features/admin/custom_emojis_spec.rb b/spec/features/admin/custom_emojis_spec.rb
new file mode 100644
index 00000000000000..3fea8f06fe6f50
--- /dev/null
+++ b/spec/features/admin/custom_emojis_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe 'Admin::CustomEmojis' do
+ let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
+
+ before do
+ sign_in current_user
+ end
+
+ describe 'Performing batch updates' do
+ before do
+ visit admin_custom_emojis_path
+ end
+
+ context 'without selecting any records' do
+ it 'displays a notice about selection' do
+ click_button button_for_enable
+
+ expect(page).to have_content(selection_error_text)
+ end
+ end
+
+ def button_for_enable
+ I18n.t('admin.custom_emojis.enable')
+ end
+
+ def selection_error_text
+ I18n.t('admin.custom_emojis.no_emoji_selected')
+ end
+ end
+end
diff --git a/spec/features/admin/domain_blocks_spec.rb b/spec/features/admin/domain_blocks_spec.rb
index 4672c1e1a9ee45..0d7b90c21cd5d2 100644
--- a/spec/features/admin/domain_blocks_spec.rb
+++ b/spec/features/admin/domain_blocks_spec.rb
@@ -13,7 +13,7 @@
fill_in 'domain_block_domain', with: 'example.com'
select I18n.t('admin.domain_blocks.new.severity.silence'), from: 'domain_block_severity'
- click_on I18n.t('admin.domain_blocks.new.create')
+ click_button I18n.t('admin.domain_blocks.new.create')
expect(DomainBlock.exists?(domain: 'example.com', severity: 'silence')).to be true
end
@@ -25,13 +25,13 @@
fill_in 'domain_block_domain', with: 'example.com'
select I18n.t('admin.domain_blocks.new.severity.suspend'), from: 'domain_block_severity'
- click_on I18n.t('admin.domain_blocks.new.create')
+ click_button I18n.t('admin.domain_blocks.new.create')
# It presents a confirmation screen
expect(page).to have_title(I18n.t('admin.domain_blocks.confirm_suspension.title', domain: 'example.com'))
# Confirming creates a block
- click_on I18n.t('admin.domain_blocks.confirm_suspension.confirm')
+ click_button I18n.t('admin.domain_blocks.confirm_suspension.confirm')
expect(DomainBlock.exists?(domain: 'example.com', severity: 'suspend')).to be true
end
@@ -45,13 +45,13 @@
fill_in 'domain_block_domain', with: 'example.com'
select I18n.t('admin.domain_blocks.new.severity.suspend'), from: 'domain_block_severity'
- click_on I18n.t('admin.domain_blocks.new.create')
+ click_button I18n.t('admin.domain_blocks.new.create')
# It presents a confirmation screen
expect(page).to have_title(I18n.t('admin.domain_blocks.confirm_suspension.title', domain: 'example.com'))
# Confirming updates the block
- click_on I18n.t('admin.domain_blocks.confirm_suspension.confirm')
+ click_button I18n.t('admin.domain_blocks.confirm_suspension.confirm')
expect(domain_block.reload.severity).to eq 'suspend'
end
@@ -65,13 +65,13 @@
fill_in 'domain_block_domain', with: 'subdomain.example.com'
select I18n.t('admin.domain_blocks.new.severity.suspend'), from: 'domain_block_severity'
- click_on I18n.t('admin.domain_blocks.new.create')
+ click_button I18n.t('admin.domain_blocks.new.create')
# It presents a confirmation screen
expect(page).to have_title(I18n.t('admin.domain_blocks.confirm_suspension.title', domain: 'subdomain.example.com'))
# Confirming creates the block
- click_on I18n.t('admin.domain_blocks.confirm_suspension.confirm')
+ click_button I18n.t('admin.domain_blocks.confirm_suspension.confirm')
expect(DomainBlock.where(domain: 'subdomain.example.com', severity: 'suspend')).to exist
@@ -88,13 +88,13 @@
visit edit_admin_domain_block_path(domain_block)
select I18n.t('admin.domain_blocks.new.severity.suspend'), from: 'domain_block_severity'
- click_on I18n.t('generic.save_changes')
+ click_button I18n.t('generic.save_changes')
# It presents a confirmation screen
expect(page).to have_title(I18n.t('admin.domain_blocks.confirm_suspension.title', domain: 'example.com'))
# Confirming updates the block
- click_on I18n.t('admin.domain_blocks.confirm_suspension.confirm')
+ click_button I18n.t('admin.domain_blocks.confirm_suspension.confirm')
expect(domain_block.reload.severity).to eq 'suspend'
end
diff --git a/spec/features/admin/email_domain_blocks_spec.rb b/spec/features/admin/email_domain_blocks_spec.rb
new file mode 100644
index 00000000000000..80efe72e95c568
--- /dev/null
+++ b/spec/features/admin/email_domain_blocks_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe 'Admin::EmailDomainBlocks' do
+ let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
+
+ before do
+ sign_in current_user
+ end
+
+ describe 'Performing batch updates' do
+ before do
+ visit admin_email_domain_blocks_path
+ end
+
+ context 'without selecting any records' do
+ it 'displays a notice about selection' do
+ click_button button_for_delete
+
+ expect(page).to have_content(selection_error_text)
+ end
+ end
+
+ def button_for_delete
+ I18n.t('admin.email_domain_blocks.delete')
+ end
+
+ def selection_error_text
+ I18n.t('admin.email_domain_blocks.no_email_domain_block_selected')
+ end
+ end
+end
diff --git a/spec/features/admin/ip_blocks_spec.rb b/spec/features/admin/ip_blocks_spec.rb
new file mode 100644
index 00000000000000..465c8891907013
--- /dev/null
+++ b/spec/features/admin/ip_blocks_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe 'Admin::IpBlocks' do
+ let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
+
+ before do
+ sign_in current_user
+ end
+
+ describe 'Performing batch updates' do
+ before do
+ visit admin_ip_blocks_path
+ end
+
+ context 'without selecting any records' do
+ it 'displays a notice about selection' do
+ click_button button_for_delete
+
+ expect(page).to have_content(selection_error_text)
+ end
+ end
+
+ def button_for_delete
+ I18n.t('admin.ip_blocks.delete')
+ end
+
+ def selection_error_text
+ I18n.t('admin.ip_blocks.no_ip_block_selected')
+ end
+ end
+end
diff --git a/spec/features/admin/software_updates_spec.rb b/spec/features/admin/software_updates_spec.rb
index 4a635d1a794f8f..a2373d35a6080c 100644
--- a/spec/features/admin/software_updates_spec.rb
+++ b/spec/features/admin/software_updates_spec.rb
@@ -11,13 +11,13 @@
it 'shows a link to the software updates page, which links to release notes' do
visit settings_profile_path
- click_on I18n.t('admin.critical_update_pending')
+ click_link I18n.t('admin.critical_update_pending')
expect(page).to have_title(I18n.t('admin.software_updates.title'))
expect(page).to have_content('99.99.99')
- click_on I18n.t('admin.software_updates.release_notes')
+ click_link I18n.t('admin.software_updates.release_notes')
expect(page).to have_current_path('https://github.com/mastodon/mastodon/releases/v99', url: true)
end
end
diff --git a/spec/features/admin/statuses_spec.rb b/spec/features/admin/statuses_spec.rb
new file mode 100644
index 00000000000000..a21c901a921b23
--- /dev/null
+++ b/spec/features/admin/statuses_spec.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe 'Admin::Statuses' do
+ let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
+
+ before do
+ sign_in current_user
+ end
+
+ describe 'Performing batch updates' do
+ before do
+ _status = Fabricate(:status, account: current_user.account)
+ visit admin_account_statuses_path(account_id: current_user.account_id)
+ end
+
+ context 'without selecting any records' do
+ it 'displays a notice about selection' do
+ click_button button_for_report
+
+ expect(page).to have_content(selection_error_text)
+ end
+ end
+
+ def button_for_report
+ I18n.t('admin.statuses.batch.report')
+ end
+
+ def selection_error_text
+ I18n.t('admin.statuses.no_status_selected')
+ end
+ end
+end
diff --git a/spec/features/admin/trends/links/preview_card_providers_spec.rb b/spec/features/admin/trends/links/preview_card_providers_spec.rb
new file mode 100644
index 00000000000000..cf9796abf362cd
--- /dev/null
+++ b/spec/features/admin/trends/links/preview_card_providers_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe 'Admin::Trends::Links::PreviewCardProviders' do
+ let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
+
+ before do
+ sign_in current_user
+ end
+
+ describe 'Performing batch updates' do
+ before do
+ visit admin_trends_links_preview_card_providers_path
+ end
+
+ context 'without selecting any records' do
+ it 'displays a notice about selection' do
+ click_button button_for_allow
+
+ expect(page).to have_content(selection_error_text)
+ end
+ end
+
+ def button_for_allow
+ I18n.t('admin.trends.allow')
+ end
+
+ def selection_error_text
+ I18n.t('admin.trends.links.publishers.no_publisher_selected')
+ end
+ end
+end
diff --git a/spec/features/admin/trends/links_spec.rb b/spec/features/admin/trends/links_spec.rb
new file mode 100644
index 00000000000000..8b1b991a5a85cc
--- /dev/null
+++ b/spec/features/admin/trends/links_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe 'Admin::Trends::Links' do
+ let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
+
+ before do
+ sign_in current_user
+ end
+
+ describe 'Performing batch updates' do
+ before do
+ visit admin_trends_links_path
+ end
+
+ context 'without selecting any records' do
+ it 'displays a notice about selection' do
+ click_button button_for_allow
+
+ expect(page).to have_content(selection_error_text)
+ end
+ end
+
+ def button_for_allow
+ I18n.t('admin.trends.links.allow')
+ end
+
+ def selection_error_text
+ I18n.t('admin.trends.links.no_link_selected')
+ end
+ end
+end
diff --git a/spec/features/admin/trends/statuses_spec.rb b/spec/features/admin/trends/statuses_spec.rb
new file mode 100644
index 00000000000000..a578ab05593c08
--- /dev/null
+++ b/spec/features/admin/trends/statuses_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe 'Admin::Trends::Statuses' do
+ let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
+
+ before do
+ sign_in current_user
+ end
+
+ describe 'Performing batch updates' do
+ before do
+ visit admin_trends_statuses_path
+ end
+
+ context 'without selecting any records' do
+ it 'displays a notice about selection' do
+ click_button button_for_allow
+
+ expect(page).to have_content(selection_error_text)
+ end
+ end
+
+ def button_for_allow
+ I18n.t('admin.trends.statuses.allow')
+ end
+
+ def selection_error_text
+ I18n.t('admin.trends.statuses.no_status_selected')
+ end
+ end
+end
diff --git a/spec/features/admin/trends/tags_spec.rb b/spec/features/admin/trends/tags_spec.rb
new file mode 100644
index 00000000000000..7502bc8c6f50c1
--- /dev/null
+++ b/spec/features/admin/trends/tags_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe 'Admin::Trends::Tags' do
+ let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
+
+ before do
+ sign_in current_user
+ end
+
+ describe 'Performing batch updates' do
+ before do
+ visit admin_trends_tags_path
+ end
+
+ context 'without selecting any records' do
+ it 'displays a notice about selection' do
+ click_button button_for_allow
+
+ expect(page).to have_content(selection_error_text)
+ end
+ end
+
+ def button_for_allow
+ I18n.t('admin.trends.allow')
+ end
+
+ def selection_error_text
+ I18n.t('admin.trends.tags.no_tag_selected')
+ end
+ end
+end
diff --git a/spec/features/captcha_spec.rb b/spec/features/captcha_spec.rb
index db89ff3e616c58..6ccf066208fae5 100644
--- a/spec/features/captcha_spec.rb
+++ b/spec/features/captcha_spec.rb
@@ -27,7 +27,7 @@
expect(user.reload.confirmed?).to be false
# It redirects to app and confirms user
- click_on I18n.t('challenge.confirm')
+ click_button I18n.t('challenge.confirm')
expect(user.reload.confirmed?).to be true
expect(page).to have_current_path(/\A#{client_app.confirmation_redirect_uri}/, url: true)
end
diff --git a/spec/features/log_in_spec.rb b/spec/features/log_in_spec.rb
index c64e19d2b7c43f..7e5196aba99564 100644
--- a/spec/features/log_in_spec.rb
+++ b/spec/features/log_in_spec.rb
@@ -19,7 +19,7 @@
it 'A valid email and password user is able to log in' do
fill_in 'user_email', with: email
fill_in 'user_password', with: password
- click_on I18n.t('auth.login')
+ click_button I18n.t('auth.login')
expect(subject).to have_css('div.app-holder')
end
@@ -27,7 +27,7 @@
it 'A invalid email and password user is not able to log in' do
fill_in 'user_email', with: 'invalid_email'
fill_in 'user_password', with: 'invalid_password'
- click_on I18n.t('auth.login')
+ click_button I18n.t('auth.login')
expect(subject).to have_css('.flash-message', text: failure_message('invalid'))
end
@@ -38,7 +38,7 @@
it 'A unconfirmed user is able to log in' do
fill_in 'user_email', with: email
fill_in 'user_password', with: password
- click_on I18n.t('auth.login')
+ click_button I18n.t('auth.login')
expect(subject).to have_css('div.admin-wrapper')
end
diff --git a/spec/features/oauth_spec.rb b/spec/features/oauth_spec.rb
index 967956cc8ea91a..0e612b56a5a24f 100644
--- a/spec/features/oauth_spec.rb
+++ b/spec/features/oauth_spec.rb
@@ -20,7 +20,7 @@
expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.authorize'))
# Upon authorizing, it redirects to the apps' callback URL
- click_on I18n.t('doorkeeper.authorizations.buttons.authorize')
+ click_button I18n.t('doorkeeper.authorizations.buttons.authorize')
expect(page).to have_current_path(/\A#{client_app.redirect_uri}/, url: true)
# It grants the app access to the account
@@ -35,7 +35,7 @@
expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.deny'))
# Upon denying, it redirects to the apps' callback URL
- click_on I18n.t('doorkeeper.authorizations.buttons.deny')
+ click_button I18n.t('doorkeeper.authorizations.buttons.deny')
expect(page).to have_current_path(/\A#{client_app.redirect_uri}/, url: true)
# It does not grant the app access to the account
@@ -63,17 +63,17 @@
# Failing to log-in presents the form again
fill_in 'user_email', with: email
fill_in 'user_password', with: 'wrong password'
- click_on I18n.t('auth.login')
+ click_button I18n.t('auth.login')
expect(page).to have_content(I18n.t('auth.login'))
# Logging in redirects to an authorization page
fill_in 'user_email', with: email
fill_in 'user_password', with: password
- click_on I18n.t('auth.login')
+ click_button I18n.t('auth.login')
expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.authorize'))
# Upon authorizing, it redirects to the apps' callback URL
- click_on I18n.t('doorkeeper.authorizations.buttons.authorize')
+ click_button I18n.t('doorkeeper.authorizations.buttons.authorize')
expect(page).to have_current_path(/\A#{client_app.redirect_uri}/, url: true)
# It grants the app access to the account
@@ -90,17 +90,17 @@
# Failing to log-in presents the form again
fill_in 'user_email', with: email
fill_in 'user_password', with: 'wrong password'
- click_on I18n.t('auth.login')
+ click_button I18n.t('auth.login')
expect(page).to have_content(I18n.t('auth.login'))
# Logging in redirects to an authorization page
fill_in 'user_email', with: email
fill_in 'user_password', with: password
- click_on I18n.t('auth.login')
+ click_button I18n.t('auth.login')
expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.authorize'))
# Upon denying, it redirects to the apps' callback URL
- click_on I18n.t('doorkeeper.authorizations.buttons.deny')
+ click_button I18n.t('doorkeeper.authorizations.buttons.deny')
expect(page).to have_current_path(/\A#{client_app.redirect_uri}/, url: true)
# It does not grant the app access to the account
@@ -120,27 +120,27 @@
# Failing to log-in presents the form again
fill_in 'user_email', with: email
fill_in 'user_password', with: 'wrong password'
- click_on I18n.t('auth.login')
+ click_button I18n.t('auth.login')
expect(page).to have_content(I18n.t('auth.login'))
# Logging in redirects to a two-factor authentication page
fill_in 'user_email', with: email
fill_in 'user_password', with: password
- click_on I18n.t('auth.login')
+ click_button I18n.t('auth.login')
expect(page).to have_content(I18n.t('simple_form.hints.sessions.otp'))
# Filling in an incorrect two-factor authentication code presents the form again
fill_in 'user_otp_attempt', with: 'wrong'
- click_on I18n.t('auth.login')
+ click_button I18n.t('auth.login')
expect(page).to have_content(I18n.t('simple_form.hints.sessions.otp'))
# Filling in the correct TOTP code redirects to an app authorization page
fill_in 'user_otp_attempt', with: user.current_otp
- click_on I18n.t('auth.login')
+ click_button I18n.t('auth.login')
expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.authorize'))
# Upon authorizing, it redirects to the apps' callback URL
- click_on I18n.t('doorkeeper.authorizations.buttons.authorize')
+ click_button I18n.t('doorkeeper.authorizations.buttons.authorize')
expect(page).to have_current_path(/\A#{client_app.redirect_uri}/, url: true)
# It grants the app access to the account
@@ -157,27 +157,27 @@
# Failing to log-in presents the form again
fill_in 'user_email', with: email
fill_in 'user_password', with: 'wrong password'
- click_on I18n.t('auth.login')
+ click_button I18n.t('auth.login')
expect(page).to have_content(I18n.t('auth.login'))
# Logging in redirects to a two-factor authentication page
fill_in 'user_email', with: email
fill_in 'user_password', with: password
- click_on I18n.t('auth.login')
+ click_button I18n.t('auth.login')
expect(page).to have_content(I18n.t('simple_form.hints.sessions.otp'))
# Filling in an incorrect two-factor authentication code presents the form again
fill_in 'user_otp_attempt', with: 'wrong'
- click_on I18n.t('auth.login')
+ click_button I18n.t('auth.login')
expect(page).to have_content(I18n.t('simple_form.hints.sessions.otp'))
# Filling in the correct TOTP code redirects to an app authorization page
fill_in 'user_otp_attempt', with: user.current_otp
- click_on I18n.t('auth.login')
+ click_button I18n.t('auth.login')
expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.authorize'))
# Upon denying, it redirects to the apps' callback URL
- click_on I18n.t('doorkeeper.authorizations.buttons.deny')
+ click_button I18n.t('doorkeeper.authorizations.buttons.deny')
expect(page).to have_current_path(/\A#{client_app.redirect_uri}/, url: true)
# It does not grant the app access to the account
diff --git a/spec/fixtures/requests/json-ld.activitystreams.txt b/spec/fixtures/requests/json-ld.activitystreams.txt
deleted file mode 100644
index 395797b2721801..00000000000000
--- a/spec/fixtures/requests/json-ld.activitystreams.txt
+++ /dev/null
@@ -1,391 +0,0 @@
-HTTP/1.1 200 OK
-Date: Tue, 01 May 2018 23:25:57 GMT
-Content-Location: activitystreams.jsonld
-Vary: negotiate,accept
-TCN: choice
-Last-Modified: Mon, 16 Apr 2018 00:28:23 GMT
-ETag: "1eb0-569ec4caa97c0;d3-540ee27e0eec0"
-Accept-Ranges: bytes
-Content-Length: 7856
-Cache-Control: max-age=21600
-Expires: Wed, 02 May 2018 05:25:57 GMT
-P3P: policyref="http://www.w3.org/2014/08/p3p.xml"
-Access-Control-Allow-Origin: *
-Content-Type: application/ld+json
-Strict-Transport-Security: max-age=15552000; includeSubdomains; preload
-Content-Security-Policy: upgrade-insecure-requests
-
-{
- "@context": {
- "@vocab": "_:",
- "xsd": "http://www.w3.org/2001/XMLSchema#",
- "as": "https://www.w3.org/ns/activitystreams#",
- "ldp": "http://www.w3.org/ns/ldp#",
- "id": "@id",
- "type": "@type",
- "Accept": "as:Accept",
- "Activity": "as:Activity",
- "IntransitiveActivity": "as:IntransitiveActivity",
- "Add": "as:Add",
- "Announce": "as:Announce",
- "Application": "as:Application",
- "Arrive": "as:Arrive",
- "Article": "as:Article",
- "Audio": "as:Audio",
- "Block": "as:Block",
- "Collection": "as:Collection",
- "CollectionPage": "as:CollectionPage",
- "Relationship": "as:Relationship",
- "Create": "as:Create",
- "Delete": "as:Delete",
- "Dislike": "as:Dislike",
- "Document": "as:Document",
- "Event": "as:Event",
- "Follow": "as:Follow",
- "Flag": "as:Flag",
- "Group": "as:Group",
- "Ignore": "as:Ignore",
- "Image": "as:Image",
- "Invite": "as:Invite",
- "Join": "as:Join",
- "Leave": "as:Leave",
- "Like": "as:Like",
- "Link": "as:Link",
- "Mention": "as:Mention",
- "Note": "as:Note",
- "Object": "as:Object",
- "Offer": "as:Offer",
- "OrderedCollection": "as:OrderedCollection",
- "OrderedCollectionPage": "as:OrderedCollectionPage",
- "Organization": "as:Organization",
- "Page": "as:Page",
- "Person": "as:Person",
- "Place": "as:Place",
- "Profile": "as:Profile",
- "Question": "as:Question",
- "Reject": "as:Reject",
- "Remove": "as:Remove",
- "Service": "as:Service",
- "TentativeAccept": "as:TentativeAccept",
- "TentativeReject": "as:TentativeReject",
- "Tombstone": "as:Tombstone",
- "Undo": "as:Undo",
- "Update": "as:Update",
- "Video": "as:Video",
- "View": "as:View",
- "Listen": "as:Listen",
- "Read": "as:Read",
- "Move": "as:Move",
- "Travel": "as:Travel",
- "IsFollowing": "as:IsFollowing",
- "IsFollowedBy": "as:IsFollowedBy",
- "IsContact": "as:IsContact",
- "IsMember": "as:IsMember",
- "subject": {
- "@id": "as:subject",
- "@type": "@id"
- },
- "relationship": {
- "@id": "as:relationship",
- "@type": "@id"
- },
- "actor": {
- "@id": "as:actor",
- "@type": "@id"
- },
- "attributedTo": {
- "@id": "as:attributedTo",
- "@type": "@id"
- },
- "attachment": {
- "@id": "as:attachment",
- "@type": "@id"
- },
- "bcc": {
- "@id": "as:bcc",
- "@type": "@id"
- },
- "bto": {
- "@id": "as:bto",
- "@type": "@id"
- },
- "cc": {
- "@id": "as:cc",
- "@type": "@id"
- },
- "context": {
- "@id": "as:context",
- "@type": "@id"
- },
- "current": {
- "@id": "as:current",
- "@type": "@id"
- },
- "first": {
- "@id": "as:first",
- "@type": "@id"
- },
- "generator": {
- "@id": "as:generator",
- "@type": "@id"
- },
- "icon": {
- "@id": "as:icon",
- "@type": "@id"
- },
- "image": {
- "@id": "as:image",
- "@type": "@id"
- },
- "inReplyTo": {
- "@id": "as:inReplyTo",
- "@type": "@id"
- },
- "items": {
- "@id": "as:items",
- "@type": "@id"
- },
- "instrument": {
- "@id": "as:instrument",
- "@type": "@id"
- },
- "orderedItems": {
- "@id": "as:items",
- "@type": "@id",
- "@container": "@list"
- },
- "last": {
- "@id": "as:last",
- "@type": "@id"
- },
- "location": {
- "@id": "as:location",
- "@type": "@id"
- },
- "next": {
- "@id": "as:next",
- "@type": "@id"
- },
- "object": {
- "@id": "as:object",
- "@type": "@id"
- },
- "oneOf": {
- "@id": "as:oneOf",
- "@type": "@id"
- },
- "anyOf": {
- "@id": "as:anyOf",
- "@type": "@id"
- },
- "closed": {
- "@id": "as:closed",
- "@type": "xsd:dateTime"
- },
- "origin": {
- "@id": "as:origin",
- "@type": "@id"
- },
- "accuracy": {
- "@id": "as:accuracy",
- "@type": "xsd:float"
- },
- "prev": {
- "@id": "as:prev",
- "@type": "@id"
- },
- "preview": {
- "@id": "as:preview",
- "@type": "@id"
- },
- "replies": {
- "@id": "as:replies",
- "@type": "@id"
- },
- "result": {
- "@id": "as:result",
- "@type": "@id"
- },
- "audience": {
- "@id": "as:audience",
- "@type": "@id"
- },
- "partOf": {
- "@id": "as:partOf",
- "@type": "@id"
- },
- "tag": {
- "@id": "as:tag",
- "@type": "@id"
- },
- "target": {
- "@id": "as:target",
- "@type": "@id"
- },
- "to": {
- "@id": "as:to",
- "@type": "@id"
- },
- "url": {
- "@id": "as:url",
- "@type": "@id"
- },
- "altitude": {
- "@id": "as:altitude",
- "@type": "xsd:float"
- },
- "content": "as:content",
- "contentMap": {
- "@id": "as:content",
- "@container": "@language"
- },
- "name": "as:name",
- "nameMap": {
- "@id": "as:name",
- "@container": "@language"
- },
- "duration": {
- "@id": "as:duration",
- "@type": "xsd:duration"
- },
- "endTime": {
- "@id": "as:endTime",
- "@type": "xsd:dateTime"
- },
- "height": {
- "@id": "as:height",
- "@type": "xsd:nonNegativeInteger"
- },
- "href": {
- "@id": "as:href",
- "@type": "@id"
- },
- "hreflang": "as:hreflang",
- "latitude": {
- "@id": "as:latitude",
- "@type": "xsd:float"
- },
- "longitude": {
- "@id": "as:longitude",
- "@type": "xsd:float"
- },
- "mediaType": "as:mediaType",
- "published": {
- "@id": "as:published",
- "@type": "xsd:dateTime"
- },
- "radius": {
- "@id": "as:radius",
- "@type": "xsd:float"
- },
- "rel": "as:rel",
- "startIndex": {
- "@id": "as:startIndex",
- "@type": "xsd:nonNegativeInteger"
- },
- "startTime": {
- "@id": "as:startTime",
- "@type": "xsd:dateTime"
- },
- "summary": "as:summary",
- "summaryMap": {
- "@id": "as:summary",
- "@container": "@language"
- },
- "totalItems": {
- "@id": "as:totalItems",
- "@type": "xsd:nonNegativeInteger"
- },
- "units": "as:units",
- "updated": {
- "@id": "as:updated",
- "@type": "xsd:dateTime"
- },
- "width": {
- "@id": "as:width",
- "@type": "xsd:nonNegativeInteger"
- },
- "describes": {
- "@id": "as:describes",
- "@type": "@id"
- },
- "formerType": {
- "@id": "as:formerType",
- "@type": "@id"
- },
- "deleted": {
- "@id": "as:deleted",
- "@type": "xsd:dateTime"
- },
- "inbox": {
- "@id": "ldp:inbox",
- "@type": "@id"
- },
- "outbox": {
- "@id": "as:outbox",
- "@type": "@id"
- },
- "following": {
- "@id": "as:following",
- "@type": "@id"
- },
- "followers": {
- "@id": "as:followers",
- "@type": "@id"
- },
- "streams": {
- "@id": "as:streams",
- "@type": "@id"
- },
- "preferredUsername": "as:preferredUsername",
- "endpoints": {
- "@id": "as:endpoints",
- "@type": "@id"
- },
- "uploadMedia": {
- "@id": "as:uploadMedia",
- "@type": "@id"
- },
- "proxyUrl": {
- "@id": "as:proxyUrl",
- "@type": "@id"
- },
- "liked": {
- "@id": "as:liked",
- "@type": "@id"
- },
- "oauthAuthorizationEndpoint": {
- "@id": "as:oauthAuthorizationEndpoint",
- "@type": "@id"
- },
- "oauthTokenEndpoint": {
- "@id": "as:oauthTokenEndpoint",
- "@type": "@id"
- },
- "provideClientKey": {
- "@id": "as:provideClientKey",
- "@type": "@id"
- },
- "signClientKey": {
- "@id": "as:signClientKey",
- "@type": "@id"
- },
- "sharedInbox": {
- "@id": "as:sharedInbox",
- "@type": "@id"
- },
- "Public": {
- "@id": "as:Public",
- "@type": "@id"
- },
- "source": "as:source",
- "likes": {
- "@id": "as:likes",
- "@type": "@id"
- },
- "shares": {
- "@id": "as:shares",
- "@type": "@id"
- }
- }
-}
diff --git a/spec/fixtures/requests/json-ld.identity.txt b/spec/fixtures/requests/json-ld.identity.txt
deleted file mode 100644
index 8810526cb13931..00000000000000
--- a/spec/fixtures/requests/json-ld.identity.txt
+++ /dev/null
@@ -1,100 +0,0 @@
-HTTP/1.1 200 OK
-Accept-Ranges: bytes
-Access-Control-Allow-Headers: DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Accept-Encoding
-Access-Control-Allow-Origin: *
-Content-Type: application/ld+json
-Date: Tue, 01 May 2018 23:28:21 GMT
-Etag: "e26-547a6fc75b04a-gzip"
-Last-Modified: Fri, 03 Feb 2017 21:30:09 GMT
-Server: Apache/2.4.7 (Ubuntu)
-Vary: Accept-Encoding
-Transfer-Encoding: chunked
-
-{
- "@context": {
- "id": "@id",
- "type": "@type",
-
- "cred": "https://w3id.org/credentials#",
- "dc": "http://purl.org/dc/terms/",
- "identity": "https://w3id.org/identity#",
- "perm": "https://w3id.org/permissions#",
- "ps": "https://w3id.org/payswarm#",
- "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
- "rdfs": "http://www.w3.org/2000/01/rdf-schema#",
- "sec": "https://w3id.org/security#",
- "schema": "http://schema.org/",
- "xsd": "http://www.w3.org/2001/XMLSchema#",
-
- "Group": "https://www.w3.org/ns/activitystreams#Group",
-
- "claim": {"@id": "cred:claim", "@type": "@id"},
- "credential": {"@id": "cred:credential", "@type": "@id"},
- "issued": {"@id": "cred:issued", "@type": "xsd:dateTime"},
- "issuer": {"@id": "cred:issuer", "@type": "@id"},
- "recipient": {"@id": "cred:recipient", "@type": "@id"},
- "Credential": "cred:Credential",
- "CryptographicKeyCredential": "cred:CryptographicKeyCredential",
-
- "about": {"@id": "schema:about", "@type": "@id"},
- "address": {"@id": "schema:address", "@type": "@id"},
- "addressCountry": "schema:addressCountry",
- "addressLocality": "schema:addressLocality",
- "addressRegion": "schema:addressRegion",
- "comment": "rdfs:comment",
- "created": {"@id": "dc:created", "@type": "xsd:dateTime"},
- "creator": {"@id": "dc:creator", "@type": "@id"},
- "description": "schema:description",
- "email": "schema:email",
- "familyName": "schema:familyName",
- "givenName": "schema:givenName",
- "image": {"@id": "schema:image", "@type": "@id"},
- "label": "rdfs:label",
- "name": "schema:name",
- "postalCode": "schema:postalCode",
- "streetAddress": "schema:streetAddress",
- "title": "dc:title",
- "url": {"@id": "schema:url", "@type": "@id"},
- "Person": "schema:Person",
- "PostalAddress": "schema:PostalAddress",
- "Organization": "schema:Organization",
-
- "identityService": {"@id": "identity:identityService", "@type": "@id"},
- "idp": {"@id": "identity:idp", "@type": "@id"},
- "Identity": "identity:Identity",
-
- "paymentProcessor": "ps:processor",
- "preferences": {"@id": "ps:preferences", "@type": "@vocab"},
-
- "cipherAlgorithm": "sec:cipherAlgorithm",
- "cipherData": "sec:cipherData",
- "cipherKey": "sec:cipherKey",
- "digestAlgorithm": "sec:digestAlgorithm",
- "digestValue": "sec:digestValue",
- "domain": "sec:domain",
- "expires": {"@id": "sec:expiration", "@type": "xsd:dateTime"},
- "initializationVector": "sec:initializationVector",
- "member": {"@id": "schema:member", "@type": "@id"},
- "memberOf": {"@id": "schema:memberOf", "@type": "@id"},
- "nonce": "sec:nonce",
- "normalizationAlgorithm": "sec:normalizationAlgorithm",
- "owner": {"@id": "sec:owner", "@type": "@id"},
- "password": "sec:password",
- "privateKey": {"@id": "sec:privateKey", "@type": "@id"},
- "privateKeyPem": "sec:privateKeyPem",
- "publicKey": {"@id": "sec:publicKey", "@type": "@id"},
- "publicKeyPem": "sec:publicKeyPem",
- "publicKeyService": {"@id": "sec:publicKeyService", "@type": "@id"},
- "revoked": {"@id": "sec:revoked", "@type": "xsd:dateTime"},
- "signature": "sec:signature",
- "signatureAlgorithm": "sec:signatureAlgorithm",
- "signatureValue": "sec:signatureValue",
- "CryptographicKey": "sec:Key",
- "EncryptedMessage": "sec:EncryptedMessage",
- "GraphSignature2012": "sec:GraphSignature2012",
- "LinkedDataSignature2015": "sec:LinkedDataSignature2015",
-
- "accessControl": {"@id": "perm:accessControl", "@type": "@id"},
- "writePermission": {"@id": "perm:writePermission", "@type": "@id"}
- }
-}
diff --git a/spec/fixtures/requests/json-ld.security.txt b/spec/fixtures/requests/json-ld.security.txt
deleted file mode 100644
index 0d29903e60731f..00000000000000
--- a/spec/fixtures/requests/json-ld.security.txt
+++ /dev/null
@@ -1,61 +0,0 @@
-HTTP/1.1 200 OK
-Accept-Ranges: bytes
-Access-Control-Allow-Headers: DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Accept-Encoding
-Access-Control-Allow-Origin: *
-Content-Type: application/ld+json
-Date: Wed, 02 May 2018 16:25:32 GMT
-Etag: "7e3-5651ec0f7c5ed-gzip"
-Last-Modified: Tue, 13 Feb 2018 21:34:04 GMT
-Server: Apache/2.4.7 (Ubuntu)
-Vary: Accept-Encoding
-Content-Length: 2019
-
-{
- "@context": {
- "id": "@id",
- "type": "@type",
-
- "dc": "http://purl.org/dc/terms/",
- "sec": "https://w3id.org/security#",
- "xsd": "http://www.w3.org/2001/XMLSchema#",
-
- "EcdsaKoblitzSignature2016": "sec:EcdsaKoblitzSignature2016",
- "Ed25519Signature2018": "sec:Ed25519Signature2018",
- "EncryptedMessage": "sec:EncryptedMessage",
- "GraphSignature2012": "sec:GraphSignature2012",
- "LinkedDataSignature2015": "sec:LinkedDataSignature2015",
- "LinkedDataSignature2016": "sec:LinkedDataSignature2016",
- "CryptographicKey": "sec:Key",
-
- "authenticationTag": "sec:authenticationTag",
- "canonicalizationAlgorithm": "sec:canonicalizationAlgorithm",
- "cipherAlgorithm": "sec:cipherAlgorithm",
- "cipherData": "sec:cipherData",
- "cipherKey": "sec:cipherKey",
- "created": {"@id": "dc:created", "@type": "xsd:dateTime"},
- "creator": {"@id": "dc:creator", "@type": "@id"},
- "digestAlgorithm": "sec:digestAlgorithm",
- "digestValue": "sec:digestValue",
- "domain": "sec:domain",
- "encryptionKey": "sec:encryptionKey",
- "expiration": {"@id": "sec:expiration", "@type": "xsd:dateTime"},
- "expires": {"@id": "sec:expiration", "@type": "xsd:dateTime"},
- "initializationVector": "sec:initializationVector",
- "iterationCount": "sec:iterationCount",
- "nonce": "sec:nonce",
- "normalizationAlgorithm": "sec:normalizationAlgorithm",
- "owner": {"@id": "sec:owner", "@type": "@id"},
- "password": "sec:password",
- "privateKey": {"@id": "sec:privateKey", "@type": "@id"},
- "privateKeyPem": "sec:privateKeyPem",
- "publicKey": {"@id": "sec:publicKey", "@type": "@id"},
- "publicKeyBase58": "sec:publicKeyBase58",
- "publicKeyPem": "sec:publicKeyPem",
- "publicKeyService": {"@id": "sec:publicKeyService", "@type": "@id"},
- "revoked": {"@id": "sec:revoked", "@type": "xsd:dateTime"},
- "salt": "sec:salt",
- "signature": "sec:signature",
- "signatureAlgorithm": "sec:signingAlgorithm",
- "signatureValue": "sec:signatureValue"
- }
-}
diff --git a/spec/generators/post_deployment_migration_generator_spec.rb b/spec/generators/post_deployment_migration_generator_spec.rb
index d552880e3bd33b..d770a78e97c1e4 100644
--- a/spec/generators/post_deployment_migration_generator_spec.rb
+++ b/spec/generators/post_deployment_migration_generator_spec.rb
@@ -1,13 +1,13 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'rails/generators/testing/behaviour'
+require 'rails/generators/testing/behavior'
require 'rails/generators/testing/assertions'
require 'generators/post_deployment_migration/post_deployment_migration_generator'
describe PostDeploymentMigrationGenerator, type: :generator do
- include Rails::Generators::Testing::Behaviour
+ include Rails::Generators::Testing::Behavior
include Rails::Generators::Testing::Assertions
include FileUtils
diff --git a/spec/helpers/admin/disputes_helper_spec.rb b/spec/helpers/admin/disputes_helper_spec.rb
new file mode 100644
index 00000000000000..5f9a85df869140
--- /dev/null
+++ b/spec/helpers/admin/disputes_helper_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Admin::DisputesHelper do
+ describe 'strike_action_label' do
+ it 'returns html describing the appeal' do
+ adam = Account.new(username: 'Adam')
+ becky = Account.new(username: 'Becky')
+ strike = AccountWarning.new(account: adam, action: :suspend)
+ appeal = Appeal.new(strike: strike, account: becky)
+
+ expected = <<~OUTPUT.strip
+ Adam suspended Becky's account
+ OUTPUT
+ result = helper.strike_action_label(appeal)
+
+ expect(result).to eq(expected)
+ end
+ end
+end
diff --git a/spec/helpers/jsonld_helper_spec.rb b/spec/helpers/jsonld_helper_spec.rb
index 3575bba859815b..5124bcf855b488 100644
--- a/spec/helpers/jsonld_helper_spec.rb
+++ b/spec/helpers/jsonld_helper_spec.rb
@@ -158,14 +158,14 @@
it 'deems a safe compacting as such' do
json['object'].delete('convo')
compacted = compact(json)
- deemed_compatible = patch_for_forwarding!(json, compacted)
+ patch_for_forwarding!(json, compacted)
expect(compacted['to']).to eq ['https://www.w3.org/ns/activitystreams#Public']
expect(safe_for_forwarding?(json, compacted)).to be true
end
it 'deems an unsafe compacting as such' do
compacted = compact(json)
- deemed_compatible = patch_for_forwarding!(json, compacted)
+ patch_for_forwarding!(json, compacted)
expect(compacted['to']).to eq ['https://www.w3.org/ns/activitystreams#Public']
expect(safe_for_forwarding?(json, compacted)).to be false
end
diff --git a/spec/helpers/languages_helper_spec.rb b/spec/helpers/languages_helper_spec.rb
index 98c8064a3355d1..99461b293ba6f9 100644
--- a/spec/helpers/languages_helper_spec.rb
+++ b/spec/helpers/languages_helper_spec.rb
@@ -60,4 +60,30 @@
end
end
end
+
+ describe 'sorted_locales' do
+ context 'when sorting with native name' do
+ it 'returns Suomi after Gàidhlig' do
+ expect(described_class.sorted_locale_keys(%w(fi gd))).to eq(%w(gd fi))
+ end
+ end
+
+ context 'when sorting with diacritics' do
+ it 'returns Íslensk before Suomi' do
+ expect(described_class.sorted_locale_keys(%w(fi is))).to eq(%w(is fi))
+ end
+ end
+
+ context 'when sorting with non-Latin' do
+ it 'returns Suomi before Amharic' do
+ expect(described_class.sorted_locale_keys(%w(am fi))).to eq(%w(fi am))
+ end
+ end
+
+ context 'when sorting with local variants' do
+ it 'returns variant in-line' do
+ expect(described_class.sorted_locale_keys(%w(en eo en-GB))).to eq(%w(en en-GB eo))
+ end
+ end
+ end
end
diff --git a/spec/models/account_statuses_filter_spec.rb b/spec/lib/account_statuses_filter_spec.rb
similarity index 91%
rename from spec/models/account_statuses_filter_spec.rb
rename to spec/lib/account_statuses_filter_spec.rb
index 0cf6453fe35b5a..c821eb4bac04f8 100644
--- a/spec/models/account_statuses_filter_spec.rb
+++ b/spec/lib/account_statuses_filter_spec.rb
@@ -202,7 +202,7 @@ def status_with_media_attachment!(visibility)
context 'when blocking a reblogged domain' do
let(:other_account) { Fabricate(:account, domain: 'example.com') }
let(:reblogging_status) { Fabricate(:status, account: other_account) }
- let(:reblog) { Fabricate(:status, account: account, visibility: 'public', reblog: reblogging_status) }
+ let!(:reblog) { Fabricate(:status, account: account, visibility: 'public', reblog: reblogging_status) }
before do
current_account.block_domain!(other_account.domain)
@@ -213,6 +213,20 @@ def status_with_media_attachment!(visibility)
end
end
+ context 'when blocking an unrelated domain' do
+ let(:other_account) { Fabricate(:account, domain: nil) }
+ let(:reblogging_status) { Fabricate(:status, account: other_account, visibility: 'public') }
+ let!(:reblog) { Fabricate(:status, account: account, visibility: 'public', reblog: reblogging_status) }
+
+ before do
+ current_account.block_domain!('example.com')
+ end
+
+ it 'returns the reblog from the non-blocked domain' do
+ expect(subject.results.pluck(:id)).to include(reblog.id)
+ end
+ end
+
context 'when muting a reblogged account' do
let(:reblog) { status_with_reblog!('public') }
diff --git a/spec/lib/activitypub/linked_data_signature_spec.rb b/spec/lib/activitypub/linked_data_signature_spec.rb
index 6a6ad1a706430a..97268eea6d04b2 100644
--- a/spec/lib/activitypub/linked_data_signature_spec.rb
+++ b/spec/lib/activitypub/linked_data_signature_spec.rb
@@ -18,10 +18,6 @@
let(:json) { raw_json.merge('signature' => signature) }
- before do
- stub_jsonld_contexts!
- end
-
describe '#verify_actor!' do
context 'when signature matches' do
let(:raw_signature) do
@@ -38,6 +34,40 @@
end
end
+ context 'when local account record is missing a public key' do
+ let(:raw_signature) do
+ {
+ 'creator' => 'http://example.com/alice',
+ 'created' => '2017-09-23T20:21:34Z',
+ }
+ end
+
+ let(:signature) { raw_signature.merge('type' => 'RsaSignature2017', 'signatureValue' => sign(sender, raw_signature, raw_json)) }
+
+ let(:service_stub) { instance_double(ActivityPub::FetchRemoteKeyService) }
+
+ before do
+ # Ensure signature is computed with the old key
+ signature
+
+ # Unset key
+ old_key = sender.public_key
+ sender.update!(private_key: '', public_key: '')
+
+ allow(ActivityPub::FetchRemoteKeyService).to receive(:new).and_return(service_stub)
+
+ allow(service_stub).to receive(:call).with('http://example.com/alice', id: false) do
+ sender.update!(public_key: old_key)
+ sender
+ end
+ end
+
+ it 'fetches key and returns creator' do
+ expect(subject.verify_actor!).to eq sender
+ expect(service_stub).to have_received(:call).with('http://example.com/alice', id: false).once
+ end
+ end
+
context 'when signature is missing' do
let(:signature) { nil }
diff --git a/spec/lib/cache_buster_spec.rb b/spec/lib/cache_buster_spec.rb
index 84085608e8544e..78ca183490ee87 100644
--- a/spec/lib/cache_buster_spec.rb
+++ b/spec/lib/cache_buster_spec.rb
@@ -28,6 +28,14 @@
end
context 'when using default options' do
+ around do |example|
+ # Disables the CacheBuster.new deprecation warning about default arguments.
+ # Remove this `silence` block when default arg support is removed from CacheBuster
+ Rails.application.deprecators[:mastodon].silence do
+ example.run
+ end
+ end
+
include_examples 'makes_request'
end
diff --git a/spec/lib/feed_manager_spec.rb b/spec/lib/feed_manager_spec.rb
index 0dc71f58e23b2f..b3cd1ca4abaf20 100644
--- a/spec/lib/feed_manager_spec.rb
+++ b/spec/lib/feed_manager_spec.rb
@@ -532,6 +532,44 @@
end
end
+ describe '#unmerge_tag_from_home' do
+ let(:receiver) { Fabricate(:account) }
+ let(:tag) { Fabricate(:tag) }
+
+ it 'leaves a tagged status' do
+ status = Fabricate(:status)
+ status.tags << tag
+ described_class.instance.push_to_home(receiver, status)
+
+ described_class.instance.unmerge_tag_from_home(tag, receiver)
+
+ expect(redis.zrange("feed:home:#{receiver.id}", 0, -1)).to_not include(status.id.to_s)
+ end
+
+ it 'remains a tagged status written by receiver\'s followee' do
+ followee = Fabricate(:account)
+ receiver.follow!(followee)
+
+ status = Fabricate(:status, account: followee)
+ status.tags << tag
+ described_class.instance.push_to_home(receiver, status)
+
+ described_class.instance.unmerge_tag_from_home(tag, receiver)
+
+ expect(redis.zrange("feed:home:#{receiver.id}", 0, -1)).to include(status.id.to_s)
+ end
+
+ it 'remains a tagged status written by receiver' do
+ status = Fabricate(:status, account: receiver)
+ status.tags << tag
+ described_class.instance.push_to_home(receiver, status)
+
+ described_class.instance.unmerge_tag_from_home(tag, receiver)
+
+ expect(redis.zrange("feed:home:#{receiver.id}", 0, -1)).to include(status.id.to_s)
+ end
+ end
+
describe '#clear_from_home' do
let(:account) { Fabricate(:account) }
let(:followed_account) { Fabricate(:account) }
diff --git a/spec/lib/link_details_extractor_spec.rb b/spec/lib/link_details_extractor_spec.rb
index 599bc4e6de2f60..8c485cef2afb5b 100644
--- a/spec/lib/link_details_extractor_spec.rb
+++ b/spec/lib/link_details_extractor_spec.rb
@@ -82,6 +82,10 @@
'name' => 'Pet News',
'url' => 'https://example.com',
},
+ 'inLanguage' => {
+ name: 'English',
+ alternateName: 'en',
+ },
}.to_json
end
@@ -115,6 +119,12 @@
expect(subject.provider_name).to eq 'Pet News'
end
end
+
+ describe '#language' do
+ it 'returns the language from structured data' do
+ expect(subject.language).to eq 'en'
+ end
+ end
end
context 'when is wrapped in CDATA tags' do
diff --git a/spec/lib/mastodon/cli/accounts_spec.rb b/spec/lib/mastodon/cli/accounts_spec.rb
index a263d673de760b..2c8c994712d069 100644
--- a/spec/lib/mastodon/cli/accounts_spec.rb
+++ b/spec/lib/mastodon/cli/accounts_spec.rb
@@ -6,6 +6,24 @@
describe Mastodon::CLI::Accounts do
let(:cli) { described_class.new }
+ # `parallelize_with_progress` cannot run in transactions, so instead,
+ # stub it with an alternative implementation that runs sequentially
+ # and can run in transactions.
+ def stub_parallelize_with_progress!
+ allow(cli).to receive(:parallelize_with_progress) do |scope, &block|
+ aggregate = 0
+ total = 0
+
+ scope.reorder(nil).find_each do |record|
+ value = block.call(record)
+ aggregate += value if value.is_a?(Integer)
+ total += 1
+ end
+
+ [total, aggregate]
+ end
+ end
+
describe '.exit_on_failure?' do
it 'returns true' do
expect(described_class.exit_on_failure?).to be true
@@ -551,20 +569,15 @@
let!(:follower_rony) { Fabricate(:account, username: 'rony') }
let!(:follower_charles) { Fabricate(:account, username: 'charles') }
let(:follow_service) { instance_double(FollowService, call: nil) }
- let(:scope) { Account.local.without_suspended }
before do
- allow(cli).to receive(:parallelize_with_progress).and_yield(follower_bob)
- .and_yield(follower_rony)
- .and_yield(follower_charles)
- .and_return([3, nil])
allow(FollowService).to receive(:new).and_return(follow_service)
+ stub_parallelize_with_progress!
end
it 'makes all local accounts follow the target account' do
cli.follow(target_account.username)
- expect(cli).to have_received(:parallelize_with_progress).with(scope).once
expect(follow_service).to have_received(:call).with(follower_bob, target_account, any_args).once
expect(follow_service).to have_received(:call).with(follower_rony, target_account, any_args).once
expect(follow_service).to have_received(:call).with(follower_charles, target_account, any_args).once
@@ -572,7 +585,7 @@
it 'displays a successful message' do
expect { cli.follow(target_account.username) }.to output(
- a_string_including('OK, followed target from 3 accounts')
+ a_string_including("OK, followed target from #{Account.local.count} accounts")
).to_stdout
end
end
@@ -592,26 +605,21 @@
context 'when the given username is found' do
let!(:target_account) { Fabricate(:account) }
- let!(:follower_chris) { Fabricate(:account, username: 'chris') }
- let!(:follower_rambo) { Fabricate(:account, username: 'rambo') }
- let!(:follower_ana) { Fabricate(:account, username: 'ana') }
+ let!(:follower_chris) { Fabricate(:account, username: 'chris', domain: nil) }
+ let!(:follower_rambo) { Fabricate(:account, username: 'rambo', domain: nil) }
+ let!(:follower_ana) { Fabricate(:account, username: 'ana', domain: nil) }
let(:unfollow_service) { instance_double(UnfollowService, call: nil) }
- let(:scope) { target_account.followers.local }
before do
accounts = [follower_chris, follower_rambo, follower_ana]
- accounts.each { |account| target_account.follow!(account) }
- allow(cli).to receive(:parallelize_with_progress).and_yield(follower_chris)
- .and_yield(follower_rambo)
- .and_yield(follower_ana)
- .and_return([3, nil])
+ accounts.each { |account| account.follow!(target_account) }
allow(UnfollowService).to receive(:new).and_return(unfollow_service)
+ stub_parallelize_with_progress!
end
it 'makes all local accounts unfollow the target account' do
cli.unfollow(target_account.username)
- expect(cli).to have_received(:parallelize_with_progress).with(scope).once
expect(unfollow_service).to have_received(:call).with(follower_chris, target_account).once
expect(unfollow_service).to have_received(:call).with(follower_rambo, target_account).once
expect(unfollow_service).to have_received(:call).with(follower_ana, target_account).once
@@ -671,6 +679,8 @@
let(:scope) { Account.remote }
before do
+ # TODO: we should be using `stub_parallelize_with_progress!` but
+ # this makes the assertions harder to write
allow(cli).to receive(:parallelize_with_progress).and_yield(remote_account_example_com)
.and_yield(account_example_net)
.and_return([2, nil])
@@ -1112,26 +1122,19 @@
describe '#cull' do
let(:delete_account_service) { instance_double(DeleteAccountService, call: nil) }
- let!(:tom) { Fabricate(:account, updated_at: 30.days.ago, username: 'tom', uri: 'https://example.com/users/tom', domain: 'example.com') }
- let!(:bob) { Fabricate(:account, updated_at: 30.days.ago, last_webfingered_at: nil, username: 'bob', uri: 'https://example.org/users/bob', domain: 'example.org') }
- let!(:gon) { Fabricate(:account, updated_at: 15.days.ago, last_webfingered_at: 15.days.ago, username: 'gon', uri: 'https://example.net/users/gon', domain: 'example.net') }
- let!(:ana) { Fabricate(:account, username: 'ana', uri: 'https://example.com/users/ana', domain: 'example.com') }
- let!(:tales) { Fabricate(:account, updated_at: 10.days.ago, last_webfingered_at: nil, username: 'tales', uri: 'https://example.net/users/tales', domain: 'example.net') }
+ let!(:tom) { Fabricate(:account, updated_at: 30.days.ago, username: 'tom', uri: 'https://example.com/users/tom', domain: 'example.com', protocol: :activitypub) }
+ let!(:bob) { Fabricate(:account, updated_at: 30.days.ago, last_webfingered_at: nil, username: 'bob', uri: 'https://example.org/users/bob', domain: 'example.org', protocol: :activitypub) }
+ let!(:gon) { Fabricate(:account, updated_at: 15.days.ago, last_webfingered_at: 15.days.ago, username: 'gon', uri: 'https://example.net/users/gon', domain: 'example.net', protocol: :activitypub) }
+ let!(:ana) { Fabricate(:account, username: 'ana', uri: 'https://example.com/users/ana', domain: 'example.com', protocol: :activitypub) }
+ let!(:tales) { Fabricate(:account, updated_at: 10.days.ago, last_webfingered_at: nil, username: 'tales', uri: 'https://example.net/users/tales', domain: 'example.net', protocol: :activitypub) }
before do
allow(DeleteAccountService).to receive(:new).and_return(delete_account_service)
end
context 'when no domain is specified' do
- let(:scope) { Account.remote.where(protocol: :activitypub).partitioned }
-
before do
- allow(cli).to receive(:parallelize_with_progress).and_yield(tom)
- .and_yield(bob)
- .and_yield(gon)
- .and_yield(ana)
- .and_yield(tales)
- .and_return([5, 3])
+ stub_parallelize_with_progress!
stub_request(:head, 'https://example.org/users/bob').to_return(status: 404)
stub_request(:head, 'https://example.net/users/gon').to_return(status: 410)
stub_request(:head, 'https://example.net/users/tales').to_return(status: 200)
@@ -1140,7 +1143,6 @@
it 'deletes all inactive remote accounts that longer exist in the origin server' do
cli.cull
- expect(cli).to have_received(:parallelize_with_progress).with(scope).once
expect(delete_account_service).to have_received(:call).with(bob, reserve_username: false).once
expect(delete_account_service).to have_received(:call).with(gon, reserve_username: false).once
end
@@ -1148,35 +1150,27 @@
it 'does not delete any active remote account that still exists in the origin server' do
cli.cull
- expect(cli).to have_received(:parallelize_with_progress).with(scope).once
expect(delete_account_service).to_not have_received(:call).with(tom, reserve_username: false)
expect(delete_account_service).to_not have_received(:call).with(ana, reserve_username: false)
expect(delete_account_service).to_not have_received(:call).with(tales, reserve_username: false)
end
it 'touches inactive remote accounts that have not been deleted' do
- allow(tales).to receive(:touch)
-
- cli.cull
-
- expect(tales).to have_received(:touch).once
+ expect { cli.cull }.to(change { tales.reload.updated_at })
end
it 'displays the summary correctly' do
expect { cli.cull }.to output(
- a_string_including('Visited 5 accounts, removed 3')
+ a_string_including('Visited 5 accounts, removed 2')
).to_stdout
end
end
context 'when a domain is specified' do
let(:domain) { 'example.net' }
- let(:scope) { Account.remote.where(protocol: :activitypub, domain: domain).partitioned }
before do
- allow(cli).to receive(:parallelize_with_progress).and_yield(gon)
- .and_yield(tales)
- .and_return([2, 2])
+ stub_parallelize_with_progress!
stub_request(:head, 'https://example.net/users/gon').to_return(status: 410)
stub_request(:head, 'https://example.net/users/tales').to_return(status: 404)
end
@@ -1184,13 +1178,12 @@
it 'deletes inactive remote accounts that longer exist in the specified domain' do
cli.cull(domain)
- expect(cli).to have_received(:parallelize_with_progress).with(scope).once
expect(delete_account_service).to have_received(:call).with(gon, reserve_username: false).once
expect(delete_account_service).to have_received(:call).with(tales, reserve_username: false).once
end
it 'displays the summary correctly' do
- expect { cli.cull }.to output(
+ expect { cli.cull(domain) }.to output(
a_string_including('Visited 2 accounts, removed 2')
).to_stdout
end
@@ -1199,7 +1192,9 @@
context 'when a domain is unavailable' do
shared_examples 'an unavailable domain' do
before do
- allow(cli).to receive(:parallelize_with_progress).and_yield(tales).and_return([1, 0])
+ stub_parallelize_with_progress!
+ stub_request(:head, 'https://example.org/users/bob').to_return(status: 200)
+ stub_request(:head, 'https://example.net/users/gon').to_return(status: 200)
end
it 'skips accounts from the unavailable domain' do
@@ -1210,7 +1205,7 @@
it 'displays the summary correctly' do
expect { cli.cull }.to output(
- a_string_including("Visited 1 accounts, removed 0\nThe following domains were not available during the check:\n example.net")
+ a_string_including("Visited 5 accounts, removed 0\nThe following domains were not available during the check:\n example.net")
).to_stdout
end
end
@@ -1361,4 +1356,254 @@
end
end
end
+
+ describe '#prune' do
+ let!(:local_account) { Fabricate(:account) }
+ let!(:bot_account) { Fabricate(:account, bot: true, domain: 'example.com') }
+ let!(:group_account) { Fabricate(:account, actor_type: 'Group', domain: 'example.com') }
+ let!(:mentioned_account) { Fabricate(:account, domain: 'example.com') }
+ let!(:prunable_accounts) do
+ Fabricate.times(3, :account, domain: 'example.com', bot: false, suspended_at: nil, silenced_at: nil)
+ end
+
+ before do
+ Fabricate(:mention, account: mentioned_account, status: Fabricate(:status, account: Fabricate(:account)))
+ stub_parallelize_with_progress!
+ end
+
+ it 'prunes all remote accounts with no interactions with local users' do
+ cli.prune
+
+ prunable_account_ids = prunable_accounts.pluck(:id)
+
+ expect(Account.where(id: prunable_account_ids).count).to eq(0)
+ end
+
+ it 'displays a successful message' do
+ expect { cli.prune }.to output(
+ a_string_including("OK, pruned #{prunable_accounts.size} accounts")
+ ).to_stdout
+ end
+
+ it 'does not prune local accounts' do
+ cli.prune
+
+ expect(Account.exists?(id: local_account.id)).to be(true)
+ end
+
+ it 'does not prune bot accounts' do
+ cli.prune
+
+ expect(Account.exists?(id: bot_account.id)).to be(true)
+ end
+
+ it 'does not prune group accounts' do
+ cli.prune
+
+ expect(Account.exists?(id: group_account.id)).to be(true)
+ end
+
+ it 'does not prune accounts that have been mentioned' do
+ cli.prune
+
+ expect(Account.exists?(id: mentioned_account.id)).to be true
+ end
+
+ context 'with --dry-run option' do
+ before do
+ cli.options = { dry_run: true }
+ end
+
+ it 'does not prune any account' do
+ cli.prune
+
+ prunable_account_ids = prunable_accounts.pluck(:id)
+
+ expect(Account.where(id: prunable_account_ids).count).to eq(prunable_accounts.size)
+ end
+
+ it 'displays a successful message with (DRY RUN)' do
+ expect { cli.prune }.to output(
+ a_string_including("OK, pruned #{prunable_accounts.size} accounts (DRY RUN)")
+ ).to_stdout
+ end
+ end
+ end
+
+ describe '#migrate' do
+ let!(:source_account) { Fabricate(:account) }
+ let!(:target_account) { Fabricate(:account, domain: 'example.com') }
+ let(:arguments) { [source_account.username] }
+ let(:resolve_account_service) { instance_double(ResolveAccountService, call: nil) }
+ let(:move_service) { instance_double(MoveService, call: nil) }
+
+ before do
+ allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service)
+ allow(MoveService).to receive(:new).and_return(move_service)
+ end
+
+ shared_examples 'a successful migration' do
+ it 'calls the MoveService for the last migration' do
+ cli.invoke(:migrate, arguments, options)
+
+ last_migration = source_account.migrations.last
+
+ expect(move_service).to have_received(:call).with(last_migration).once
+ end
+
+ it 'displays a successful message' do
+ expect { cli.invoke(:migrate, arguments, options) }.to output(
+ a_string_including("OK, migrated #{source_account.acct} to #{target_account.acct}")
+ ).to_stdout
+ end
+ end
+
+ context 'when both --replay and --target options are given' do
+ let(:options) { { replay: true, target: "#{target_account.username}@example.com" } }
+
+ it 'exits with an error message indicating that using both options is not possible' do
+ expect { cli.invoke(:migrate, arguments, options) }.to output(
+ a_string_including('Use --replay or --target, not both')
+ ).to_stdout
+ .and raise_error(SystemExit)
+ end
+ end
+
+ context 'when no option is given' do
+ it 'exits with an error message indicating that at least one option must be used' do
+ expect { cli.invoke(:migrate, arguments, {}) }.to output(
+ a_string_including('Use either --replay or --target')
+ ).to_stdout
+ .and raise_error(SystemExit)
+ end
+ end
+
+ context 'when the given username is not found' do
+ let(:arguments) { ['non_existent_username'] }
+
+ it 'exits with an error message indicating that there is no such account' do
+ expect { cli.invoke(:migrate, arguments, replay: true) }.to output(
+ a_string_including("No such account: #{arguments.first}")
+ ).to_stdout
+ .and raise_error(SystemExit)
+ end
+ end
+
+ context 'with --replay option' do
+ let(:options) { { replay: true } }
+
+ context 'when the specified account has no previous migrations' do
+ it 'exits with an error message indicating that the given account has no previous migrations' do
+ expect { cli.invoke(:migrate, arguments, options) }.to output(
+ a_string_including('The specified account has not performed any migration')
+ ).to_stdout
+ .and raise_error(SystemExit)
+ end
+ end
+
+ context 'when the specified account has a previous migration' do
+ before do
+ allow(resolve_account_service).to receive(:call).with(source_account.acct, any_args).and_return(source_account)
+ allow(resolve_account_service).to receive(:call).with(target_account.acct, any_args).and_return(target_account)
+ target_account.aliases.create!(acct: source_account.acct)
+ source_account.migrations.create!(acct: target_account.acct)
+ source_account.update!(moved_to_account: target_account)
+ end
+
+ it_behaves_like 'a successful migration'
+
+ context 'when the specified account is redirecting to a different target account' do
+ before do
+ source_account.update!(moved_to_account: nil)
+ end
+
+ it 'exits with an error message' do
+ expect { cli.invoke(:migrate, arguments, options) }.to output(
+ a_string_including('The specified account is not redirecting to its last migration target. Use --force if you want to replay the migration anyway')
+ ).to_stdout
+ .and raise_error(SystemExit)
+ end
+ end
+
+ context 'with --force option' do
+ let(:options) { { replay: true, force: true } }
+
+ it_behaves_like 'a successful migration'
+ end
+ end
+ end
+
+ context 'with --target option' do
+ let(:options) { { target: target_account.acct } }
+
+ before do
+ allow(resolve_account_service).to receive(:call).with(source_account.acct, any_args).and_return(source_account)
+ allow(resolve_account_service).to receive(:call).with(target_account.acct, any_args).and_return(target_account)
+ end
+
+ context 'when the specified target account is not found' do
+ before do
+ allow(resolve_account_service).to receive(:call).with(target_account.acct).and_return(nil)
+ end
+
+ it 'exits with an error message indicating that there is no such account' do
+ expect { cli.invoke(:migrate, arguments, options) }.to output(
+ a_string_including("The specified target account could not be found: #{options[:target]}")
+ ).to_stdout
+ .and raise_error(SystemExit)
+ end
+ end
+
+ context 'when the specified target account exists' do
+ before do
+ target_account.aliases.create!(acct: source_account.acct)
+ end
+
+ it 'creates a migration for the specified account with the target account' do
+ cli.invoke(:migrate, arguments, options)
+
+ last_migration = source_account.migrations.last
+
+ expect(last_migration.acct).to eq(target_account.acct)
+ end
+
+ it_behaves_like 'a successful migration'
+ end
+
+ context 'when the migration record is invalid' do
+ it 'exits with an error indicating that the validation failed' do
+ expect { cli.invoke(:migrate, arguments, options) }.to output(
+ a_string_including('Error: Validation failed')
+ ).to_stdout
+ .and raise_error(SystemExit)
+ end
+ end
+
+ context 'when the specified account is redirecting to a different target account' do
+ before do
+ allow(Account).to receive(:find_local).with(source_account.username).and_return(source_account)
+ allow(source_account).to receive(:moved_to_account_id).and_return(-1)
+ end
+
+ it 'exits with an error message' do
+ expect { cli.invoke(:migrate, arguments, options) }.to output(
+ a_string_including('The specified account is redirecting to a different target account. Use --force if you want to change the migration target')
+ ).to_stdout
+ .and raise_error(SystemExit)
+ end
+ end
+
+ context 'with --target and --force options' do
+ let(:options) { { target: target_account.acct, force: true } }
+
+ before do
+ target_account.aliases.create!(acct: source_account.acct)
+ allow(Account).to receive(:find_local).with(source_account.username).and_return(source_account)
+ allow(source_account).to receive(:moved_to_account_id).and_return(-1)
+ end
+
+ it_behaves_like 'a successful migration'
+ end
+ end
+ end
end
diff --git a/spec/lib/mastodon/cli/media_spec.rb b/spec/lib/mastodon/cli/media_spec.rb
index 29f7d424a9cbfe..9543640e967667 100644
--- a/spec/lib/mastodon/cli/media_spec.rb
+++ b/spec/lib/mastodon/cli/media_spec.rb
@@ -4,9 +4,78 @@
require 'mastodon/cli/media'
describe Mastodon::CLI::Media do
+ let(:cli) { described_class.new }
+
describe '.exit_on_failure?' do
it 'returns true' do
expect(described_class.exit_on_failure?).to be true
end
end
+
+ describe '#remove' do
+ context 'with --prune-profiles and --remove-headers' do
+ let(:options) { { prune_profiles: true, remove_headers: true } }
+
+ it 'warns about usage and exits' do
+ expect { cli.invoke(:remove, [], options) }.to output(
+ a_string_including('--prune-profiles and --remove-headers should not be specified simultaneously')
+ ).to_stdout.and raise_error(SystemExit)
+ end
+ end
+
+ context 'with --include-follows but not including --prune-profiles and --remove-headers' do
+ let(:options) { { include_follows: true } }
+
+ it 'warns about usage and exits' do
+ expect { cli.invoke(:remove, [], options) }.to output(
+ a_string_including('--include-follows can only be used with --prune-profiles or --remove-headers')
+ ).to_stdout.and raise_error(SystemExit)
+ end
+ end
+
+ context 'with a relevant account' do
+ let!(:account) do
+ Fabricate(:account, domain: 'example.com', updated_at: 1.month.ago, last_webfingered_at: 1.month.ago, avatar: attachment_fixture('attachment.jpg'), header: attachment_fixture('attachment.jpg'))
+ end
+
+ context 'with --prune-profiles' do
+ let(:options) { { prune_profiles: true } }
+
+ it 'removes account avatars' do
+ expect { cli.invoke(:remove, [], options) }.to output(
+ a_string_including('Visited 1')
+ ).to_stdout
+
+ expect(account.reload.avatar).to be_blank
+ end
+ end
+
+ context 'with --remove-headers' do
+ let(:options) { { remove_headers: true } }
+
+ it 'removes account header' do
+ expect { cli.invoke(:remove, [], options) }.to output(
+ a_string_including('Visited 1')
+ ).to_stdout
+
+ expect(account.reload.header).to be_blank
+ end
+ end
+ end
+
+ context 'with a relevant media attachment' do
+ let!(:media_attachment) { Fabricate(:media_attachment, remote_url: 'https://example.com/image.jpg', created_at: 1.month.ago) }
+
+ context 'without options' do
+ it 'removes account avatars' do
+ expect { cli.invoke(:remove) }.to output(
+ a_string_including('Removed 1')
+ ).to_stdout
+
+ expect(media_attachment.reload.file).to be_blank
+ expect(media_attachment.reload.thumbnail).to be_blank
+ end
+ end
+ end
+ end
end
diff --git a/spec/lib/mastodon/cli/preview_cards_spec.rb b/spec/lib/mastodon/cli/preview_cards_spec.rb
index b4b018b3be5cb5..1e064ed58ed0cf 100644
--- a/spec/lib/mastodon/cli/preview_cards_spec.rb
+++ b/spec/lib/mastodon/cli/preview_cards_spec.rb
@@ -4,9 +4,52 @@
require 'mastodon/cli/preview_cards'
describe Mastodon::CLI::PreviewCards do
+ let(:cli) { described_class.new }
+
describe '.exit_on_failure?' do
it 'returns true' do
expect(described_class.exit_on_failure?).to be true
end
end
+
+ describe '#remove' do
+ context 'with relevant preview cards' do
+ before do
+ Fabricate(:preview_card, updated_at: 10.years.ago, type: :link)
+ Fabricate(:preview_card, updated_at: 10.months.ago, type: :photo)
+ Fabricate(:preview_card, updated_at: 10.days.ago, type: :photo)
+ end
+
+ context 'with no arguments' do
+ it 'deletes thumbnails for local preview cards' do
+ expect { cli.invoke(:remove) }.to output(
+ a_string_including('Removed 2 preview cards')
+ .and(a_string_including('approx. 119 KB'))
+ ).to_stdout
+ end
+ end
+
+ context 'with the --link option' do
+ let(:options) { { link: true } }
+
+ it 'deletes thumbnails for local preview cards' do
+ expect { cli.invoke(:remove, [], options) }.to output(
+ a_string_including('Removed 1 link-type preview cards')
+ .and(a_string_including('approx. 59.6 KB'))
+ ).to_stdout
+ end
+ end
+
+ context 'with the --days option' do
+ let(:options) { { days: 365 } }
+
+ it 'deletes thumbnails for local preview cards' do
+ expect { cli.invoke(:remove, [], options) }.to output(
+ a_string_including('Removed 1 preview cards')
+ .and(a_string_including('approx. 59.6 KB'))
+ ).to_stdout
+ end
+ end
+ end
+ end
end
diff --git a/spec/lib/mastodon/cli/statuses_spec.rb b/spec/lib/mastodon/cli/statuses_spec.rb
index 2430a8841644b8..38ebcd99347103 100644
--- a/spec/lib/mastodon/cli/statuses_spec.rb
+++ b/spec/lib/mastodon/cli/statuses_spec.rb
@@ -4,9 +4,31 @@
require 'mastodon/cli/statuses'
describe Mastodon::CLI::Statuses do
+ let(:cli) { described_class.new }
+
describe '.exit_on_failure?' do
it 'returns true' do
expect(described_class.exit_on_failure?).to be true
end
end
+
+ describe '#remove', use_transactional_tests: false do
+ context 'with small batch size' do
+ let(:options) { { batch_size: 0 } }
+
+ it 'exits with error message' do
+ expect { cli.invoke :remove, [], options }.to output(
+ a_string_including('Cannot run')
+ ).to_stdout.and raise_error(SystemExit)
+ end
+ end
+
+ context 'with default batch size' do
+ it 'removes unreferenced statuses' do
+ expect { cli.invoke :remove }.to output(
+ a_string_including('Done after')
+ ).to_stdout
+ end
+ end
+ end
end
diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb
index cf593349a7aefb..b5d942412e1cc8 100644
--- a/spec/models/account_spec.rb
+++ b/spec/models/account_spec.rb
@@ -356,7 +356,7 @@
end
it 'does not return suspended users' do
- match = Fabricate(
+ Fabricate(
:account,
display_name: 'Display Name',
username: 'username',
@@ -483,7 +483,7 @@
end
it 'does not return non-followed accounts' do
- match = Fabricate(
+ Fabricate(
:account,
display_name: 'A & l & i & c & e',
username: 'username',
@@ -495,7 +495,7 @@
end
it 'does not return suspended users' do
- match = Fabricate(
+ Fabricate(
:account,
display_name: 'Display Name',
username: 'username',
@@ -535,7 +535,7 @@
end
it 'does not return suspended users' do
- match = Fabricate(
+ Fabricate(
:account,
display_name: 'Display Name',
username: 'username',
@@ -700,7 +700,7 @@
expect(subject.match('Check this out https://medium.com/@alice/some-article#.abcdef123')).to be_nil
end
- xit 'does not match URL query string' do
+ it 'does not match URL query string' do
expect(subject.match('https://example.com/?x=@alice')).to be_nil
end
end
@@ -719,10 +719,10 @@
context 'when is local' do
it 'is invalid if the username is not unique in case-insensitive comparison among local accounts' do
- account_1 = Fabricate(:account, username: 'the_doctor')
- account_2 = Fabricate.build(:account, username: 'the_Doctor')
- account_2.valid?
- expect(account_2).to model_have_error_on_field(:username)
+ _account = Fabricate(:account, username: 'the_doctor')
+ non_unique_account = Fabricate.build(:account, username: 'the_Doctor')
+ non_unique_account.valid?
+ expect(non_unique_account).to model_have_error_on_field(:username)
end
it 'is invalid if the username is reserved' do
@@ -743,9 +743,9 @@
end
it 'is valid if we are creating a possibly-conflicting instance actor account' do
- account_1 = Fabricate(:account, username: 'examplecom')
- account_2 = Fabricate.build(:account, id: -99, actor_type: 'Application', locked: true, username: 'example.com')
- expect(account_2.valid?).to be true
+ _account = Fabricate(:account, username: 'examplecom')
+ instance_account = Fabricate.build(:account, id: -99, actor_type: 'Application', locked: true, username: 'example.com')
+ expect(instance_account.valid?).to be true
end
it 'is invalid if the username doesn\'t only contains letters, numbers and underscores' do
@@ -877,17 +877,17 @@
describe 'remote' do
it 'returns an array of accounts who have a domain' do
- account_1 = Fabricate(:account, domain: nil)
- account_2 = Fabricate(:account, domain: 'example.com')
- expect(described_class.remote).to contain_exactly(account_2)
+ _account = Fabricate(:account, domain: nil)
+ account_with_domain = Fabricate(:account, domain: 'example.com')
+ expect(described_class.remote).to contain_exactly(account_with_domain)
end
end
describe 'local' do
it 'returns an array of accounts who do not have a domain' do
- account_1 = Fabricate(:account, domain: nil)
- account_2 = Fabricate(:account, domain: 'example.com')
- expect(described_class.where('id > 0').local).to contain_exactly(account_1)
+ local_account = Fabricate(:account, domain: nil)
+ _account_with_domain = Fabricate(:account, domain: 'example.com')
+ expect(described_class.where('id > 0').local).to contain_exactly(local_account)
end
end
@@ -911,17 +911,17 @@
describe 'silenced' do
it 'returns an array of accounts who are silenced' do
- account_1 = Fabricate(:account, silenced: true)
- account_2 = Fabricate(:account, silenced: false)
- expect(described_class.silenced).to contain_exactly(account_1)
+ silenced_account = Fabricate(:account, silenced: true)
+ _account = Fabricate(:account, silenced: false)
+ expect(described_class.silenced).to contain_exactly(silenced_account)
end
end
describe 'suspended' do
it 'returns an array of accounts who are suspended' do
- account_1 = Fabricate(:account, suspended: true)
- account_2 = Fabricate(:account, suspended: false)
- expect(described_class.suspended).to contain_exactly(account_1)
+ suspended_account = Fabricate(:account, suspended: true)
+ _account = Fabricate(:account, suspended: false)
+ expect(described_class.suspended).to contain_exactly(suspended_account)
end
end
diff --git a/spec/models/domain_block_spec.rb b/spec/models/domain_block_spec.rb
index 67f53fa7851349..d595441fd30a8d 100644
--- a/spec/models/domain_block_spec.rb
+++ b/spec/models/domain_block_spec.rb
@@ -11,10 +11,10 @@
end
it 'is invalid if the same normalized domain already exists' do
- domain_block_1 = Fabricate(:domain_block, domain: 'にゃん')
- domain_block_2 = Fabricate.build(:domain_block, domain: 'xn--r9j5b5b')
- domain_block_2.valid?
- expect(domain_block_2).to model_have_error_on_field(:domain)
+ _domain_block = Fabricate(:domain_block, domain: 'にゃん')
+ domain_block_with_normalized_value = Fabricate.build(:domain_block, domain: 'xn--r9j5b5b')
+ domain_block_with_normalized_value.valid?
+ expect(domain_block_with_normalized_value).to model_have_error_on_field(:domain)
end
end
diff --git a/spec/models/poll_spec.rb b/spec/models/poll_spec.rb
index 8ae04ca41f8188..5aa5548cc83a1f 100644
--- a/spec/models/poll_spec.rb
+++ b/spec/models/poll_spec.rb
@@ -29,4 +29,23 @@
end
end
end
+
+ describe 'validations' do
+ context 'when valid' do
+ let(:poll) { Fabricate.build(:poll) }
+
+ it 'is valid with valid attributes' do
+ expect(poll).to be_valid
+ end
+ end
+
+ context 'when not valid' do
+ let(:poll) { Fabricate.build(:poll, expires_at: nil) }
+
+ it 'is invalid without an expire date' do
+ poll.valid?
+ expect(poll).to model_have_error_on_field(:expires_at)
+ end
+ end
+ end
end
diff --git a/spec/models/preview_card_spec.rb b/spec/models/preview_card_spec.rb
new file mode 100644
index 00000000000000..a17c7532e9eeb3
--- /dev/null
+++ b/spec/models/preview_card_spec.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe PreviewCard do
+ describe 'validations' do
+ describe 'urls' do
+ it 'allows http schemes' do
+ record = described_class.new(url: 'http://example.host/path')
+
+ expect(record).to be_valid
+ end
+
+ it 'allows https schemes' do
+ record = described_class.new(url: 'https://example.host/path')
+
+ expect(record).to be_valid
+ end
+
+ it 'does not allow javascript: schemes' do
+ record = described_class.new(url: 'javascript:alert()')
+
+ expect(record).to_not be_valid
+ expect(record).to model_have_error_on_field(:url)
+ end
+ end
+ end
+end
diff --git a/spec/models/relationship_filter_spec.rb b/spec/models/relationship_filter_spec.rb
index ac318857748adc..fccd42aaad0622 100644
--- a/spec/models/relationship_filter_spec.rb
+++ b/spec/models/relationship_filter_spec.rb
@@ -6,32 +6,60 @@
let(:account) { Fabricate(:account) }
describe '#results' do
- context 'when default params are used' do
- subject do
- described_class.new(account, 'order' => 'active').results
- end
+ let(:account_of_7_months) { Fabricate(:account_stat, statuses_count: 1, last_status_at: 7.months.ago).account }
+ let(:account_of_1_day) { Fabricate(:account_stat, statuses_count: 1, last_status_at: 1.day.ago).account }
+ let(:account_of_3_days) { Fabricate(:account_stat, statuses_count: 1, last_status_at: 3.days.ago).account }
+ let(:silent_account) { Fabricate(:account_stat, statuses_count: 0, last_status_at: nil).account }
+
+ before do
+ account.follow!(account_of_7_months)
+ account.follow!(account_of_1_day)
+ account.follow!(account_of_3_days)
+ account.follow!(silent_account)
+ end
- before do
- add_following_account_with(last_status_at: 7.days.ago)
- add_following_account_with(last_status_at: 1.day.ago)
- add_following_account_with(last_status_at: 3.days.ago)
+ context 'when ordering by last activity' do
+ context 'when not filtering' do
+ subject do
+ described_class.new(account, 'order' => 'active').results
+ end
+
+ it 'returns followings ordered by last activity' do
+ expect(subject).to eq [account_of_1_day, account_of_3_days, account_of_7_months, silent_account]
+ end
end
- it 'returns followings ordered by last activity' do
- expected_result = account.following.eager_load(:account_stat).reorder(nil).by_recent_status
+ context 'when filtering for dormant accounts' do
+ subject do
+ described_class.new(account, 'order' => 'active', 'activity' => 'dormant').results
+ end
- expect(subject).to eq expected_result
+ it 'returns dormant followings ordered by last activity' do
+ expect(subject).to eq [account_of_7_months, silent_account]
+ end
end
end
- end
- def add_following_account_with(last_status_at:)
- following_account = Fabricate(:account)
- Fabricate(:account_stat, account: following_account,
- last_status_at: last_status_at,
- statuses_count: 1,
- following_count: 0,
- followers_count: 0)
- Fabricate(:follow, account: account, target_account: following_account).account
+ context 'when ordering by account creation' do
+ context 'when not filtering' do
+ subject do
+ described_class.new(account, 'order' => 'recent').results
+ end
+
+ it 'returns followings ordered by last account creation' do
+ expect(subject).to eq [silent_account, account_of_3_days, account_of_1_day, account_of_7_months]
+ end
+ end
+
+ context 'when filtering for dormant accounts' do
+ subject do
+ described_class.new(account, 'order' => 'recent', 'activity' => 'dormant').results
+ end
+
+ it 'returns dormant followings ordered by last activity' do
+ expect(subject).to eq [silent_account, account_of_7_months]
+ end
+ end
+ end
end
end
diff --git a/spec/models/status_spec.rb b/spec/models/status_spec.rb
index f38e7c23719129..8868308d323692 100644
--- a/spec/models/status_spec.rb
+++ b/spec/models/status_spec.rb
@@ -166,7 +166,7 @@
describe '#replies_count' do
it 'is the number of replies' do
- reply = Fabricate(:status, account: bob, thread: subject)
+ Fabricate(:status, account: bob, thread: subject)
expect(subject.replies_count).to eq 1
end
diff --git a/spec/models/tag_spec.rb b/spec/models/tag_spec.rb
index 4d6e5c380b0470..80b9c861fcdb8a 100644
--- a/spec/models/tag_spec.rb
+++ b/spec/models/tag_spec.rb
@@ -32,44 +32,48 @@
expect(subject.match('https://en.wikipedia.org/wiki/Ghostbusters_(song)#Lawsuit')).to be_nil
end
+ it 'does not match URLs with hashtag-like anchors after an empty query parameter' do
+ expect(subject.match('https://en.wikipedia.org/wiki/Ghostbusters_(song)?foo=#Lawsuit')).to be_nil
+ end
+
it 'matches #aesthetic' do
- expect(subject.match('this is #aesthetic').to_s).to eq ' #aesthetic'
+ expect(subject.match('this is #aesthetic').to_s).to eq '#aesthetic'
end
it 'matches digits at the start' do
- expect(subject.match('hello #3d').to_s).to eq ' #3d'
+ expect(subject.match('hello #3d').to_s).to eq '#3d'
end
it 'matches digits in the middle' do
- expect(subject.match('hello #l33ts35k').to_s).to eq ' #l33ts35k'
+ expect(subject.match('hello #l33ts35k').to_s).to eq '#l33ts35k'
end
it 'matches digits at the end' do
- expect(subject.match('hello #world2016').to_s).to eq ' #world2016'
+ expect(subject.match('hello #world2016').to_s).to eq '#world2016'
end
it 'matches underscores at the beginning' do
- expect(subject.match('hello #_test').to_s).to eq ' #_test'
+ expect(subject.match('hello #_test').to_s).to eq '#_test'
end
it 'matches underscores at the end' do
- expect(subject.match('hello #test_').to_s).to eq ' #test_'
+ expect(subject.match('hello #test_').to_s).to eq '#test_'
end
it 'matches underscores in the middle' do
- expect(subject.match('hello #one_two_three').to_s).to eq ' #one_two_three'
+ expect(subject.match('hello #one_two_three').to_s).to eq '#one_two_three'
end
it 'matches middle dots' do
- expect(subject.match('hello #one·two·three').to_s).to eq ' #one·two·three'
+ expect(subject.match('hello #one·two·three').to_s).to eq '#one·two·three'
end
it 'matches ・unicode in ぼっち・ざ・ろっく correctly' do
- expect(subject.match('testing #ぼっち・ざ・ろっく').to_s).to eq ' #ぼっち・ざ・ろっく'
+ expect(subject.match('testing #ぼっち・ざ・ろっく').to_s).to eq '#ぼっち・ざ・ろっく'
end
it 'matches ZWNJ' do
- expect(subject.match('just add #نرمافزار and').to_s).to eq ' #نرمافزار'
+ expect(subject.match('just add #نرمافزار and').to_s).to eq '#نرمافزار'
end
it 'does not match middle dots at the start' do
@@ -77,7 +81,7 @@
end
it 'does not match middle dots at the end' do
- expect(subject.match('hello #one·two·three·').to_s).to eq ' #one·two·three'
+ expect(subject.match('hello #one·two·three·').to_s).to eq '#one·two·three'
end
it 'does not match purely-numeric hashtags' do
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index bb61c02a637ce1..92ce87e3696329 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -55,17 +55,17 @@
describe 'scopes' do
describe 'recent' do
it 'returns an array of recent users ordered by id' do
- user_1 = Fabricate(:user)
- user_2 = Fabricate(:user)
- expect(described_class.recent).to eq [user_2, user_1]
+ first_user = Fabricate(:user)
+ second_user = Fabricate(:user)
+ expect(described_class.recent).to eq [second_user, first_user]
end
end
describe 'confirmed' do
it 'returns an array of users who are confirmed' do
- user_1 = Fabricate(:user, confirmed_at: nil)
- user_2 = Fabricate(:user, confirmed_at: Time.zone.now)
- expect(described_class.confirmed).to contain_exactly(user_2)
+ Fabricate(:user, confirmed_at: nil)
+ confirmed_user = Fabricate(:user, confirmed_at: Time.zone.now)
+ expect(described_class.confirmed).to contain_exactly(confirmed_user)
end
end
diff --git a/spec/models/webauthn_credentials_spec.rb b/spec/models/webauthn_credentials_spec.rb
index 4579ebb82e99a4..9631245e11bbc7 100644
--- a/spec/models/webauthn_credentials_spec.rb
+++ b/spec/models/webauthn_credentials_spec.rb
@@ -37,7 +37,7 @@
end
it 'is invalid if already exist a webauthn credential with the same external id' do
- existing_webauthn_credential = Fabricate(:webauthn_credential, external_id: '_Typ0ygudDnk9YUVWLQayw')
+ Fabricate(:webauthn_credential, external_id: '_Typ0ygudDnk9YUVWLQayw')
new_webauthn_credential = Fabricate.build(:webauthn_credential, external_id: '_Typ0ygudDnk9YUVWLQayw')
new_webauthn_credential.valid?
@@ -47,7 +47,7 @@
it 'is invalid if user already registered a webauthn credential with the same nickname' do
user = Fabricate(:user)
- existing_webauthn_credential = Fabricate(:webauthn_credential, user_id: user.id, nickname: 'USB Key')
+ Fabricate(:webauthn_credential, user_id: user.id, nickname: 'USB Key')
new_webauthn_credential = Fabricate.build(:webauthn_credential, user_id: user.id, nickname: 'USB Key')
new_webauthn_credential.valid?
diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb
index 7b8dccb6a0b34c..8d9677f6ced70f 100644
--- a/spec/rails_helper.rb
+++ b/spec/rails_helper.rb
@@ -54,26 +54,6 @@ def sign_in(resource, _deprecated = nil, scope: nil)
end
end
-module SignedRequestHelpers
- def get(path, headers: nil, sign_with: nil, **args)
- return super path, headers: headers, **args if sign_with.nil?
-
- headers ||= {}
- headers['Date'] = Time.now.utc.httpdate
- headers['Host'] = ENV.fetch('LOCAL_DOMAIN')
- signed_headers = headers.merge('(request-target)' => "get #{path}").slice('(request-target)', 'Host', 'Date')
-
- key_id = ActivityPub::TagManager.instance.key_uri_for(sign_with)
- keypair = sign_with.keypair
- signed_string = signed_headers.map { |key, value| "#{key.downcase}: #{value}" }.join("\n")
- signature = Base64.strict_encode64(keypair.sign(OpenSSL::Digest.new('SHA256'), signed_string))
-
- headers['Signature'] = "keyId=\"#{key_id}\",algorithm=\"rsa-sha256\",headers=\"#{signed_headers.keys.join(' ').downcase}\",signature=\"#{signature}\""
-
- super path, headers: headers, **args
- end
-end
-
RSpec.configure do |config|
# This is set before running spec:system, see lib/tasks/tests.rake
config.filter_run_excluding type: lambda { |type|
@@ -105,6 +85,12 @@ def get(path, headers: nil, sign_with: nil, **args)
config.include Redisable
config.include SignedRequestHelpers, type: :request
+ config.around(:each, use_transactional_tests: false) do |example|
+ self.use_transactional_tests = false
+ example.run
+ self.use_transactional_tests = true
+ end
+
config.before :each, type: :cli do
stub_stdout
stub_reset_connection_pools
@@ -114,14 +100,6 @@ def get(path, headers: nil, sign_with: nil, **args)
Capybara.current_driver = :rack_test
end
- config.before :each, type: :controller do
- stub_jsonld_contexts!
- end
-
- config.before :each, type: :service do
- stub_jsonld_contexts!
- end
-
config.before :suite do
if RUN_SYSTEM_SPECS
Webpacker.compile
@@ -212,9 +190,3 @@ def stub_reset_connection_pools
allow(ActiveRecord::Base).to receive(:establish_connection)
allow(RedisConfiguration).to receive(:establish_pool)
end
-
-def stub_jsonld_contexts!
- stub_request(:get, 'https://www.w3.org/ns/activitystreams').to_return(request_fixture('json-ld.activitystreams.txt'))
- stub_request(:get, 'https://w3id.org/identity/v1').to_return(request_fixture('json-ld.identity.txt'))
- stub_request(:get, 'https://w3id.org/security/v1').to_return(request_fixture('json-ld.security.txt'))
-end
diff --git a/spec/requests/api/v1/admin/account_actions_spec.rb b/spec/requests/api/v1/admin/account_actions_spec.rb
index 9295d262d61d5e..bdf1f08e43b75c 100644
--- a/spec/requests/api/v1/admin/account_actions_spec.rb
+++ b/spec/requests/api/v1/admin/account_actions_spec.rb
@@ -51,14 +51,9 @@
it_behaves_like 'a successful notification delivery'
it_behaves_like 'a successful logged action', :disable, :user
- it 'returns http success' do
- subject
-
- expect(response).to have_http_status(200)
- end
-
it 'disables the target account' do
expect { subject }.to change { target_account.reload.user_disabled? }.from(false).to(true)
+ expect(response).to have_http_status(200)
end
end
@@ -70,14 +65,9 @@
it_behaves_like 'a successful notification delivery'
it_behaves_like 'a successful logged action', :sensitive, :account
- it 'returns http success' do
- subject
-
- expect(response).to have_http_status(200)
- end
-
it 'marks the target account as sensitive' do
expect { subject }.to change { target_account.reload.sensitized? }.from(false).to(true)
+ expect(response).to have_http_status(200)
end
end
@@ -89,14 +79,9 @@
it_behaves_like 'a successful notification delivery'
it_behaves_like 'a successful logged action', :silence, :account
- it 'returns http success' do
- subject
-
- expect(response).to have_http_status(200)
- end
-
it 'marks the target account as silenced' do
expect { subject }.to change { target_account.reload.silenced? }.from(false).to(true)
+ expect(response).to have_http_status(200)
end
end
@@ -108,14 +93,9 @@
it_behaves_like 'a successful notification delivery'
it_behaves_like 'a successful logged action', :suspend, :account
- it 'returns http success' do
- subject
-
- expect(response).to have_http_status(200)
- end
-
it 'marks the target account as suspended' do
expect { subject }.to change { target_account.reload.suspended? }.from(false).to(true)
+ expect(response).to have_http_status(200)
end
end
diff --git a/spec/requests/api/v1/admin/accounts_spec.rb b/spec/requests/api/v1/admin/accounts_spec.rb
new file mode 100644
index 00000000000000..8e158f623d690c
--- /dev/null
+++ b/spec/requests/api/v1/admin/accounts_spec.rb
@@ -0,0 +1,401 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe 'Accounts' do
+ let(:role) { UserRole.find_by(name: 'Admin') }
+ let(:user) { Fabricate(:user, role: role) }
+ let(:scopes) { 'admin:read:accounts admin:write:accounts' }
+ let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
+ let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
+
+ describe 'GET /api/v1/admin/accounts' do
+ subject do
+ get '/api/v1/admin/accounts', headers: headers, params: params
+ end
+
+ shared_examples 'a successful request' do
+ it 'returns the correct accounts', :aggregate_failures do
+ subject
+
+ expect(response).to have_http_status(200)
+ expect(body_as_json.pluck(:id)).to match_array(expected_results.map { |a| a.id.to_s })
+ end
+ end
+
+ let!(:remote_account) { Fabricate(:account, domain: 'example.org') }
+ let!(:suspended_account) { Fabricate(:account, suspended: true) }
+ let!(:disabled_account) { Fabricate(:user, disabled: true).account }
+ let!(:pending_account) { Fabricate(:user, approved: false).account }
+ let!(:admin_account) { user.account }
+ let(:params) { {} }
+
+ it_behaves_like 'forbidden for wrong scope', 'read read:accounts admin:write admin:write:accounts'
+ it_behaves_like 'forbidden for wrong role', ''
+
+ context 'when requesting active local staff accounts' do
+ let(:expected_results) { [admin_account] }
+ let(:params) { { active: 'true', local: 'true', staff: 'true' } }
+
+ it_behaves_like 'a successful request'
+ end
+
+ context 'when requesting remote accounts from a specified domain' do
+ let(:expected_results) { [remote_account] }
+ let(:params) { { by_domain: 'example.org', remote: 'true' } }
+
+ before do
+ Fabricate(:account, domain: 'foo.bar')
+ end
+
+ it_behaves_like 'a successful request'
+ end
+
+ context 'when requesting suspended accounts' do
+ let(:expected_results) { [suspended_account] }
+ let(:params) { { suspended: 'true' } }
+
+ before do
+ Fabricate(:account, domain: 'foo.bar', suspended: true)
+ end
+
+ it_behaves_like 'a successful request'
+ end
+
+ context 'when requesting disabled accounts' do
+ let(:expected_results) { [disabled_account] }
+ let(:params) { { disabled: 'true' } }
+
+ it_behaves_like 'a successful request'
+ end
+
+ context 'when requesting pending accounts' do
+ let(:expected_results) { [pending_account] }
+ let(:params) { { pending: 'true' } }
+
+ before do
+ pending_account.user.update(approved: false)
+ end
+
+ it_behaves_like 'a successful request'
+ end
+
+ context 'when no parameter is given' do
+ let(:expected_results) { [disabled_account, pending_account, admin_account] }
+
+ it_behaves_like 'a successful request'
+ end
+
+ context 'with limit param' do
+ let(:params) { { limit: 2 } }
+
+ it 'returns only the requested number of accounts', :aggregate_failures do
+ subject
+
+ expect(response).to have_http_status(200)
+ expect(body_as_json.size).to eq(params[:limit])
+ end
+ end
+ end
+
+ describe 'GET /api/v1/admin/accounts/:id' do
+ subject do
+ get "/api/v1/admin/accounts/#{account.id}", headers: headers
+ end
+
+ let(:account) { Fabricate(:account) }
+
+ it_behaves_like 'forbidden for wrong scope', 'read read:accounts admin:write admin:write:accounts'
+ it_behaves_like 'forbidden for wrong role', ''
+
+ it 'returns the requested account successfully', :aggregate_failures do
+ subject
+
+ expect(response).to have_http_status(200)
+ expect(body_as_json).to match(
+ a_hash_including(id: account.id.to_s, username: account.username, email: account.user.email)
+ )
+ end
+
+ context 'when the account is not found' do
+ it 'returns http not found' do
+ get '/api/v1/admin/accounts/-1', headers: headers
+
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+
+ describe 'POST /api/v1/admin/accounts/:id/approve' do
+ subject do
+ post "/api/v1/admin/accounts/#{account.id}/approve", headers: headers
+ end
+
+ let(:account) { Fabricate(:account) }
+
+ context 'when the account is pending' do
+ before do
+ account.user.update(approved: false)
+ end
+
+ it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read'
+ it_behaves_like 'forbidden for wrong role', ''
+
+ it 'approves the user successfully', :aggregate_failures do
+ subject
+
+ expect(response).to have_http_status(200)
+ expect(account.reload.user_approved?).to be(true)
+ end
+
+ it 'logs action', :aggregate_failures do
+ subject
+
+ log_item = Admin::ActionLog.last
+
+ expect(log_item).to be_present
+ expect(log_item.action).to eq :approve
+ expect(log_item.account_id).to eq user.account_id
+ expect(log_item.target_id).to eq account.user.id
+ end
+ end
+
+ context 'when the account is already approved' do
+ it 'returns http forbidden' do
+ subject
+
+ expect(response).to have_http_status(403)
+ end
+ end
+
+ context 'when the account is not found' do
+ it 'returns http not found' do
+ post '/api/v1/admin/accounts/-1/approve', headers: headers
+
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+
+ describe 'POST /api/v1/admin/accounts/:id/reject' do
+ subject do
+ post "/api/v1/admin/accounts/#{account.id}/reject", headers: headers
+ end
+
+ let(:account) { Fabricate(:account) }
+
+ context 'when the account is pending' do
+ before do
+ account.user.update(approved: false)
+ end
+
+ it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read'
+ it_behaves_like 'forbidden for wrong role', ''
+
+ it 'removes the user successfully', :aggregate_failures do
+ subject
+
+ expect(response).to have_http_status(200)
+ expect(User.where(id: account.user.id)).to_not exist
+ end
+
+ it 'logs action', :aggregate_failures do
+ subject
+
+ log_item = Admin::ActionLog.last
+
+ expect(log_item).to be_present
+ expect(log_item.action).to eq :reject
+ expect(log_item.account_id).to eq user.account_id
+ expect(log_item.target_id).to eq account.user.id
+ end
+ end
+
+ context 'when account is already approved' do
+ it 'returns http forbidden' do
+ subject
+
+ expect(response).to have_http_status(403)
+ end
+ end
+
+ context 'when the account is not found' do
+ it 'returns http not found' do
+ post '/api/v1/admin/accounts/-1/reject', headers: headers
+
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+
+ describe 'POST /api/v1/admin/accounts/:id/enable' do
+ subject do
+ post "/api/v1/admin/accounts/#{account.id}/enable", headers: headers
+ end
+
+ let(:account) { Fabricate(:account) }
+
+ before do
+ account.user.update(disabled: true)
+ end
+
+ it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read'
+ it_behaves_like 'forbidden for wrong role', ''
+
+ it 'enables the user successfully', :aggregate_failures do
+ subject
+
+ expect(response).to have_http_status(200)
+ expect(account.reload.user_disabled?).to be false
+ end
+
+ context 'when the account is not found' do
+ it 'returns http not found' do
+ post '/api/v1/admin/accounts/-1/enable', headers: headers
+
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+
+ describe 'POST /api/v1/admin/accounts/:id/unsuspend' do
+ subject do
+ post "/api/v1/admin/accounts/#{account.id}/unsuspend", headers: headers
+ end
+
+ let(:account) { Fabricate(:account) }
+
+ context 'when the account is suspended' do
+ before do
+ account.suspend!
+ end
+
+ it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read'
+ it_behaves_like 'forbidden for wrong role', ''
+
+ it 'unsuspends the account successfully', :aggregate_failures do
+ subject
+
+ expect(response).to have_http_status(200)
+ expect(account.reload.suspended?).to be false
+ end
+ end
+
+ context 'when the account is not suspended' do
+ it 'returns http forbidden' do
+ subject
+
+ expect(response).to have_http_status(403)
+ end
+ end
+
+ context 'when the account is not found' do
+ it 'returns http not found' do
+ post '/api/v1/admin/accounts/-1/unsuspend', headers: headers
+
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+
+ describe 'POST /api/v1/admin/accounts/:id/unsensitive' do
+ subject do
+ post "/api/v1/admin/accounts/#{account.id}/unsensitive", headers: headers
+ end
+
+ let(:account) { Fabricate(:account) }
+
+ before do
+ account.update(sensitized_at: 10.days.ago)
+ end
+
+ it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read'
+ it_behaves_like 'forbidden for wrong role', ''
+
+ it 'unsensitizes the account successfully', :aggregate_failures do
+ subject
+
+ expect(response).to have_http_status(200)
+ expect(account.reload.sensitized?).to be false
+ end
+
+ context 'when the account is not found' do
+ it 'returns http not found' do
+ post '/api/v1/admin/accounts/-1/unsensitive', headers: headers
+
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+
+ describe 'POST /api/v1/admin/accounts/:id/unsilence' do
+ subject do
+ post "/api/v1/admin/accounts/#{account.id}/unsilence", headers: headers
+ end
+
+ let(:account) { Fabricate(:account) }
+
+ before do
+ account.update(silenced_at: 3.days.ago)
+ end
+
+ it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read'
+ it_behaves_like 'forbidden for wrong role', ''
+
+ it 'unsilences the account successfully', :aggregate_failures do
+ subject
+
+ expect(response).to have_http_status(200)
+ expect(account.reload.silenced?).to be false
+ end
+
+ context 'when the account is not found' do
+ it 'returns http not found' do
+ post '/api/v1/admin/accounts/-1/unsilence', headers: headers
+
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+
+ describe 'DELETE /api/v1/admin/accounts/:id' do
+ subject do
+ delete "/api/v1/admin/accounts/#{account.id}", headers: headers
+ end
+
+ let(:account) { Fabricate(:account) }
+
+ context 'when account is suspended' do
+ before do
+ account.suspend!
+ end
+
+ it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read'
+ it_behaves_like 'forbidden for wrong role', ''
+
+ it 'deletes the account successfully', :aggregate_failures do
+ allow(Admin::AccountDeletionWorker).to receive(:perform_async)
+ subject
+
+ expect(response).to have_http_status(200)
+ expect(Admin::AccountDeletionWorker).to have_received(:perform_async).with(account.id).once
+ end
+ end
+
+ context 'when account is not suspended' do
+ it 'returns http forbidden' do
+ subject
+
+ expect(response).to have_http_status(403)
+ end
+ end
+
+ context 'when the account is not found' do
+ it 'returns http not found' do
+ delete '/api/v1/admin/accounts/-1', headers: headers
+
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/v1/admin/canonical_email_blocks_spec.rb b/spec/requests/api/v1/admin/canonical_email_blocks_spec.rb
index 4382cb84e545f2..3f33b50f39ab1f 100644
--- a/spec/requests/api/v1/admin/canonical_email_blocks_spec.rb
+++ b/spec/requests/api/v1/admin/canonical_email_blocks_spec.rb
@@ -92,15 +92,10 @@
it_behaves_like 'forbidden for wrong role', 'Moderator'
context 'when the requested canonical email block exists' do
- it 'returns http success' do
+ it 'returns the requested canonical email block data correctly', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'returns the requested canonical email block data correctly' do
- subject
-
json = body_as_json
expect(json[:id]).to eq(canonical_email_block.id.to_s)
@@ -142,29 +137,19 @@
context 'when there is a matching canonical email block' do
let!(:canonical_email_block) { CanonicalEmailBlock.create(params) }
- it 'returns http success' do
+ it 'returns the expected canonical email hash', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'returns the expected canonical email hash' do
- subject
-
expect(body_as_json[0][:canonical_email_hash]).to eq(canonical_email_block.canonical_email_hash)
end
end
context 'when there is no matching canonical email block' do
- it 'returns http success' do
+ it 'returns an empty list', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'returns an empty list' do
- subject
-
expect(body_as_json).to be_empty
end
end
@@ -183,15 +168,10 @@
it_behaves_like 'forbidden for wrong role', ''
it_behaves_like 'forbidden for wrong role', 'Moderator'
- it 'returns http success' do
+ it 'returns the canonical_email_hash correctly', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'returns the canonical_email_hash correctly' do
- subject
-
expect(body_as_json[:canonical_email_hash]).to eq(canonical_email_block.canonical_email_hash)
end
@@ -208,15 +188,10 @@
context 'when the canonical_email_hash param is provided instead of email' do
let(:params) { { canonical_email_hash: 'dd501ce4e6b08698f19df96f2f15737e48a75660b1fa79b6ff58ea25ee4851a4' } }
- it 'returns http success' do
+ it 'returns the correct canonical_email_hash', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'returns the correct canonical_email_hash' do
- subject
-
expect(body_as_json[:canonical_email_hash]).to eq(params[:canonical_email_hash])
end
end
@@ -224,15 +199,10 @@
context 'when both email and canonical_email_hash params are provided' do
let(:params) { { email: 'example@email.com', canonical_email_hash: 'dd501ce4e6b08698f19df96f2f15737e48a75660b1fa79b6ff58ea25ee4851a4' } }
- it 'returns http success' do
+ it 'ignores the canonical_email_hash param', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'ignores the canonical_email_hash param' do
- subject
-
expect(body_as_json[:canonical_email_hash]).to eq(canonical_email_block.canonical_email_hash)
end
end
@@ -262,15 +232,10 @@
it_behaves_like 'forbidden for wrong role', ''
it_behaves_like 'forbidden for wrong role', 'Moderator'
- it 'returns http success' do
+ it 'deletes the canonical email block', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'deletes the canonical email block' do
- subject
-
expect(CanonicalEmailBlock.find_by(id: canonical_email_block.id)).to be_nil
end
diff --git a/spec/requests/api/v1/admin/domain_allows_spec.rb b/spec/requests/api/v1/admin/domain_allows_spec.rb
index 96000e3ef4832c..6db1ab6e307a17 100644
--- a/spec/requests/api/v1/admin/domain_allows_spec.rb
+++ b/spec/requests/api/v1/admin/domain_allows_spec.rb
@@ -75,15 +75,10 @@
it_behaves_like 'forbidden for wrong role', ''
it_behaves_like 'forbidden for wrong role', 'Moderator'
- it 'returns http success' do
+ it 'returns the expected allowed domain name', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'returns the expected allowed domain name' do
- subject
-
expect(body_as_json[:domain]).to eq domain_allow.domain
end
@@ -108,21 +103,11 @@
it_behaves_like 'forbidden for wrong role', 'Moderator'
context 'with a valid domain name' do
- it 'returns http success' do
+ it 'returns the expected domain name', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'returns the expected domain name' do
- subject
-
expect(body_as_json[:domain]).to eq 'foo.bar.com'
- end
-
- it 'creates a domain allow' do
- subject
-
expect(DomainAllow.find_by(domain: 'foo.bar.com')).to be_present
end
end
@@ -171,15 +156,10 @@
it_behaves_like 'forbidden for wrong role', ''
it_behaves_like 'forbidden for wrong role', 'Moderator'
- it 'returns http success' do
+ it 'deletes the allowed domain', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'deletes the allowed domain' do
- subject
-
expect(DomainAllow.find_by(id: domain_allow.id)).to be_nil
end
diff --git a/spec/requests/api/v1/admin/domain_blocks_spec.rb b/spec/requests/api/v1/admin/domain_blocks_spec.rb
index 7a5ac28c565e1f..1fb6fc8228b0b9 100644
--- a/spec/requests/api/v1/admin/domain_blocks_spec.rb
+++ b/spec/requests/api/v1/admin/domain_blocks_spec.rb
@@ -89,15 +89,10 @@
it_behaves_like 'forbidden for wrong role', ''
it_behaves_like 'forbidden for wrong role', 'Moderator'
- it 'returns http success' do
+ it 'returns the expected domain block content', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'returns the expected domain block content' do
- subject
-
expect(body_as_json).to eq(
{
id: domain_block.id.to_s,
@@ -133,27 +128,18 @@
it_behaves_like 'forbidden for wrong role', ''
it_behaves_like 'forbidden for wrong role', 'Moderator'
- it 'returns http success' do
- subject
-
- expect(response).to have_http_status(200)
- end
-
- it 'returns expected domain name and severity' do
+ it 'returns expected domain name and severity', :aggregate_failures do
subject
body = body_as_json
+ expect(response).to have_http_status(200)
expect(body).to match a_hash_including(
{
domain: 'foo.bar.com',
severity: 'silence',
}
)
- end
-
- it 'creates a domain block' do
- subject
expect(DomainBlock.find_by(domain: 'foo.bar.com')).to be_present
end
@@ -163,15 +149,10 @@
Fabricate(:domain_block, domain: 'bar.com', severity: :suspend)
end
- it 'returns http unprocessable entity' do
+ it 'returns existing domain block in error', :aggregate_failures do
subject
expect(response).to have_http_status(422)
- end
-
- it 'returns existing domain block in error' do
- subject
-
expect(body_as_json[:existing_domain_block][:domain]).to eq('bar.com')
end
end
@@ -199,15 +180,10 @@
it_behaves_like 'forbidden for wrong role', ''
it_behaves_like 'forbidden for wrong role', 'Moderator'
- it 'returns http success' do
+ it 'returns the updated domain block', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'returns the updated domain block' do
- subject
-
expect(body_as_json).to match a_hash_including(
{
id: domain_block.id.to_s,
@@ -241,15 +217,10 @@
it_behaves_like 'forbidden for wrong role', ''
it_behaves_like 'forbidden for wrong role', 'Moderator'
- it 'returns http success' do
+ it 'deletes the domain block', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'deletes the domain block' do
- subject
-
expect(DomainBlock.find_by(id: domain_block.id)).to be_nil
end
diff --git a/spec/requests/api/v1/admin/email_domain_blocks_spec.rb b/spec/requests/api/v1/admin/email_domain_blocks_spec.rb
index d512def86690d0..16656e0202c2f2 100644
--- a/spec/requests/api/v1/admin/email_domain_blocks_spec.rb
+++ b/spec/requests/api/v1/admin/email_domain_blocks_spec.rb
@@ -93,15 +93,10 @@
it_behaves_like 'forbidden for wrong role', 'Moderator'
context 'when email domain block exists' do
- it 'returns http success' do
+ it 'returns the correct blocked domain', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'returns the correct blocked domain' do
- subject
-
expect(body_as_json[:domain]).to eq(email_domain_block.domain)
end
end
@@ -126,15 +121,10 @@
it_behaves_like 'forbidden for wrong role', ''
it_behaves_like 'forbidden for wrong role', 'Moderator'
- it 'returns http success' do
+ it 'returns the correct blocked email domain', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'returns the correct blocked email domain' do
- subject
-
expect(body_as_json[:domain]).to eq(params[:domain])
end
@@ -182,21 +172,11 @@
it_behaves_like 'forbidden for wrong role', ''
it_behaves_like 'forbidden for wrong role', 'Moderator'
- it 'returns http success' do
+ it 'deletes email domain block', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'returns an empty body' do
- subject
-
expect(body_as_json).to be_empty
- end
-
- it 'deletes email domain block' do
- subject
-
expect(EmailDomainBlock.find_by(id: email_domain_block.id)).to be_nil
end
diff --git a/spec/requests/api/v1/admin/ip_blocks_spec.rb b/spec/requests/api/v1/admin/ip_blocks_spec.rb
index d03886c51b06d1..fbcb39e3bef371 100644
--- a/spec/requests/api/v1/admin/ip_blocks_spec.rb
+++ b/spec/requests/api/v1/admin/ip_blocks_spec.rb
@@ -84,15 +84,10 @@
it_behaves_like 'forbidden for wrong role', ''
it_behaves_like 'forbidden for wrong role', 'Moderator'
- it 'returns http success' do
+ it 'returns the correct ip block', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'returns the correct ip block' do
- subject
-
json = body_as_json
expect(json[:ip]).to eq("#{ip_block.ip}/#{ip_block.ip.prefix}")
@@ -119,15 +114,10 @@
it_behaves_like 'forbidden for wrong role', ''
it_behaves_like 'forbidden for wrong role', 'Moderator'
- it 'returns http success' do
+ it 'returns the correct ip block', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'returns the correct ip block' do
- subject
-
json = body_as_json
expect(json[:ip]).to eq("#{params[:ip]}/32")
@@ -186,15 +176,10 @@
let!(:ip_block) { IpBlock.create(ip: '185.200.13.3', severity: 'no_access', comment: 'Spam', expires_in: 48.hours) }
let(:params) { { severity: 'sign_up_requires_approval', comment: 'Decreasing severity' } }
- it 'returns http success' do
+ it 'returns the correct ip block', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'returns the correct ip block' do
- subject
-
expect(body_as_json).to match(hash_including({
ip: "#{ip_block.ip}/#{ip_block.ip.prefix}",
severity: 'sign_up_requires_approval',
@@ -226,21 +211,11 @@
let!(:ip_block) { IpBlock.create(ip: '185.200.13.3', severity: 'no_access') }
- it 'returns http success' do
+ it 'deletes the ip block', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'returns an empty body' do
- subject
-
expect(body_as_json).to be_empty
- end
-
- it 'deletes the ip block' do
- subject
-
expect(IpBlock.find_by(id: ip_block.id)).to be_nil
end
diff --git a/spec/requests/api/v1/admin/reports_spec.rb b/spec/requests/api/v1/admin/reports_spec.rb
index 91c3c11f5dab49..5403457db029ee 100644
--- a/spec/requests/api/v1/admin/reports_spec.rb
+++ b/spec/requests/api/v1/admin/reports_spec.rb
@@ -122,15 +122,10 @@
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
it_behaves_like 'forbidden for wrong role', ''
- it 'returns http success' do
+ it 'returns the requested report content', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'returns the requested report content' do
- subject
-
expect(body_as_json).to include(
{
id: report.id.to_s,
@@ -155,18 +150,10 @@
let!(:report) { Fabricate(:report, category: :other) }
let(:params) { { category: 'spam' } }
- it 'returns http success' do
- subject
-
- expect(response).to have_http_status(200)
- end
-
- it 'updates the report category' do
+ it 'updates the report category', :aggregate_failures do
expect { subject }.to change { report.reload.category }.from('other').to('spam')
- end
- it 'returns the updated report content' do
- subject
+ expect(response).to have_http_status(200)
report.reload
@@ -196,14 +183,9 @@
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
it_behaves_like 'forbidden for wrong role', ''
- it 'returns http success' do
- subject
-
- expect(response).to have_http_status(200)
- end
-
- it 'marks report as resolved' do
+ it 'marks report as resolved', :aggregate_failures do
expect { subject }.to change { report.reload.unresolved? }.from(true).to(false)
+ expect(response).to have_http_status(200)
end
end
@@ -217,14 +199,9 @@
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
it_behaves_like 'forbidden for wrong role', ''
- it 'returns http success' do
- subject
-
- expect(response).to have_http_status(200)
- end
-
- it 'marks report as unresolved' do
+ it 'marks report as unresolved', :aggregate_failures do
expect { subject }.to change { report.reload.unresolved? }.from(false).to(true)
+ expect(response).to have_http_status(200)
end
end
@@ -238,14 +215,9 @@
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
it_behaves_like 'forbidden for wrong role', ''
- it 'returns http success' do
- subject
-
- expect(response).to have_http_status(200)
- end
-
- it 'assigns report to the requesting user' do
+ it 'assigns report to the requesting user', :aggregate_failures do
expect { subject }.to change { report.reload.assigned_account_id }.from(nil).to(user.account.id)
+ expect(response).to have_http_status(200)
end
end
@@ -259,14 +231,9 @@
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
it_behaves_like 'forbidden for wrong role', ''
- it 'returns http success' do
- subject
-
- expect(response).to have_http_status(200)
- end
-
- it 'unassigns report from assignee' do
+ it 'unassigns report from assignee', :aggregate_failures do
expect { subject }.to change { report.reload.assigned_account_id }.from(user.account.id).to(nil)
+ expect(response).to have_http_status(200)
end
end
end
diff --git a/spec/requests/api/v1/admin/trends/links/links_spec.rb b/spec/requests/api/v1/admin/trends/links/links_spec.rb
new file mode 100644
index 00000000000000..05020b0fd0642c
--- /dev/null
+++ b/spec/requests/api/v1/admin/trends/links/links_spec.rb
@@ -0,0 +1,129 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe 'Links' do
+ let(:role) { UserRole.find_by(name: 'Admin') }
+ let(:user) { Fabricate(:user, role: role) }
+ let(:scopes) { 'admin:read admin:write' }
+ let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
+ let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
+
+ describe 'GET /api/v1/admin/trends/links' do
+ subject do
+ get '/api/v1/admin/trends/links', headers: headers
+ end
+
+ it 'returns http success' do
+ subject
+
+ expect(response).to have_http_status(200)
+ end
+ end
+
+ describe 'POST /api/v1/admin/trends/links/:id/approve' do
+ subject do
+ post "/api/v1/admin/trends/links/#{preview_card.id}/approve", headers: headers
+ end
+
+ let(:preview_card) { Fabricate(:preview_card, trendable: false) }
+
+ it_behaves_like 'forbidden for wrong scope', 'read write'
+ it_behaves_like 'forbidden for wrong role', ''
+
+ it 'returns http success' do
+ subject
+
+ expect(response).to have_http_status(200)
+ end
+
+ it 'sets the link as trendable' do
+ expect { subject }.to change { preview_card.reload.trendable }.from(false).to(true)
+ end
+
+ it 'returns the link data' do
+ subject
+
+ expect(body_as_json).to match(
+ a_hash_including(
+ url: preview_card.url,
+ title: preview_card.title,
+ description: preview_card.description,
+ type: 'link',
+ requires_review: false
+ )
+ )
+ end
+
+ context 'when the link does not exist' do
+ it 'returns http not found' do
+ post '/api/v1/admin/trends/links/-1/approve', headers: headers
+
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context 'without an authorization header' do
+ let(:headers) { {} }
+
+ it 'returns http forbidden' do
+ subject
+
+ expect(response).to have_http_status(403)
+ end
+ end
+ end
+
+ describe 'POST /api/v1/admin/trends/links/:id/reject' do
+ subject do
+ post "/api/v1/admin/trends/links/#{preview_card.id}/reject", headers: headers
+ end
+
+ let(:preview_card) { Fabricate(:preview_card, trendable: false) }
+
+ it_behaves_like 'forbidden for wrong scope', 'read write'
+ it_behaves_like 'forbidden for wrong role', ''
+
+ it 'returns http success' do
+ subject
+
+ expect(response).to have_http_status(200)
+ end
+
+ it 'does not set the link as trendable' do
+ expect { subject }.to_not(change { preview_card.reload.trendable })
+ end
+
+ it 'returns the link data' do
+ subject
+
+ expect(body_as_json).to match(
+ a_hash_including(
+ url: preview_card.url,
+ title: preview_card.title,
+ description: preview_card.description,
+ type: 'link',
+ requires_review: false
+ )
+ )
+ end
+
+ context 'when the link does not exist' do
+ it 'returns http not found' do
+ post '/api/v1/admin/trends/links/-1/reject', headers: headers
+
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context 'without an authorization header' do
+ let(:headers) { {} }
+
+ it 'returns http forbidden' do
+ subject
+
+ expect(response).to have_http_status(403)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/v1/apps/credentials_spec.rb b/spec/requests/api/v1/apps/credentials_spec.rb
index dafe168c56f645..e1455fe799a068 100644
--- a/spec/requests/api/v1/apps/credentials_spec.rb
+++ b/spec/requests/api/v1/apps/credentials_spec.rb
@@ -9,7 +9,30 @@
end
context 'with an oauth token' do
- let(:token) { Fabricate(:accessible_access_token, scopes: 'read', application: Fabricate(:application)) }
+ let(:application) { Fabricate(:application, scopes: 'read') }
+ let(:token) { Fabricate(:accessible_access_token, application: application) }
+ let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
+
+ it 'returns the app information correctly', :aggregate_failures do
+ subject
+
+ expect(response).to have_http_status(200)
+
+ expect(body_as_json).to match(
+ a_hash_including(
+ name: token.application.name,
+ website: token.application.website,
+ vapid_key: Rails.configuration.x.vapid_public_key,
+ scopes: token.application.scopes.map(&:to_s),
+ client_id: token.application.uid
+ )
+ )
+ end
+ end
+
+ context 'with a non-read scoped oauth token' do
+ let(:application) { Fabricate(:application, scopes: 'admin:write') }
+ let(:token) { Fabricate(:accessible_access_token, application: application) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
it 'returns http success' do
@@ -25,7 +48,9 @@
a_hash_including(
name: token.application.name,
website: token.application.website,
- vapid_key: Rails.configuration.x.vapid_public_key
+ vapid_key: Rails.configuration.x.vapid_public_key,
+ scopes: token.application.scopes.map(&:to_s),
+ client_id: token.application.uid
)
)
end
@@ -40,5 +65,49 @@
expect(response).to have_http_status(401)
end
end
+
+ context 'with a revoked oauth token' do
+ let(:application) { Fabricate(:application, scopes: 'read') }
+ let(:token) { Fabricate(:accessible_access_token, application: application, revoked_at: DateTime.now.utc) }
+ let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
+
+ it 'returns http authorization error' do
+ subject
+
+ expect(response).to have_http_status(401)
+ end
+
+ it 'returns the error in the json response' do
+ subject
+
+ expect(body_as_json).to match(
+ a_hash_including(
+ error: 'The access token was revoked'
+ )
+ )
+ end
+ end
+
+ context 'with an invalid oauth token' do
+ let(:application) { Fabricate(:application, scopes: 'read') }
+ let(:token) { Fabricate(:accessible_access_token, application: application) }
+ let(:headers) { { 'Authorization' => "Bearer #{token.token}-invalid" } }
+
+ it 'returns http authorization error' do
+ subject
+
+ expect(response).to have_http_status(401)
+ end
+
+ it 'returns the error in the json response' do
+ subject
+
+ expect(body_as_json).to match(
+ a_hash_including(
+ error: 'The access token is invalid'
+ )
+ )
+ end
+ end
end
end
diff --git a/spec/requests/api/v1/apps_spec.rb b/spec/requests/api/v1/apps_spec.rb
index 88f9eee360c1c7..acabbc93f0bbd3 100644
--- a/spec/requests/api/v1/apps_spec.rb
+++ b/spec/requests/api/v1/apps_spec.rb
@@ -23,20 +23,11 @@
end
context 'with valid params' do
- it 'returns http success' do
+ it 'creates an OAuth app', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'creates an OAuth app' do
- subject
-
expect(Doorkeeper::Application.find_by(name: client_name)).to be_present
- end
-
- it 'returns client ID and client secret' do
- subject
body = body_as_json
@@ -58,15 +49,10 @@
context 'with many duplicate scopes' do
let(:scopes) { (%w(read) * 40).join(' ') }
- it 'returns http success' do
+ it 'only saves the scope once', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'only saves the scope once' do
- subject
-
expect(Doorkeeper::Application.find_by(name: client_name).scopes.to_s).to eq 'read'
end
end
diff --git a/spec/requests/api/v1/blocks_spec.rb b/spec/requests/api/v1/blocks_spec.rb
new file mode 100644
index 00000000000000..62543157c32df4
--- /dev/null
+++ b/spec/requests/api/v1/blocks_spec.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe 'Blocks' do
+ let(:user) { Fabricate(:user) }
+ let(:scopes) { 'read:blocks' }
+ let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
+ let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
+
+ describe 'GET /api/v1/blocks' do
+ subject do
+ get '/api/v1/blocks', headers: headers, params: params
+ end
+
+ let!(:blocks) { Fabricate.times(3, :block, account: user.account) }
+ let(:params) { {} }
+
+ let(:expected_response) do
+ blocks.map { |block| a_hash_including(id: block.target_account.id.to_s, username: block.target_account.username) }
+ end
+
+ it_behaves_like 'forbidden for wrong scope', 'write write:blocks'
+
+ it 'returns the blocked accounts', :aggregate_failures do
+ subject
+
+ expect(response).to have_http_status(200)
+ expect(body_as_json).to match_array(expected_response)
+ end
+
+ context 'with limit param' do
+ let(:params) { { limit: 2 } }
+
+ it 'returns only the requested number of blocked accounts' do
+ subject
+
+ expect(body_as_json.size).to eq(params[:limit])
+ end
+
+ it 'sets the correct pagination header for the prev path' do
+ subject
+
+ expect(response.headers['Link'].find_link(%w(rel prev)).href).to eq(api_v1_blocks_url(limit: params[:limit], since_id: blocks.last.id))
+ end
+
+ it 'sets the correct pagination header for the next path' do
+ subject
+
+ expect(response.headers['Link'].find_link(%w(rel next)).href).to eq(api_v1_blocks_url(limit: params[:limit], max_id: blocks[1].id))
+ end
+ end
+
+ context 'with max_id param' do
+ let(:params) { { max_id: blocks[1].id } }
+
+ it 'queries the blocks in range according to max_id', :aggregate_failures do
+ subject
+
+ response_body = body_as_json
+
+ expect(response_body.size).to be 1
+ expect(response_body[0][:id]).to eq(blocks[0].target_account.id.to_s)
+ end
+ end
+
+ context 'with since_id param' do
+ let(:params) { { since_id: blocks[1].id } }
+
+ it 'queries the blocks in range according to since_id', :aggregate_failures do
+ subject
+
+ response_body = body_as_json
+
+ expect(response_body.size).to be 1
+ expect(response_body[0][:id]).to eq(blocks[2].target_account.id.to_s)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/v1/domain_blocks_spec.rb b/spec/requests/api/v1/domain_blocks_spec.rb
index 0f4fd4e90e5448..954497ebe15131 100644
--- a/spec/requests/api/v1/domain_blocks_spec.rb
+++ b/spec/requests/api/v1/domain_blocks_spec.rb
@@ -22,15 +22,10 @@
it_behaves_like 'forbidden for wrong scope', 'write:blocks'
- it 'returns http success' do
+ it 'returns the domains blocked by the requesting user', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'returns the domains blocked by the requesting user' do
- subject
-
expect(body_as_json).to match_array(blocked_domains)
end
@@ -54,15 +49,10 @@
it_behaves_like 'forbidden for wrong scope', 'read read:blocks'
- it 'returns http success' do
+ it 'creates a domain block', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'creates a domain block' do
- subject
-
expect(user.account.domain_blocking?(params[:domain])).to be(true)
end
@@ -100,15 +90,10 @@
it_behaves_like 'forbidden for wrong scope', 'read read:blocks'
- it 'returns http success' do
+ it 'deletes the specified domain block', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'deletes the specified domain block' do
- subject
-
expect(user.account.domain_blocking?('example.com')).to be(false)
end
diff --git a/spec/requests/api/v1/favourites_spec.rb b/spec/requests/api/v1/favourites_spec.rb
new file mode 100644
index 00000000000000..713990592c38a5
--- /dev/null
+++ b/spec/requests/api/v1/favourites_spec.rb
@@ -0,0 +1,71 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe 'Favourites' do
+ let(:user) { Fabricate(:user) }
+ let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
+ let(:scopes) { 'read:favourites' }
+ let(:headers) { { Authorization: "Bearer #{token.token}" } }
+
+ describe 'GET /api/v1/favourites' do
+ subject do
+ get '/api/v1/favourites', headers: headers, params: params
+ end
+
+ let(:params) { {} }
+ let!(:favourites) { Fabricate.times(3, :favourite, account: user.account) }
+
+ let(:expected_response) do
+ favourites.map do |favourite|
+ a_hash_including(id: favourite.status.id.to_s, account: a_hash_including(id: favourite.status.account.id.to_s))
+ end
+ end
+
+ it_behaves_like 'forbidden for wrong scope', 'write'
+
+ it 'returns http success' do
+ subject
+
+ expect(response).to have_http_status(200)
+ end
+
+ it 'returns the favourites' do
+ subject
+
+ expect(body_as_json).to match_array(expected_response)
+ end
+
+ context 'with limit param' do
+ let(:params) { { limit: 2 } }
+
+ it 'returns only the requested number of favourites' do
+ subject
+
+ expect(body_as_json.size).to eq(params[:limit])
+ end
+
+ it 'sets the correct pagination header for the prev path' do
+ subject
+
+ expect(response.headers['Link'].find_link(%w(rel prev)).href).to eq(api_v1_favourites_url(limit: params[:limit], min_id: favourites.last.id))
+ end
+
+ it 'sets the correct pagination header for the next path' do
+ subject
+
+ expect(response.headers['Link'].find_link(%w(rel next)).href).to eq(api_v1_favourites_url(limit: params[:limit], max_id: favourites[1].id))
+ end
+ end
+
+ context 'without an authorization header' do
+ let(:headers) { {} }
+
+ it 'returns http unauthorized' do
+ subject
+
+ expect(response).to have_http_status(401)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/v1/follow_requests_spec.rb b/spec/requests/api/v1/follow_requests_spec.rb
index 9d4ef8cd55970a..1d78c9be19fdfe 100644
--- a/spec/requests/api/v1/follow_requests_spec.rb
+++ b/spec/requests/api/v1/follow_requests_spec.rb
@@ -32,15 +32,10 @@
it_behaves_like 'forbidden for wrong scope', 'write write:follows'
- it 'returns http success' do
+ it 'returns the expected content from accounts requesting to follow', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'returns the expected content from accounts requesting to follow' do
- subject
-
expect(body_as_json).to match_array(expected_response)
end
@@ -68,19 +63,9 @@
it_behaves_like 'forbidden for wrong scope', 'read read:follows'
- it 'returns http success' do
- subject
-
- expect(response).to have_http_status(200)
- end
-
- it 'allows the requesting follower to follow' do
+ it 'allows the requesting follower to follow', :aggregate_failures do
expect { subject }.to change { follower.following?(user.account) }.from(false).to(true)
- end
-
- it 'returns JSON with followed_by set to true' do
- subject
-
+ expect(response).to have_http_status(200)
expect(body_as_json[:followed_by]).to be true
end
end
@@ -98,21 +83,11 @@
it_behaves_like 'forbidden for wrong scope', 'read read:follows'
- it 'returns http success' do
+ it 'removes the follow request', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'removes the follow request' do
- subject
-
expect(FollowRequest.where(target_account: user.account, account: follower)).to_not exist
- end
-
- it 'returns JSON with followed_by set to false' do
- subject
-
expect(body_as_json[:followed_by]).to be false
end
end
diff --git a/spec/requests/api/v1/followed_tags_spec.rb b/spec/requests/api/v1/followed_tags_spec.rb
new file mode 100644
index 00000000000000..9391c7bdc8b9ba
--- /dev/null
+++ b/spec/requests/api/v1/followed_tags_spec.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe 'Followed tags' do
+ let(:user) { Fabricate(:user) }
+ let(:scopes) { 'read:follows' }
+ let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
+ let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
+
+ describe 'GET /api/v1/followed_tags' do
+ subject do
+ get '/api/v1/followed_tags', headers: headers, params: params
+ end
+
+ let!(:tag_follows) { Fabricate.times(5, :tag_follow, account: user.account) }
+ let(:params) { {} }
+
+ let(:expected_response) do
+ tag_follows.map do |tag_follow|
+ a_hash_including(name: tag_follow.tag.name, following: true)
+ end
+ end
+
+ before do
+ Fabricate(:tag_follow)
+ end
+
+ it_behaves_like 'forbidden for wrong scope', 'write write:follows'
+
+ it 'returns http success' do
+ subject
+
+ expect(response).to have_http_status(:success)
+ end
+
+ it 'returns the followed tags correctly' do
+ subject
+
+ expect(body_as_json).to match_array(expected_response)
+ end
+
+ context 'with limit param' do
+ let(:params) { { limit: 3 } }
+
+ it 'returns only the requested number of follow tags' do
+ subject
+
+ expect(body_as_json.size).to eq(params[:limit])
+ end
+
+ it 'sets the correct pagination header for the prev path' do
+ subject
+
+ expect(response.headers['Link'].find_link(%w(rel prev)).href).to eq(api_v1_followed_tags_url(limit: params[:limit], since_id: tag_follows.last.id))
+ end
+
+ it 'sets the correct pagination header for the next path' do
+ subject
+
+ expect(response.headers['Link'].find_link(%w(rel next)).href).to eq(api_v1_followed_tags_url(limit: params[:limit], max_id: tag_follows[2].id))
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/v1/lists/accounts_spec.rb b/spec/requests/api/v1/lists/accounts_spec.rb
new file mode 100644
index 00000000000000..4d2a168b34b512
--- /dev/null
+++ b/spec/requests/api/v1/lists/accounts_spec.rb
@@ -0,0 +1,178 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe 'Accounts' do
+ let(:user) { Fabricate(:user) }
+ let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
+ let(:scopes) { 'read:lists write:lists' }
+ let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
+
+ describe 'GET /api/v1/lists/:id/accounts' do
+ subject do
+ get "/api/v1/lists/#{list.id}/accounts", headers: headers, params: params
+ end
+
+ let(:params) { { limit: 0 } }
+ let(:list) { Fabricate(:list, account: user.account) }
+ let(:accounts) { Fabricate.times(3, :account) }
+
+ let(:expected_response) do
+ accounts.map do |account|
+ a_hash_including(id: account.id.to_s, username: account.username, acct: account.acct)
+ end
+ end
+
+ before do
+ accounts.each { |account| user.account.follow!(account) }
+ list.accounts << accounts
+ end
+
+ it_behaves_like 'forbidden for wrong scope', 'write write:lists'
+
+ it 'returns the accounts in the requested list', :aggregate_failures do
+ subject
+
+ expect(response).to have_http_status(200)
+ expect(body_as_json).to match_array(expected_response)
+ end
+
+ context 'with limit param' do
+ let(:params) { { limit: 1 } }
+
+ it 'returns only the requested number of accounts' do
+ subject
+
+ expect(body_as_json.size).to eq(params[:limit])
+ end
+ end
+ end
+
+ describe 'POST /api/v1/lists/:id/accounts' do
+ subject do
+ post "/api/v1/lists/#{list.id}/accounts", headers: headers, params: params
+ end
+
+ let(:list) { Fabricate(:list, account: user.account) }
+ let(:bob) { Fabricate(:account, username: 'bob') }
+ let(:params) { { account_ids: [bob.id] } }
+
+ it_behaves_like 'forbidden for wrong scope', 'read read:lists'
+
+ context 'when the added account is followed' do
+ before do
+ user.account.follow!(bob)
+ end
+
+ it 'adds account to the list', :aggregate_failures do
+ subject
+
+ expect(response).to have_http_status(200)
+ expect(list.accounts).to include(bob)
+ end
+ end
+
+ context 'when the added account has been sent a follow request' do
+ before do
+ user.account.follow_requests.create!(target_account: bob)
+ end
+
+ it 'adds account to the list', :aggregate_failures do
+ subject
+
+ expect(response).to have_http_status(200)
+ expect(list.accounts).to include(bob)
+ end
+ end
+
+ context 'when the added account is not followed' do
+ it 'does not add the account to the list', :aggregate_failures do
+ subject
+
+ expect(response).to have_http_status(404)
+ expect(list.accounts).to_not include(bob)
+ end
+ end
+
+ context 'when the list is not owned by the requesting user' do
+ let(:list) { Fabricate(:list) }
+
+ before do
+ user.account.follow!(bob)
+ end
+
+ it 'returns http not found' do
+ subject
+
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context 'when account is already in the list' do
+ before do
+ user.account.follow!(bob)
+ list.accounts << bob
+ end
+
+ it 'returns http unprocessable entity' do
+ subject
+
+ expect(response).to have_http_status(422)
+ end
+ end
+ end
+
+ describe 'DELETE /api/v1/lists/:id/accounts' do
+ subject do
+ delete "/api/v1/lists/#{list.id}/accounts", headers: headers, params: params
+ end
+
+ context 'when the list is owned by the requesting user' do
+ let(:list) { Fabricate(:list, account: user.account) }
+ let(:bob) { Fabricate(:account, username: 'bob') }
+ let(:peter) { Fabricate(:account, username: 'peter') }
+ let(:params) { { account_ids: [bob.id] } }
+
+ before do
+ user.account.follow!(bob)
+ user.account.follow!(peter)
+ list.accounts << [bob, peter]
+ end
+
+ it 'removes the specified account from the list', :aggregate_failures do
+ subject
+
+ expect(response).to have_http_status(200)
+ expect(list.accounts).to_not include(bob)
+ end
+
+ it 'does not remove any other account from the list' do
+ subject
+
+ expect(list.accounts).to include(peter)
+ end
+
+ context 'when the specified account is not in the list' do
+ let(:params) { { account_ids: [0] } }
+
+ it 'does not remove any account from the list', :aggregate_failures do
+ subject
+
+ expect(response).to have_http_status(200)
+ expect(list.accounts).to contain_exactly(bob, peter)
+ end
+ end
+ end
+
+ context 'when the list is not owned by the requesting user' do
+ let(:list) { Fabricate(:list) }
+ let(:params) { {} }
+
+ it 'returns http not found' do
+ subject
+
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/v1/lists_spec.rb b/spec/requests/api/v1/lists_spec.rb
index 383e09d0c3fe31..22dde43a19063c 100644
--- a/spec/requests/api/v1/lists_spec.rb
+++ b/spec/requests/api/v1/lists_spec.rb
@@ -39,15 +39,10 @@
it_behaves_like 'forbidden for wrong scope', 'write write:lists'
- it 'returns http success' do
+ it 'returns the expected lists', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'returns the expected lists' do
- subject
-
expect(body_as_json).to match_array(expected_response)
end
end
@@ -61,15 +56,10 @@
it_behaves_like 'forbidden for wrong scope', 'write write:lists'
- it 'returns http success' do
+ it 'returns the requested list correctly', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'returns the requested list correctly' do
- subject
-
expect(body_as_json).to eq({
id: list.id.to_s,
title: list.title,
@@ -106,21 +96,11 @@
it_behaves_like 'forbidden for wrong scope', 'read read:lists'
- it 'returns http success' do
+ it 'returns the new list', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'returns the new list' do
- subject
-
expect(body_as_json).to match(a_hash_including(title: 'my list', replies_policy: 'none', exclusive: true))
- end
-
- it 'creates a list' do
- subject
-
expect(List.where(account: user.account).count).to eq(1)
end
@@ -155,15 +135,10 @@
it_behaves_like 'forbidden for wrong scope', 'read read:lists'
- it 'returns http success' do
+ it 'returns the updated list', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'returns the updated list' do
- subject
-
list.reload
expect(body_as_json).to eq({
@@ -214,15 +189,10 @@
it_behaves_like 'forbidden for wrong scope', 'read read:lists'
- it 'returns http success' do
+ it 'deletes the list', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'deletes the list' do
- subject
-
expect(List.where(id: list.id)).to_not exist
end
diff --git a/spec/requests/api/v1/media_spec.rb b/spec/requests/api/v1/media_spec.rb
new file mode 100644
index 00000000000000..7253a9f1e8560d
--- /dev/null
+++ b/spec/requests/api/v1/media_spec.rb
@@ -0,0 +1,189 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe 'Media' do
+ let(:user) { Fabricate(:user) }
+ let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
+ let(:scopes) { 'write:media' }
+ let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
+
+ describe 'GET /api/v1/media/:id' do
+ subject do
+ get "/api/v1/media/#{media.id}", headers: headers
+ end
+
+ let(:media) { Fabricate(:media_attachment, account: user.account) }
+
+ it_behaves_like 'forbidden for wrong scope', 'read'
+
+ it 'returns http success' do
+ subject
+
+ expect(response).to have_http_status(200)
+ end
+
+ it 'returns the media information' do
+ subject
+
+ expect(body_as_json).to match(
+ a_hash_including(
+ id: media.id.to_s,
+ description: media.description,
+ type: media.type
+ )
+ )
+ end
+
+ context 'when the media is still being processed' do
+ before do
+ media.update(processing: :in_progress)
+ end
+
+ it 'returns http partial content' do
+ subject
+
+ expect(response).to have_http_status(206)
+ end
+ end
+
+ context 'when the media belongs to somebody else' do
+ let(:media) { Fabricate(:media_attachment) }
+
+ it 'returns http not found' do
+ subject
+
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context 'when media is attached to a status' do
+ let(:media) { Fabricate(:media_attachment, account: user.account, status: Fabricate.build(:status)) }
+
+ it 'returns http not found' do
+ subject
+
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+
+ describe 'POST /api/v1/media' do
+ subject do
+ post '/api/v1/media', headers: headers, params: params
+ end
+
+ let(:params) { {} }
+
+ shared_examples 'a successful media upload' do |media_type|
+ it 'uploads the file successfully', :aggregate_failures do
+ subject
+
+ expect(response).to have_http_status(200)
+ expect(MediaAttachment.first).to be_present
+ expect(MediaAttachment.first).to have_attached_file(:file)
+ end
+
+ it 'returns the correct media content' do
+ subject
+
+ body = body_as_json
+
+ expect(body).to match(
+ a_hash_including(id: MediaAttachment.first.id.to_s, description: params[:description], type: media_type)
+ )
+ end
+ end
+
+ it_behaves_like 'forbidden for wrong scope', 'read read:media'
+
+ describe 'when paperclip errors occur' do
+ let(:media_attachments) { double }
+ let(:params) { { file: fixture_file_upload('attachment.jpg', 'image/jpeg') } }
+
+ before do
+ allow(User).to receive(:find).with(token.resource_owner_id).and_return(user)
+ allow(user.account).to receive(:media_attachments).and_return(media_attachments)
+ end
+
+ context 'when imagemagick cannot identify the file type' do
+ it 'returns http unprocessable entity' do
+ allow(media_attachments).to receive(:create!).and_raise(Paperclip::Errors::NotIdentifiedByImageMagickError)
+
+ subject
+
+ expect(response).to have_http_status(422)
+ end
+ end
+
+ context 'when there is a generic error' do
+ it 'returns http 500' do
+ allow(media_attachments).to receive(:create!).and_raise(Paperclip::Error)
+
+ subject
+
+ expect(response).to have_http_status(500)
+ end
+ end
+ end
+
+ context 'with image/jpeg', paperclip_processing: true do
+ let(:params) { { file: fixture_file_upload('attachment.jpg', 'image/jpeg'), description: 'jpeg image' } }
+
+ it_behaves_like 'a successful media upload', 'image'
+ end
+
+ context 'with image/gif', paperclip_processing: true do
+ let(:params) { { file: fixture_file_upload('attachment.gif', 'image/gif') } }
+
+ it_behaves_like 'a successful media upload', 'image'
+ end
+
+ context 'with video/webm', paperclip_processing: true do
+ let(:params) { { file: fixture_file_upload('attachment.webm', 'video/webm') } }
+
+ it_behaves_like 'a successful media upload', 'gifv'
+ end
+ end
+
+ describe 'PUT /api/v1/media/:id' do
+ subject do
+ put "/api/v1/media/#{media.id}", headers: headers, params: params
+ end
+
+ let(:params) { {} }
+ let(:media) { Fabricate(:media_attachment, status: status, account: user.account, description: 'old') }
+
+ it_behaves_like 'forbidden for wrong scope', 'read read:media'
+
+ context 'when the media belongs to somebody else' do
+ let(:media) { Fabricate(:media_attachment, status: nil) }
+ let(:params) { { description: 'Lorem ipsum!!!' } }
+
+ it 'returns http not found' do
+ subject
+
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context 'when the requesting user owns the media' do
+ let(:status) { nil }
+ let(:params) { { description: 'Lorem ipsum!!!' } }
+
+ it 'updates the description' do
+ expect { subject }.to change { media.reload.description }.from('old').to('Lorem ipsum!!!')
+ end
+
+ context 'when the media is attached to a status' do
+ let(:status) { Fabricate(:status, account: user.account) }
+
+ it 'returns http not found' do
+ subject
+
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/v1/notifications_spec.rb b/spec/requests/api/v1/notifications_spec.rb
new file mode 100644
index 00000000000000..7a879c35b7cba7
--- /dev/null
+++ b/spec/requests/api/v1/notifications_spec.rb
@@ -0,0 +1,183 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe 'Notifications' do
+ let(:user) { Fabricate(:user, account_attributes: { username: 'alice' }) }
+ let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
+ let(:scopes) { 'read:notifications write:notifications' }
+ let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
+
+ describe 'GET /api/v1/notifications' do
+ subject do
+ get '/api/v1/notifications', headers: headers, params: params
+ end
+
+ let(:bob) { Fabricate(:user) }
+ let(:tom) { Fabricate(:user) }
+ let(:params) { {} }
+
+ before do
+ first_status = PostStatusService.new.call(user.account, text: 'Test')
+ ReblogService.new.call(bob.account, first_status)
+ mentioning_status = PostStatusService.new.call(bob.account, text: 'Hello @alice')
+ mentioning_status.mentions.first
+ FavouriteService.new.call(bob.account, first_status)
+ FavouriteService.new.call(tom.account, first_status)
+ FollowService.new.call(bob.account, user.account)
+ end
+
+ it_behaves_like 'forbidden for wrong scope', 'write write:notifications'
+
+ context 'with no options' do
+ it 'returns expected notification types', :aggregate_failures do
+ subject
+
+ expect(response).to have_http_status(200)
+ expect(body_json_types).to include 'reblog'
+ expect(body_json_types).to include 'mention'
+ expect(body_json_types).to include 'favourite'
+ expect(body_json_types).to include 'follow'
+ end
+ end
+
+ context 'with account_id param' do
+ let(:params) { { account_id: tom.account.id } }
+
+ it 'returns only notifications from specified user', :aggregate_failures do
+ subject
+
+ expect(response).to have_http_status(200)
+ expect(body_json_account_ids.uniq).to eq [tom.account.id.to_s]
+ end
+
+ def body_json_account_ids
+ body_as_json.map { |x| x[:account][:id] }
+ end
+ end
+
+ context 'with invalid account_id param' do
+ let(:params) { { account_id: 'foo' } }
+
+ it 'returns nothing', :aggregate_failures do
+ subject
+
+ expect(response).to have_http_status(200)
+ expect(body_as_json.size).to eq 0
+ end
+ end
+
+ context 'with exclude_types param' do
+ let(:params) { { exclude_types: %w(mention) } }
+
+ it 'returns everything but excluded type', :aggregate_failures do
+ subject
+
+ expect(response).to have_http_status(200)
+ expect(body_as_json.size).to_not eq 0
+ expect(body_json_types.uniq).to_not include 'mention'
+ end
+ end
+
+ context 'with types param' do
+ let(:params) { { types: %w(mention) } }
+
+ it 'returns only requested type', :aggregate_failures do
+ subject
+
+ expect(response).to have_http_status(200)
+ expect(body_json_types.uniq).to eq ['mention']
+ end
+ end
+
+ context 'with limit param' do
+ let(:params) { { limit: 3 } }
+
+ it 'returns the requested number of notifications paginated', :aggregate_failures do
+ subject
+
+ notifications = user.account.notifications
+
+ expect(body_as_json.size).to eq(params[:limit])
+ expect(response.headers['Link'].find_link(%w(rel prev)).href).to eq(api_v1_notifications_url(limit: params[:limit], min_id: notifications.last.id.to_s))
+ expect(response.headers['Link'].find_link(%w(rel next)).href).to eq(api_v1_notifications_url(limit: params[:limit], max_id: notifications[2].id.to_s))
+ end
+ end
+
+ def body_json_types
+ body_as_json.pluck(:type)
+ end
+ end
+
+ describe 'GET /api/v1/notifications/:id' do
+ subject do
+ get "/api/v1/notifications/#{notification.id}", headers: headers
+ end
+
+ let(:notification) { Fabricate(:notification, account: user.account) }
+
+ it_behaves_like 'forbidden for wrong scope', 'write write:notifications'
+
+ it 'returns http success' do
+ subject
+
+ expect(response).to have_http_status(200)
+ end
+
+ context 'when notification belongs to someone else' do
+ let(:notification) { Fabricate(:notification) }
+
+ it 'returns http not found' do
+ subject
+
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+
+ describe 'POST /api/v1/notifications/:id/dismiss' do
+ subject do
+ post "/api/v1/notifications/#{notification.id}/dismiss", headers: headers
+ end
+
+ let!(:notification) { Fabricate(:notification, account: user.account) }
+
+ it_behaves_like 'forbidden for wrong scope', 'read read:notifications'
+
+ it 'destroys the notification' do
+ subject
+
+ expect(response).to have_http_status(200)
+ expect { notification.reload }.to raise_error(ActiveRecord::RecordNotFound)
+ end
+
+ context 'when notification belongs to someone else' do
+ let(:notification) { Fabricate(:notification) }
+
+ it 'returns http not found' do
+ subject
+
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+
+ describe 'POST /api/v1/notifications/clear' do
+ subject do
+ post '/api/v1/notifications/clear', headers: headers
+ end
+
+ before do
+ Fabricate.times(3, :notification, account: user.account)
+ end
+
+ it_behaves_like 'forbidden for wrong scope', 'read read:notifications'
+
+ it 'clears notifications for the account' do
+ subject
+
+ expect(user.account.reload.notifications).to be_empty
+ expect(response).to have_http_status(200)
+ end
+ end
+end
diff --git a/spec/requests/api/v1/reports_spec.rb b/spec/requests/api/v1/reports_spec.rb
new file mode 100644
index 00000000000000..ba3d2b3060e033
--- /dev/null
+++ b/spec/requests/api/v1/reports_spec.rb
@@ -0,0 +1,89 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe 'Reports' do
+ let(:user) { Fabricate(:user) }
+ let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
+ let(:scopes) { 'write:reports' }
+ let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
+
+ describe 'POST /api/v1/reports' do
+ subject do
+ post '/api/v1/reports', headers: headers, params: params
+ end
+
+ let!(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
+ let(:status) { Fabricate(:status) }
+ let(:target_account) { status.account }
+ let(:category) { 'other' }
+ let(:forward) { nil }
+ let(:rule_ids) { nil }
+
+ let(:params) do
+ {
+ status_ids: [status.id],
+ account_id: target_account.id,
+ comment: 'reasons',
+ category: category,
+ rule_ids: rule_ids,
+ forward: forward,
+ }
+ end
+
+ it_behaves_like 'forbidden for wrong scope', 'read read:reports'
+
+ it 'creates a report', :aggregate_failures do
+ perform_enqueued_jobs do
+ subject
+
+ expect(response).to have_http_status(200)
+ expect(body_as_json).to match(
+ a_hash_including(
+ status_ids: [status.id.to_s],
+ category: category,
+ comment: 'reasons'
+ )
+ )
+
+ expect(target_account.targeted_reports).to_not be_empty
+ expect(target_account.targeted_reports.first.comment).to eq 'reasons'
+
+ expect(ActionMailer::Base.deliveries.first.to).to eq([admin.email])
+ end
+ end
+
+ context 'when a status does not belong to the reported account' do
+ let(:target_account) { Fabricate(:account) }
+
+ it 'returns http not found' do
+ subject
+
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context 'when a category is chosen' do
+ let(:category) { 'spam' }
+
+ it 'saves category' do
+ subject
+
+ expect(target_account.targeted_reports.first.spam?).to be true
+ end
+ end
+
+ context 'when violated rules are chosen' do
+ let(:rule) { Fabricate(:rule) }
+ let(:category) { 'violation' }
+ let(:rule_ids) { [rule.id] }
+
+ it 'saves category and rule_ids' do
+ subject
+
+ expect(target_account.targeted_reports.first.violation?).to be true
+ expect(target_account.targeted_reports.first.rule_ids).to contain_exactly(rule.id)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/v1/statuses/sources_spec.rb b/spec/requests/api/v1/statuses/sources_spec.rb
new file mode 100644
index 00000000000000..c79ec8964853d7
--- /dev/null
+++ b/spec/requests/api/v1/statuses/sources_spec.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe 'Sources' do
+ let(:user) { Fabricate(:user) }
+ let(:scopes) { 'read:statuses' }
+ let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
+ let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
+
+ describe 'GET /api/v1/statuses/:status_id/source' do
+ subject do
+ get "/api/v1/statuses/#{status.id}/source", headers: headers
+ end
+
+ let(:status) { Fabricate(:status) }
+
+ it_behaves_like 'forbidden for wrong scope', 'write write:statuses'
+
+ context 'with public status' do
+ it 'returns the source properties of the status', :aggregate_failures do
+ subject
+
+ expect(response).to have_http_status(200)
+ expect(body_as_json).to eq({
+ id: status.id.to_s,
+ text: status.text,
+ spoiler_text: status.spoiler_text,
+ content_type: nil,
+ })
+ end
+ end
+
+ context 'with private status of non-followed account' do
+ let(:status) { Fabricate(:status, visibility: :private) }
+
+ it 'returns http not found' do
+ subject
+
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context 'with private status of followed account' do
+ let(:status) { Fabricate(:status, visibility: :private) }
+
+ before do
+ user.account.follow!(status.account)
+ end
+
+ it 'returns the source properties of the status', :aggregate_failures do
+ subject
+
+ expect(response).to have_http_status(200)
+ expect(body_as_json).to eq({
+ id: status.id.to_s,
+ text: status.text,
+ spoiler_text: status.spoiler_text,
+ content_type: nil,
+ })
+ end
+ end
+
+ context 'without an authorization header' do
+ let(:headers) { {} }
+
+ it 'returns http unauthorized' do
+ subject
+
+ expect(response).to have_http_status(401)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/v1/tags_spec.rb b/spec/requests/api/v1/tags_spec.rb
index 300ddf805c91f1..db74a6f0373572 100644
--- a/spec/requests/api/v1/tags_spec.rb
+++ b/spec/requests/api/v1/tags_spec.rb
@@ -17,15 +17,10 @@
let!(:tag) { Fabricate(:tag) }
let(:name) { tag.name }
- it 'returns http success' do
+ it 'returns the tag', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'returns the tag' do
- subject
-
expect(body_as_json[:name]).to eq(name)
end
end
@@ -62,15 +57,10 @@
it_behaves_like 'forbidden for wrong scope', 'read read:follows'
context 'when the tag exists' do
- it 'returns http success' do
+ it 'creates follow', :aggregate_failures do
subject
expect(response).to have_http_status(:success)
- end
-
- it 'creates follow' do
- subject
-
expect(TagFollow.where(tag: tag, account: user.account)).to exist
end
end
@@ -78,21 +68,11 @@
context 'when the tag does not exist' do
let(:name) { 'hoge' }
- it 'returns http success' do
+ it 'creates a new tag with the specified name', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'creates a new tag with the specified name' do
- subject
-
expect(Tag.where(name: name)).to exist
- end
-
- it 'creates follow' do
- subject
-
expect(TagFollow.where(tag: Tag.find_by(name: name), account: user.account)).to exist
end
end
@@ -133,15 +113,10 @@
it_behaves_like 'forbidden for wrong scope', 'read read:follows'
- it 'returns http success' do
+ it 'removes the follow', :aggregate_failures do
subject
expect(response).to have_http_status(200)
- end
-
- it 'removes the follow' do
- subject
-
expect(TagFollow.where(tag: tag, account: user.account)).to_not exist
end
diff --git a/spec/requests/api/v1/timelines/tag_spec.rb b/spec/requests/api/v1/timelines/tag_spec.rb
new file mode 100644
index 00000000000000..a8f20213eb0eea
--- /dev/null
+++ b/spec/requests/api/v1/timelines/tag_spec.rb
@@ -0,0 +1,116 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe 'Tag' do
+ let(:user) { Fabricate(:user) }
+ let(:scopes) { 'read:statuses' }
+ let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
+ let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
+
+ shared_examples 'a successful request to the tag timeline' do
+ it 'returns the expected statuses', :aggregate_failures do
+ subject
+
+ expect(response).to have_http_status(200)
+ expect(body_as_json.pluck(:id)).to match_array(expected_statuses.map { |status| status.id.to_s })
+ end
+ end
+
+ describe 'GET /api/v1/timelines/tag/:hashtag' do
+ subject do
+ get "/api/v1/timelines/tag/#{hashtag}", headers: headers, params: params
+ end
+
+ before do
+ Setting.timeline_preview = true
+ end
+
+ let(:account) { Fabricate(:account) }
+ let!(:private_status) { PostStatusService.new.call(account, visibility: :private, text: '#life could be a dream') } # rubocop:disable RSpec/LetSetup
+ let!(:life_status) { PostStatusService.new.call(account, text: 'tell me what is my #life without your #love') }
+ let!(:war_status) { PostStatusService.new.call(user.account, text: '#war, war never changes') }
+ let!(:love_status) { PostStatusService.new.call(account, text: 'what is #love?') }
+ let(:params) { {} }
+ let(:hashtag) { 'life' }
+
+ context 'when given only one hashtag' do
+ let(:expected_statuses) { [life_status] }
+
+ it_behaves_like 'a successful request to the tag timeline'
+ end
+
+ context 'with any param' do
+ let(:expected_statuses) { [life_status, love_status] }
+ let(:params) { { any: %(love) } }
+
+ it_behaves_like 'a successful request to the tag timeline'
+ end
+
+ context 'with all param' do
+ let(:expected_statuses) { [life_status] }
+ let(:params) { { all: %w(love) } }
+
+ it_behaves_like 'a successful request to the tag timeline'
+ end
+
+ context 'with none param' do
+ let(:expected_statuses) { [war_status] }
+ let(:hashtag) { 'war' }
+ let(:params) { { none: %w(life love) } }
+
+ it_behaves_like 'a successful request to the tag timeline'
+ end
+
+ context 'with limit param' do
+ let(:hashtag) { 'love' }
+ let(:params) { { limit: 1 } }
+
+ it 'returns only the requested number of statuses' do
+ subject
+
+ expect(body_as_json.size).to eq(params[:limit])
+ end
+
+ it 'sets the correct pagination headers', :aggregate_failures do
+ subject
+
+ headers = response.headers['Link']
+
+ expect(headers.find_link(%w(rel prev)).href).to eq(api_v1_timelines_tag_url(limit: 1, min_id: love_status.id.to_s))
+ expect(headers.find_link(%w(rel next)).href).to eq(api_v1_timelines_tag_url(limit: 1, max_id: love_status.id.to_s))
+ end
+ end
+
+ context 'when the instance allows public preview' do
+ context 'when the user is not authenticated' do
+ let(:headers) { {} }
+ let(:expected_statuses) { [life_status] }
+
+ it_behaves_like 'a successful request to the tag timeline'
+ end
+ end
+
+ context 'when the instance does not allow public preview' do
+ before do
+ Form::AdminSettings.new(timeline_preview: false).save
+ end
+
+ context 'when the user is not authenticated' do
+ let(:headers) { {} }
+
+ it 'returns http unauthorized' do
+ subject
+
+ expect(response).to have_http_status(401)
+ end
+ end
+
+ context 'when the user is authenticated' do
+ let(:expected_statuses) { [life_status] }
+
+ it_behaves_like 'a successful request to the tag timeline'
+ end
+ end
+ end
+end
diff --git a/spec/requests/cache_spec.rb b/spec/requests/cache_spec.rb
index 178d19ed0daf97..c391c8b3da9f51 100644
--- a/spec/requests/cache_spec.rb
+++ b/spec/requests/cache_spec.rb
@@ -30,6 +30,7 @@ module TestEndpoints
/directory
/@alice
/@alice/110224538612341312
+ /deck/home
).freeze
# Endpoints that should be cachable when accessed anonymously but have a Vary
diff --git a/spec/requests/content_security_policy_spec.rb b/spec/requests/content_security_policy_spec.rb
index d327ac1b45d0c3..350442da7df602 100644
--- a/spec/requests/content_security_policy_spec.rb
+++ b/spec/requests/content_security_policy_spec.rb
@@ -21,7 +21,7 @@
"child-src 'self' blob: https://cb6e6126.ngrok.io",
"worker-src 'self' blob: https://cb6e6126.ngrok.io",
"connect-src 'self' blob: data: ws://localhost:4000 https://cb6e6126.ngrok.io",
- "script-src 'self' https://cb6e6126.ngrok.io 'wasm-unsafe-eval'"
+ "script-src 'self' https://cb6e6126.ngrok.io 'wasm-unsafe-eval' 'nonce-ZbA+JmE7+bK8F5qvADZHuQ=='"
)
end
end
diff --git a/spec/serializers/activitypub/note_serializer_spec.rb b/spec/serializers/activitypub/note_serializer_spec.rb
index 4b2b8ec875667f..31ee31f132f4c3 100644
--- a/spec/serializers/activitypub/note_serializer_spec.rb
+++ b/spec/serializers/activitypub/note_serializer_spec.rb
@@ -7,7 +7,7 @@
let!(:account) { Fabricate(:account) }
let!(:other) { Fabricate(:account) }
- let!(:parent) { Fabricate(:status, account: account, visibility: :public) }
+ let!(:parent) { Fabricate(:status, account: account, visibility: :public, language: 'zh-TW') }
let!(:reply_by_account_first) { Fabricate(:status, account: account, thread: parent, visibility: :public) }
let!(:reply_by_account_next) { Fabricate(:status, account: account, thread: parent, visibility: :public) }
let!(:reply_by_other_first) { Fabricate(:status, account: other, thread: parent, visibility: :public) }
@@ -18,8 +18,15 @@
@serialization = ActiveModelSerializers::SerializableResource.new(parent, serializer: described_class, adapter: ActivityPub::Adapter)
end
- it 'has a Note type' do
- expect(subject['type']).to eql('Note')
+ it 'has the expected shape' do
+ expect(subject).to include({
+ '@context' => include('https://www.w3.org/ns/activitystreams'),
+ 'type' => 'Note',
+ 'attributedTo' => ActivityPub::TagManager.instance.uri_for(account),
+ 'contentMap' => include({
+ 'zh-TW' => a_kind_of(String),
+ }),
+ })
end
it 'has a replies collection' do
diff --git a/spec/services/account_search_service_spec.rb b/spec/services/account_search_service_spec.rb
index 1cd036f4848878..4f89cd220c8df8 100644
--- a/spec/services/account_search_service_spec.rb
+++ b/spec/services/account_search_service_spec.rb
@@ -56,7 +56,7 @@
service = instance_double(ResolveAccountService, call: nil)
allow(ResolveAccountService).to receive(:new).and_return(service)
- results = subject.call('newuser@remote.com', nil, limit: 10, resolve: true)
+ subject.call('newuser@remote.com', nil, limit: 10, resolve: true)
expect(service).to have_received(:call).with('newuser@remote.com')
end
@@ -64,14 +64,14 @@
service = instance_double(ResolveAccountService, call: nil)
allow(ResolveAccountService).to receive(:new).and_return(service)
- results = subject.call('newuser@remote.com', nil, limit: 10, resolve: false)
+ subject.call('newuser@remote.com', nil, limit: 10, resolve: false)
expect(service).to_not have_received(:call)
end
end
it 'returns the fuzzy match first, and does not return suspended exacts' do
partial = Fabricate(:account, username: 'exactness')
- exact = Fabricate(:account, username: 'exact', suspended: true)
+ Fabricate(:account, username: 'exact', suspended: true)
results = subject.call('exact', nil, limit: 10)
expect(results.size).to eq 1
@@ -79,7 +79,7 @@
end
it 'does not return suspended remote accounts' do
- remote = Fabricate(:account, username: 'a', domain: 'remote', display_name: 'e', suspended: true)
+ Fabricate(:account, username: 'a', domain: 'remote', display_name: 'e', suspended: true)
results = subject.call('a@example.com', nil, limit: 2)
expect(results.size).to eq 0
diff --git a/spec/services/after_block_domain_from_account_service_spec.rb b/spec/services/after_block_domain_from_account_service_spec.rb
index 9bfaa35807f20a..05af125997c750 100644
--- a/spec/services/after_block_domain_from_account_service_spec.rb
+++ b/spec/services/after_block_domain_from_account_service_spec.rb
@@ -9,7 +9,6 @@
let!(:alice) { Fabricate(:account, username: 'alice') }
before do
- stub_jsonld_contexts!
allow(ActivityPub::DeliveryWorker).to receive(:perform_async)
end
diff --git a/spec/services/post_status_service_spec.rb b/spec/services/post_status_service_spec.rb
index 7d7679c889bcc2..1e5c420a63b245 100644
--- a/spec/services/post_status_service_spec.rb
+++ b/spec/services/post_status_service_spec.rb
@@ -155,7 +155,7 @@
it 'processes duplicate mentions correctly' do
account = Fabricate(:account)
- mentioned_account = Fabricate(:account, username: 'alice')
+ Fabricate(:account, username: 'alice')
expect do
subject.call(account, text: '@alice @alice @alice hey @alice')
@@ -212,7 +212,7 @@
account = Fabricate(:account)
media = Fabricate(:media_attachment, account: Fabricate(:account))
- status = subject.call(
+ subject.call(
account,
text: 'test status update',
media_ids: [media.id]
diff --git a/spec/services/precompute_feed_service_spec.rb b/spec/services/precompute_feed_service_spec.rb
index 54e0d94ee0a80e..663babae8a9c02 100644
--- a/spec/services/precompute_feed_service_spec.rb
+++ b/spec/services/precompute_feed_service_spec.rb
@@ -27,7 +27,7 @@
muted_account = Fabricate(:account)
Fabricate(:mute, account: account, target_account: muted_account)
reblog = Fabricate(:status, account: muted_account)
- status = Fabricate(:status, account: account, reblog: reblog)
+ Fabricate(:status, account: account, reblog: reblog)
subject.call(account)
diff --git a/spec/services/report_service_spec.rb b/spec/services/report_service_spec.rb
index 616368bf489609..d3bcd5d31cbdfa 100644
--- a/spec/services/report_service_spec.rb
+++ b/spec/services/report_service_spec.rb
@@ -36,7 +36,7 @@
expect(report.uri).to_not be_nil
end
- context 'when reporting a reply' do
+ context 'when reporting a reply on a different remote server' do
let(:remote_thread_account) { Fabricate(:account, domain: 'foo.com', protocol: :activitypub, inbox_url: 'http://foo.com/inbox') }
let(:reported_status) { Fabricate(:status, account: remote_account, thread: Fabricate(:status, account: remote_thread_account)) }
@@ -67,6 +67,25 @@
end
end
end
+
+ context 'when reporting a reply on the same remote server as the person being replied-to' do
+ let(:remote_thread_account) { Fabricate(:account, domain: 'example.com', protocol: :activitypub, inbox_url: 'http://example.com/inbox') }
+ let(:reported_status) { Fabricate(:status, account: remote_account, thread: Fabricate(:status, account: remote_thread_account)) }
+
+ context 'when forward_to_domains includes both the replied-to domain and the origin domain' do
+ it 'sends ActivityPub payload only once' do
+ subject.call(source_account, remote_account, status_ids: [reported_status.id], forward: forward, forward_to_domains: [remote_account.domain])
+ expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once
+ end
+ end
+
+ context 'when forward_to_domains does not include the replied-to domain' do
+ it 'sends ActivityPub payload only once' do
+ subject.call(source_account, remote_account, status_ids: [reported_status.id], forward: forward)
+ expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once
+ end
+ end
+ end
end
context 'when forward is false' do
diff --git a/spec/services/resolve_url_service_spec.rb b/spec/services/resolve_url_service_spec.rb
index 7991aa6ef14383..bcfb9dbfb0f893 100644
--- a/spec/services/resolve_url_service_spec.rb
+++ b/spec/services/resolve_url_service_spec.rb
@@ -7,8 +7,8 @@
describe '#call' do
it 'returns nil when there is no resource url' do
- url = 'http://example.com/missing-resource'
- known_account = Fabricate(:account, uri: url, domain: 'example.com')
+ url = 'http://example.com/missing-resource'
+ Fabricate(:account, uri: url, domain: 'example.com')
service = instance_double(FetchResourceService)
allow(FetchResourceService).to receive(:new).and_return service
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index b4c20545f541a1..6ff0a8f8420f87 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -36,6 +36,12 @@
config.after :suite do
FileUtils.rm_rf(Dir[Rails.root.join('spec', 'test_files')])
end
+
+ # Use the GitHub Annotations formatter for CI
+ if ENV['GITHUB_ACTIONS'] == 'true' && ENV['GITHUB_RSPEC'] == 'true'
+ require 'rspec/github'
+ config.add_formatter RSpec::Github::Formatter
+ end
end
def body_as_json
diff --git a/spec/support/examples/cache.rb b/spec/support/examples/cache.rb
new file mode 100644
index 00000000000000..43cfbade8242f9
--- /dev/null
+++ b/spec/support/examples/cache.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+shared_examples 'cacheable response' do |expects_vary: false|
+ it 'does not set cookies' do
+ expect(response.cookies).to be_empty
+ expect(response.headers['Set-Cookies']).to be_nil
+ end
+
+ it 'does not set sessions' do
+ expect(session).to be_empty
+ end
+
+ if expects_vary
+ it 'returns Vary header' do
+ expect(response.headers['Vary']).to include(expects_vary)
+ end
+ end
+
+ it 'returns public Cache-Control header' do
+ expect(response.headers['Cache-Control']).to include('public')
+ end
+end
diff --git a/spec/support/signed_request_helpers.rb b/spec/support/signed_request_helpers.rb
new file mode 100644
index 00000000000000..33d7dba6b87b90
--- /dev/null
+++ b/spec/support/signed_request_helpers.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module SignedRequestHelpers
+ def get(path, headers: nil, sign_with: nil, **args)
+ return super path, headers: headers, **args if sign_with.nil?
+
+ headers ||= {}
+ headers['Date'] = Time.now.utc.httpdate
+ headers['Host'] = ENV.fetch('LOCAL_DOMAIN')
+ signed_headers = headers.merge('(request-target)' => "get #{path}").slice('(request-target)', 'Host', 'Date')
+
+ key_id = ActivityPub::TagManager.instance.key_uri_for(sign_with)
+ keypair = sign_with.keypair
+ signed_string = signed_headers.map { |key, value| "#{key.downcase}: #{value}" }.join("\n")
+ signature = Base64.strict_encode64(keypair.sign(OpenSSL::Digest.new('SHA256'), signed_string))
+
+ headers['Signature'] = "keyId=\"#{key_id}\",algorithm=\"rsa-sha256\",headers=\"#{signed_headers.keys.join(' ').downcase}\",signature=\"#{signature}\""
+
+ super path, headers: headers, **args
+ end
+end
diff --git a/spec/support/stories/profile_stories.rb b/spec/support/stories/profile_stories.rb
index 2b345ddef10b31..82667ca080c99b 100644
--- a/spec/support/stories/profile_stories.rb
+++ b/spec/support/stories/profile_stories.rb
@@ -18,7 +18,7 @@ def as_a_logged_in_user
visit new_user_session_path
fill_in 'user_email', with: email
fill_in 'user_password', with: password
- click_on I18n.t('auth.login')
+ click_button I18n.t('auth.login')
end
def with_alice_as_local_user
diff --git a/spec/system/new_statuses_spec.rb b/spec/system/new_statuses_spec.rb
index 6faed6c808c30c..244101f4d4fd6b 100644
--- a/spec/system/new_statuses_spec.rb
+++ b/spec/system/new_statuses_spec.rb
@@ -24,10 +24,10 @@
within('.compose-form') do
fill_in "What's on your mind?", with: status_text
- click_on 'Publish!'
+ click_button 'Publish!'
end
- expect(subject).to have_selector('.status__content__text', text: status_text)
+ expect(subject).to have_css('.status__content__text', text: status_text)
end
it 'can be posted again' do
@@ -37,9 +37,9 @@
within('.compose-form') do
fill_in "What's on your mind?", with: status_text
- click_on 'Publish!'
+ click_button 'Publish!'
end
- expect(subject).to have_selector('.status__content__text', text: status_text)
+ expect(subject).to have_css('.status__content__text', text: status_text)
end
end
diff --git a/spec/validators/existing_username_validator_spec.rb b/spec/validators/existing_username_validator_spec.rb
new file mode 100644
index 00000000000000..4f1dd55a17bb07
--- /dev/null
+++ b/spec/validators/existing_username_validator_spec.rb
@@ -0,0 +1,83 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe ExistingUsernameValidator do
+ let(:record_class) do
+ Class.new do
+ include ActiveModel::Validations
+ attr_accessor :contact, :friends
+
+ def self.name
+ 'Record'
+ end
+
+ validates :contact, existing_username: true
+ validates :friends, existing_username: { multiple: true }
+ end
+ end
+ let(:record) { record_class.new }
+
+ describe '#validate_each' do
+ context 'with a nil value' do
+ it 'does not add errors' do
+ record.contact = nil
+
+ expect(record).to be_valid
+ expect(record.errors).to be_empty
+ end
+ end
+
+ context 'when there are no accounts' do
+ it 'adds errors to the record' do
+ record.contact = 'user@example.com'
+
+ expect(record).to_not be_valid
+ expect(record.errors.first.attribute).to eq(:contact)
+ expect(record.errors.first.type).to eq I18n.t('existing_username_validator.not_found')
+ end
+ end
+
+ context 'when there are accounts' do
+ before { Fabricate(:account, domain: 'example.com', username: 'user') }
+
+ context 'when the value does not match' do
+ it 'adds errors to the record' do
+ record.contact = 'friend@other.host'
+
+ expect(record).to_not be_valid
+ expect(record.errors.first.attribute).to eq(:contact)
+ expect(record.errors.first.type).to eq I18n.t('existing_username_validator.not_found')
+ end
+
+ context 'when multiple is true' do
+ it 'adds errors to the record' do
+ record.friends = 'friend@other.host'
+
+ expect(record).to_not be_valid
+ expect(record.errors.first.attribute).to eq(:friends)
+ expect(record.errors.first.type).to eq I18n.t('existing_username_validator.not_found_multiple', usernames: 'friend@other.host')
+ end
+ end
+ end
+
+ context 'when the value does match' do
+ it 'does not add errors to the record' do
+ record.contact = 'user@example.com'
+
+ expect(record).to be_valid
+ expect(record.errors).to be_empty
+ end
+
+ context 'when multiple is true' do
+ it 'does not add errors to the record' do
+ record.friends = 'user@example.com'
+
+ expect(record).to be_valid
+ expect(record.errors).to be_empty
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/validators/unreserved_username_validator_spec.rb b/spec/validators/unreserved_username_validator_spec.rb
index 6f353eeafdc517..0eb5f83683df4f 100644
--- a/spec/validators/unreserved_username_validator_spec.rb
+++ b/spec/validators/unreserved_username_validator_spec.rb
@@ -2,41 +2,118 @@
require 'rails_helper'
-RSpec.describe UnreservedUsernameValidator, type: :validator do
- describe '#validate' do
- before do
- allow(validator).to receive(:reserved_username?) { reserved_username }
- validator.validate(account)
- end
+describe UnreservedUsernameValidator do
+ let(:record_class) do
+ Class.new do
+ include ActiveModel::Validations
+ attr_accessor :username
- let(:validator) { described_class.new }
- let(:account) { instance_double(Account, username: username, errors: errors) }
- let(:errors) { instance_double(ActiveModel::Errors, add: nil) }
+ validates_with UnreservedUsernameValidator
+ end
+ end
+ let(:record) { record_class.new }
- context 'when @username is blank?' do
- let(:username) { nil }
+ describe '#validate' do
+ context 'when username is nil' do
+ it 'does not add errors' do
+ record.username = nil
- it 'not calls errors.add' do
- expect(errors).to_not have_received(:add).with(:username, any_args)
+ expect(record).to be_valid
+ expect(record.errors).to be_empty
end
end
- context 'when @username is not blank?' do
- let(:username) { 'f' }
+ context 'when PAM is enabled' do
+ before do
+ allow(Devise).to receive(:pam_authentication).and_return(true)
+ end
+
+ context 'with a pam service available' do
+ let(:service) { double }
+ let(:pam_class) do
+ Class.new do
+ def self.account(service, username); end
+ end
+ end
+
+ before do
+ stub_const('Rpam2', pam_class)
+ allow(Devise).to receive(:pam_controlled_service).and_return(service)
+ end
+
+ context 'when the account exists' do
+ before do
+ allow(Rpam2).to receive(:account).with(service, 'username').and_return(true)
+ end
+
+ it 'adds errors to the record' do
+ record.username = 'username'
+
+ expect(record).to_not be_valid
+ expect(record.errors.first.attribute).to eq(:username)
+ expect(record.errors.first.type).to eq(:reserved)
+ end
+ end
+
+ context 'when the account does not exist' do
+ before do
+ allow(Rpam2).to receive(:account).with(service, 'username').and_return(false)
+ end
- context 'with reserved_username?' do
- let(:reserved_username) { true }
+ it 'does not add errors to the record' do
+ record.username = 'username'
- it 'calls errors.add' do
- expect(errors).to have_received(:add).with(:username, :reserved)
+ expect(record).to be_valid
+ expect(record.errors).to be_empty
+ end
end
end
- context 'when username is not reserved' do
- let(:reserved_username) { false }
+ context 'without a pam service' do
+ before do
+ allow(Devise).to receive(:pam_controlled_service).and_return(false)
+ end
+
+ context 'when there are not any reserved usernames' do
+ before do
+ stub_reserved_usernames(nil)
+ end
+
+ it 'does not add errors to the record' do
+ record.username = 'username'
+
+ expect(record).to be_valid
+ expect(record.errors).to be_empty
+ end
+ end
+
+ context 'when there are reserved usernames' do
+ before do
+ stub_reserved_usernames(%w(alice bob))
+ end
+
+ context 'when the username is reserved' do
+ it 'adds errors to the record' do
+ record.username = 'alice'
+
+ expect(record).to_not be_valid
+ expect(record.errors.first.attribute).to eq(:username)
+ expect(record.errors.first.type).to eq(:reserved)
+ end
+ end
+
+ context 'when the username is not reserved' do
+ it 'does not add errors to the record' do
+ record.username = 'chris'
+
+ expect(record).to be_valid
+ expect(record.errors).to be_empty
+ end
+ end
+ end
- it 'not calls errors.add' do
- expect(errors).to_not have_received(:add).with(:username, any_args)
+ def stub_reserved_usernames(value)
+ allow(Setting).to receive(:[]).with('reserved_usernames').and_return(value)
end
end
end
diff --git a/spec/views/admin/trends/links/_preview_card.html.haml_spec.rb b/spec/views/admin/trends/links/_preview_card.html.haml_spec.rb
new file mode 100644
index 00000000000000..82a1dee6d72feb
--- /dev/null
+++ b/spec/views/admin/trends/links/_preview_card.html.haml_spec.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe 'admin/trends/links/_preview_card.html.haml' do
+ it 'correctly escapes user supplied url values' do
+ form = instance_double(ActionView::Helpers::FormHelper, check_box: nil)
+ trend = PreviewCardTrend.new(allowed: false)
+ preview_card = Fabricate.build(
+ :preview_card,
+ url: 'https://host.example/path?query=