Merge commit 'a863e68d174b176dc350d8e3472c010cd37b7807' into glitch-soc/merge-upstream

Conflicts:
- `app/models/trends/statuses.rb`:
  Conflict because of glitch-soc's setting to allow CWs in trends.
  Kept glitch-soc's setting but followed upstream's refactor.
- `docker-compose.yml`:
  Conflict because of upstream VS glitch-soc repos.
  Updated version number as upstream did, but kept glitch-soc repos.
This commit is contained in:
Claire
2025-07-24 18:10:38 +02:00
94 changed files with 477 additions and 458 deletions

View File

@@ -2,6 +2,26 @@
All notable changes to this project will be documented in this file.
## [4.4.2] - 2025-07-23
### Security
- Update dependencies
### Fixed
- Fix menu not clickable in Firefox (#35390 and #35414 by @diondiondion)
- Add `lang` attribute to current composer language in alt text modal (#35412 by @diondiondion)
- Fix quote posts styling on notifications page (#35411 by @diondiondion)
- Improve a11y of custom select menus in notifications settings (#35403 by @diondiondion)
- Fix selected item in poll select menus is unreadable in Firefox (#35402 by @diondiondion)
- Update age limit wording (#35387 by @diondiondion)
- Fix support for quote verification in implicit status updates (#35384 by @ClearlyClaire)
- Improve `Dropdown` component accessibility (#35373 by @diondiondion)
- Fix processing some incoming quotes failing because of missing JSON-LD context (#35354 and #35380 by @ClearlyClaire)
- Make bio hashtags open the local page instead of the remote instance (#35349 by @ChaosExAnima)
- Fix styling of external log-in button (#35320 by @ClearlyClaire)
## [4.4.1] - 2025-07-09
### Fixed

View File

@@ -287,7 +287,7 @@ GEM
activesupport (>= 5.1)
haml (>= 4.0.6)
railties (>= 5.1)
haml_lint (0.65.0)
haml_lint (0.65.1)
haml (>= 5.0)
parallel (~> 1.10)
rainbow
@@ -315,7 +315,7 @@ GEM
http_accept_language (2.1.1)
httpclient (2.9.0)
mutex_m
httplog (1.7.1)
httplog (1.7.2)
rack (>= 2.0)
rainbow (>= 2.0.0)
i18n (1.14.7)

View File

@@ -19,15 +19,13 @@ module Admin
log_action :resend, @user
flash[:notice] = I18n.t('admin.accounts.resend_confirmation.success')
redirect_to admin_accounts_path
redirect_to admin_accounts_path, notice: t('admin.accounts.resend_confirmation.success')
end
private
def redirect_confirmed_user
flash[:error] = I18n.t('admin.accounts.resend_confirmation.already_confirmed')
redirect_to admin_accounts_path
redirect_to admin_accounts_path, flash: { error: t('admin.accounts.resend_confirmation.already_confirmed') }
end
def user_confirmed?

View File

@@ -14,8 +14,7 @@ module Admin
@admin_settings = Form::AdminSettings.new(settings_params)
if @admin_settings.save
flash[:notice] = I18n.t('generic.changes_saved_msg')
redirect_to after_update_redirect_path
redirect_to after_update_redirect_path, notice: t('generic.changes_saved_msg')
else
render :show
end

View File

@@ -16,16 +16,7 @@ class Api::V1::Push::SubscriptionsController < Api::BaseController
def create
with_redis_lock("push_subscription:#{current_user.id}") do
destroy_web_push_subscriptions!
@push_subscription = Web::PushSubscription.create!(
endpoint: subscription_params[:endpoint],
key_p256dh: subscription_params[:keys][:p256dh],
key_auth: subscription_params[:keys][:auth],
standard: subscription_params[:standard] || false,
data: data_params,
user_id: current_user.id,
access_token_id: doorkeeper_token.id
)
@push_subscription = Web::PushSubscription.create!(web_push_subscription_params)
end
render json: @push_subscription, serializer: REST::WebPushSubscriptionSerializer
@@ -55,6 +46,18 @@ class Api::V1::Push::SubscriptionsController < Api::BaseController
not_found if @push_subscription.nil?
end
def web_push_subscription_params
{
access_token_id: doorkeeper_token.id,
data: data_params,
endpoint: subscription_params[:endpoint],
key_auth: subscription_params[:keys][:auth],
key_p256dh: subscription_params[:keys][:p256dh],
standard: subscription_params[:standard] || false,
user_id: current_user.id,
}
end
def subscription_params
params.expect(subscription: [:endpoint, :standard, keys: [:auth, :p256dh]])
end

View File

@@ -49,7 +49,7 @@ class Api::Web::PushSubscriptionsController < Api::Web::BaseController
{
policy: 'all',
alerts: Notification::TYPES.index_with { alerts_enabled },
}
}.deep_stringify_keys
end
def alerts_enabled

View File

@@ -19,8 +19,7 @@ class Auth::PasswordsController < Devise::PasswordsController
private
def redirect_invalid_reset_token
flash[:error] = I18n.t('auth.invalid_reset_password_token')
redirect_to new_password_path(resource_name)
redirect_to new_password_path(resource_name), flash: { error: t('auth.invalid_reset_password_token') }
end
def reset_password_token_is_valid?

View File

@@ -8,8 +8,7 @@ class Settings::SessionsController < Settings::BaseController
def destroy
@session.destroy!
flash[:notice] = I18n.t('sessions.revoke_success')
redirect_to edit_user_registration_path
redirect_to edit_user_registration_path, notice: t('sessions.revoke_success')
end
private

View File

@@ -86,13 +86,11 @@ module Settings
private
def redirect_invalid_otp
flash[:error] = t('webauthn_credentials.otp_required')
redirect_to settings_two_factor_authentication_methods_path
redirect_to settings_two_factor_authentication_methods_path, flash: { error: t('webauthn_credentials.otp_required') }
end
def redirect_invalid_webauthn
flash[:error] = t('webauthn_credentials.not_enabled')
redirect_to settings_two_factor_authentication_methods_path
redirect_to settings_two_factor_authentication_methods_path, flash: { error: t('webauthn_credentials.not_enabled') }
end
end
end

View File

@@ -3,8 +3,8 @@ import { useCallback } from 'react';
import { useLinks } from 'mastodon/hooks/useLinks';
import { EmojiHTML } from '../features/emoji/emoji_html';
import { isFeatureEnabled } from '../initial_state';
import { useAppSelector } from '../store';
import { isModernEmojiEnabled } from '../utils/environment';
interface AccountBioProps {
className: string;
@@ -32,9 +32,7 @@ export const AccountBio: React.FC<AccountBioProps> = ({
if (!account) {
return '';
}
return isFeatureEnabled('modern_emojis')
? account.note
: account.note_emojified;
return isModernEmojiEnabled() ? account.note : account.note_emojified;
});
const extraEmojis = useAppSelector((state) => {
const account = state.accounts.get(accountId);

View File

@@ -37,7 +37,6 @@ export const GIFV = forwardRef<HTMLVideoElement, Props>(
role='button'
tabIndex={0}
aria-label={alt}
title={alt}
lang={lang}
onClick={handleClick}
/>
@@ -49,7 +48,6 @@ export const GIFV = forwardRef<HTMLVideoElement, Props>(
role='button'
tabIndex={0}
aria-label={alt}
title={alt}
lang={lang}
width={width}
height={height}

View File

@@ -13,8 +13,9 @@ import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react'
import { Icon } from 'mastodon/components/icon';
import { Poll } from 'mastodon/components/poll';
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
import { autoPlayGif, isFeatureEnabled, languages as preloadedLanguages } from 'mastodon/initial_state';
import { autoPlayGif, languages as preloadedLanguages } from 'mastodon/initial_state';
import { EmojiHTML } from '../features/emoji/emoji_html';
import { isModernEmojiEnabled } from '../utils/environment';
const MAX_HEIGHT = 706; // 22px * 32 (+ 2px padding at the top)
@@ -24,7 +25,7 @@ const MAX_HEIGHT = 706; // 22px * 32 (+ 2px padding at the top)
* @returns {string}
*/
export function getStatusContent(status) {
if (isFeatureEnabled('modern_emojis')) {
if (isModernEmojiEnabled()) {
return status.getIn(['translation', 'content']) || status.get('content');
}
return status.getIn(['translation', 'contentHtml']) || status.get('contentHtml');

View File

@@ -41,9 +41,11 @@ export default class StatusList extends ImmutablePureComponent {
};
componentDidMount() {
this.columnHeaderHeight = parseFloat(
getComputedStyle(this.node.node).getPropertyValue('--column-header-height')
) || 0;
this.columnHeaderHeight = this.node?.node
? parseFloat(
getComputedStyle(this.node.node).getPropertyValue('--column-header-height')
) || 0
: 0;
}
getFeaturedStatusCount = () => {
@@ -69,8 +71,8 @@ export default class StatusList extends ImmutablePureComponent {
};
_selectChild = (id, index, direction) => {
const listContainer = this.node.node;
let listItem = listContainer.querySelector(
const listContainer = this.node?.node;
let listItem = listContainer?.querySelector(
// :nth-child uses 1-based indexing
`.item-list > :nth-child(${index + 1 + direction})`
);

View File

@@ -5,8 +5,8 @@ import type { List as ImmutableList } from 'immutable';
import { isList } from 'immutable';
import type { ApiCustomEmojiJSON } from '@/mastodon/api_types/custom_emoji';
import { isFeatureEnabled } from '@/mastodon/initial_state';
import type { CustomEmoji } from '@/mastodon/models/custom_emoji';
import { isModernEmojiEnabled } from '@/mastodon/utils/environment';
import { useEmojiAppState } from './hooks';
import { emojifyElement } from './render';
@@ -25,7 +25,7 @@ export const EmojiHTML: React.FC<EmojiHTMLProps> = ({
extraEmojis,
...props
}) => {
if (isFeatureEnabled('modern_emojis')) {
if (isModernEmojiEnabled()) {
return (
<ModernEmojiHTML
htmlString={htmlString}

View File

@@ -1,4 +1,5 @@
import initialState from '@/mastodon/initial_state';
import { loadWorker } from '@/mastodon/utils/workers';
import { toSupportedLocale } from './locale';
@@ -9,9 +10,8 @@ let worker: Worker | null = null;
export async function initializeEmoji() {
if (!worker && 'Worker' in window) {
try {
worker = new Worker(new URL('./worker', import.meta.url), {
worker = loadWorker(new URL('./worker', import.meta.url), {
type: 'module',
credentials: 'omit',
});
} catch (err) {
console.warn('Error creating web worker:', err);

View File

@@ -36,15 +36,16 @@ async function fetchAndCheckEtag<ResultType extends object[]>(
): Promise<ResultType | null> {
const locale = toSupportedLocaleOrCustom(localeOrCustom);
let uri: string;
// Use location.origin as this script may be loaded from a CDN domain.
const url = new URL(location.origin);
if (locale === 'custom') {
uri = '/api/v1/custom_emojis';
url.pathname = '/api/v1/custom_emojis';
} else {
uri = `/packs${isDevelopment() ? '-dev' : ''}/emoji/${locale}.json`;
url.pathname = `/packs${isDevelopment() ? '-dev' : ''}/emoji/${locale}.json`;
}
const oldEtag = await loadLatestEtag(locale);
const response = await fetch(uri, {
const response = await fetch(url, {
headers: {
'Content-Type': 'application/json',
'If-None-Match': oldEtag ?? '', // Send the old ETag to check for modifications

View File

@@ -21,6 +21,7 @@ import { openModal } from 'mastodon/actions/modal';
import { IconButton } from 'mastodon/components/icon_button';
import { useIdentity } from 'mastodon/identity_context';
import { me } from 'mastodon/initial_state';
import type { Account } from 'mastodon/models/account';
import type { Status } from 'mastodon/models/status';
import { makeGetStatus } from 'mastodon/selectors';
import type { RootState } from 'mastodon/store';
@@ -66,10 +67,7 @@ export const Footer: React.FC<{
const dispatch = useAppDispatch();
const getStatus = useMemo(() => makeGetStatus(), []) as GetStatusSelector;
const status = useAppSelector((state) => getStatus(state, { id: statusId }));
const accountId = status?.get('account') as string | undefined;
const account = useAppSelector((state) =>
accountId ? state.accounts.get(accountId) : undefined,
);
const account = status?.get('account') as Account | undefined;
const askReplyConfirmation = useAppSelector(
(state) => (state.compose.get('text') as string).trim().length !== 0,
);

View File

@@ -306,10 +306,8 @@ export const ZoomableImage: React.FC<ZoomableImageProps> = ({
<animated.img
style={{ transform }}
role='presentation'
ref={imageRef}
alt={alt}
title={alt}
lang={lang}
src={src}
width={width}

View File

@@ -142,12 +142,4 @@ export function getAccessToken() {
return getMeta('access_token');
}
/**
* @param {string} feature
* @returns {boolean}
*/
export function isFeatureEnabled(feature) {
return initialState?.features?.includes(feature) || false;
}
export default initialState;

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "عرض المزيد من المتابعين على {domain}",
"hints.profiles.see_more_follows": "اطلع على المزيد من المتابعين على {domain}",
"hints.profiles.see_more_posts": "عرض المزيد من المنشورات من {domain}",
"hints.threads.replies_may_be_missing": "قد تكون الردود الواردة من الخوادم الأخرى غائبة.",
"hints.threads.see_more": "اطلع على المزيد من الردود على {domain}",
"home.column_settings.show_quotes": "إظهار الاقتباسات",
"home.column_settings.show_reblogs": "اعرض المعاد نشرها",
"home.column_settings.show_replies": "اعرض الردود",

View File

@@ -266,7 +266,6 @@
"hashtag.counter_by_accounts": "{count, plural, one {{counter} participante} other {{counter} participantes}}",
"hashtag.follow": "Siguir a la etiqueta",
"hashtag.unfollow": "Dexar de siguir a la etiqueta",
"hints.threads.replies_may_be_missing": "Ye posible que falten les rempuestes d'otros sirvidores.",
"home.column_settings.show_reblogs": "Amosar los artículos compartíos",
"home.column_settings.show_replies": "Amosar les rempuestes",
"home.pending_critical_update.body": "¡Anueva'l sirvidor de Mastodon namás que puedas!",

View File

@@ -404,8 +404,6 @@
"hints.profiles.see_more_followers": "Глядзець больш падпісаных на {domain}",
"hints.profiles.see_more_follows": "Глядзець больш падпісак на {domain}",
"hints.profiles.see_more_posts": "Глядзець больш допісаў на {domain}",
"hints.threads.replies_may_be_missing": "Адказы з іншых сервераў могуць адсутнічаць.",
"hints.threads.see_more": "Глядзіце больш адказаў на {domain}",
"home.column_settings.show_quotes": "Паказаць цытаты",
"home.column_settings.show_reblogs": "Паказваць пашырэнні",
"home.column_settings.show_replies": "Паказваць адказы",

View File

@@ -419,8 +419,6 @@
"hints.profiles.see_more_followers": "Преглед на още последователи на {domain}",
"hints.profiles.see_more_follows": "Преглед на още последвания на {domain}",
"hints.profiles.see_more_posts": "Преглед на още публикации на {domain}",
"hints.threads.replies_may_be_missing": "Отговори от други сървъри може да липсват.",
"hints.threads.see_more": "Преглед на още отговори на {domain}",
"home.column_settings.show_quotes": "Показване на цитираното",
"home.column_settings.show_reblogs": "Показване на подсилванията",
"home.column_settings.show_replies": "Показване на отговорите",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "Vegeu més seguidors a {domain}",
"hints.profiles.see_more_follows": "Vegeu més seguiments a {domain}",
"hints.profiles.see_more_posts": "Vegeu més publicacions a {domain}",
"hints.threads.replies_may_be_missing": "Es poden haver perdut respostes d'altres servidors.",
"hints.threads.see_more": "Vegeu més respostes a {domain}",
"home.column_settings.show_quotes": "Mostrar les cites",
"home.column_settings.show_reblogs": "Mostra els impulsos",
"home.column_settings.show_replies": "Mostra les respostes",
@@ -846,6 +844,8 @@
"status.bookmark": "Marca",
"status.cancel_reblog_private": "Desfés l'impuls",
"status.cannot_reblog": "No es pot impulsar aquest tut",
"status.context.load_new_replies": "Hi ha respostes noves",
"status.context.loading": "Comprovació de més respostes",
"status.continued_thread": "Continuació del fil",
"status.copy": "Copia l'enllaç al tut",
"status.delete": "Elimina",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "Zobrazit více sledujících na {domain}",
"hints.profiles.see_more_follows": "Zobrazit další sledování na {domain}",
"hints.profiles.see_more_posts": "Zobrazit další příspěvky na {domain}",
"hints.threads.replies_may_be_missing": "Odpovědi z jiných serverů mohou chybět.",
"hints.threads.see_more": "Zobrazit další odpovědi na {domain}",
"home.column_settings.show_quotes": "Zobrazit citace",
"home.column_settings.show_reblogs": "Zobrazit boosty",
"home.column_settings.show_replies": "Zobrazit odpovědi",
@@ -847,6 +845,8 @@
"status.bookmark": "Přidat do záložek",
"status.cancel_reblog_private": "Zrušit boostnutí",
"status.cannot_reblog": "Tento příspěvek nemůže být boostnutý",
"status.context.load_new_replies": "K dispozici jsou nové odpovědi",
"status.context.loading": "Hledání dalších odpovědí",
"status.continued_thread": "Pokračuje ve vlákně",
"status.copy": "Zkopírovat odkaz na příspěvek",
"status.delete": "Smazat",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "Gweld mwy o ddilynwyr ar {domain}",
"hints.profiles.see_more_follows": "Gweld mwy o 'yn dilyn' ar {domain}",
"hints.profiles.see_more_posts": "Gweld mwy o bostiadau ar {domain}",
"hints.threads.replies_may_be_missing": "Mae'n bosibl y bydd ymatebion gan weinyddion eraill ar goll.",
"hints.threads.see_more": "Gweld mwy o ymatebion ar {domain}",
"home.column_settings.show_quotes": "Dangos dyfyniadau",
"home.column_settings.show_reblogs": "Dangos hybiau",
"home.column_settings.show_replies": "Dangos ymatebion",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "Se flere følgere på {domain}",
"hints.profiles.see_more_follows": "Se flere fulgte på {domain}",
"hints.profiles.see_more_posts": "Se flere indlæg på {domain}",
"hints.threads.replies_may_be_missing": "Der kan mangle svar fra andre servere.",
"hints.threads.see_more": "Se flere svar på {domain}",
"home.column_settings.show_quotes": "Vis citater",
"home.column_settings.show_reblogs": "Vis fremhævelser",
"home.column_settings.show_replies": "Vis svar",
@@ -847,6 +845,8 @@
"status.bookmark": "Bogmærk",
"status.cancel_reblog_private": "Fjern fremhævelse",
"status.cannot_reblog": "Dette indlæg kan ikke fremhæves",
"status.context.load_new_replies": "Nye svar tilgængelige",
"status.context.loading": "Tjekker for flere svar",
"status.continued_thread": "Fortsat tråd",
"status.copy": "Kopiér link til indlæg",
"status.delete": "Slet",

View File

@@ -6,7 +6,7 @@
"about.domain_blocks.no_reason_available": "Grund unbekannt",
"about.domain_blocks.preamble": "Mastodon erlaubt es dir grundsätzlich, alle Inhalte von allen Nutzer*innen auf allen Servern im Fediverse zu sehen und mit ihnen zu interagieren. Für diesen Server gibt es aber ein paar Ausnahmen.",
"about.domain_blocks.silenced.explanation": "Standardmäßig werden von diesem Server keine Inhalte oder Profile angezeigt. Du kannst die Profile und Inhalte aber dennoch sehen, wenn du explizit nach diesen suchst oder diesen folgst.",
"about.domain_blocks.silenced.title": "Stummgeschaltet",
"about.domain_blocks.silenced.title": "Ausgeblendet",
"about.domain_blocks.suspended.explanation": "Es werden keine Daten von diesem Server verarbeitet, gespeichert oder ausgetauscht, sodass eine Interaktion oder Kommunikation mit Nutzer*innen dieses Servers nicht möglich ist.",
"about.domain_blocks.suspended.title": "Gesperrt",
"about.language_label": "Sprache",
@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "Weitere Follower auf {domain} ansehen",
"hints.profiles.see_more_follows": "Weitere gefolgte Profile auf {domain} ansehen",
"hints.profiles.see_more_posts": "Weitere Beiträge auf {domain} ansehen",
"hints.threads.replies_may_be_missing": "Möglicherweise werden nicht alle Antworten von anderen Servern angezeigt.",
"hints.threads.see_more": "Weitere Antworten auf {domain} ansehen",
"home.column_settings.show_quotes": "Zitierte Beiträge anzeigen",
"home.column_settings.show_reblogs": "Geteilte Beiträge anzeigen",
"home.column_settings.show_replies": "Antworten anzeigen",
@@ -847,6 +845,8 @@
"status.bookmark": "Lesezeichen setzen",
"status.cancel_reblog_private": "Beitrag nicht mehr teilen",
"status.cannot_reblog": "Dieser Beitrag kann nicht geteilt werden",
"status.context.load_new_replies": "Neue Antworten verfügbar",
"status.context.loading": "Weitere Antworten werden abgerufen",
"status.continued_thread": "Fortgeführter Thread",
"status.copy": "Link zum Beitrag kopieren",
"status.delete": "Beitrag löschen",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "Δες περισσότερους ακόλουθους στο {domain}",
"hints.profiles.see_more_follows": "Δες περισσότερα άτομα που ακολουθούνται στο {domain}",
"hints.profiles.see_more_posts": "Δες περισσότερες αναρτήσεις στο {domain}",
"hints.threads.replies_may_be_missing": "Απαντήσεις από άλλους διακομιστές μπορεί να λείπουν.",
"hints.threads.see_more": "Δες περισσότερες απαντήσεις στο {domain}",
"home.column_settings.show_quotes": "Εμφάνιση παραθεμάτων",
"home.column_settings.show_reblogs": "Εμφάνιση προωθήσεων",
"home.column_settings.show_replies": "Εμφάνιση απαντήσεων",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "See more followers on {domain}",
"hints.profiles.see_more_follows": "See more follows on {domain}",
"hints.profiles.see_more_posts": "See more posts on {domain}",
"hints.threads.replies_may_be_missing": "Replies from other servers may be missing.",
"hints.threads.see_more": "See more replies on {domain}",
"home.column_settings.show_quotes": "Show quotes",
"home.column_settings.show_reblogs": "Show boosts",
"home.column_settings.show_replies": "Show replies",

View File

@@ -1,7 +1,7 @@
{
"about.blocks": "Reguligitaj serviloj",
"about.contact": "Kontakto:",
"about.default_locale": "기본",
"about.default_locale": "Defaŭlta",
"about.disclaimer": "Mastodon estas libera, malfermitkoda programo kaj varmarko de la firmao Mastodon gGmbH.",
"about.domain_blocks.no_reason_available": "Kialo ne disponeblas",
"about.domain_blocks.preamble": "Mastodon ĝenerale rajtigas vidi la enhavojn de uzantoj el aliaj serviloj en la fediverso, kaj komuniki kun ili. Jen la limigoj deciditaj de tiu ĉi servilo mem.",
@@ -331,6 +331,7 @@
"featured_carousel.next": "Antaŭen",
"featured_carousel.post": "Afiŝi",
"featured_carousel.previous": "Malantaŭen",
"featured_carousel.slide": "{index} de {total}",
"filter_modal.added.context_mismatch_explanation": "Ĉi tiu filtrilkategorio ne kongruas kun la kunteksto en kiu vi akcesis ĉi tiun afiŝon. Se vi volas ke la afiŝo estas ankaŭ filtrita en ĉi tiu kunteksto, vi devus redakti la filtrilon.",
"filter_modal.added.context_mismatch_title": "Ne kongruas la kunteksto!",
"filter_modal.added.expired_explanation": "Ĉi tiu filtrilkategorio eksvalidiĝis, vu bezonos ŝanĝi la eksvaliddaton por ĝi.",
@@ -409,8 +410,7 @@
"hints.profiles.see_more_followers": "Vidi pli da sekvantoj sur {domain}",
"hints.profiles.see_more_follows": "Vidi pli da sekvatoj sur {domain}",
"hints.profiles.see_more_posts": "Vidi pli da afiŝoj sur {domain}",
"hints.threads.replies_may_be_missing": "Respondoj de aliaj serviloj eble mankas.",
"hints.threads.see_more": "Vidi pli da respondoj sur {domain}",
"home.column_settings.show_quotes": "Montri citaĵojn",
"home.column_settings.show_reblogs": "Montri diskonigojn",
"home.column_settings.show_replies": "Montri respondojn",
"home.hide_announcements": "Kaŝi la anoncojn",
@@ -533,8 +533,10 @@
"mute_modal.you_wont_see_mentions": "Vi ne vidos afiŝojn, kiuj mencias ilin.",
"mute_modal.you_wont_see_posts": "Ili ankoraŭ povas vidi viajn afiŝojn, sed vi ne vidos iliajn.",
"navigation_bar.about": "Pri",
"navigation_bar.account_settings": "Pasvorto kaj sekureco",
"navigation_bar.administration": "Administrado",
"navigation_bar.advanced_interface": "Malfermi altnivelan retpaĝan interfacon",
"navigation_bar.automated_deletion": "Aŭtomata forigo de afiŝoj",
"navigation_bar.blocks": "Blokitaj uzantoj",
"navigation_bar.bookmarks": "Legosignoj",
"navigation_bar.direct": "Privataj mencioj",
@@ -544,6 +546,7 @@
"navigation_bar.follow_requests": "Petoj de sekvado",
"navigation_bar.followed_tags": "Sekvataj kradvortoj",
"navigation_bar.follows_and_followers": "Sekvatoj kaj sekvantoj",
"navigation_bar.import_export": "Importo kaj eksporto",
"navigation_bar.lists": "Listoj",
"navigation_bar.logout": "Elsaluti",
"navigation_bar.moderation": "Modereco",
@@ -551,6 +554,7 @@
"navigation_bar.mutes": "Silentigitaj uzantoj",
"navigation_bar.opened_in_classic_interface": "Afiŝoj, kontoj, kaj aliaj specifaj paĝoj kiuj estas malfermititaj defaulta en la klasika reta interfaco.",
"navigation_bar.preferences": "Preferoj",
"navigation_bar.privacy_and_reach": "Privateco kaj atingo",
"navigation_bar.search": "Serĉi",
"not_signed_in_indicator.not_signed_in": "Necesas saluti por aliri tiun rimedon.",
"notification.admin.report": "{name} raportis {target}",
@@ -787,7 +791,7 @@
"search.quick_action.open_url": "Malfermi URL en Mastodono",
"search.quick_action.status_search": "Afiŝoj kiuj konformas kun {x}",
"search.search_or_paste": "Serĉu aŭ algluu URL-on",
"search_popout.full_text_search_disabled_message": "Ne havebla sur {domain}.",
"search_popout.full_text_search_disabled_message": "Ne disponebla sur {domain}.",
"search_popout.full_text_search_logged_out_message": "Disponebla nur kiam ensalutinte.",
"search_popout.language_code": "ISO-lingva kodo",
"search_popout.options": "Serĉaj opcioj",
@@ -820,6 +824,8 @@
"status.bookmark": "Aldoni al la legosignoj",
"status.cancel_reblog_private": "Ne plu diskonigi",
"status.cannot_reblog": "Ĉi tiun afiŝon ne eblas diskonigi",
"status.context.load_new_replies": "Disponeblaj novaj respondoj",
"status.context.loading": "Serĉante pliajn respondojn",
"status.continued_thread": "Daŭrigis fadenon",
"status.copy": "Kopii la ligilon al la afiŝo",
"status.delete": "Forigi",
@@ -845,6 +851,9 @@
"status.mute_conversation": "Silentigi konversacion",
"status.open": "Pligrandigu ĉi tiun afiŝon",
"status.pin": "Alpingli al la profilo",
"status.quote_error.not_found": "Ĉi tiu afiŝo ne povas esti montrata.",
"status.quote_error.rejected": "Ĉi tiu afiŝo ne povas esti montrata ĉar la originala aŭtoro ne permesas ĝian citadon.",
"status.quote_error.removed": "Ĉi tiu afiŝo estis forigita de ĝia aŭtoro.",
"status.read_more": "Legi pli",
"status.reblog": "Diskonigi",
"status.reblog_private": "Diskonigi kun la sama videbleco",
@@ -876,6 +885,7 @@
"tabs_bar.home": "Hejmo",
"tabs_bar.menu": "Menuo",
"tabs_bar.notifications": "Sciigoj",
"tabs_bar.publish": "Nova afiŝo",
"tabs_bar.search": "Serĉi",
"terms_of_service.effective_as_of": "Ĝi ekvalidas de {date}",
"terms_of_service.title": "Kondiĉoj de uzado",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "Ver más seguidores en {domain}",
"hints.profiles.see_more_follows": "Ver más seguimientos en {domain}",
"hints.profiles.see_more_posts": "Ver más mensajes en {domain}",
"hints.threads.replies_may_be_missing": "Es posible que falten respuestas de otros servidores.",
"hints.threads.see_more": "Ver más respuestas en {domain}",
"home.column_settings.show_quotes": "Mostrar citas",
"home.column_settings.show_reblogs": "Mostrar adhesiones",
"home.column_settings.show_replies": "Mostrar respuestas",
@@ -847,6 +845,8 @@
"status.bookmark": "Marcar",
"status.cancel_reblog_private": "Quitar adhesión",
"status.cannot_reblog": "No se puede adherir a este mensaje",
"status.context.load_new_replies": "Hay nuevas respuestas",
"status.context.loading": "Buscando más respuestas",
"status.continued_thread": "Continuación de hilo",
"status.copy": "Copiar enlace al mensaje",
"status.delete": "Eliminar",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "Ver más seguidores en {domain}",
"hints.profiles.see_more_follows": "Ver más perfiles seguidos en {domain}",
"hints.profiles.see_more_posts": "Ver más publicaciones en {domain}",
"hints.threads.replies_may_be_missing": "Puede que no se muestren algunas respuestas de otros servidores.",
"hints.threads.see_more": "Ver más respuestas en {domain}",
"home.column_settings.show_quotes": "Mostrar citas",
"home.column_settings.show_reblogs": "Mostrar impulsos",
"home.column_settings.show_replies": "Mostrar respuestas",
@@ -847,6 +845,8 @@
"status.bookmark": "Añadir marcador",
"status.cancel_reblog_private": "Deshacer impulso",
"status.cannot_reblog": "Esta publicación no puede ser impulsada",
"status.context.load_new_replies": "Nuevas respuestas disponibles",
"status.context.loading": "Comprobando si hay más respuestas",
"status.continued_thread": "Hilo continuado",
"status.copy": "Copiar enlace al estado",
"status.delete": "Borrar",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "Ver más seguidores en {domain}",
"hints.profiles.see_more_follows": "Ver más perfiles seguidos en {domain}",
"hints.profiles.see_more_posts": "Ver más publicaciones en {domain}",
"hints.threads.replies_may_be_missing": "Puede que no se muestren algunas respuestas de otros servidores.",
"hints.threads.see_more": "Ver más respuestas en {domain}",
"home.column_settings.show_quotes": "Mostrar citas",
"home.column_settings.show_reblogs": "Mostrar impulsos",
"home.column_settings.show_replies": "Mostrar respuestas",
@@ -847,6 +845,8 @@
"status.bookmark": "Añadir marcador",
"status.cancel_reblog_private": "Deshacer impulso",
"status.cannot_reblog": "Esta publicación no se puede impulsar",
"status.context.load_new_replies": "Hay nuevas respuestas",
"status.context.loading": "Buscando más respuestas",
"status.continued_thread": "Continuó el hilo",
"status.copy": "Copiar enlace a la publicación",
"status.delete": "Borrar",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "Vaata rohkem jälgijaid kohas {domain}",
"hints.profiles.see_more_follows": "Vaata rohkem jälgitavaid kohas {domain}",
"hints.profiles.see_more_posts": "Vaata rohkem postitusi kohas {domain}",
"hints.threads.replies_may_be_missing": "Vastuseid teistest serveritest võib olla puudu.",
"hints.threads.see_more": "Vaata rohkem vastuseid kohas {domain}",
"home.column_settings.show_quotes": "Näita tsiteeritut",
"home.column_settings.show_reblogs": "Näita jagamisi",
"home.column_settings.show_replies": "Näita vastuseid",

View File

@@ -30,6 +30,7 @@
"account.edit_profile": "Editatu profila",
"account.enable_notifications": "Jakinarazi @{name} erabiltzaileak argitaratzean",
"account.endorse": "Nabarmendu profilean",
"account.familiar_followers_many": "Jarraitzaileak: {name1}, {name2} eta beste {othersCount, plural, one {ezagun bat} other {# ezagun}}",
"account.familiar_followers_one": "{name1}-k jarraitzen du",
"account.familiar_followers_two": "{name1}-k eta {name2}-k jarraitzen dute",
"account.featured": "Gailenak",
@@ -118,6 +119,8 @@
"annual_report.summary.most_used_hashtag.most_used_hashtag": "traola erabiliena",
"annual_report.summary.most_used_hashtag.none": "Bat ere ez",
"annual_report.summary.new_posts.new_posts": "bidalketa berriak",
"annual_report.summary.percentile.text": "<topLabel>Horrek jartzen zaitu top </topLabel> <percentage> </percentage>(e)an <bottomLabel> {domain} erabiltzaileen artean </bottomLabel>",
"annual_report.summary.percentile.we_wont_tell_bernie": "Bernieri ez diogu ezer esango ;)..",
"annual_report.summary.thanks": "Eskerrik asko Mastodonen parte izateagatik!",
"attachments_list.unprocessed": "(prozesatu gabe)",
"audio.hide": "Ezkutatu audioa",
@@ -216,6 +219,7 @@
"confirmations.discard_draft.edit.message": "Jarraitzeak editatzen ari zaren mezuan egindako aldaketak baztertuko ditu.",
"confirmations.discard_draft.edit.title": "Baztertu zure argitalpenari egindako aldaketak?",
"confirmations.discard_draft.post.cancel": "Zirriborroa berrekin",
"confirmations.discard_draft.post.message": "Jarraituz gero, idazten ari zaren sarrera bertan behera geratuko da.",
"confirmations.discard_draft.post.title": "Zure argitalpenaren zirriborroa baztertu nahi duzu?",
"confirmations.discard_edit_media.confirm": "Baztertu",
"confirmations.discard_edit_media.message": "Multimediaren deskribapen edo aurrebistan gorde gabeko aldaketak daude, baztertu nahi dituzu?",
@@ -413,8 +417,6 @@
"hints.profiles.see_more_followers": "Ikusi jarraitzaile gehiago {domain}-(e)n",
"hints.profiles.see_more_follows": "Ikusi jarraitzaile gehiago {domain}-(e)n",
"hints.profiles.see_more_posts": "Ikusi bidalketa gehiago {domain}-(e)n",
"hints.threads.replies_may_be_missing": "Baliteke beste zerbitzari batzuen erantzun batzuk ez erakustea.",
"hints.threads.see_more": "Ikusi erantzun gehiago {domain}-(e)n",
"home.column_settings.show_quotes": "Erakutsi aipamenak",
"home.column_settings.show_reblogs": "Erakutsi bultzadak",
"home.column_settings.show_replies": "Erakutsi erantzunak",
@@ -435,6 +437,7 @@
"ignore_notifications_modal.not_following_title": "Jarraitzen ez dituzun pertsonen jakinarazpenei ez ikusiarena egin?",
"ignore_notifications_modal.private_mentions_title": "Eskatu gabeko aipamen pribatuen jakinarazpenei ez ikusiarena egin?",
"info_button.label": "Laguntza",
"info_button.what_is_alt_text": "<h1>Zer da Alt testua?</h1><p>Alt testuak irudiak deskribatzeko aukera ematen du, ikusmen-urritasunak, banda-zabalera txikiko konexioak edo testuinguru gehigarria nahi duten pertsonentzat.</p><p>Alt testu argi, zehatz eta objektiboen bidez, guztion irisgarritasuna eta ulermena hobetu ditzakezu.</p><ul><li>Hartu elementu garrantzitsuenak</li><li>Laburbildu irudietako testua</li><li>Erabili esaldien egitura erregularra</li><li>Baztertu informazio erredundantea.</li><li>Enfokatu joeretan eta funtsezko elementuetan irudi konplexuetan (diagrametan edo mapetan, adibidez)</li></ul>",
"interaction_modal.action.favourite": "Jarraitzeko, zure kontutik atsegindu behar duzu.",
"interaction_modal.action.follow": "Jarraitzeko zure kontutik jarraitu behar duzu.",
"interaction_modal.action.reply": "Jarraitzeko zure kontutik erantzun behar duzu.",
@@ -903,6 +906,7 @@
"video.hide": "Ezkutatu bideoa",
"video.pause": "Pausatu",
"video.play": "Jo",
"video.skip_forward": "Jauzi aurrerantz",
"video.unmute": "Soinua ezarri",
"video.volume_down": "Bolumena jaitsi",
"video.volume_up": "Bolumena Igo"

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "دیدن پی‌گیرندگان بیش‌تر روی {domain}",
"hints.profiles.see_more_follows": "دیدن پی‌گرفته‌های بیش‌تر روی {domain}",
"hints.profiles.see_more_posts": "دیدن فرسته‌های بیش‌تر روی {domain}",
"hints.threads.replies_may_be_missing": "شاید پاسخ‌ها از دیگر کارسازها نباشند.",
"hints.threads.see_more": "دیدن پاسخ‌های بیش‌تر روی {domain}",
"home.column_settings.show_quotes": "نمایش نقل‌قول‌ها",
"home.column_settings.show_reblogs": "نمایش تقویت‌ها",
"home.column_settings.show_replies": "نمایش پاسخ‌ها",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "Näytä lisää seuraajia palvelimella {domain}",
"hints.profiles.see_more_follows": "Näytä lisää seurattavia palvelimella {domain}",
"hints.profiles.see_more_posts": "Näytä lisää julkaisuja palvelimella {domain}",
"hints.threads.replies_may_be_missing": "Muiden palvelinten vastauksia saattaa puuttua.",
"hints.threads.see_more": "Näytä lisää vastauksia palvelimella {domain}",
"home.column_settings.show_quotes": "Näytä lainaukset",
"home.column_settings.show_reblogs": "Näytä tehostukset",
"home.column_settings.show_replies": "Näytä vastaukset",
@@ -847,6 +845,8 @@
"status.bookmark": "Lisää kirjanmerkki",
"status.cancel_reblog_private": "Peru tehostus",
"status.cannot_reblog": "Tätä julkaisua ei voi tehostaa",
"status.context.load_new_replies": "Uusia vastauksia saatavilla",
"status.context.loading": "Tarkistetaan lisävastauksia",
"status.continued_thread": "Jatkoi ketjua",
"status.copy": "Kopioi linkki julkaisuun",
"status.delete": "Poista",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "Sí fleiri fylgjarar á {domain}",
"hints.profiles.see_more_follows": "Sí fleiri, ið viðkomandi fylgir, á {domain}",
"hints.profiles.see_more_posts": "Sí fleiri postar á {domain}",
"hints.threads.replies_may_be_missing": "Svar frá øðrum ambætarum mangla møguliga.",
"hints.threads.see_more": "Sí fleiri svar á {domain}",
"home.column_settings.show_quotes": "Vís siteringar",
"home.column_settings.show_reblogs": "Vís lyft",
"home.column_settings.show_replies": "Vís svar",
@@ -847,6 +845,8 @@
"status.bookmark": "Goym",
"status.cancel_reblog_private": "Strika stimbran",
"status.cannot_reblog": "Tað ber ikki til at stimbra hendan postin",
"status.context.load_new_replies": "Nýggj svar tøk",
"status.context.loading": "Kanni um tað eru fleiri svar",
"status.continued_thread": "Framhaldandi tráður",
"status.copy": "Kopiera leinki til postin",
"status.delete": "Strika",

View File

@@ -423,8 +423,6 @@
"hints.profiles.see_more_followers": "Afficher plus d'abonné·e·s sur {domain}",
"hints.profiles.see_more_follows": "Afficher plus d'abonné·e·s sur {domain}",
"hints.profiles.see_more_posts": "Voir plus de messages sur {domain}",
"hints.threads.replies_may_be_missing": "Les réponses provenant des autres serveurs pourraient être manquantes.",
"hints.threads.see_more": "Afficher plus de réponses sur {domain}",
"home.column_settings.show_quotes": "Afficher les citations",
"home.column_settings.show_reblogs": "Afficher boosts",
"home.column_settings.show_replies": "Afficher réponses",

View File

@@ -423,8 +423,6 @@
"hints.profiles.see_more_followers": "Afficher plus d'abonné·e·s sur {domain}",
"hints.profiles.see_more_follows": "Afficher plus d'abonné·e·s sur {domain}",
"hints.profiles.see_more_posts": "Voir plus de messages sur {domain}",
"hints.threads.replies_may_be_missing": "Les réponses provenant des autres serveurs pourraient être manquantes.",
"hints.threads.see_more": "Afficher plus de réponses sur {domain}",
"home.column_settings.show_quotes": "Afficher les citations",
"home.column_settings.show_reblogs": "Afficher les partages",
"home.column_settings.show_replies": "Afficher les réponses",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "Besjoch mear folgers op {domain}",
"hints.profiles.see_more_follows": "Besjoch mear folge accounts op {domain}",
"hints.profiles.see_more_posts": "Besjoch mear berjochten op {domain}",
"hints.threads.replies_may_be_missing": "Antwurden fan oare servers kinne ûntbrekke.",
"hints.threads.see_more": "Besjoch mear reaksjes op {domain}",
"home.column_settings.show_quotes": "Sitaten toane",
"home.column_settings.show_reblogs": "Boosts toane",
"home.column_settings.show_replies": "Reaksjes toane",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "Féach ar a thuilleadh leantóirí ar {domain}",
"hints.profiles.see_more_follows": "Féach tuilleadh seo a leanas ar {domain}",
"hints.profiles.see_more_posts": "Féach ar a thuilleadh postálacha ar {domain}",
"hints.threads.replies_may_be_missing": "Seans go bhfuil freagraí ó fhreastalaithe eile in easnamh.",
"hints.threads.see_more": "Féach ar a thuilleadh freagraí ar {domain}",
"home.column_settings.show_quotes": "Taispeáin Sleachta",
"home.column_settings.show_reblogs": "Taispeáin moltaí",
"home.column_settings.show_replies": "Taispeán freagraí",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "Faic barrachd luchd-leantainn air {domain}",
"hints.profiles.see_more_follows": "Faic barrachd a tha 'gan leantainn air {domain}",
"hints.profiles.see_more_posts": "Faic barrachd phostaichean air {domain}",
"hints.threads.replies_may_be_missing": "Dhfhaoidte gu bheil freagairtean o fhrithealaichean eile a dhìth.",
"hints.threads.see_more": "Faic barrachd fhreagairtean air {domain}",
"home.column_settings.show_quotes": "Seall luaidhean",
"home.column_settings.show_reblogs": "Seall na brosnachaidhean",
"home.column_settings.show_replies": "Seall na freagairtean",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "Mira máis seguidoras en {domain}",
"hints.profiles.see_more_follows": "Mira máis seguimentos en {domain}",
"hints.profiles.see_more_posts": "Mira máis publicacións en {domain}",
"hints.threads.replies_may_be_missing": "Poderían faltar respostas desde outros servidores.",
"hints.threads.see_more": "Mira máis respostas en {domain}",
"home.column_settings.show_quotes": "Mostrar citas",
"home.column_settings.show_reblogs": "Amosar compartidos",
"home.column_settings.show_replies": "Amosar respostas",
@@ -847,6 +845,8 @@
"status.bookmark": "Marcar",
"status.cancel_reblog_private": "Desfacer compartido",
"status.cannot_reblog": "Esta publicación non pode ser promovida",
"status.context.load_new_replies": "Non hai respostas dispoñibles",
"status.context.loading": "Mirando se hai máis respostas",
"status.continued_thread": "Continua co fío",
"status.copy": "Copiar ligazón á publicación",
"status.delete": "Eliminar",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "צפיה בעוד עוקבים משרת {domain}",
"hints.profiles.see_more_follows": "צפיה בעוד נעקבים בשרת {domain}",
"hints.profiles.see_more_posts": "צפיה בעוד פרסומים בשרת {domain}",
"hints.threads.replies_may_be_missing": "תגובות משרתים אחרים עלולות להיות חסרות.",
"hints.threads.see_more": "צפיה בעוד תגובות משרת {domain}",
"home.column_settings.show_quotes": "הצגת ציטוטים",
"home.column_settings.show_reblogs": "הצגת הדהודים",
"home.column_settings.show_replies": "הצגת תגובות",
@@ -847,6 +845,8 @@
"status.bookmark": "סימניה",
"status.cancel_reblog_private": "הסרת הדהוד",
"status.cannot_reblog": "לא ניתן להדהד חצרוץ זה",
"status.context.load_new_replies": "הגיעו תגובות חדשות",
"status.context.loading": "מחפש תגובות חדשות",
"status.continued_thread": "שרשור מתמשך",
"status.copy": "העתק/י קישור להודעה זו",
"status.delete": "מחיקה",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "További követők megtekintése itt: {domain}",
"hints.profiles.see_more_follows": "További követések megtekintése itt: {domain}",
"hints.profiles.see_more_posts": "További bejegyzések megtekintése itt: {domain}",
"hints.threads.replies_may_be_missing": "A más kiszolgálókról érkező válaszok lehet, hogy hiányoznak.",
"hints.threads.see_more": "További válaszok megtekintése itt: {domain}",
"home.column_settings.show_quotes": "Idézetek megjelenítése",
"home.column_settings.show_reblogs": "Megtolások megjelenítése",
"home.column_settings.show_replies": "Válaszok megjelenítése",
@@ -847,6 +845,8 @@
"status.bookmark": "Könyvjelzőzés",
"status.cancel_reblog_private": "Megtolás visszavonása",
"status.cannot_reblog": "Ezt a bejegyzést nem lehet megtolni",
"status.context.load_new_replies": "Új válaszok érhetőek el",
"status.context.loading": "További válaszok keresése",
"status.continued_thread": "Folytatott szál",
"status.copy": "Link másolása bejegyzésbe",
"status.delete": "Törlés",

View File

@@ -404,8 +404,6 @@
"hints.profiles.see_more_followers": "Vider plus de sequitores sur {domain}",
"hints.profiles.see_more_follows": "Vider plus de sequites sur {domain}",
"hints.profiles.see_more_posts": "Vider plus de messages sur {domain}",
"hints.threads.replies_may_be_missing": "Responsas de altere servitores pote mancar.",
"hints.threads.see_more": "Vider plus de responsas sur {domain}",
"home.column_settings.show_reblogs": "Monstrar impulsos",
"home.column_settings.show_replies": "Monstrar responsas",
"home.hide_announcements": "Celar annuncios",

View File

@@ -383,8 +383,6 @@
"hints.profiles.see_more_followers": "Vidar plu multa sequanti sur {domain}",
"hints.profiles.see_more_follows": "Vidar plu multa sequati sur {domain}",
"hints.profiles.see_more_posts": "Vidar plu multa posti sur {domain}",
"hints.threads.replies_may_be_missing": "Respondi de altra servili forsan ne esas hike.",
"hints.threads.see_more": "Vidar plu multa demandi sur {domain}",
"home.column_settings.show_reblogs": "Montrar repeti",
"home.column_settings.show_replies": "Montrar respondi",
"home.hide_announcements": "Celez anunci",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "Sjá fleiri fylgjendur á {domain}",
"hints.profiles.see_more_follows": "Sjá fleiri sem þú fylgist með á {domain}",
"hints.profiles.see_more_posts": "Sjá fleiri færslur á {domain}",
"hints.threads.replies_may_be_missing": "Svör af öðrum netþjónum gæti vantað.",
"hints.threads.see_more": "Sjá fleiri svör á {domain}",
"home.column_settings.show_quotes": "Birta tilvitnanir",
"home.column_settings.show_reblogs": "Sýna endurbirtingar",
"home.column_settings.show_replies": "Birta svör",
@@ -847,6 +845,8 @@
"status.bookmark": "Bókamerki",
"status.cancel_reblog_private": "Taka úr endurbirtingu",
"status.cannot_reblog": "Þessa færslu er ekki hægt að endurbirta",
"status.context.load_new_replies": "Ný svör hafa borist",
"status.context.loading": "Athuga með fleiri svör",
"status.continued_thread": "Hélt samtali áfram",
"status.copy": "Afrita tengil í færslu",
"status.delete": "Eyða",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "Vedi altri seguaci su {domain}",
"hints.profiles.see_more_follows": "Vedi altri profili seguiti su {domain}",
"hints.profiles.see_more_posts": "Vedi altri post su {domain}",
"hints.threads.replies_may_be_missing": "Le risposte da altri server potrebbero essere mancanti.",
"hints.threads.see_more": "Vedi altre risposte su {domain}",
"home.column_settings.show_quotes": "Mostra le citazioni",
"home.column_settings.show_reblogs": "Mostra reblog",
"home.column_settings.show_replies": "Mostra risposte",
@@ -847,6 +845,8 @@
"status.bookmark": "Aggiungi segnalibro",
"status.cancel_reblog_private": "Annulla reblog",
"status.cannot_reblog": "Questo post non può essere condiviso",
"status.context.load_new_replies": "Nuove risposte disponibili",
"status.context.loading": "Controllo per altre risposte",
"status.continued_thread": "Discussione continua",
"status.copy": "Copia link al post",
"status.delete": "Elimina",

View File

@@ -423,8 +423,6 @@
"hints.profiles.see_more_followers": "{domain} で正確な情報を見る",
"hints.profiles.see_more_follows": "{domain} で正確な情報を見る",
"hints.profiles.see_more_posts": "{domain} でその他の投稿を見る",
"hints.threads.replies_may_be_missing": "リモートの返信は表示されない場合があります。",
"hints.threads.see_more": "{domain} でその他の返信を見る",
"home.column_settings.show_quotes": "引用を表示",
"home.column_settings.show_reblogs": "ブースト表示",
"home.column_settings.show_replies": "返信表示",

View File

@@ -297,8 +297,6 @@
"hashtag.follow": "Ḍfeṛ ahacṭag",
"hashtag.mute": "Sgugem #{hashtag}",
"hashtags.and_other": "…d {count, plural, one {}other {# nniḍen}}",
"hints.threads.replies_may_be_missing": "Tiririyin d-yusan deg iqeddacen nniḍen, yezmer ur d-ddant ara.",
"hints.threads.see_more": "Wali ugar n tririt deg {domain}",
"home.column_settings.show_reblogs": "Ssken-d beṭṭu",
"home.column_settings.show_replies": "Ssken-d tiririyin",
"home.hide_announcements": "Ffer ulɣuyen",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "{domain}에서 더 많은 팔로워 보기",
"hints.profiles.see_more_follows": "{domain}에서 더 많은 팔로우 보기",
"hints.profiles.see_more_posts": "{domain}에서 더 많은 게시물 보기",
"hints.threads.replies_may_be_missing": "다른 서버의 답글은 일부 누락되었을 수 있습니다.",
"hints.threads.see_more": "{domain}에서 더 많은 답글 보기",
"home.column_settings.show_quotes": "인용 보기",
"home.column_settings.show_reblogs": "부스트 표시",
"home.column_settings.show_replies": "답글 표시",

View File

@@ -272,7 +272,6 @@
"hashtag.column_settings.tag_toggle": "Ji bo vê stûnê hin pêvekan tevlî bike",
"hashtag.follow": "Hashtagê bişopîne",
"hashtag.unfollow": "Hashtagê neşopîne",
"hints.threads.replies_may_be_missing": "Beriv ji rajekarên din dibe ku wendayî bin.",
"home.column_settings.show_reblogs": "Bilindkirinan nîşan bike",
"home.column_settings.show_replies": "Bersivan nîşan bide",
"home.hide_announcements": "Reklaman veşêre",

View File

@@ -368,8 +368,6 @@
"hints.profiles.see_more_followers": "Ve mas suivantes en {domain}",
"hints.profiles.see_more_follows": "Ve mas segidos en {domain}",
"hints.profiles.see_more_posts": "Ve mas puvlikasyones en {domain}",
"hints.threads.replies_may_be_missing": "Puede mankar repuestas de otros sirvidores.",
"hints.threads.see_more": "Ve mas repuestas en {domain}",
"home.column_settings.show_reblogs": "Amostra repartajasyones",
"home.column_settings.show_replies": "Amostra repuestas",
"home.hide_announcements": "Eskonde pregones",

View File

@@ -396,8 +396,6 @@
"hints.profiles.see_more_followers": "Žiūrėti daugiau sekėjų serveryje {domain}",
"hints.profiles.see_more_follows": "Žiūrėti daugiau sekimų serveryje {domain}",
"hints.profiles.see_more_posts": "Žiūrėti daugiau įrašų serveryje {domain}",
"hints.threads.replies_may_be_missing": "Atsakymai iš kitų serverių gali būti nepateikti.",
"hints.threads.see_more": "Žiūrėti daugiau atsakymų serveryje {domain}",
"home.column_settings.show_reblogs": "Rodyti pakėlimus",
"home.column_settings.show_replies": "Rodyti atsakymus",
"home.hide_announcements": "Slėpti skelbimus",

View File

@@ -386,8 +386,6 @@
"hints.profiles.see_more_followers": "Skatīt vairāk sekotāju {domain}",
"hints.profiles.see_more_follows": "Skatīt vairāk sekojumu {domain}",
"hints.profiles.see_more_posts": "Skatīt vairāk ierakstu {domain}",
"hints.threads.replies_may_be_missing": "Var trūkt atbilžu no citiem serveriem.",
"hints.threads.see_more": "Skatīt vairāk atbilžu {domain}",
"home.column_settings.show_quotes": "Rādīt citātus",
"home.column_settings.show_reblogs": "Rādīt pastiprinātos ierakstus",
"home.column_settings.show_replies": "Rādīt atbildes",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "佇 {domain} 看koh khah tsē跟tuè lí ê",
"hints.profiles.see_more_follows": "佇 {domain} 看koh khah tsē lí跟tuè ê",
"hints.profiles.see_more_posts": "佇 {domain} 看koh khah tsē ê PO文",
"hints.threads.replies_may_be_missing": "Tuì其他ê服侍器來ê回應可能有phah m̄見。",
"hints.threads.see_more": "佇 {domain} 看koh khah tsē ê回應",
"home.column_settings.show_quotes": "顯示引用",
"home.column_settings.show_reblogs": "顯示轉PO",
"home.column_settings.show_replies": "顯示回應",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "Bekijk meer volgers op {domain}",
"hints.profiles.see_more_follows": "Bekijk meer gevolgde accounts op {domain}",
"hints.profiles.see_more_posts": "Bekijk meer berichten op {domain}",
"hints.threads.replies_may_be_missing": "Antwoorden van andere servers kunnen ontbreken.",
"hints.threads.see_more": "Bekijk meer reacties op {domain}",
"home.column_settings.show_quotes": "Citaten tonen",
"home.column_settings.show_reblogs": "Boosts tonen",
"home.column_settings.show_replies": "Reacties tonen",
@@ -847,6 +845,8 @@
"status.bookmark": "Bladwijzer toevoegen",
"status.cancel_reblog_private": "Niet langer boosten",
"status.cannot_reblog": "Dit bericht kan niet geboost worden",
"status.context.load_new_replies": "Nieuwe reacties beschikbaar",
"status.context.loading": "Op nieuwe reacties aan het controleren",
"status.continued_thread": "Vervolg van gesprek",
"status.copy": "Link naar bericht kopiëren",
"status.delete": "Verwijderen",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "Sjå fleire fylgjarar på {domain}",
"hints.profiles.see_more_follows": "Sjå fleire fylgjer på {domain}",
"hints.profiles.see_more_posts": "Sjå fleire innlegg på {domain}",
"hints.threads.replies_may_be_missing": "Svar frå andre tenarar manglar kanskje.",
"hints.threads.see_more": "Sjå fleire svar på {domain}",
"home.column_settings.show_quotes": "Vis sitat",
"home.column_settings.show_reblogs": "Vis framhevingar",
"home.column_settings.show_replies": "Vis svar",

View File

@@ -417,8 +417,6 @@
"hints.profiles.see_more_followers": "Se flere følgere på {domain}",
"hints.profiles.see_more_follows": "Se flere som følger på {domain}",
"hints.profiles.see_more_posts": "Se flere innlegg på {domain}",
"hints.threads.replies_may_be_missing": "Svar fra andre servere mangler kanskje.",
"hints.threads.see_more": "Se flere svar på {domain}",
"home.column_settings.show_quotes": "Vis sitater",
"home.column_settings.show_reblogs": "Vis fremhevinger",
"home.column_settings.show_replies": "Vis svar",

View File

@@ -276,7 +276,6 @@
"hints.profiles.see_more_followers": "{domain} ਉੱਤੇ ਹੋਰ ਫ਼ਾਲੋਅਰ ਵੇਖੋ",
"hints.profiles.see_more_follows": "{domain} ਉੱਤੇ ਹੋਰ ਫ਼ਾਲੋ ਨੂੰ ਵੇਖੋ",
"hints.profiles.see_more_posts": "{domain} ਉੱਤੇ ਹੋਰ ਪੋਸਟਾਂ ਨੂੰ ਵੇਖੋ",
"hints.threads.see_more": "{domain} ਤੋਂ ਹੋਰ ਜਵਾਬਾਂ ਨੂੰ ਵੇਖੋ",
"home.column_settings.show_reblogs": "ਬੂਸਟਾਂ ਨੂੰ ਵੇਖੋ",
"home.column_settings.show_replies": "ਜਵਾਬਾਂ ਨੂੰ ਵੇਖੋ",
"home.hide_announcements": "ਐਲਾਨਾਂ ਨੂੰ ਓਹਲੇ ਕਰੋ",

View File

@@ -383,8 +383,6 @@
"hints.profiles.see_more_followers": "Zobacz więcej obserwujących na {domain}",
"hints.profiles.see_more_follows": "Zobacz więcej obserwowanych na {domain}",
"hints.profiles.see_more_posts": "Zobacz więcej wpisów na {domain}",
"hints.threads.replies_may_be_missing": "Komentarze z innych serwerów mogą być niewidoczne.",
"hints.threads.see_more": "Zobacz więcej komentarzy na {domain}",
"home.column_settings.show_reblogs": "Pokazuj podbicia",
"home.column_settings.show_replies": "Pokazuj odpowiedzi",
"home.hide_announcements": "Ukryj ogłoszenia",

View File

@@ -414,8 +414,6 @@
"hints.profiles.see_more_followers": "Ver mais seguidores no {domain}",
"hints.profiles.see_more_follows": "Ver mais seguidores no {domain}",
"hints.profiles.see_more_posts": "Ver mais publicações em {domain}",
"hints.threads.replies_may_be_missing": "Respostas de outros servidores podem estar faltando.",
"hints.threads.see_more": "Ver mais respostas no {domain}",
"home.column_settings.show_reblogs": "Mostrar boosts",
"home.column_settings.show_replies": "Mostrar respostas",
"home.hide_announcements": "Ocultar comunicados",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "Ver mais seguidores em {domain}",
"hints.profiles.see_more_follows": "Ver mais perfis seguidos em {domain}",
"hints.profiles.see_more_posts": "Ver mais publicações em {domain}",
"hints.threads.replies_may_be_missing": "É possível que não estejam a ser mostradas todas as respostas de outros servidores.",
"hints.threads.see_more": "Ver mais respostas em {domain}",
"home.column_settings.show_quotes": "Mostrar citações",
"home.column_settings.show_reblogs": "Mostrar impulsos",
"home.column_settings.show_replies": "Mostrar respostas",

View File

@@ -45,7 +45,7 @@
"account.followers_counter": "{count, plural, one {{counter} подписчик} few {{counter} подписчика} other {{counter} подписчиков}}",
"account.followers_you_know_counter": "{count, plural, one {{counter} ваш знакомый} other {{counter} ваших знакомых}}",
"account.following": "Подписки",
"account.following_counter": "{count, plural, one {# подписка} many {# подписок} other {# подписки}}",
"account.following_counter": "{count, plural, one {{counter} подписка} few {{counter} подписки} many {{counter} подписок} other {{counter} подписок}}",
"account.follows.empty": "Этот пользователь пока ни на кого не подписался.",
"account.follows_you": "Подписан(а) на вас",
"account.go_to_profile": "Перейти к профилю",
@@ -273,7 +273,7 @@
"domain_block_modal.they_cant_follow": "Пользователи с этого сервера не смогут подписаться на вас.",
"domain_block_modal.they_wont_know": "Пользователи с этого сервера не будут знать, что вы их блокируете.",
"domain_block_modal.title": "Заблокировать домен?",
"domain_block_modal.you_will_lose_num_followers": "Вы потеряете {followersCount, plural, one {{followersCountDisplay} подписчика} few {{followersCountDisplay} подписчика} other {{followersCountDisplay} подписчиков}} и {followingCount, plural, one {{followingCountDisplay} подписку} few {{followingCountDisplay} подписки} other {{followingCountDisplay} подписок}}.",
"domain_block_modal.you_will_lose_num_followers": "Вы потеряете {followersCount, plural, one {{followersCountDisplay} подписчика} few {{followersCountDisplay} подписчиков} other {{followersCountDisplay} подписчиков}} и {followingCount, plural, one {{followingCountDisplay} подписку} few {{followingCountDisplay} подписки} other {{followingCountDisplay} подписок}}.",
"domain_block_modal.you_will_lose_relationships": "Вы потеряете все подписки и всех подписчиков с этого сервера.",
"domain_block_modal.you_wont_see_posts": "Вы не будете видеть посты и уведомления от пользователей с этого сервера.",
"domain_pill.activitypub_lets_connect": "Благодаря ему вы можете связываться и взаимодействовать не только с пользователями Mastodon, но и с пользователями других платформ.",
@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "Перейдите на {domain}, чтобы увидеть всех подписчиков",
"hints.profiles.see_more_follows": "Перейдите на {domain}, чтобы увидеть все подписки",
"hints.profiles.see_more_posts": "Перейдите на {domain}, чтобы увидеть все посты",
"hints.threads.replies_may_be_missing": "Некоторые ответы с других серверов могут здесь отсутствовать.",
"hints.threads.see_more": "Перейдите на {domain}, чтобы увидеть все ответы",
"home.column_settings.show_quotes": "Показывать цитирования",
"home.column_settings.show_reblogs": "Показывать продвижения",
"home.column_settings.show_replies": "Показывать ответы",

View File

@@ -313,8 +313,6 @@
"hashtags.and_other": "… e {count, plural, one {un'àteru} other {àteros #}}",
"hints.profiles.posts_may_be_missing": "Podet èssere chi ammanchent tzertas publicatziones de custu profilu.",
"hints.profiles.see_more_posts": "Bide prus publicatziones a {domain}",
"hints.threads.replies_may_be_missing": "Podet èssere chi ammanchent rispostas dae àteros serbidores.",
"hints.threads.see_more": "Bide prus rispostas a {domain}",
"home.column_settings.show_reblogs": "Ammustra is cumpartziduras",
"home.column_settings.show_replies": "Ammustra rispostas",
"home.hide_announcements": "Cua annùntzios",

View File

@@ -406,8 +406,6 @@
"hints.profiles.see_more_followers": "{domain}හි තවත් අනුගාමිකයින් බලන්න",
"hints.profiles.see_more_follows": "{domain}හි තවත් පහත ඒවා බලන්න.",
"hints.profiles.see_more_posts": "{domain}හි තවත් සටහන් බලන්න",
"hints.threads.replies_may_be_missing": "අනෙකුත් සේවාදායකයන්ගෙන් ලැබෙන පිළිතුරු අස්ථානගත වී තිබිය හැක.",
"hints.threads.see_more": "{domain}හි තවත් පිළිතුරු බලන්න.",
"home.column_settings.show_reblogs": "බූස්ට් පෙන්වන්න",
"home.column_settings.show_replies": "පිළිතුරු පෙන්වන්න",
"home.hide_announcements": "නිවේදන සඟවන්න",

View File

@@ -365,8 +365,6 @@
"hints.profiles.see_more_followers": "Pozri viac nasledovateľov na {domain}",
"hints.profiles.see_more_follows": "Pozri viac nasledovateľov na {domain}",
"hints.profiles.see_more_posts": "Pozri viac príspevkov na {domain}",
"hints.threads.replies_may_be_missing": "Odpovede z ostatných serverov môžu chýbať.",
"hints.threads.see_more": "Pozri viac odpovedí na {domain}",
"home.column_settings.show_reblogs": "Zobraziť zdieľania",
"home.column_settings.show_replies": "Zobraziť odpovede",
"home.hide_announcements": "Skryť oznámenia",

View File

@@ -383,8 +383,6 @@
"hints.profiles.see_more_followers": "Pokaži več sledilcev na {domain}",
"hints.profiles.see_more_follows": "Pokaži več sledenih ljudi na zbirališču {domain}",
"hints.profiles.see_more_posts": "Pokaži več objav na {domain}",
"hints.threads.replies_may_be_missing": "Odgovori z drugih strežnikov morda manjkajo.",
"hints.threads.see_more": "Pokaži več odgovorov na {domain}",
"home.column_settings.show_reblogs": "Pokaži izpostavitve",
"home.column_settings.show_replies": "Pokaži odgovore",
"home.hide_announcements": "Skrij obvestila",

View File

@@ -419,8 +419,6 @@
"hints.profiles.see_more_followers": "Shihni më tepër ndjekës në {domain}",
"hints.profiles.see_more_follows": "Shihni më tepër ndjekje në {domain}",
"hints.profiles.see_more_posts": "Shihni më tepër postime në {domain}",
"hints.threads.replies_may_be_missing": "Mund të mungojnë përgjigje nga shërbyes të tjerë.",
"hints.threads.see_more": "Shihni më tepër përgjigje në {domain}",
"home.column_settings.show_quotes": "Shfaq thonjëza",
"home.column_settings.show_reblogs": "Shfaq përforcime",
"home.column_settings.show_replies": "Shfaq përgjigje",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "Se fler följare på {domain}",
"hints.profiles.see_more_follows": "Se fler följare på {domain}",
"hints.profiles.see_more_posts": "Se fler inlägg på {domain}",
"hints.threads.replies_may_be_missing": "Det kan saknas svar från andra servrar.",
"hints.threads.see_more": "Se fler svar på {domain}",
"home.column_settings.show_quotes": "Visa citat",
"home.column_settings.show_reblogs": "Visa boostar",
"home.column_settings.show_replies": "Visa svar",

View File

@@ -397,8 +397,6 @@
"hints.profiles.see_more_followers": "ดูผู้ติดตามเพิ่มเติมใน {domain}",
"hints.profiles.see_more_follows": "ดูการติดตามเพิ่มเติมใน {domain}",
"hints.profiles.see_more_posts": "ดูโพสต์เพิ่มเติมใน {domain}",
"hints.threads.replies_may_be_missing": "การตอบกลับจากเซิร์ฟเวอร์อื่น ๆ อาจขาดหายไป",
"hints.threads.see_more": "ดูการตอบกลับเพิ่มเติมใน {domain}",
"home.column_settings.show_reblogs": "แสดงการดัน",
"home.column_settings.show_replies": "แสดงการตอบกลับ",
"home.hide_announcements": "ซ่อนประกาศ",

View File

@@ -371,8 +371,6 @@
"hints.profiles.see_more_followers": "o lukin e jan ni lon ma {domain}: ona li kute e jan ni.",
"hints.profiles.see_more_follows": "o lukin e jan ni lon ma {domain}: jan ni li kute e ona.",
"hints.profiles.see_more_posts": "o lukin e toki ante lon ma {domain}",
"hints.threads.replies_may_be_missing": "toki pi ma ante li weka lon ken.",
"hints.threads.see_more": "o lukin e toki ante lon ma {domain}",
"home.column_settings.show_reblogs": "o lukin e pana toki",
"home.hide_announcements": "o lukin ala e toki lawa suli",
"home.pending_critical_update.body": "o sin e ilo Mastodon lon tenpo lili a!",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "{domain} adresinde daha fazla takipçi gör",
"hints.profiles.see_more_follows": "{domain} adresinde daha fazla takip edilen gör",
"hints.profiles.see_more_posts": "{domain} adresinde daha fazla gönderi gör",
"hints.threads.replies_may_be_missing": "Diğer sunuculardan yanıtlar eksik olabilir.",
"hints.threads.see_more": "{domain} adresinde daha fazla yanıt gör",
"home.column_settings.show_quotes": "Alıntıları göster",
"home.column_settings.show_reblogs": "Yeniden paylaşımları göster",
"home.column_settings.show_replies": "Yanıtları göster",

View File

@@ -395,8 +395,6 @@
"hints.profiles.see_more_followers": "Переглянути більше підписників на {domain}",
"hints.profiles.see_more_follows": "Переглянути більше підписок на {domain}",
"hints.profiles.see_more_posts": "Переглянути більше дописів на {domain}",
"hints.threads.replies_may_be_missing": "Відповіді з інших серверів можуть бути не показані.",
"hints.threads.see_more": "Переглянути більше відповідей на {domain}",
"home.column_settings.show_reblogs": "Показувати поширення",
"home.column_settings.show_replies": "Показувати відповіді",
"home.hide_announcements": "Приховати оголошення",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "Xem thêm người theo dõi ở {domain}",
"hints.profiles.see_more_follows": "Xem thêm người mà người này theo dõi ở {domain}",
"hints.profiles.see_more_posts": "Xem thêm tút ở {domain}",
"hints.threads.replies_may_be_missing": "Những trả lời từ máy chủ khác có thể không đầy đủ.",
"hints.threads.see_more": "Xem thêm ở {domain}",
"home.column_settings.show_quotes": "Hiện những trích dẫn",
"home.column_settings.show_reblogs": "Hiện những lượt đăng lại",
"home.column_settings.show_replies": "Hiện những tút dạng trả lời",
@@ -847,6 +845,8 @@
"status.bookmark": "Lưu",
"status.cancel_reblog_private": "Bỏ đăng lại",
"status.cannot_reblog": "Không thể đăng lại tút này",
"status.context.load_new_replies": "Có những trả lời mới",
"status.context.loading": "Kiểm tra nhiều trả lời hơn",
"status.continued_thread": "Tiếp tục chủ đề",
"status.copy": "Sao chép URL",
"status.delete": "Xóa",

View File

@@ -412,8 +412,6 @@
"hints.profiles.see_more_followers": "在 {domain} 查看更多关注者",
"hints.profiles.see_more_follows": "在 {domain} 查看更多关注",
"hints.profiles.see_more_posts": "在 {domain} 查看更多嘟文",
"hints.threads.replies_may_be_missing": "来自其它实例的回复可能没有完全显示。",
"hints.threads.see_more": "在 {domain} 查看更多回复",
"home.column_settings.show_quotes": "显示引用",
"home.column_settings.show_reblogs": "显示转嘟",
"home.column_settings.show_replies": "显示回复",

View File

@@ -424,8 +424,6 @@
"hints.profiles.see_more_followers": "於 {domain} 檢視更多跟隨者",
"hints.profiles.see_more_follows": "於 {domain} 檢視更多正在跟隨",
"hints.profiles.see_more_posts": "於 {domain} 檢視更多嘟文",
"hints.threads.replies_may_be_missing": "來自其他站點之回覆或有缺失。",
"hints.threads.see_more": "於 {domain} 檢視更多回覆",
"home.column_settings.show_quotes": "顯示引用嘟文",
"home.column_settings.show_reblogs": "顯示轉嘟",
"home.column_settings.show_replies": "顯示回覆",
@@ -847,6 +845,8 @@
"status.bookmark": "書籤",
"status.cancel_reblog_private": "取消轉嘟",
"status.cannot_reblog": "這則嘟文無法被轉嘟",
"status.context.load_new_replies": "有新回嘟",
"status.context.loading": "正在檢查更多回嘟",
"status.continued_thread": "接續討論串",
"status.copy": "複製嘟文連結",
"status.delete": "刪除",

View File

@@ -4,12 +4,16 @@ import { Globals } from '@react-spring/web';
import { setupBrowserNotifications } from 'mastodon/actions/notifications';
import Mastodon from 'mastodon/containers/mastodon';
import { isFeatureEnabled, me, reduceMotion } from 'mastodon/initial_state';
import { me, reduceMotion } from 'mastodon/initial_state';
import * as perf from 'mastodon/performance';
import ready from 'mastodon/ready';
import { store } from 'mastodon/store';
import { isProduction, isDevelopment } from './utils/environment';
import {
isProduction,
isDevelopment,
isModernEmojiEnabled,
} from './utils/environment';
function main() {
perf.start('main()');
@@ -29,7 +33,7 @@ function main() {
});
}
if (isFeatureEnabled('modern_emojis')) {
if (isModernEmojiEnabled()) {
const { initializeEmoji } = await import('@/mastodon/features/emoji');
await initializeEmoji();
}

View File

@@ -1,3 +1,5 @@
import initialState from '../initial_state';
export function isDevelopment() {
if (typeof process !== 'undefined')
return process.env.NODE_ENV === 'development';
@@ -9,3 +11,13 @@ export function isProduction() {
return process.env.NODE_ENV === 'production';
else return import.meta.env.PROD;
}
export type Features = 'modern_emojis';
export function isFeatureEnabled(feature: Features) {
return initialState?.features.includes(feature) ?? false;
}
export function isModernEmojiEnabled() {
return isFeatureEnabled('modern_emojis') && isDevelopment();
}

View File

@@ -0,0 +1,29 @@
/**
* Loads Web Worker that is compatible with cross-origin scripts for CDNs.
*
* Returns null if the environment doesn't support web workers.
*/
export function loadWorker(url: string | URL, options: WorkerOptions = {}) {
if (!('Worker' in window)) {
return null;
}
try {
// Check if the script origin and the window origin are the same.
const scriptUrl = new URL(import.meta.url);
if (location.origin === scriptUrl.origin) {
// Not cross-origin, can just load normally.
return new Worker(url, options);
}
} catch (err) {
// In case the URL parsing fails.
console.warn('Error instantiating Worker:', err);
}
// Import the worker script from a same-origin Blob.
const contents = `import ${JSON.stringify(url)};`;
const blob = URL.createObjectURL(
new Blob([contents], { type: 'text/javascript' }),
);
return new Worker(blob, options);
}

View File

@@ -90,14 +90,28 @@ class Trends::Statuses < Trends::Base
def eligible?(status)
status.created_at.past? &&
status.public_visibility? &&
status.account.discoverable? &&
!status.account.silenced? &&
!status.account.sensitized? &&
(status.spoiler_text.blank? || Setting.trending_status_cw) &&
!status.sensitive? &&
opted_into_trends?(status) &&
!sensitive_content?(status) &&
!status.reply? &&
valid_locale?(status.language)
valid_locale?(status.language) &&
(status.quote.nil? || trendable_quote?(status.quote))
end
def opted_into_trends?(status)
status.public_visibility? &&
status.account.discoverable? &&
!status.account.silenced?
end
def sensitive_content?(status)
status.account.sensitized? || (status.spoiler_text.present? && !Setting.trending_status_cw) || status.sensitive?
end
def trendable_quote?(quote)
quote.acceptable? &&
quote.quoted_status.present? &&
opted_into_trends?(quote.quoted_status) &&
!sensitive_content?(quote.quoted_status)
end
def calculate_scores(statuses, at_time)

View File

@@ -21,6 +21,7 @@
.fields-group.fields-row__column.fields-row__column-6
= ff.input :default_privacy,
collection: Status.selectable_visibilities,
selected: current_user.setting_default_privacy,
hint: false,
include_blank: false,
label_method: ->(visibility) { safe_join([I18n.t("statuses.visibilities.#{visibility}"), I18n.t("statuses.visibilities.#{visibility}_long")], ' - ') },

View File

@@ -19,6 +19,9 @@ Rails.application.configure do
# Enable server timing.
config.server_timing = true
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
config.asset_host = ENV['CDN_HOST'] if ENV['CDN_HOST'].present?
# Enable/disable caching. By default caching is disabled.
# Run rails dev:cache to toggle caching.
if Rails.root.join('tmp', 'caching-dev.txt').exist?

View File

@@ -1477,56 +1477,56 @@ ru:
other: Проверьте введённые вами данные! Далее по странице вы можете увидеть %{count} сообщений об ошибке
imports:
errors:
empty: Пустой CSV-файл
incompatible_type: Несовместимость с выбранным типом импорта
invalid_csv_file: 'Неверный файл CSV. Ошибка: %{error}'
empty: Файл CSV пуст
incompatible_type: Несовместим с выбранным типом данных для импорта
invalid_csv_file: 'Ошибка при чтении файла CSV: %{error}'
over_rows_processing_limit: содержит более %{count} строк
too_large: Файл слишком большой
failures: Ошибки
imported: Импортирован
mismatched_types_warning: Возможно, вы выбрали неверный тип для этого импорта, пожалуйста, перепроверьте.
imported: Импортировано
mismatched_types_warning: По-видимому, вы выбрали неверный тип данных для импорта. Проверьте всё внимательно!
modes:
merge: Объединить
merge_long: Сохранить имеющиеся данные и добавить новые.
overwrite: Перезаписать
overwrite_long: Перезаписать имеющиеся данные новыми.
merge_long: Добавить новые данные к уже имеющимся
overwrite: Заменить
overwrite_long: Заменить имеющиеся данные новыми
overwrite_preambles:
blocking_html:
few: Вы собираетесь <strong>заменить свой список блокировки</strong>, в котором сейчас <strong>%{count} аккаунта</strong>, из файла <strong>%{filename}</strong>.
many: Вы собираетесь <strong>заменить свой список блокировки</strong>, в котором сейчас <strong>%{count} аккаунов</strong>, из файла <strong>%{filename}</strong>.
one: Вы собираетесь <strong>заменить свой список блокировки</strong>, в котором сейчас <strong>%{count} аккаунт</strong>, из файла <strong>%{filename}</strong>.
other: Вы собираетесь <strong>заменить свой список блокировки</strong>, в котором сейчас <strong>%{count} аккаунтов</strong>, из файла <strong>%{filename}</strong>.
few: Вы собираетесь <strong>заменить свой список заблокированных пользователей</strong> данными из файла <strong>%{filename}</strong>, после чего вы будете блокировать <strong>%{count} пользователей</strong>.
many: Вы собираетесь <strong>заменить свой список заблокированных пользователей</strong> данными из файла <strong>%{filename}</strong>, после чего вы будете блокировать <strong>%{count} пользователей</strong>.
one: Вы собираетесь <strong>заменить свой список заблокированных пользователей</strong> данными из файла <strong>%{filename}</strong>, после чего вы будете блокировать <strong>%{count} пользователя</strong>.
other: Вы собираетесь <strong>заменить свой список заблокированных пользователей</strong> данными из файла <strong>%{filename}</strong>, после чего вы будете блокировать <strong>%{count} пользователей</strong>.
bookmarks_html:
few: Вы собираетесь <strong>заменить свои закладки</strong>, в которых сейчас <strong>%{count} поста</strong>, из файла <strong>%{filename}</strong>.
many: Вы собираетесь <strong>заменить свои закладки</strong>, в которых сейчас <strong>%{count} постов</strong>, из файла <strong>%{filename}</strong>.
one: Вы собираетесь <strong>заменить свои закладки</strong>, в которых сейчас <strong>%{count} пост</strong>, из файла <strong>%{filename}</strong>.
other: Вы собираетесь <strong>заменить свои закладки</strong>, в которых сейчас <strong>%{count} постов</strong>, из файла <strong>%{filename}</strong>.
few: Вы собираетесь <strong>заменить свои закладки</strong> данными из файла <strong>%{filename}</strong>, после чего у вас в закладках будет <strong>%{count} поста</strong>.
many: Вы собираетесь <strong>заменить свои закладки</strong> данными из файла <strong>%{filename}</strong>, после чего у вас в закладках будет <strong>%{count} постов</strong>.
one: Вы собираетесь <strong>заменить свои закладки</strong> данными из файла <strong>%{filename}</strong>, после чего у вас в закладках будет <strong>%{count} пост</strong>.
other: Вы собираетесь <strong>заменить свои закладки</strong> данными из файла <strong>%{filename}</strong>, после чего у вас в закладках будет <strong>%{count} постов</strong>.
domain_blocking_html:
few: Вы собираетесь <strong>заменить свой список доменных блокировок</strong>, в котором сейчас <strong>%{count} домена</strong>, из файла <strong>%{filename}</strong>.
many: Вы собираетесь <strong>заменить свой список доменных блокировок</strong>, в котором сейчас <strong>%{count} доменов</strong>, из файла <strong>%{filename}</strong>.
one: Вы собираетесь <strong>заменить свой список доменных блокировок</strong>, в котором сейчас <strong>%{count} домен</strong>, из файла <strong>%{filename}</strong>.
other: Вы собираетесь <strong>заменить свой список доменных блокировок</strong>, в котором сейчас <strong>%{count} доменов</strong>, из файла <strong>%{filename}</strong>.
few: Вы собираетесь <strong>заменить свой список заблокированных доменов</strong> данными из файла <strong>%{filename}</strong>, после чего вы будете блокировать <strong>%{count} домена</strong>.
many: Вы собираетесь <strong>заменить свой список заблокированных доменов</strong> данными из файла <strong>%{filename}</strong>, после чего вы будете блокировать <strong>%{count} доменов</strong>.
one: Вы собираетесь <strong>заменить свой список заблокированных доменов</strong> данными из файла <strong>%{filename}</strong>, после чего вы будете блокировать <strong>%{count} домен</strong>.
other: Вы собираетесь <strong>заменить свой список заблокированных доменов</strong> данными из файла <strong>%{filename}</strong>, после чего вы будете блокировать <strong>%{count} доменов</strong>.
following_html:
few: Вы собираетесь <strong>подписаться</strong> на <strong>%{count} аккаунта</strong> из файла <strong>%{filename}</strong> и <strong>отписаться от всех прочих</strong>.
many: Вы собираетесь <strong>подписаться</strong> на <strong>%{count} аккаунтов</strong> из файла <strong>%{filename}</strong> и <strong>отписаться от всех прочих</strong>.
one: Вы собираетесь <strong>подписаться</strong> на <strong>%{count} аккаунт</strong> из файла <strong>%{filename}</strong> и <strong>отписаться от всех прочих</strong>.
other: Вы собираетесь <strong>подписаться</strong> на <strong>%{count} аккаунтов</strong> из файла <strong>%{filename}</strong> и <strong>отписаться от всех прочих</strong>.
few: Вы собираетесь <strong>подписаться</strong> на <strong>%{count} пользователей</strong> из файла <strong>%{filename}</strong> и <strong>отписаться от всех прочих</strong>.
many: Вы собираетесь <strong>подписаться</strong> на <strong>%{count} пользователей</strong> из файла <strong>%{filename}</strong> и <strong>отписаться от всех прочих</strong>.
one: Вы собираетесь <strong>подписаться</strong> на <strong>%{count} пользователя</strong> из файла <strong>%{filename}</strong> и <strong>отписаться от всех прочих</strong>.
other: Вы собираетесь <strong>подписаться</strong> на <strong>%{count} пользователей</strong> из файла <strong>%{filename}</strong> и <strong>отписаться от всех прочих</strong>.
lists_html:
few: Вы собираетесь <strong>заменить свои списки</strong> содержимым файла <strong>%{filename}</strong>. В новые списки будут добавлены <strong>%{count} аккаунта</strong>.
many: Вы собираетесь <strong>заменить свои списки</strong> содержимым файла <strong>%{filename}</strong>. В новые списки будут добавлены <strong>%{count} аккаунтов</strong>.
one: Вы собираетесь <strong>заменить свои списки</strong> содержимым файла <strong>%{filename}</strong>. В новые списки будет добавлен <strong>%{count} аккаунт</strong>.
other: Вы собираетесь <strong>заменить свои списки</strong> содержимым файла <strong>%{filename}</strong>. В новые списки будут добавлены <strong>%{count} аккаунтов</strong>.
few: Вы собираетесь <strong>заменить свои списки</strong> содержимым файла <strong>%{filename}</strong>. В новые списки будут добавлены <strong>%{count} пользователя</strong>.
many: Вы собираетесь <strong>заменить свои списки</strong> содержимым файла <strong>%{filename}</strong>. В новые списки будут добавлены <strong>%{count} пользователей</strong>.
one: Вы собираетесь <strong>заменить свои списки</strong> содержимым файла <strong>%{filename}</strong>. В новые списки будет добавлен <strong>%{count} пользователь</strong>.
other: Вы собираетесь <strong>заменить свои списки</strong> содержимым файла <strong>%{filename}</strong>. В новые списки будут добавлены <strong>%{count} пользователей</strong>.
muting_html:
few: Вы собираетесь <strong>заменить свой список игнорируемых пользователей</strong> списком из <strong>%{count} аккаунтов</strong> из файла <strong>%{filename}</strong>.
many: Вы собираетесь <strong>заменить свой список игнорируемых пользователей</strong> списком из <strong>%{count} аккаунтов</strong> из файла <strong>%{filename}</strong>.
one: Вы собираетесь <strong>заменить свой список игнорируемых пользователей</strong> списком из <strong>%{count} аккаунта</strong> из файла <strong>%{filename}</strong>.
other: Вы собираетесь <strong>заменить свой список игнорируемых пользователей</strong> списком из <strong>%{count} аккаунтов</strong> из файла <strong>%{filename}</strong>.
few: Вы собираетесь <strong>заменить свой список игнорируемых пользователей</strong> данными из файла <strong>%{filename}</strong>, после чего вы будете игнорировать <strong>%{count} пользователей</strong>.
many: Вы собираетесь <strong>заменить свой список игнорируемых пользователей</strong> данными из файла <strong>%{filename}</strong>, после чего вы будете игнорировать <strong>%{count} пользователей</strong>.
one: Вы собираетесь <strong>заменить свой список игнорируемых пользователей</strong> данными из файла <strong>%{filename}</strong>, после чего вы будете игнорировать <strong>%{count} пользователя</strong>.
other: Вы собираетесь <strong>заменить свой список игнорируемых пользователей</strong> данными из файла <strong>%{filename}</strong>, после чего вы будете игнорировать <strong>%{count} пользователей</strong>.
preambles:
blocking_html:
few: Вы собираетесь <strong>заблокировать</strong> <strong>%{count} аккаунта</strong> из файла <strong>%{filename}</strong>.
many: Вы собираетесь <strong>заблокировать</strong> <strong>%{count} аккаунтов</strong> из файла <strong>%{filename}</strong>.
one: Вы собираетесь <strong>заблокировать</strong> <strong>%{count} аккаунт</strong> из файла <strong>%{filename}</strong>.
other: Вы собираетесь <strong>заблокировать</strong> <strong>%{count} аккаунтов</strong> из файла <strong>%{filename}</strong>.
few: Вы собираетесь <strong>заблокировать</strong> <strong>%{count} пользователей</strong> из файла <strong>%{filename}</strong>.
many: Вы собираетесь <strong>заблокировать</strong> <strong>%{count} пользователей</strong> из файла <strong>%{filename}</strong>.
one: Вы собираетесь <strong>заблокировать</strong> <strong>%{count} пользователя</strong> из файла <strong>%{filename}</strong>.
other: Вы собираетесь <strong>заблокировать</strong> <strong>%{count} пользователей</strong> из файла <strong>%{filename}</strong>.
bookmarks_html:
few: Вы собираетесь добавить <strong>%{count} поста</strong> из файла <strong>%{filename}</strong> в свои <strong>закладки</strong>.
many: Вы собираетесь добавить <strong>%{count} постов</strong> из файла <strong>%{filename}</strong> в свои <strong>закладки</strong>.
@@ -1538,20 +1538,20 @@ ru:
one: Вы собираетесь <strong>заблокировать</strong> <strong>%{count} домен</strong> из файла <strong>%{filename}</strong>.
other: Вы собираетесь <strong>заблокировать</strong> <strong>%{count} доменов</strong> из файла <strong>%{filename}</strong>.
following_html:
few: Вы собираетесь <strong>подписаться</strong> на <strong>%{count} аккаунта</strong> из файла <strong>%{filename}</strong>.
many: Вы собираетесь <strong>подписаться</strong> на <strong>%{count} аккаунтов</strong> из файла <strong>%{filename}</strong>.
one: Вы собираетесь <strong>подписаться</strong> на <strong>%{count} аккаунт</strong> из файла <strong>%{filename}</strong>.
other: Вы собираетесь <strong>подписаться</strong> на <strong>%{count} аккаунтов</strong> из файла <strong>%{filename}</strong>.
few: Вы собираетесь <strong>подписаться</strong> на <strong>%{count} пользователей</strong> из файла <strong>%{filename}</strong>.
many: Вы собираетесь <strong>подписаться</strong> на <strong>%{count} пользователей</strong> из файла <strong>%{filename}</strong>.
one: Вы собираетесь <strong>подписаться</strong> на <strong>%{count} пользователя</strong> из файла <strong>%{filename}</strong>.
other: Вы собираетесь <strong>подписаться</strong> на <strong>%{count} пользователей</strong> из файла <strong>%{filename}</strong>.
lists_html:
few: Вы собираетесь добавить <strong>%{count} аккаунта</strong> из файла <strong>%{filename}</strong> в свои <strong>списки</strong>. Если соответствующих списков нет, они будут созданы.
many: Вы собираетесь добавить <strong>%{count} аккаунтов</strong> из файла <strong>%{filename}</strong> в свои <strong>списки</strong>. Если соответствующих списков нет, они будут созданы.
one: Вы собираетесь добавить <strong>%{count} аккаунт</strong> из файла <strong>%{filename}</strong> в свои <strong>списки</strong>. Если соответствующих списков нет, они будут созданы.
other: Вы собираетесь добавить <strong>%{count} аккаунтов</strong> из файла <strong>%{filename}</strong> в свои <strong>списки</strong>. Если соответствующих списков нет, они будут созданы.
few: Вы собираетесь добавить <strong>%{count} пользователей</strong> из файла <strong>%{filename}</strong> в свои <strong>списки</strong>. Если соответствующих списков нет, они будут созданы.
many: Вы собираетесь добавить <strong>%{count} пользователей</strong> из файла <strong>%{filename}</strong> в свои <strong>списки</strong>. Если соответствующих списков нет, они будут созданы.
one: Вы собираетесь добавить <strong>%{count} пользователя</strong> из файла <strong>%{filename}</strong> в свои <strong>списки</strong>. Если соответствующих списков нет, они будут созданы.
other: Вы собираетесь добавить <strong>%{count} пользователей</strong> из файла <strong>%{filename}</strong> в свои <strong>списки</strong>. Если соответствующих списков нет, они будут созданы.
muting_html:
few: Вы собираетесь <strong>начать игнорировать</strong> <strong>%{count} аккаунта</strong> из файла <strong>%{filename}</strong>.
many: Вы собираетесь <strong>начать игнорировать</strong> <strong>%{count} аккаунтов</strong> из файла <strong>%{filename}</strong>.
one: Вы собираетесь <strong>начать игнорировать</strong> <strong>%{count} аккаунт</strong> из файла <strong>%{filename}</strong>.
other: Вы собираетесь <strong>начать игнорировать</strong> <strong>%{count} аккаунтов</strong> из файла <strong>%{filename}</strong>.
few: Вы собираетесь <strong>игнорировать</strong> <strong>%{count} пользователей</strong> из файла <strong>%{filename}</strong>.
many: Вы собираетесь <strong>игнорировать</strong> <strong>%{count} пользователей</strong> из файла <strong>%{filename}</strong>.
one: Вы собираетесь <strong>игнорировать</strong> <strong>%{count} пользователя</strong> из файла <strong>%{filename}</strong>.
other: Вы собираетесь <strong>игнорировать</strong> <strong>%{count} пользователей</strong> из файла <strong>%{filename}</strong>.
preface: Вы можете загрузить некоторые данные, например, списки людей, на которых Вы подписаны или которых блокируете, в Вашу учётную запись на этом узле из файлов, экспортированных с другого узла.
recent_imports: Недавно импортированное
states:
@@ -1563,23 +1563,23 @@ ru:
success: Ваши данные были успешно загружены и будут обработаны с должной скоростью
time_started: Началось в
titles:
blocking: Импорт заблокированных аккаунтов
blocking: Импорт списка заблокированных пользователей
bookmarks: Импорт закладок
domain_blocking: Импорт заблокированных доменов
following: Импорт последующих аккаунтов
lists: Импортировать список
muting: Импорт отключенных аккаунтов
domain_blocking: Импорт списка заблокированных доменов
following: Импорт подписок
lists: Импорт списков
muting: Импорт списка игнорируемых пользователей
type: Тип импорта
type_groups:
constructive: Подписки и закладки
destructive: Блокировки и игнорируемые
types:
blocking: Список блокировки
blocking: Заблокированные пользователи
bookmarks: Закладки
domain_blocking: Список доменных блокировок
domain_blocking: Заблокированные домены
following: Подписки
lists: Списки
muting: Список глушения
muting: Игнорируемые пользователи
upload: Загрузить
invites:
delete: Удалить

View File

@@ -59,7 +59,7 @@ services:
web:
# You can uncomment the following line if you want to not use the prebuilt image, for example if you have local code changes
# build: .
image: ghcr.io/glitch-soc/mastodon:v4.4.1
image: ghcr.io/glitch-soc/mastodon:v4.4.2
restart: always
env_file: .env.production
command: bundle exec puma -C config/puma.rb
@@ -83,7 +83,7 @@ services:
# build:
# dockerfile: ./streaming/Dockerfile
# context: .
image: ghcr.io/glitch-soc/mastodon-streaming:v4.4.1
image: ghcr.io/glitch-soc/mastodon-streaming:v4.4.2
restart: always
env_file: .env.production
command: node ./streaming/index.js
@@ -102,7 +102,7 @@ services:
sidekiq:
# You can uncomment the following line if you want to not use the prebuilt image, for example if you have local code changes
# build: .
image: ghcr.io/glitch-soc/mastodon:v4.4.1
image: ghcr.io/glitch-soc/mastodon:v4.4.2
restart: always
env_file: .env.production
command: bundle exec sidekiq

View File

@@ -1,124 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Api::Web::PushSubscriptionsController do
render_views
let(:user) { Fabricate(:user) }
let(:create_payload) do
{
subscription: {
endpoint: 'https://fcm.googleapis.com/fcm/send/fiuH06a27qE:APA91bHnSiGcLwdaxdyqVXNDR9w1NlztsHb6lyt5WDKOC_Z_Q8BlFxQoR8tWFSXUIDdkyw0EdvxTu63iqamSaqVSevW5LfoFwojws8XYDXv_NRRLH6vo2CdgiN4jgHv5VLt2A8ah6lUX',
keys: {
p256dh: 'BEm_a0bdPDhf0SOsrnB2-ategf1hHoCnpXgQsFj5JCkcoMrMt2WHoPfEYOYPzOIs9mZE8ZUaD7VA5vouy0kEkr8=',
auth: 'eH_C8rq2raXqlcBVDa1gLg==',
},
standard: standard,
},
}
end
let(:alerts_payload) do
{
data: {
policy: 'all',
alerts: {
follow: true,
follow_request: false,
favourite: false,
reblog: true,
mention: false,
poll: true,
status: false,
},
},
}
end
let(:standard) { '1' }
before do
sign_in(user)
stub_request(:post, create_payload[:subscription][:endpoint]).to_return(status: 200)
end
describe 'POST #create' do
it 'saves push subscriptions' do
post :create, format: :json, params: create_payload
expect(response).to have_http_status(200)
user.reload
expect(created_push_subscription)
.to have_attributes(
endpoint: eq(create_payload[:subscription][:endpoint]),
key_p256dh: eq(create_payload[:subscription][:keys][:p256dh]),
key_auth: eq(create_payload[:subscription][:keys][:auth])
)
.and be_standard
expect(user.session_activations.first.web_push_subscription).to eq(created_push_subscription)
end
context 'when standard is provided as false value' do
let(:standard) { '0' }
it 'saves push subscription with standard as false' do
post :create, format: :json, params: create_payload
expect(created_push_subscription)
.to_not be_standard
end
end
context 'with a user who has a session with a prior subscription' do
let!(:prior_subscription) { Fabricate(:web_push_subscription, session_activation: user.session_activations.last) }
it 'destroys prior subscription when creating new one' do
post :create, format: :json, params: create_payload
expect(response).to have_http_status(200)
expect { prior_subscription.reload }.to raise_error(ActiveRecord::RecordNotFound)
end
end
context 'with initial data' do
it 'saves alert settings' do
post :create, format: :json, params: create_payload.merge(alerts_payload)
expect(response).to have_http_status(200)
expect(created_push_subscription.data['policy']).to eq 'all'
%w(follow follow_request favourite reblog mention poll status).each do |type|
expect(created_push_subscription.data['alerts'][type]).to eq(alerts_payload[:data][:alerts][type.to_sym].to_s)
end
end
end
end
describe 'PUT #update' do
it 'changes alert settings' do
post :create, format: :json, params: create_payload
expect(response).to have_http_status(200)
alerts_payload[:id] = created_push_subscription.id
put :update, format: :json, params: alerts_payload
expect(created_push_subscription.data['policy']).to eq 'all'
%w(follow follow_request favourite reblog mention poll status).each do |type|
expect(created_push_subscription.data['alerts'][type]).to eq(alerts_payload[:data][:alerts][type.to_sym].to_s)
end
end
end
def created_push_subscription
Web::PushSubscription.find_by(endpoint: create_payload[:subscription][:endpoint])
end
end

View File

@@ -111,12 +111,16 @@ RSpec.describe Trends::Statuses do
let!(:yesterday) { today - 1.day }
let!(:status_foo) { Fabricate(:status, text: 'Foo', language: 'en', trendable: true, created_at: yesterday) }
let!(:status_bar) { Fabricate(:status, text: 'Bar', language: 'en', trendable: true, created_at: today) }
let!(:status_bar) { Fabricate(:status, text: 'Bar', language: 'en', trendable: true, created_at: today, quote: Quote.new(state: :accepted, quoted_status: status_foo)) }
let!(:status_baz) { Fabricate(:status, text: 'Baz', language: 'en', trendable: true, created_at: today) }
let!(:untrendable) { Fabricate(:status, text: 'Untrendable', language: 'en', trendable: true, visibility: :unlisted) }
let!(:untrendable_quote) { Fabricate(:status, text: 'Untrendable quote!', language: 'en', trendable: true, created_at: today, quote: Quote.new(state: :accepted, quoted_status: untrendable)) }
before do
default_threshold_value.times { reblog(status_foo, today) }
default_threshold_value.times { reblog(status_bar, today) }
default_threshold_value.times { reblog(untrendable, today) }
default_threshold_value.times { reblog(untrendable_quote, today) }
(default_threshold_value - 1).times { reblog(status_baz, today) }
end
@@ -129,7 +133,7 @@ RSpec.describe Trends::Statuses do
results = subject.query.limit(10).to_a
expect(results).to eq [status_bar, status_foo]
expect(results).to_not include(status_baz)
expect(results).to_not include(status_baz, untrendable, untrendable_quote)
end
end

View File

@@ -166,17 +166,30 @@ RSpec.describe 'API V1 Push Subscriptions' do
describe 'GET /api/v1/push/subscription' do
subject { get '/api/v1/push/subscription', headers: headers }
before { create_subscription_with_token }
context 'with a subscription' do
before { create_subscription_with_token }
it 'shows subscription details' do
subject
it 'shows subscription details' do
subject
expect(response)
.to have_http_status(200)
expect(response.content_type)
.to start_with('application/json')
expect(response.parsed_body)
.to include(endpoint: endpoint)
expect(response)
.to have_http_status(200)
expect(response.content_type)
.to start_with('application/json')
expect(response.parsed_body)
.to include(endpoint: endpoint)
end
end
context 'without a subscription' do
it 'returns not found' do
subject
expect(response)
.to have_http_status(404)
expect(response.content_type)
.to start_with('application/json')
end
end
end

View File

@@ -3,6 +3,38 @@
require 'rails_helper'
RSpec.describe 'API Web Push Subscriptions' do
let(:create_payload) do
{
subscription: {
endpoint: 'https://fcm.googleapis.com/fcm/send/fiuH06a27qE:APA91bHnSiGcLwdaxdyqVXNDR9w1NlztsHb6lyt5WDKOC_Z_Q8BlFxQoR8tWFSXUIDdkyw0EdvxTu63iqamSaqVSevW5LfoFwojws8XYDXv_NRRLH6vo2CdgiN4jgHv5VLt2A8ah6lUX',
keys: {
p256dh: 'BEm_a0bdPDhf0SOsrnB2-ategf1hHoCnpXgQsFj5JCkcoMrMt2WHoPfEYOYPzOIs9mZE8ZUaD7VA5vouy0kEkr8=',
auth: 'eH_C8rq2raXqlcBVDa1gLg==',
},
standard: standard,
},
}
end
let(:alerts_payload) do
{
data: {
policy: 'all',
alerts: {
follow: true,
follow_request: false,
favourite: false,
reblog: true,
mention: false,
poll: true,
status: false,
},
},
}
end
let(:standard) { '1' }
describe 'DELETE /api/web/push_subscriptions/:id' do
subject { delete api_web_push_subscription_path(token) }
@@ -54,7 +86,9 @@ RSpec.describe 'API Web Push Subscriptions' do
end
describe 'POST /api/web/push_subscriptions' do
before { sign_in Fabricate :user }
before { sign_in(user) }
let(:user) { Fabricate :user }
it 'gracefully handles invalid nested params' do
post api_web_push_subscriptions_path, params: { subscription: 'invalid' }
@@ -62,6 +96,69 @@ RSpec.describe 'API Web Push Subscriptions' do
expect(response)
.to have_http_status(400)
end
it 'saves push subscriptions with valid params' do
post api_web_push_subscriptions_path, params: create_payload
expect(response)
.to have_http_status(200)
expect(created_push_subscription)
.to have_attributes(
endpoint: eq(create_payload[:subscription][:endpoint]),
key_p256dh: eq(create_payload[:subscription][:keys][:p256dh]),
key_auth: eq(create_payload[:subscription][:keys][:auth])
)
.and be_standard
expect(user.session_activations.first.web_push_subscription)
.to eq(created_push_subscription)
end
context 'when standard is provided as false value' do
let(:standard) { '0' }
it 'saves push subscription with standard as false' do
post api_web_push_subscriptions_path, params: create_payload
expect(created_push_subscription)
.to_not be_standard
end
end
context 'with a user who has a session with a prior subscription' do
before do
# Trigger creation of a `SessionActivation` for the user so that the
# prior_subscription setup and verification works as expected
get about_path
end
let!(:prior_subscription) { Fabricate(:web_push_subscription, user:, session_activation: user.session_activations.last) }
it 'destroys prior subscription when creating new one' do
post api_web_push_subscriptions_path, params: create_payload
expect(response)
.to have_http_status(200)
expect { prior_subscription.reload }
.to raise_error(ActiveRecord::RecordNotFound)
end
end
context 'with initial data' do
it 'saves alert settings' do
post api_web_push_subscriptions_path, params: create_payload.merge(alerts_payload)
expect(response)
.to have_http_status(200)
expect(created_push_subscription.data['policy'])
.to eq 'all'
alert_types.each do |type|
expect(created_push_subscription.data['alerts'][type])
.to eq(alerts_payload[:data][:alerts][type.to_sym].to_s)
end
end
end
end
describe 'PUT /api/web/push_subscriptions' do
@@ -75,5 +172,30 @@ RSpec.describe 'API Web Push Subscriptions' do
expect(response)
.to have_http_status(400)
end
it 'changes existing alert settings' do
# Create record this way to correctly associate a `SessionActivation`
# during full POST->create cycle
post api_web_push_subscriptions_path params: create_payload
expect(response)
.to have_http_status(200)
put api_web_push_subscription_path(created_push_subscription), params: alerts_payload
expect(created_push_subscription.data['policy'])
.to eq 'all'
alert_types.each do |type|
expect(created_push_subscription.data['alerts'][type])
.to eq(alerts_payload[:data][:alerts][type.to_sym].to_s)
end
end
end
def created_push_subscription
Web::PushSubscription
.find_by(endpoint: create_payload[:subscription][:endpoint])
end
def alert_types
Notification::LEGACY_TYPE_CLASS_MAP.values.map(&:to_s)
end
end

View File

@@ -65,6 +65,11 @@ export const config: UserConfigFnPromise = async ({ mode, command }) => {
// but it needs to be scoped to the whole domain
'Service-Worker-Allowed': '/',
},
hmr: {
// Forcing the protocol to be insecure helps if you are proxying your dev server with SSL,
// because Vite still tries to connect to localhost.
protocol: 'ws',
},
port: 3036,
},
build: {

133
yarn.lock
View File

@@ -73,39 +73,39 @@ __metadata:
languageName: node
linkType: hard
"@babel/core@npm:^7.18.9, @babel/core@npm:^7.21.3, @babel/core@npm:^7.24.4, @babel/core@npm:^7.26.10, @babel/core@npm:^7.27.4":
version: 7.27.4
resolution: "@babel/core@npm:7.27.4"
"@babel/core@npm:^7.18.9, @babel/core@npm:^7.21.3, @babel/core@npm:^7.24.4, @babel/core@npm:^7.26.10, @babel/core@npm:^7.28.0":
version: 7.28.0
resolution: "@babel/core@npm:7.28.0"
dependencies:
"@ampproject/remapping": "npm:^2.2.0"
"@babel/code-frame": "npm:^7.27.1"
"@babel/generator": "npm:^7.27.3"
"@babel/generator": "npm:^7.28.0"
"@babel/helper-compilation-targets": "npm:^7.27.2"
"@babel/helper-module-transforms": "npm:^7.27.3"
"@babel/helpers": "npm:^7.27.4"
"@babel/parser": "npm:^7.27.4"
"@babel/helpers": "npm:^7.27.6"
"@babel/parser": "npm:^7.28.0"
"@babel/template": "npm:^7.27.2"
"@babel/traverse": "npm:^7.27.4"
"@babel/types": "npm:^7.27.3"
"@babel/traverse": "npm:^7.28.0"
"@babel/types": "npm:^7.28.0"
convert-source-map: "npm:^2.0.0"
debug: "npm:^4.1.0"
gensync: "npm:^1.0.0-beta.2"
json5: "npm:^2.2.3"
semver: "npm:^6.3.1"
checksum: 10c0/d2d17b106a8d91d3eda754bb3f26b53a12eb7646df73c2b2d2e9b08d90529186bc69e3823f70a96ec6e5719dc2372fb54e14ad499da47ceeb172d2f7008787b5
checksum: 10c0/423302e7c721e73b1c096217880272e02020dfb697a55ccca60ad01bba90037015f84d0c20c6ce297cf33a19bb704bc5c2b3d3095f5284dfa592bd1de0b9e8c3
languageName: node
linkType: hard
"@babel/generator@npm:^7.27.3":
version: 7.27.3
resolution: "@babel/generator@npm:7.27.3"
"@babel/generator@npm:^7.28.0":
version: 7.28.0
resolution: "@babel/generator@npm:7.28.0"
dependencies:
"@babel/parser": "npm:^7.27.3"
"@babel/types": "npm:^7.27.3"
"@jridgewell/gen-mapping": "npm:^0.3.5"
"@jridgewell/trace-mapping": "npm:^0.3.25"
"@babel/parser": "npm:^7.28.0"
"@babel/types": "npm:^7.28.0"
"@jridgewell/gen-mapping": "npm:^0.3.12"
"@jridgewell/trace-mapping": "npm:^0.3.28"
jsesc: "npm:^3.0.2"
checksum: 10c0/341622e17c61d008fc746b655ab95ef7febb543df8efb4148f57cf06e60ade1abe091ed7d6811df17b064d04d64f69bb7f35ab0654137116d55c54a73145a61a
checksum: 10c0/1b3d122268ea3df50fde707ad864d9a55c72621357d5cebb972db3dd76859c45810c56e16ad23123f18f80cc2692f5a015d2858361300f0f224a05dc43d36a92
languageName: node
linkType: hard
@@ -176,6 +176,13 @@ __metadata:
languageName: node
linkType: hard
"@babel/helper-globals@npm:^7.28.0":
version: 7.28.0
resolution: "@babel/helper-globals@npm:7.28.0"
checksum: 10c0/5a0cd0c0e8c764b5f27f2095e4243e8af6fa145daea2b41b53c0c1414fe6ff139e3640f4e2207ae2b3d2153a1abd346f901c26c290ee7cb3881dd922d4ee9232
languageName: node
linkType: hard
"@babel/helper-member-expression-to-functions@npm:^7.27.1":
version: 7.27.1
resolution: "@babel/helper-member-expression-to-functions@npm:7.27.1"
@@ -293,24 +300,24 @@ __metadata:
languageName: node
linkType: hard
"@babel/helpers@npm:^7.27.4":
version: 7.27.4
resolution: "@babel/helpers@npm:7.27.4"
"@babel/helpers@npm:^7.27.6":
version: 7.27.6
resolution: "@babel/helpers@npm:7.27.6"
dependencies:
"@babel/template": "npm:^7.27.2"
"@babel/types": "npm:^7.27.3"
checksum: 10c0/3463551420926b3f403c1a30d66ac67bba5c4f73539a8ccb71544da129c4709ac37c57fac740ed8a261b3e6bbbf353b05e03b36ea1a6bf1081604b2a94ca43c1
"@babel/types": "npm:^7.27.6"
checksum: 10c0/448bac96ef8b0f21f2294a826df9de6bf4026fd023f8a6bb6c782fe3e61946801ca24381490b8e58d861fee75cd695a1882921afbf1f53b0275ee68c938bd6d3
languageName: node
linkType: hard
"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.25.4, @babel/parser@npm:^7.27.2, @babel/parser@npm:^7.27.3, @babel/parser@npm:^7.27.4":
version: 7.27.4
resolution: "@babel/parser@npm:7.27.4"
"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.25.4, @babel/parser@npm:^7.27.2, @babel/parser@npm:^7.28.0":
version: 7.28.0
resolution: "@babel/parser@npm:7.28.0"
dependencies:
"@babel/types": "npm:^7.27.3"
"@babel/types": "npm:^7.28.0"
bin:
parser: ./bin/babel-parser.js
checksum: 10c0/d1bf17e7508585235e2a76594ba81828e48851877112bb8abbecd7161a31fb66654e993e458ddaedb18a3d5fa31970e5f3feca5ae2900f51e6d8d3d35da70dbf
checksum: 10c0/c2ef81d598990fa949d1d388429df327420357cb5200271d0d0a2784f1e6d54afc8301eb8bdf96d8f6c77781e402da93c7dc07980fcc136ac5b9d5f1fce701b5
languageName: node
linkType: hard
@@ -1157,28 +1164,28 @@ __metadata:
languageName: node
linkType: hard
"@babel/traverse@npm:^7.18.9, @babel/traverse@npm:^7.26.10, @babel/traverse@npm:^7.27.1, @babel/traverse@npm:^7.27.3, @babel/traverse@npm:^7.27.4":
version: 7.27.4
resolution: "@babel/traverse@npm:7.27.4"
"@babel/traverse@npm:^7.18.9, @babel/traverse@npm:^7.26.10, @babel/traverse@npm:^7.27.1, @babel/traverse@npm:^7.27.3, @babel/traverse@npm:^7.28.0":
version: 7.28.0
resolution: "@babel/traverse@npm:7.28.0"
dependencies:
"@babel/code-frame": "npm:^7.27.1"
"@babel/generator": "npm:^7.27.3"
"@babel/parser": "npm:^7.27.4"
"@babel/generator": "npm:^7.28.0"
"@babel/helper-globals": "npm:^7.28.0"
"@babel/parser": "npm:^7.28.0"
"@babel/template": "npm:^7.27.2"
"@babel/types": "npm:^7.27.3"
"@babel/types": "npm:^7.28.0"
debug: "npm:^4.3.1"
globals: "npm:^11.1.0"
checksum: 10c0/6de8aa2a0637a6ee6d205bf48b9e923928a02415771fdec60085ed754dcdf605e450bb3315c2552fa51c31a4662275b45d5ae4ad527ce55a7db9acebdbbbb8ed
checksum: 10c0/32794402457827ac558173bcebdcc0e3a18fa339b7c41ca35621f9f645f044534d91bb923ff385f5f960f2e495f56ce18d6c7b0d064d2f0ccb55b285fa6bc7b9
languageName: node
linkType: hard
"@babel/types@npm:^7.0.0, @babel/types@npm:^7.18.9, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.3, @babel/types@npm:^7.25.4, @babel/types@npm:^7.26.10, @babel/types@npm:^7.27.1, @babel/types@npm:^7.27.3, @babel/types@npm:^7.4.4":
version: 7.27.3
resolution: "@babel/types@npm:7.27.3"
"@babel/types@npm:^7.0.0, @babel/types@npm:^7.18.9, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.3, @babel/types@npm:^7.25.4, @babel/types@npm:^7.26.10, @babel/types@npm:^7.27.1, @babel/types@npm:^7.27.6, @babel/types@npm:^7.28.0, @babel/types@npm:^7.4.4":
version: 7.28.1
resolution: "@babel/types@npm:7.28.1"
dependencies:
"@babel/helper-string-parser": "npm:^7.27.1"
"@babel/helper-validator-identifier": "npm:^7.27.1"
checksum: 10c0/bafdfc98e722a6b91a783b6f24388f478fd775f0c0652e92220e08be2cc33e02d42088542f1953ac5e5ece2ac052172b3dadedf12bec9aae57899e92fb9a9757
checksum: 10c0/5e99b346c11ee42ffb0cadc28159fe0b184d865a2cc1593df79b199772a534f6453969b4942aa5e4a55a3081863096e1cc3fc1c724d826926dc787cf229b845d
languageName: node
linkType: hard
@@ -2542,14 +2549,13 @@ __metadata:
languageName: node
linkType: hard
"@jridgewell/gen-mapping@npm:^0.3.5":
version: 0.3.5
resolution: "@jridgewell/gen-mapping@npm:0.3.5"
"@jridgewell/gen-mapping@npm:^0.3.12, @jridgewell/gen-mapping@npm:^0.3.5":
version: 0.3.12
resolution: "@jridgewell/gen-mapping@npm:0.3.12"
dependencies:
"@jridgewell/set-array": "npm:^1.2.1"
"@jridgewell/sourcemap-codec": "npm:^1.4.10"
"@jridgewell/sourcemap-codec": "npm:^1.5.0"
"@jridgewell/trace-mapping": "npm:^0.3.24"
checksum: 10c0/1be4fd4a6b0f41337c4f5fdf4afc3bd19e39c3691924817108b82ffcb9c9e609c273f936932b9fba4b3a298ce2eb06d9bff4eb1cc3bd81c4f4ee1b4917e25feb
checksum: 10c0/32f771ae2467e4d440be609581f7338d786d3d621bac3469e943b9d6d116c23c4becb36f84898a92bbf2f3c0511365c54a945a3b86a83141547a2a360a5ec0c7
languageName: node
linkType: hard
@@ -2560,13 +2566,6 @@ __metadata:
languageName: node
linkType: hard
"@jridgewell/set-array@npm:^1.2.1":
version: 1.2.1
resolution: "@jridgewell/set-array@npm:1.2.1"
checksum: 10c0/2a5aa7b4b5c3464c895c802d8ae3f3d2b92fcbe84ad12f8d0bfbb1f5ad006717e7577ee1fd2eac00c088abe486c7adb27976f45d2941ff6b0b92b2c3302c60f4
languageName: node
linkType: hard
"@jridgewell/source-map@npm:^0.3.3":
version: 0.3.6
resolution: "@jridgewell/source-map@npm:0.3.6"
@@ -2577,20 +2576,20 @@ __metadata:
languageName: node
linkType: hard
"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.5.0":
"@jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.5.0":
version: 1.5.0
resolution: "@jridgewell/sourcemap-codec@npm:1.5.0"
checksum: 10c0/2eb864f276eb1096c3c11da3e9bb518f6d9fc0023c78344cdc037abadc725172c70314bdb360f2d4b7bffec7f5d657ce006816bc5d4ecb35e61b66132db00c18
languageName: node
linkType: hard
"@jridgewell/trace-mapping@npm:^0.3.23, @jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25":
version: 0.3.25
resolution: "@jridgewell/trace-mapping@npm:0.3.25"
"@jridgewell/trace-mapping@npm:^0.3.23, @jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25, @jridgewell/trace-mapping@npm:^0.3.28":
version: 0.3.29
resolution: "@jridgewell/trace-mapping@npm:0.3.29"
dependencies:
"@jridgewell/resolve-uri": "npm:^3.1.0"
"@jridgewell/sourcemap-codec": "npm:^1.4.14"
checksum: 10c0/3d1ce6ebc69df9682a5a8896b414c6537e428a1d68b02fcc8363b04284a8ca0df04d0ee3013132252ab14f2527bc13bea6526a912ecb5658f0e39fd2860b4df4
checksum: 10c0/fb547ba31658c4d74eb17e7389f4908bf7c44cef47acb4c5baa57289daf68e6fe53c639f41f751b3923aca67010501264f70e7b49978ad1f040294b22c37b333
languageName: node
linkType: hard
@@ -3213,10 +3212,10 @@ __metadata:
languageName: node
linkType: hard
"@rolldown/pluginutils@npm:1.0.0-beta.19":
version: 1.0.0-beta.19
resolution: "@rolldown/pluginutils@npm:1.0.0-beta.19"
checksum: 10c0/e4205df56e6231a347ac601d044af365639741d51b5bea4e91ecc37e19e9777cb79d1daa924b8709ddf1f743ed6922e4e68e2445126434c4d420d9f4416f4feb
"@rolldown/pluginutils@npm:1.0.0-beta.27":
version: 1.0.0-beta.27
resolution: "@rolldown/pluginutils@npm:1.0.0-beta.27"
checksum: 10c0/9658f235b345201d4f6bfb1f32da9754ca164f892d1cb68154fe5f53c1df42bd675ecd409836dff46884a7847d6c00bdc38af870f7c81e05bba5c2645eb4ab9c
languageName: node
linkType: hard
@@ -4737,18 +4736,18 @@ __metadata:
linkType: hard
"@vitejs/plugin-react@npm:^4.2.1":
version: 4.6.0
resolution: "@vitejs/plugin-react@npm:4.6.0"
version: 4.7.0
resolution: "@vitejs/plugin-react@npm:4.7.0"
dependencies:
"@babel/core": "npm:^7.27.4"
"@babel/core": "npm:^7.28.0"
"@babel/plugin-transform-react-jsx-self": "npm:^7.27.1"
"@babel/plugin-transform-react-jsx-source": "npm:^7.27.1"
"@rolldown/pluginutils": "npm:1.0.0-beta.19"
"@rolldown/pluginutils": "npm:1.0.0-beta.27"
"@types/babel__core": "npm:^7.20.5"
react-refresh: "npm:^0.17.0"
peerDependencies:
vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0
checksum: 10c0/73b8f271978a0337debb255afd1667f49c2018c118962a8613120383375c4038255a5315cee2ef210dc7fd07cd30d5b12271077ad47db29980f8156b8a49be2c
vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
checksum: 10c0/692f23960972879485d647713663ec299c478222c96567d60285acf7c7dc5c178e71abfe9d2eefddef1eeb01514dacbc2ed68aad84628debf9c7116134734253
languageName: node
linkType: hard