Merge pull request #2803 from ClearlyClaire/glitch-soc/merge-upstream

Merge upstream changes up to a50c8e951f
This commit is contained in:
Claire 2024-07-31 20:05:52 +02:00 committed by GitHub
commit a9ffec4cbe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
46 changed files with 351 additions and 187 deletions

View file

@ -517,7 +517,7 @@ GEM
opentelemetry-api (~> 1.0)
opentelemetry-instrumentation-active_support (~> 0.1)
opentelemetry-instrumentation-base (~> 0.22.1)
opentelemetry-instrumentation-active_job (0.7.3)
opentelemetry-instrumentation-active_job (0.7.4)
opentelemetry-api (~> 1.0)
opentelemetry-instrumentation-base (~> 0.22.1)
opentelemetry-instrumentation-active_model_serializers (0.20.2)

View file

@ -33,7 +33,8 @@ class Api::V2Alpha::NotificationsController < Api::BaseController
'app.notification_grouping.status.unique_count' => statuses.uniq.size
)
render json: @grouped_notifications, each_serializer: REST::NotificationGroupSerializer, relationships: @relationships, group_metadata: @group_metadata
presenter = GroupedNotificationsPresenter.new(@grouped_notifications)
render json: presenter, serializer: REST::DedupNotificationGroupSerializer, relationships: @relationships, group_metadata: @group_metadata
end
end
@ -47,7 +48,8 @@ class Api::V2Alpha::NotificationsController < Api::BaseController
def show
@notification = current_account.notifications.without_suspended.find_by!(group_key: params[:id])
render json: NotificationGroup.from_notification(@notification), serializer: REST::NotificationGroupSerializer
presenter = GroupedNotificationsPresenter.new([NotificationGroup.from_notification(@notification)])
render json: presenter, serializer: REST::DedupNotificationGroupSerializer
end
def clear

View file

@ -38,10 +38,6 @@ function dispatchAssociatedRecords(
const fetchedStatuses: ApiStatusJSON[] = [];
notifications.forEach((notification) => {
if ('sample_accounts' in notification) {
fetchedAccounts.push(...notification.sample_accounts);
}
if (notification.type === 'admin.report') {
fetchedAccounts.push(notification.report.target_account);
}
@ -75,7 +71,9 @@ export const fetchNotifications = createDataLoadingThunk(
: excludeAllTypesExcept(activeFilter),
});
},
({ notifications }, { dispatch }) => {
({ notifications, accounts, statuses }, { dispatch }) => {
dispatch(importFetchedAccounts(accounts));
dispatch(importFetchedStatuses(statuses));
dispatchAssociatedRecords(dispatch, notifications);
const payload: (ApiNotificationGroupJSON | NotificationGap)[] =
notifications;
@ -95,7 +93,9 @@ export const fetchNotificationsGap = createDataLoadingThunk(
async (params: { gap: NotificationGap }) =>
apiFetchNotifications({ max_id: params.gap.maxId }),
({ notifications }, { dispatch }) => {
({ notifications, accounts, statuses }, { dispatch }) => {
dispatch(importFetchedAccounts(accounts));
dispatch(importFetchedStatuses(statuses));
dispatchAssociatedRecords(dispatch, notifications);
return { notifications };

View file

@ -1,17 +1,24 @@
import api, { apiRequest, getLinks } from 'flavours/glitch/api';
import type { ApiNotificationGroupJSON } from 'flavours/glitch/api_types/notifications';
import type { ApiNotificationGroupsResultJSON } from 'flavours/glitch/api_types/notifications';
export const apiFetchNotifications = async (params?: {
exclude_types?: string[];
max_id?: string;
}) => {
const response = await api().request<ApiNotificationGroupJSON[]>({
const response = await api().request<ApiNotificationGroupsResultJSON>({
method: 'GET',
url: '/api/v2_alpha/notifications',
params,
});
return { notifications: response.data, links: getLinks(response) };
const { statuses, accounts, notification_groups } = response.data;
return {
statuses,
accounts,
notifications: notification_groups,
links: getLinks(response),
};
};
export const apiClearNotifications = () =>

View file

@ -51,7 +51,7 @@ export interface BaseNotificationGroupJSON {
group_key: string;
notifications_count: number;
type: NotificationType;
sample_accounts: ApiAccountJSON[];
sample_account_ids: string[];
latest_page_notification_at: string; // FIXME: This will only be present if the notification group is returned in a paginated list, not requested directly
most_recent_notification_id: string;
page_min_id?: string;
@ -60,7 +60,7 @@ export interface BaseNotificationGroupJSON {
interface NotificationGroupWithStatusJSON extends BaseNotificationGroupJSON {
type: NotificationWithStatusType;
status: ApiStatusJSON;
status_id: string;
}
interface NotificationWithStatusJSON extends BaseNotificationJSON {
@ -143,3 +143,9 @@ export type ApiNotificationGroupJSON =
| AccountRelationshipSeveranceNotificationGroupJSON
| NotificationGroupWithStatusJSON
| ModerationWarningNotificationGroupJSON;
export interface ApiNotificationGroupsResultJSON {
accounts: ApiAccountJSON[];
statuses: ApiStatusJSON[];
notification_groups: ApiNotificationGroupJSON[];
}

View file

@ -49,21 +49,14 @@ export const FilteredNotificationsBanner: React.FC = () => {
<span>
<FormattedMessage
id='filtered_notifications_banner.pending_requests'
defaultMessage='Notifications from {count, plural, =0 {no one} one {one person} other {# people}} you may know'
defaultMessage='From {count, plural, =0 {no one} one {one person} other {# people}} you may know'
values={{ count: policy.summary.pending_requests_count }}
/>
</span>
</div>
<div className='filtered-notifications-banner__badge'>
<div className='filtered-notifications-banner__badge__badge'>
{toCappedNumber(policy.summary.pending_notifications_count)}
</div>
<FormattedMessage
id='filtered_notifications_banner.mentions'
defaultMessage='{count, plural, one {mention} other {mentions}}'
values={{ count: policy.summary.pending_notifications_count }}
/>
{toCappedNumber(policy.summary.pending_notifications_count)}
</div>
</Link>
);

View file

@ -7,9 +7,9 @@ import { Helmet } from 'react-helmet';
import { useSelector, useDispatch } from 'react-redux';
import DeleteIcon from '@/material-icons/400-24px/delete.svg?react';
import DoneIcon from '@/material-icons/400-24px/done.svg?react';
import InventoryIcon from '@/material-icons/400-24px/inventory_2.svg?react';
import VolumeOffIcon from '@/material-icons/400-24px/volume_off.svg?react';
import { fetchNotificationRequest, fetchNotificationsForRequest, expandNotificationsForRequest, acceptNotificationRequest, dismissNotificationRequest } from 'flavours/glitch/actions/notifications';
import Column from 'flavours/glitch/components/column';
import ColumnHeader from 'flavours/glitch/components/column_header';
@ -101,7 +101,7 @@ export const NotificationRequest = ({ multiColumn, params: { id } }) => {
showBackButton
extraButton={!removed && (
<>
<IconButton className='column-header__button' iconComponent={VolumeOffIcon} onClick={handleDismiss} title={intl.formatMessage(messages.dismiss)} />
<IconButton className='column-header__button' iconComponent={DeleteIcon} onClick={handleDismiss} title={intl.formatMessage(messages.dismiss)} />
<IconButton className='column-header__button' iconComponent={DoneIcon} onClick={handleAccept} title={intl.formatMessage(messages.accept)} />
</>
)}

View file

@ -1,5 +1,6 @@
import { FormattedMessage } from 'react-intl';
import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react';
import ReplyIcon from '@/material-icons/400-24px/reply-fill.svg?react';
import type { StatusVisibility } from 'flavours/glitch/api_types/statuses';
import type { NotificationGroupMention } from 'flavours/glitch/models/notification_group';
@ -39,7 +40,7 @@ export const NotificationMention: React.FC<{
return (
<NotificationWithStatus
type='mention'
icon={ReplyIcon}
icon={statusVisibility === 'direct' ? AlternateEmailIcon : ReplyIcon}
iconId='reply'
accountIds={notification.sampleAccountIds}
count={notification.notifications_count}

View file

@ -14,7 +14,7 @@ import type { ApiReportJSON } from 'flavours/glitch/api_types/reports';
export const NOTIFICATIONS_GROUP_MAX_AVATARS = 8;
interface BaseNotificationGroup
extends Omit<BaseNotificationGroupJSON, 'sample_accounts'> {
extends Omit<BaseNotificationGroupJSON, 'sample_account_ids'> {
sampleAccountIds: string[];
}
@ -115,8 +115,7 @@ function createAccountRelationshipSeveranceEventFromJSON(
export function createNotificationGroupFromJSON(
groupJson: ApiNotificationGroupJSON,
): NotificationGroup {
const { sample_accounts, ...group } = groupJson;
const sampleAccountIds = sample_accounts.map((account) => account.id);
const { sample_account_ids: sampleAccountIds, ...group } = groupJson;
switch (group.type) {
case 'favourite':
@ -125,9 +124,9 @@ export function createNotificationGroupFromJSON(
case 'mention':
case 'poll':
case 'update': {
const { status, ...groupWithoutStatus } = group;
const { status_id: statusId, ...groupWithoutStatus } = group;
return {
statusId: status.id,
statusId,
sampleAccountIds,
...groupWithoutStatus,
};

View file

@ -10730,25 +10730,10 @@ noscript {
}
&__badge {
display: flex;
align-items: center;
border-radius: 999px;
background: var(--background-border-color);
color: $darker-text-color;
padding: 4px;
padding-inline-end: 8px;
gap: 6px;
font-weight: 500;
font-size: 11px;
line-height: 16px;
word-break: keep-all;
&__badge {
background: $ui-button-background-color;
color: $white;
border-radius: 100px;
padding: 2px 8px;
}
background: $ui-button-background-color;
color: $white;
border-radius: 100px;
padding: 2px 8px;
}
}

View file

@ -38,10 +38,6 @@ function dispatchAssociatedRecords(
const fetchedStatuses: ApiStatusJSON[] = [];
notifications.forEach((notification) => {
if ('sample_accounts' in notification) {
fetchedAccounts.push(...notification.sample_accounts);
}
if (notification.type === 'admin.report') {
fetchedAccounts.push(notification.report.target_account);
}
@ -75,7 +71,9 @@ export const fetchNotifications = createDataLoadingThunk(
: excludeAllTypesExcept(activeFilter),
});
},
({ notifications }, { dispatch }) => {
({ notifications, accounts, statuses }, { dispatch }) => {
dispatch(importFetchedAccounts(accounts));
dispatch(importFetchedStatuses(statuses));
dispatchAssociatedRecords(dispatch, notifications);
const payload: (ApiNotificationGroupJSON | NotificationGap)[] =
notifications;
@ -95,7 +93,9 @@ export const fetchNotificationsGap = createDataLoadingThunk(
async (params: { gap: NotificationGap }) =>
apiFetchNotifications({ max_id: params.gap.maxId }),
({ notifications }, { dispatch }) => {
({ notifications, accounts, statuses }, { dispatch }) => {
dispatch(importFetchedAccounts(accounts));
dispatch(importFetchedStatuses(statuses));
dispatchAssociatedRecords(dispatch, notifications);
return { notifications };

View file

@ -1,17 +1,24 @@
import api, { apiRequest, getLinks } from 'mastodon/api';
import type { ApiNotificationGroupJSON } from 'mastodon/api_types/notifications';
import type { ApiNotificationGroupsResultJSON } from 'mastodon/api_types/notifications';
export const apiFetchNotifications = async (params?: {
exclude_types?: string[];
max_id?: string;
}) => {
const response = await api().request<ApiNotificationGroupJSON[]>({
const response = await api().request<ApiNotificationGroupsResultJSON>({
method: 'GET',
url: '/api/v2_alpha/notifications',
params,
});
return { notifications: response.data, links: getLinks(response) };
const { statuses, accounts, notification_groups } = response.data;
return {
statuses,
accounts,
notifications: notification_groups,
links: getLinks(response),
};
};
export const apiClearNotifications = () =>

View file

@ -51,7 +51,7 @@ export interface BaseNotificationGroupJSON {
group_key: string;
notifications_count: number;
type: NotificationType;
sample_accounts: ApiAccountJSON[];
sample_account_ids: string[];
latest_page_notification_at: string; // FIXME: This will only be present if the notification group is returned in a paginated list, not requested directly
most_recent_notification_id: string;
page_min_id?: string;
@ -60,7 +60,7 @@ export interface BaseNotificationGroupJSON {
interface NotificationGroupWithStatusJSON extends BaseNotificationGroupJSON {
type: NotificationWithStatusType;
status: ApiStatusJSON;
status_id: string;
}
interface NotificationWithStatusJSON extends BaseNotificationJSON {
@ -143,3 +143,9 @@ export type ApiNotificationGroupJSON =
| AccountRelationshipSeveranceNotificationGroupJSON
| NotificationGroupWithStatusJSON
| ModerationWarningNotificationGroupJSON;
export interface ApiNotificationGroupsResultJSON {
accounts: ApiAccountJSON[];
statuses: ApiStatusJSON[];
notification_groups: ApiNotificationGroupJSON[];
}

View file

@ -49,21 +49,14 @@ export const FilteredNotificationsBanner: React.FC = () => {
<span>
<FormattedMessage
id='filtered_notifications_banner.pending_requests'
defaultMessage='Notifications from {count, plural, =0 {no one} one {one person} other {# people}} you may know'
defaultMessage='From {count, plural, =0 {no one} one {one person} other {# people}} you may know'
values={{ count: policy.summary.pending_requests_count }}
/>
</span>
</div>
<div className='filtered-notifications-banner__badge'>
<div className='filtered-notifications-banner__badge__badge'>
{toCappedNumber(policy.summary.pending_notifications_count)}
</div>
<FormattedMessage
id='filtered_notifications_banner.mentions'
defaultMessage='{count, plural, one {mention} other {mentions}}'
values={{ count: policy.summary.pending_notifications_count }}
/>
{toCappedNumber(policy.summary.pending_notifications_count)}
</div>
</Link>
);

View file

@ -7,9 +7,9 @@ import { Helmet } from 'react-helmet';
import { useSelector, useDispatch } from 'react-redux';
import DeleteIcon from '@/material-icons/400-24px/delete.svg?react';
import DoneIcon from '@/material-icons/400-24px/done.svg?react';
import InventoryIcon from '@/material-icons/400-24px/inventory_2.svg?react';
import VolumeOffIcon from '@/material-icons/400-24px/volume_off.svg?react';
import { fetchNotificationRequest, fetchNotificationsForRequest, expandNotificationsForRequest, acceptNotificationRequest, dismissNotificationRequest } from 'mastodon/actions/notifications';
import Column from 'mastodon/components/column';
import ColumnHeader from 'mastodon/components/column_header';
@ -101,7 +101,7 @@ export const NotificationRequest = ({ multiColumn, params: { id } }) => {
showBackButton
extraButton={!removed && (
<>
<IconButton className='column-header__button' iconComponent={VolumeOffIcon} onClick={handleDismiss} title={intl.formatMessage(messages.dismiss)} />
<IconButton className='column-header__button' iconComponent={DeleteIcon} onClick={handleDismiss} title={intl.formatMessage(messages.dismiss)} />
<IconButton className='column-header__button' iconComponent={DoneIcon} onClick={handleAccept} title={intl.formatMessage(messages.accept)} />
</>
)}

View file

@ -1,5 +1,6 @@
import { FormattedMessage } from 'react-intl';
import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react';
import ReplyIcon from '@/material-icons/400-24px/reply-fill.svg?react';
import type { StatusVisibility } from 'mastodon/api_types/statuses';
import type { NotificationGroupMention } from 'mastodon/models/notification_group';
@ -39,7 +40,7 @@ export const NotificationMention: React.FC<{
return (
<NotificationWithStatus
type='mention'
icon={ReplyIcon}
icon={statusVisibility === 'direct' ? AlternateEmailIcon : ReplyIcon}
iconId='reply'
accountIds={notification.sampleAccountIds}
count={notification.notifications_count}

View file

@ -300,8 +300,7 @@
"filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
"filter_modal.select_filter.title": "Filter this post",
"filter_modal.title.status": "Filter a post",
"filtered_notifications_banner.mentions": "{count, plural, one {mention} other {mentions}}",
"filtered_notifications_banner.pending_requests": "Notifications from {count, plural, =0 {no one} one {one person} other {# people}} you may know",
"filtered_notifications_banner.pending_requests": "From {count, plural, =0 {no one} one {one person} other {# people}} you may know",
"filtered_notifications_banner.title": "Filtered notifications",
"firehose.all": "All",
"firehose.local": "This server",

View file

@ -1,6 +1,6 @@
{
"about.blocks": "Moderoidut palvelimet",
"about.contact": "Ota yhteys:",
"about.contact": "Yhteydenotto:",
"about.disclaimer": "Mastodon on vapaa avoimen lähdekoodin ohjelmisto ja Mastodon gGmbH:n tavaramerkki.",
"about.domain_blocks.no_reason_available": "Syy ei ole tiedossa",
"about.domain_blocks.preamble": "Mastodonin avulla voidaan yleensä tarkastella minkä tahansa fediversumiin kuuluvan palvelimen sisältöä, ja olla yhteyksissä eri palvelinten käyttäjien kanssa. Nämä poikkeukset koskevat yksin tätä palvelinta.",
@ -45,7 +45,7 @@
"account.joined_short": "Liittynyt",
"account.languages": "Vaihda tilattuja kieliä",
"account.link_verified_on": "Linkin omistus tarkistettiin {date}",
"account.locked_info": "Tilin yksityisyystilaksi on määritetty lukittu ja tilin omistaja arvioi erikseen, kuka voi seurata häntä.",
"account.locked_info": "Tilin yksityisyystilaksi on määritetty lukittu. Tilin omistaja arvioi erikseen, kuka voi seurata häntä.",
"account.media": "Media",
"account.mention": "Mainitse @{name}",
"account.moved_to": "{name} on ilmoittanut uudeksi tilikseen",
@ -119,7 +119,7 @@
"column.blocks": "Estetyt käyttäjät",
"column.bookmarks": "Kirjanmerkit",
"column.community": "Paikallinen aikajana",
"column.direct": "Yksityiset maininnat",
"column.direct": "Yksityismaininnat",
"column.directory": "Selaa profiileja",
"column.domain_blocks": "Estetyt verkkotunnukset",
"column.favourites": "Suosikit",
@ -246,7 +246,7 @@
"emoji_button.objects": "Esineet",
"emoji_button.people": "Ihmiset",
"emoji_button.recent": "Usein käytetyt",
"emoji_button.search": "Etsi...",
"emoji_button.search": "Hae...",
"emoji_button.search_results": "Hakutulokset",
"emoji_button.symbols": "Symbolit",
"emoji_button.travel": "Matkailu ja paikat",
@ -544,13 +544,13 @@
"notifications.permission_denied": "Työpöytäilmoitukset eivät ole käytettävissä, koska selaimen käyttöoikeuspyyntö on aiemmin evätty",
"notifications.permission_denied_alert": "Työpöytäilmoituksia ei voi ottaa käyttöön, koska selaimen käyttöoikeus on aiemmin evätty",
"notifications.permission_required": "Työpöytäilmoitukset eivät ole käytettävissä, koska siihen tarvittavaa käyttöoikeutta ei ole myönnetty.",
"notifications.policy.filter_new_accounts.hint": "Luotu {days, plural, one {viime päivänä} other {viimeisenä # päivänä}}",
"notifications.policy.filter_new_accounts.hint": "Luotu {days, plural, one {viime päivän} other {viimeisen # päivän}} aikana",
"notifications.policy.filter_new_accounts_title": "Uudet tilit",
"notifications.policy.filter_not_followers_hint": "Mukaan lukien alle {days, plural, one {päivän} other {# päivää}} sinua seuranneet",
"notifications.policy.filter_not_followers_title": "Henkilöt, jotka eivät seuraa sinua",
"notifications.policy.filter_not_following_hint": "Kunnes hyväksyt ne manuaalisesti",
"notifications.policy.filter_not_following_hint": "Kunnes hyväksyt heidät manuaalisesti",
"notifications.policy.filter_not_following_title": "Henkilöt, joita et seuraa",
"notifications.policy.filter_private_mentions_hint": "Suodatetaan, ellei se vastaa omaan mainintaasi tai ellet seuraa lähettäjää",
"notifications.policy.filter_private_mentions_hint": "Suodatetaan, ellei se ole vastaus omaan mainintaasi tai ellet seuraa lähettäjää",
"notifications.policy.filter_private_mentions_title": "Ei-toivotut yksityismaininnat",
"notifications.policy.title": "Suodata ilmoitukset pois kohteesta…",
"notifications_permission_banner.enable": "Ota työpöytäilmoitukset käyttöön",
@ -573,8 +573,8 @@
"onboarding.profile.note_hint": "Voit @mainita muita käyttäjiä tai #aihetunnisteita…",
"onboarding.profile.save_and_continue": "Tallenna ja jatka",
"onboarding.profile.title": "Profiilin määritys",
"onboarding.profile.upload_avatar": "Lataa profiilikuva",
"onboarding.profile.upload_header": "Lataa profiilin otsakekuva",
"onboarding.profile.upload_avatar": "Lähetä profiilikuva",
"onboarding.profile.upload_header": "Lähetä profiilin otsakekuva",
"onboarding.share.lead": "Kerro ihmisille, kuinka he voivat löytää sinut Mastodonista!",
"onboarding.share.message": "Olen {username} #Mastodonissa! Seuraa minua osoitteessa {url}",
"onboarding.share.next_steps": "Mahdolliset seuraavat vaiheet:",
@ -614,10 +614,10 @@
"privacy.private.short": "Seuraajat",
"privacy.public.long": "Kuka tahansa Mastodonissa ja sen ulkopuolella",
"privacy.public.short": "Julkinen",
"privacy.unlisted.additional": "Tämä on muutoin kuin julkinen julkaisu, mutta sitä ei näytetä livesyöte-, aihetunniste- tai selailunäkymissä eikä Mastodon-hakutuloksissakaan, vaikka ne olisivat käyttäjätililläsi yleisesti sallittuina.",
"privacy.unlisted.additional": "Tämä toimii muuten kuin julkinen, mutta julkaisut eivät näy livesyöte-, aihetunniste- tai selausnäkymissä eivätkä Mastodonin hakutuloksissa, vaikka ne olisivat käyttäjätililläsi yleisesti sallittuina.",
"privacy.unlisted.long": "Vähemmän algoritmiperusteista sisältöä",
"privacy.unlisted.short": "Vaivihkaisesti julkinen",
"privacy_policy.last_updated": "Viimeksi päivitetty {date}",
"privacy_policy.last_updated": "Päivitetty viimeksi {date}",
"privacy_policy.title": "Tietosuojakäytäntö",
"recommended": "Suositeltu",
"refresh": "Päivitä",
@ -692,7 +692,7 @@
"search.quick_action.account_search": "Profiilit haulla {x}",
"search.quick_action.go_to_account": "Siirry profiiliin {x}",
"search.quick_action.go_to_hashtag": "Siirry aihetunnisteeseen {x}",
"search.quick_action.open_url": "Avaa verkko-osoite Mastodonissa",
"search.quick_action.open_url": "Avaa URL-osoite Mastodonissa",
"search.quick_action.status_search": "Julkaisut haulla {x}",
"search.search_or_paste": "Hae tai liitä URL-osoite",
"search_popout.full_text_search_disabled_message": "Ei saatavilla palvelimella {domain}.",
@ -800,10 +800,10 @@
"units.short.billion": "{count} mrd.",
"units.short.million": "{count} milj.",
"units.short.thousand": "{count} t.",
"upload_area.title": "Lataa raahaamalla ja pudottamalla tähän",
"upload_area.title": "Lähetä raahaamalla ja pudottamalla tähän",
"upload_button.label": "Lisää kuvia, video tai äänitiedosto",
"upload_error.limit": "Tiedostolatauksien rajoitus ylitetty.",
"upload_error.poll": "Tiedostojen lisääminen ei ole sallittua kyselyjen ohessa.",
"upload_error.limit": "Tiedostolähetysten rajoitus ylitetty.",
"upload_error.poll": "Tiedostojen lisääminen äänestysten oheen ei ole sallittua.",
"upload_form.audio_description": "Kuvaile sisältöä kuuroille ja kuulorajoitteisille",
"upload_form.description": "Kuvaile sisältöä sokeille ja näkörajoitteisille",
"upload_form.edit": "Muokkaa",
@ -819,7 +819,7 @@
"upload_modal.hint": "Napsauta tai vedä ympyrä esikatselussa valitaksesi keskipiste, joka näkyy aina pienoiskuvissa.",
"upload_modal.preparing_ocr": "Valmistellaan tekstintunnistusta…",
"upload_modal.preview_label": "Esikatselu ({ratio})",
"upload_progress.label": "Tallennetaan...",
"upload_progress.label": "Lähetetään...",
"upload_progress.processing": "Käsitellään…",
"username.taken": "Tämä käyttäjänimi on jo käytössä. Kokeile toista",
"video.close": "Sulje video",

View file

@ -1,12 +1,12 @@
{
"about.blocks": "服务器被限制",
"about.blocks": "受限服务器",
"about.contact": "联系方式:",
"about.disclaimer": "Mastodon 是自由的开源软件,商标由 Mastodon gGmbH 持有。",
"about.domain_blocks.no_reason_available": "原因不可用",
"about.domain_blocks.preamble": "通常来说,在 Mastodon 上,你可以浏览联邦宇宙中任何一台服务器上的内容,并且和上面的用户互动。但其中一些在本服务器上被设置为例外。",
"about.domain_blocks.silenced.explanation": "除非明确地搜索并关注对方,否则你不会看到来自此服务器的用户信息与内容。",
"about.domain_blocks.silenced.title": "已隐藏",
"about.domain_blocks.suspended.explanation": "此服务器的数据将不会被处理、存储或者交换,本站也将无法和来自此服务器的用户互动或者交流。",
"about.domain_blocks.silenced.title": "访问受限",
"about.domain_blocks.suspended.explanation": "不处理、存储或交换来自本服务器的任何数据,不可能与本服务器上的用户进行任何交互或通信。",
"about.domain_blocks.suspended.title": "已封禁",
"about.not_available": "此信息在当前服务器尚不可用。",
"about.powered_by": "由 {mastodon} 驱动的去中心化社交媒体",
@ -63,7 +63,7 @@
"account.requested_follow": "{name} 已经向你发送了关注请求",
"account.share": "分享 @{name} 的个人资料页",
"account.show_reblogs": "显示来自 @{name} 的转嘟",
"account.statuses_counter": "{count, plural, other {{counter} 嘟文}}",
"account.statuses_counter": "{count, plural, other {{counter} 嘟文}}",
"account.unblock": "取消屏蔽 @{name}",
"account.unblock_domain": "取消屏蔽 {domain} 域名",
"account.unblock_short": "取消屏蔽",
@ -81,7 +81,7 @@
"admin.impact_report.instance_accounts": "将要删除的账户资料",
"admin.impact_report.instance_followers": "本实例用户即将丢失的关注者",
"admin.impact_report.instance_follows": "对方实例用户将会丢失的关注者",
"admin.impact_report.title": "影响摘要",
"admin.impact_report.title": "权重一览",
"alert.rate_limited.message": "请在 {retry_time, time, medium} 后重试。",
"alert.rate_limited.title": "频率受限",
"alert.unexpected.message": "发生了意外错误。",
@ -89,14 +89,14 @@
"announcement.announcement": "公告",
"attachments_list.unprocessed": "(未处理)",
"audio.hide": "隐藏音频",
"block_modal.remote_users_caveat": "我们将要求服务器 {domain} 尊重您的决定。然而,无法保证对方一定遵从,因为某些服务器可能会以不同的方处理屏蔽操作。公开嘟文仍然可能对未登录用户可见。",
"block_modal.show_less": "显示更少",
"block_modal.show_more": "显示更多",
"block_modal.remote_users_caveat": "我们将要求服务器 {domain} 尊重您的决定。然而,我们无法保证对方一定遵从,因为某些服务器可能会以不同的方处理屏蔽操作。公开嘟文仍然可能对未登录用户可见。",
"block_modal.show_less": "隐藏",
"block_modal.show_more": "展开",
"block_modal.they_cant_mention": "他们不能提及或关注你。",
"block_modal.they_cant_see_posts": "他们看不到你的嘟文,你也看不到他们的嘟文。",
"block_modal.they_will_know": "他们可以看到他们被屏蔽。",
"block_modal.title": "屏蔽用户?",
"block_modal.you_wont_see_mentions": "你不会看到提及他们的嘟文。",
"block_modal.they_cant_see_posts": "嘟文将被设置为互相不可见。",
"block_modal.they_will_know": "他们将会获知他们被屏蔽。",
"block_modal.title": "屏蔽用户?",
"block_modal.you_wont_see_mentions": "你将无法看到提及他们的嘟文。",
"boost_modal.combo": "下次按住 {combo} 即可跳过此提示",
"bundle_column_error.copy_stacktrace": "复制错误报告",
"bundle_column_error.error.body": "请求的页面无法渲染,可能是代码出现错误或浏览器存在兼容性问题。",

View file

@ -14,7 +14,7 @@ import type { ApiReportJSON } from 'mastodon/api_types/reports';
export const NOTIFICATIONS_GROUP_MAX_AVATARS = 8;
interface BaseNotificationGroup
extends Omit<BaseNotificationGroupJSON, 'sample_accounts'> {
extends Omit<BaseNotificationGroupJSON, 'sample_account_ids'> {
sampleAccountIds: string[];
}
@ -115,8 +115,7 @@ function createAccountRelationshipSeveranceEventFromJSON(
export function createNotificationGroupFromJSON(
groupJson: ApiNotificationGroupJSON,
): NotificationGroup {
const { sample_accounts, ...group } = groupJson;
const sampleAccountIds = sample_accounts.map((account) => account.id);
const { sample_account_ids: sampleAccountIds, ...group } = groupJson;
switch (group.type) {
case 'favourite':
@ -125,9 +124,9 @@ export function createNotificationGroupFromJSON(
case 'mention':
case 'poll':
case 'update': {
const { status, ...groupWithoutStatus } = group;
const { status_id: statusId, ...groupWithoutStatus } = group;
return {
statusId: status.id,
statusId,
sampleAccountIds,
...groupWithoutStatus,
};

View file

@ -10171,25 +10171,10 @@ noscript {
}
&__badge {
display: flex;
align-items: center;
border-radius: 999px;
background: var(--background-border-color);
color: $darker-text-color;
padding: 4px;
padding-inline-end: 8px;
gap: 6px;
font-weight: 500;
font-size: 11px;
line-height: 16px;
word-break: keep-all;
&__badge {
background: $ui-button-background-color;
color: $white;
border-radius: 100px;
padding: 2px 8px;
}
background: $ui-button-background-color;
color: $white;
border-radius: 100px;
padding: 2px 8px;
}
}

View file

@ -0,0 +1,21 @@
# frozen_string_literal: true
class GroupedNotificationsPresenter < ActiveModelSerializers::Model
def initialize(grouped_notifications)
super()
@grouped_notifications = grouped_notifications
end
def notification_groups
@grouped_notifications
end
def statuses
@grouped_notifications.filter_map(&:target_status).uniq(&:id)
end
def accounts
@grouped_notifications.flat_map(&:sample_accounts).uniq(&:id)
end
end

View file

@ -0,0 +1,7 @@
# frozen_string_literal: true
class REST::DedupNotificationGroupSerializer < ActiveModel::Serializer
has_many :accounts, serializer: REST::AccountSerializer
has_many :statuses, serializer: REST::StatusSerializer
has_many :notification_groups, serializer: REST::NotificationGroupSerializer
end

View file

@ -8,12 +8,20 @@ class REST::NotificationGroupSerializer < ActiveModel::Serializer
attribute :page_max_id, if: :paginated?
attribute :latest_page_notification_at, if: :paginated?
has_many :sample_accounts, serializer: REST::AccountSerializer
belongs_to :target_status, key: :status, if: :status_type?, serializer: REST::StatusSerializer
attribute :sample_account_ids
attribute :status_id, if: :status_type?
belongs_to :report, if: :report_type?, serializer: REST::ReportSerializer
belongs_to :account_relationship_severance_event, key: :event, if: :relationship_severance_event?, serializer: REST::AccountRelationshipSeveranceEventSerializer
belongs_to :account_warning, key: :moderation_warning, if: :moderation_warning_event?, serializer: REST::AccountWarningSerializer
def sample_account_ids
object.sample_accounts.pluck(:id).map(&:to_s)
end
def status_id
object.target_status&.id&.to_s
end
def status_type?
[:favourite, :reblog, :status, :mention, :poll, :update].include?(object.type)
end

View file

@ -885,7 +885,23 @@ ca:
action: Consulta aquí per a més informació
message_html: "<strong>El teu emagatzamatge d'objectes no està ben configurat. La privacitat dels teus usuaris està en risc.</strong>"
tags:
moderation:
not_trendable: No pot ser en tendència
not_usable: No es pot fer servir
pending_review: Pendent de revisió
review_requested: Revisió demanada
reviewed: Revisada
title: Estat
trendable: Pot ser tendència
unreviewed: No revisada
usable: Es pot fer servir
name: Nom
newest: Més nous
oldest: Més vells
reset: Restableix
review: Revisar l'estat
search: Cerca
title: Etiquetes
updated_msg: Ajustaments d'etiquetes actualitzats amb èxit
title: Administració
trends:

View file

@ -642,7 +642,7 @@ es-AR:
report: 'Denuncia #%{id}'
reported_account: Cuenta denunciada
reported_by: Denunciada por
reported_with_application: Informado a través de la aplicación
reported_with_application: Denunciado con aplicación
resolved: Resueltas
resolved_msg: "¡Denuncia exitosamente resuelta!"
skip_to_actions: Ir directamente a las acciones
@ -885,7 +885,23 @@ es-AR:
action: Revisá acá para más información
message_html: "<strong>El almacenamiento de tu objeto está mal configurado. La privacidad de tus usuarios está en riesgo.</strong>"
tags:
moderation:
not_trendable: No disponible para tendencia
not_usable: No disponible para uso
pending_review: Revisión pendiente
review_requested: Revisión solicitada
reviewed: Revisada
title: Estado
trendable: Disponible para tendencia
unreviewed: No revisada
usable: Disponible para uso
name: Nombre
newest: Lo más reciente
oldest: Lo más antiguo
reset: Restablecer
review: Estado de revisión
search: Buscar
title: Etiquetas
updated_msg: La configuración de la etiqueta se actualizó exitosamente
title: Administración
trends:

View file

@ -101,7 +101,7 @@ fi:
most_recent_ip: Viimeisin IP
no_account_selected: Tilejä ei muutettu, koska yhtään ei ollut valittuna
no_limits_imposed: Rajoituksia ei ole asetettu
no_role_assigned: Roolia ei määritetty
no_role_assigned: Roolia ei asetettu
not_subscribed: Ei tilaaja
pending: Odottaa tarkastusta
perform_full_suspension: Jäädytä
@ -173,8 +173,8 @@ fi:
approve_appeal: Hyväksy valitus
approve_user: Hyväksy käyttäjä
assigned_to_self_report: Ota raportti käsiteltäväksi
change_email_user: Vaihda sähköposti käyttäjälle
change_role_user: Muuta käyttäjän roolia
change_email_user: Vaihda käyttäjän sähköpostiosoite
change_role_user: Vaihda käyttäjän roolia
confirm_user: Vahvista käyttäjä
create_account_warning: Luo varoitus
create_announcement: Luo tiedote
@ -231,44 +231,44 @@ fi:
update_user_role: Päivitä rooli
actions:
approve_appeal_html: "%{name} hyväksyi käyttäjän %{target} valituksen moderointipäätöksestä"
approve_user_html: "%{name} hyväksyi käyttäjän rekisteröitymisen kohteesta %{target}"
approve_user_html: "%{name} hyväksyi käyttäjän %{target} rekisteröitymisen"
assigned_to_self_report_html: "%{name} otti raportin %{target} käsiteltäväkseen"
change_email_user_html: "%{name} vaihtoi käyttäjän %{target} sähköpostiosoitteen"
change_role_user_html: "%{name} muutti käyttäjän %{target} roolia"
confirm_user_html: "%{name} vahvisti käyttäjän %{target} sähköpostiosoitteen"
create_account_warning_html: "%{name} lähetti varoituksen käyttäjälle %{target}"
create_announcement_html: "%{name} loi uuden tiedotteen %{target}"
create_canonical_email_block_html: "%{name} esti sähköpostin tiivisteellä %{target}"
create_canonical_email_block_html: "%{name} esti sähköpostiosoitteen tiivisteellä %{target}"
create_custom_emoji_html: "%{name} lähetti uuden emojin %{target}"
create_domain_allow_html: "%{name} salli federoinnin verkkotunnuksen %{target} kanssa"
create_domain_block_html: "%{name} esti verkkotunnuksen %{target}"
create_email_domain_block_html: "%{name} esti sähköpostiverkkotunnuksen %{target}"
create_ip_block_html: "%{name} loi IP-säännön %{target}"
create_ip_block_html: "%{name} loi säännön IP-osoitteelle %{target}"
create_unavailable_domain_html: "%{name} pysäytti toimituksen verkkotunnukseen %{target}"
create_user_role_html: "%{name} loi roolin %{target}"
demote_user_html: "%{name} alensi käyttäjän %{target}"
destroy_announcement_html: "%{name} poisti tiedotteen %{target}"
destroy_canonical_email_block_html: "%{name} kumosi sähköpostin eston tiivisteellä %{target}"
destroy_canonical_email_block_html: "%{name} kumosi sähköpostiosoitteen eston tiivisteellä %{target}"
destroy_custom_emoji_html: "%{name} poisti emojin %{target}"
destroy_domain_allow_html: "%{name} kielsi federoinnin verkkotunnuksen %{target} kanssa"
destroy_domain_block_html: "%{name} kumosi verkkotunnuksen %{target} eston"
destroy_email_domain_block_html: "%{name} kumosi sähköpostiverkkotunnuksen %{target} eston"
destroy_instance_html: "%{name} tyhjensi verkkotunnuksen %{target}"
destroy_ip_block_html: "%{name} poisti IP-säännön %{target}"
destroy_ip_block_html: "%{name} poisti säännön IP-osoitteelta %{target}"
destroy_status_html: "%{name} poisti käyttäjän %{target} julkaisun"
destroy_unavailable_domain_html: "%{name} jatkoi toimitusta verkkotunnukseen %{target}"
destroy_user_role_html: "%{name} poisti roolin %{target}"
disable_2fa_user_html: "%{name} poisti käyttäjältä %{target} vaatimuksen kaksivaiheisen todentamiseen"
disable_custom_emoji_html: "%{name} poisti käytöstä emojin %{target}"
disable_sign_in_token_auth_user_html: "%{name} poisti sähköpostitunnuksella todennuksen käytöstä tililtä %{target}"
disable_user_html: "%{name} poisti kirjautumisen käyttäjältä %{target}"
disable_2fa_user_html: "%{name} poisti käyttäjältä %{target} vaatimuksen kaksivaiheiseen todentamiseen"
disable_custom_emoji_html: "%{name} poisti emojin %{target} käytöstä"
disable_sign_in_token_auth_user_html: "%{name} poisti sähköpostitunnuksella todennuksen käytöstä käyttäjältä %{target}"
disable_user_html: "%{name} poisti kirjautumisen käytöstä käyttäjältä %{target}"
enable_custom_emoji_html: "%{name} otti emojin %{target} käyttöön"
enable_sign_in_token_auth_user_html: "%{name} otti sähköpostitunnuksella todennuksen käyttöön tilille %{target}"
enable_sign_in_token_auth_user_html: "%{name} otti sähköpostitunnuksella todennuksen käyttöön käyttäjälle %{target}"
enable_user_html: "%{name} otti kirjautumisen käyttöön käyttäjälle %{target}"
memorialize_account_html: "%{name} muutti käyttäjän %{target} tilin muistosivuksi"
promote_user_html: "%{name} ylensi käyttäjän %{target}"
reject_appeal_html: "%{name} hylkäsi käyttäjän %{target} valituksen moderointipäätöksestä"
reject_user_html: "%{name} hylkäsi käyttäjän rekisteröitymisen kohteesta %{target}"
reject_user_html: "%{name} hylkäsi käyttäjän %{target} rekisteröitymisen"
remove_avatar_user_html: "%{name} poisti käyttäjän %{target} profiilikuvan"
reopen_report_html: "%{name} avasi uudelleen raportin %{target}"
resend_user_html: "%{name} lähetti vahvistussähköpostiviestin uudelleen käyttäjälle %{target}"
@ -277,7 +277,7 @@ fi:
sensitive_account_html: "%{name} merkitsi käyttäjän %{target} median arkaluonteiseksi"
silence_account_html: "%{name} rajoitti käyttäjän %{target} tiliä"
suspend_account_html: "%{name} jäädytti käyttäjän %{target} tilin"
unassigned_report_html: "%{name} poisti raportin käsittelystä %{target}"
unassigned_report_html: "%{name} poisti raportin %{target} käsittelystä"
unblock_email_account_html: "%{name} kumosi käyttäjän %{target} sähköpostiosoitteen eston"
unsensitive_account_html: "%{name} kumosi käyttäjän %{target} median arkaluonteisuusmerkinnän"
unsilence_account_html: "%{name} kumosi käyttäjän %{target} rajoituksen"
@ -476,15 +476,15 @@ fi:
view_all: Näytä kaikki tarkastuslokit
availability:
description_html:
one: Jos toimitus verkkotunnukseen epäonnistuu <strong>%{count} päivän</strong> ajan, sitä ei yritetä uudelleen ennen kuin verkkotunnuksesta <em>vastaanotetaan</em> toimitus.
other: Jos toimitus verkkotunnukseen epäonnistuu <strong>%{count} päivän</strong> ajan, sitä ei yritetä uudelleen ennen kuin verkkotunnuksesta <em>vastaanotetaan</em> toimitus.
failure_threshold_reached: Epäonnistumisen kynnys saavutettu %{date}.
one: Jos toimitus verkkotunnukseen epäonnistuu <strong>päivän ajan</strong>, sitä ei yritetä uudelleen ennen kuin verkkotunnuksesta <em>vastaanotetaan</em> toimitus.
other: Jos toimitus verkkotunnukseen epäonnistuu <strong>%{count} päivän ajan</strong>, sitä ei yritetä uudelleen ennen kuin verkkotunnuksesta <em>vastaanotetaan</em> toimitus.
failure_threshold_reached: Epäonnistumisten yläraja saavutettu %{date}.
failures_recorded:
one: Epäonnistuneita yrityksiä %{count} päivässä.
other: Epäonnistuneita yrityksiä %{count} päivää.
no_failures_recorded: Ei epäonnistumisia kirjattu.
one: Epäonnistuneita yrityksiä %{count} päivänä.
other: Epäonnistuneita yrityksiä %{count} päivänä.
no_failures_recorded: Epäonnistumisia ei kirjattu.
title: Saatavuus
warning: Viimeisin yritys yhdistää yhteys tähän palvelimeen on epäonnistunut
warning: Viimeisin yritys yhdistää tähän palvelimeen epäonnistui
back_to_all: Kaikki
back_to_limited: Rajoitettu
back_to_warning: Varoitus
@ -492,24 +492,24 @@ fi:
confirm_purge: Haluatko varmasti poistaa pysyvästi tämän verkkotunnuksen tiedot?
content_policies:
comment: Sisäinen muistiinpano
description_html: Voit määrittää sisältökäytännöt, joita sovelletaan kaikkiin tämän verkkotunnuksen ja sen aliverkkotunnuksien tileihin.
description_html: Voit määrittää sisältökäytännöt, joita sovelletaan kaikkiin tämän verkkotunnuksen ja sen aliverkkotunnusten tileihin.
limited_federation_mode_description_html: Voit valita sallitaanko federointi tällä verkkotunnuksella.
policies:
reject_media: Hylkää media
reject_reports: Hylkää raportit
silence: Rajoita
suspend: Jäädytä
policy: Käytänt
policy: Käytäntö
reason: Julkinen syy
title: Sisällön toimintatavat
title: Sisältökäytännöt
dashboard:
instance_accounts_dimension: Seuratuimmat tilit
instance_accounts_measure: tallennetut tilit
instance_followers_measure: seuraajamme siellä
instance_follows_measure: heidän seuraajansa täällä
instance_languages_dimension: Suosituimmat kielet
instance_media_attachments_measure: tallennetut median liitteet
instance_reports_measure: niitä koskevat raportit
instance_media_attachments_measure: tallennetut medialiitteet
instance_reports_measure: heitä koskevat raportit
instance_statuses_measure: tallennetut julkaisut
delivery:
all: Kaikki
@ -520,7 +520,7 @@ fi:
unavailable: Ei saatavilla
delivery_available: Toimitus on saatavilla
delivery_error_days: Toimitusvirheen päivät
delivery_error_hint: Jos toimitus ei ole mahdollista %{count} päivän aikana, se merkitään automaattisesti toimittamattomaksi.
delivery_error_hint: Jos toimitus ei ole mahdollista %{count} päivään, se merkitään automaattisesti toimituskelvottomaksi.
destroyed_msg: Palvelimelta %{domain} peräisin olevat tiedot ovat nyt jonossa poistattaviksi.
empty: Verkkotunnuksia ei löytynyt.
known_accounts:
@ -533,14 +533,14 @@ fi:
private_comment: Yksityinen kommentti
public_comment: Julkinen kommentti
purge: Tyhjennä
purge_description_html: Jos uskot, että tämä verkkotunnus on offline-tilassa tarkoituksella, voit poistaa kaikki verkkotunnuksen tilitietueet ja niihin liittyvät tiedot tallennustilastasi. Tämä voi kestää jonkin aikaa.
purge_description_html: Jos uskot, että tämä verkkotunnus on yhteydettömässä tilassa tarkoituksella, voit poistaa kaikki verkkotunnuksen tilitietueet ja niihin liittyvät tiedot tallennustilastasi. Tämä voi kestää jonkin aikaa.
title: Federointi
total_blocked_by_us: Estämämme
total_followed_by_them: Heidän seuraama
total_followed_by_us: Meidän seuraama
total_reported: Niitä koskevat raportit
total_reported: Heitä koskevat raportit
total_storage: Medialiitteet
totals_time_period_hint_html: Alla näkyvät yhteenlasketut tiedot sisältävät koko ajan.
totals_time_period_hint_html: Seuraavassa näkyvät määrät sisältävät tiedot koko ajalta.
unknown_instance: Tällä palvelimella ei tällä hetkellä ole tähän verkkotunnukseen liittyviä tietueita.
invites:
deactivate_all: Poista kaikki käytöstä
@ -689,7 +689,7 @@ fi:
description_html: "<strong>Käyttäjärooleilla</strong> voit mukauttaa, mihin Mastodonin toimintoihin ja alueisiin käyttäjäsi pääsevät käsiksi."
edit: Muokkaa roolia ”%{name}”
everyone: Oletuskäyttöoikeudet
everyone_full_description_html: Tämä on <strong>perusrooli</strong>, joka vaikuttaa <strong>kaikkiin käyttäjiin</strong>, jopa ilman määrättyä roolia. Kaikki muut roolit perivät sen käyttöoikeudet.
everyone_full_description_html: Tämä on <strong>perusrooli</strong>, joka vaikuttaa <strong>kaikkiin käyttäjiin</strong>, jopa ilman asetettua roolia. Kaikki muut roolit perivät sen käyttöoikeudet.
permissions_count:
one: "%{count} käyttöoikeus"
other: "%{count} käyttöoikeutta"
@ -794,7 +794,7 @@ fi:
federation_authentication: Federoinnin todennuksen valvonta
title: Palvelimen asetukset
site_uploads:
delete: Poista ladattu tiedosto
delete: Poista lähetetty tiedosto
destroyed_msg: Sivustolatauksen poisto onnistui!
software_updates:
critical_update: Kriittinen päivitä viivyttelemättä
@ -851,7 +851,7 @@ fi:
elasticsearch_health_red:
message_html: Elasticsearch-klusteri on vikatilassa (punainen tila), joten hakuominaisuudet eivät ole käytettävissä
elasticsearch_health_yellow:
message_html: Elasticsearch-klusteri on häiriötilassa (keltainen tila), joten suosittelemme tutkimaan syyn
message_html: Elasticsearch-klusteri on vikatilassa (keltainen tila), joten suosittelemme tutkimaan syyn
elasticsearch_index_mismatch:
message_html: Elasticsearch-indeksin sidokset ovat vanhentuneet. Suorita <code>tootctl search deploy --only=%{value}</code>
elasticsearch_preset:
@ -863,10 +863,10 @@ fi:
elasticsearch_reset_chewy:
message_html: Elasticsearch-järjestelmäindeksi on vanhentunut asetusmuutoksen vuoksi. Suorita <code>tootctl search deploy --reset-chewy</code> päivittääksesi sen.
elasticsearch_running_check:
message_html: Ei saatu yhteyttä Elasticsearchiin. Tarkista, että se on käynnissä tai poista kokotekstihaku käytöstä
message_html: Elasticsearchiin ei saatu yhteyttä. Tarkista, että se on käynnissä, tai poista kokotekstihaku käytöstä
elasticsearch_version_check:
message_html: 'Yhteensopimaton Elasticsearch-versio: %{value}'
version_comparison: Elasticsearch %{running_version} on käynnissä, kun %{required_version} vaaditaan
version_comparison: Käynnissä on Elasticsearch %{running_version}, kun vaaditaan %{required_version}
rules_check:
action: Hallitse palvelimen sääntöjä
message_html: Et ole määrittänyt lainkaan palvelimen sääntöjä.
@ -879,11 +879,11 @@ fi:
action: Näytä saatavilla olevat päivitykset
message_html: Mastodonin virhekorjauspäivitys on saatavilla.
upload_check_privacy_error:
action: Katso täältä lisätietoja
message_html: "<strong>Verkkopalvelimesi on määritetty väärin. Käyttäjiesi yksityisyys on vaarassa.</strong>"
action: Katso lisätietoja täältä
message_html: "<strong>Verkkopalvelimesi on määritetty väärin. Käyttäjiesi tietosuoja on vaarassa.</strong>"
upload_check_privacy_error_object_storage:
action: Katso täältä lisätietoja
message_html: "<strong>Objektivarastosi on määritetty virheellisesti, ja käyttäjiesi yksityisyys on vaarassa.</strong>"
action: Katso lisätietoja täältä
message_html: "<strong>Oliovarastosi on määritetty virheellisesti. Käyttäjiesi tietosuoja on vaarassa.</strong>"
tags:
moderation:
not_trendable: Ei trendattava
@ -1070,7 +1070,7 @@ fi:
apply_for_account: Pyydä tiliä
captcha_confirmation:
help_html: Jos kohtaat ongelmia CAPTCHAn ratkaisemisessa, voit pyytää meiltä apua osoitteella %{email}.
hint_html: Vielä yksi juttu! Meidän on vahvistettava, että olet ihminen (tämän avulla pidämme roskapostin poissa!). Ratkaise alla oleva CAPTCHA-vahvistus ja paina "Jatka".
hint_html: Vielä yksi asia! Meidän on vahvistettava, että olet ihminen (tämän avulla pidämme roskapostin poissa!). Ratkaise alla oleva CAPTCHA-vahvistus ja paina ”Jatka”.
title: Turvatarkastus
confirmations:
awaiting_review: Sähköpostiosoitteesi on vahvistettu! Seuraavaksi palvelimen %{domain} ylläpito tarkastaa rekisteröitymisesi, ja saat lopuksi ilmoituksen sähköpostitse, jos tilisi hyväksytään!
@ -1100,7 +1100,7 @@ fi:
migrate_account: Muuta toiseen tiliin
migrate_account_html: Jos haluat ohjata tämän tilin toiseen, voit <a href="%{path}">asettaa toisen tilin tästä</a>.
or_log_in_with: Tai käytä kirjautumiseen
privacy_policy_agreement_html: Olen lukenut ja hyväksynyt <a href="%{privacy_policy_path}" target="_blank">tietosuojakäytännön</a>
privacy_policy_agreement_html: Olen lukenut ja hyväksyn <a href="%{privacy_policy_path}" target="_blank">tietosuojakäytännön</a>
progress:
confirm: Vahvista sähköpostiosoite
details: Omat tietosi
@ -1187,7 +1187,7 @@ fi:
email_contact_html: Jos ei saavu perille, voit pyytää apua sähköpostilla <a href="mailto:%{email}">%{email}</a>
email_reconfirmation_html: Jos et saa vahvistuksen sähköpostia, niin voit <a href="%{path}">pyytää sitä uudelleen</a>
irreversible: Et voi palauttaa tiliäsi tai aktivoida sitä uudelleen
more_details_html: Lisätietoja saat <a href="%{terms_path}">tietosuojakäytännöstämme</a>.
more_details_html: Tarkempia tietoja saat <a href="%{terms_path}">tietosuojakäytännöstämme</a>.
username_available: Käyttäjänimesi tulee saataville uudelleen
username_unavailable: Käyttäjänimesi ei tule saataville enää uudelleen
disputes:
@ -1312,8 +1312,8 @@ fi:
one: "<strong>%{count}</strong> kohde tällä sivulla on valittu."
other: Kaikki <strong>%{count}</strong> kohdetta tällä sivulla on valittu.
all_matching_items_selected_html:
one: "<strong>%{count}</strong> kohde, joka vastaa hakuasi."
other: Kaikki <strong>%{count}</strong> hakuasi vastaavaa kohdetta.
one: "<strong>%{count}</strong> hakuasi vastaava kohde on valittuna."
other: Kaikki <strong>%{count}</strong> hakuasi vastaavat kohteet ovat valittuina.
cancel: Peruuta
changes_saved_msg: Muutosten tallennus onnistui!
confirm: Vahvista
@ -1324,7 +1324,7 @@ fi:
order_by: Järjestys
save_changes: Tallenna muutokset
select_all_matching_items:
one: Valitse %{count} kohde, joka vastaa hakuasi.
one: Valitse %{count} hakuasi vastaava kohde.
other: Valitse kaikki %{count} hakuasi vastaavaa kohdetta.
today: tänään
validation_errors:
@ -1475,7 +1475,7 @@ fi:
followers: Tämä toiminto siirtää kaikki seuraajat nykyisestä tilistä uudelle tilille
only_redirect_html: Vaihtoehtoisesti voit <a href="%{path}">asettaa vain ohjauksen profiiliisi</a>.
other_data: Muita tietoja ei siirretä automaattisesti
redirect: Nykyisen tilisi profiili päivitetään ohjaushuomautuksella ja suljetaan pois hauista
redirect: Nykyisen tilisi profiili päivitetään uudelleenohjaushuomautuksella ja suljetaan pois hauista
moderation:
title: Moderointi
move_handler:
@ -1858,7 +1858,7 @@ fi:
delete_statuses: Joidenkin julkaisuistasi on havaittu rikkovan ainakin yhtä yhteisön sääntöä, joten palvelimen %{instance} moderaattorit ovat poistaneet ne.
disable: Et voi enää käyttää tiliäsi, mutta profiilisi ja muut tiedot pysyvät muuttumattomina. Voit pyytää varmuuskopiota tiedoistasi, vaihtaa tilin asetuksia tai poistaa tilisi.
mark_statuses_as_sensitive: Palvelimen %{instance} moderaattorit ovat merkinneet osan julkaisuistasi arkaluonteisiksi. Tämä tarkoittaa sitä, että ihmisten täytyy napauttaa mediaa ennen kuin sen esikatselu näytetään. Voit merkitä median itse arkaluonteiseksi, kun julkaiset tulevaisuudessa.
sensitive: Tästä lähtien kaikki ladatut mediatiedostot merkitään arkaluonteisiksi ja piilotetaan napsautusvaroituksen taakse.
sensitive: Tästä lähtien kaikki lähetetyt mediatiedostot merkitään arkaluonteisiksi ja piilotetaan napsautusvaroituksen taakse.
silence: Voit edelleen käyttää tiliäsi, mutta vain sinua jo seuraavat käyttäjät näkevät julkaisusi tällä palvelimella ja sinut voidaan sulkea pois eri löytämisominaisuuksista. Toiset voivat kuitenkin edelleen seurata sinua manuaalisesti.
suspend: Et voi enää käyttää tiliäsi, eivätkä profiilisi ja muut tiedot ole enää käytettävissä. Voit silti kirjautua sisään pyytääksesi tietojesi varmuuskopiota, kunnes tiedot on poistettu kokonaan noin 30 päivän kuluttua. Säilytämme kuitenkin joitain perustietoja, jotka estävät sinua kiertämästä jäädytystä.
reason: 'Syy:'

View file

@ -40,6 +40,23 @@ hi:
upload_check_privacy_error_object_storage:
action: अधिक जानकारी हेतु यहां क्लिक करें।
message_html: "<strong> आपके वेब सर्वर का कन्फिगरेशन सही नहीं है। उपयोगकर्ताओं की निजता खतरे में है। </strong>"
tags:
moderation:
not_trendable: ट्रेंड नहीं किया जाएगा
not_usable: उपयोगी नहीं
pending_review: लंबित समीक्षा
review_requested: समीक्षा की मांग की गई
reviewed: समीक्षित
title: स्टेटस
trendable: चर्चा में
unreviewed: गैर समीक्षित
usable: उपयुक्त
name: नाम
newest: नवीनतम
oldest: सबसे पुराने
reset: पुनः नियत करें
search: खोजें
title: हैशटैग
redirects:
prompt: अगर आपको इस लिंक पर भरोसा है तो आगे बढ़ने के लिए इसे क्लिक करें
title: आप इस %{instance} को छोड़ने वाले हैं

View file

@ -885,7 +885,23 @@ it:
action: Controlla qui per maggiori informazioni
message_html: "<strong>La tua archiviazione oggetti è mal configurata. La privacy dei tuoi utenti è a rischio.</strong>"
tags:
moderation:
not_trendable: Non di tendenza
not_usable: Non utilizzabile
pending_review: In attesa di revisione
review_requested: Revisione richiesta
reviewed: Controllato
title: Stato
trendable: Di tendenza
unreviewed: Non revisionato
usable: Utilizzabile
name: Nome
newest: Più recenti
oldest: Più vecchio
reset: Ripristina
review: Esamina status
search: Cerca
title: Hashtag
updated_msg: Impostazioni hashtag aggiornate con successo
title: Amministrazione
trends:

View file

@ -885,7 +885,23 @@ pt-PT:
action: Verifique aqui para mais informações
message_html: "<strong>O seu armazenamento de objetos está mal configurado. A privacidade dos seus utilizadores está em risco.</strong>"
tags:
moderation:
not_trendable: Não pode ser tendência
not_usable: Não utilizável
pending_review: Pendente de revisão
review_requested: Revisão solicitada
reviewed: Revista
title: Estado
trendable: Pode ser tendência
unreviewed: Não revista
usable: Utilizável
name: Nome
newest: Mais recente
oldest: Mais antiga
reset: Repor
review: Estado da revisão
search: Pesquisar
title: Hashtags
updated_msg: 'Definições de #etiquetas correctamente actualizadas'
title: Administração
trends:

View file

@ -314,6 +314,7 @@ ca:
listable: Permet que aquesta etiqueta aparegui en les cerques i en el directori de perfils
name: Etiqueta
trendable: Permet que aquesta etiqueta aparegui en les tendències
usable: Permet a les publicacions emprar aquesta etiqueta localment
user:
role: Rol
time_zone: Zona horària

View file

@ -314,6 +314,7 @@ es-AR:
listable: Permitir que esta etiqueta aparezca en las búsquedas y en las sugerencias
name: Etiqueta
trendable: Permitir que esta etiqueta aparezca bajo tendencias
usable: Permitir que los mensajes usen esta etiqueta localmente
user:
role: Rol
time_zone: Zona horaria

View file

@ -77,13 +77,13 @@ fi:
warn: Piilota suodatettu sisältö varoituksen taakse, jossa mainitaan suodattimen nimi
form_admin_settings:
activity_api_enabled: Paikallisesti julkaistujen julkaisujen, aktiivisten käyttäjien ja rekisteröitymisten viikoittainen määrä
app_icon: WEBP, PNG, GIF tai JPG. Korvaa oletusarvoisen mobiililaitteiden sovelluskuvakkeen omalla kuvakkeella.
app_icon: WEBP, PNG, GIF tai JPG. Korvaa oletusarvoisen mobiililaitteiden sovelluskuvakkeen haluamallasi kuvakkeella.
backups_retention_period: Käyttäjillä on mahdollisuus arkistoida julkaisujaan myöhemmin ladattaviksi. Kun kentän arvo on positiivinen, nämä arkistot poistuvat automaattisesti, kun määritetty määrä päiviä on kulunut.
bootstrap_timeline_accounts: Nämä tilit kiinnitetään uusien käyttäjien seurantasuositusten alkuun.
closed_registrations_message: Näkyy, kun rekisteröityminen on suljettu
content_cache_retention_period: Kaikki muiden palvelinten julkaisut (mukaan lukien tehostukset ja vastaukset) poistuvat, kun määritetty määrä päiviä on kulunut, lukuun ottamatta paikallisen käyttäjän vuorovaikutusta näiden julkaisujen kanssa. Tämä sisältää julkaisut, jotka paikallinen käyttäjä on merkinnyt kirjanmerkiksi tai suosikiksi. Myös yksityismaininnat eri palvelinten käyttäjien välillä menetetään, eikä niitä voi palauttaa. Tämä asetus on tarkoitettu käytettäväksi erityistapauksissa ja rikkoo monia käyttäjien odotuksia, kun sitä sovelletaan yleiskäyttöön.
custom_css: Voit käyttää mukautettuja tyylejä Mastodonin selainversiossa.
favicon: WEBP, PNG, GIF tai JPG. Korvaa oletusarvoisen Mastodonin sivustokuvakkeen (favicon) haluamallasi kuvakkeella.
favicon: WEBP, PNG, GIF tai JPG. Korvaa oletusarvoisen Mastodonin sivustokuvakkeen haluamallasi kuvakkeella.
mascot: Ohittaa kuvituksen edistyneessä selainkäyttöliittymässä.
media_cache_retention_period: Etäkäyttäjien tekemien julkaisujen mediatiedostot ovat välimuistissa palvelimellasi. Kun kentän arvo on positiivinen, media poistuu, kun määritetty määrä päiviä on kulunut. Jos mediaa pyydetään sen poistamisen jälkeen, se ladataan uudelleen, jos lähdesisältö on vielä saatavilla. Koska linkkien esikatselun kyselyitä kolmansien osapuolien sivustoille on rajoitettu, on suositeltavaa asettaa tämä arvo vähintään 14 päivään, tai linkkien kortteja ei päivitetä pyynnöstä ennen tätä ajankohtaa.
peers_api_enabled: Luettelo verkkotunnuksista, jotka tämä palvelin on kohdannut fediversumissa. Se ei kerro, federoitko tietyn palvelimen kanssa, vaan että palvelimesi on ylipäätään tietoinen siitä. Tätä tietoa käytetään palveluissa, jotka keräävät tilastoja federoinnista yleisellä tasolla.
@ -109,14 +109,14 @@ fi:
invite_request:
text: Tämä auttaa meitä arvioimaan hakemustasi
ip_block:
comment: Valinnainen. Muista miksi lisäsit tämän säännön.
comment: Valinnainen. Muista, miksi lisäsit tämän säännön.
expires_in: IP-osoitteet ovat rajallinen resurssi joskus niitä jaetaan eteenpäin, ja ne vaihtavat usein omistajaa. Niinpä epämääräisiä IP-lohkoja ei suositella.
ip: Kirjoita IPv4- tai IPv6-osoite. Voit estää kokonaisia IP-osoitealueita CIDR-syntaksin avulla. Varo lukitsemasta itseäsi ulos!
severities:
no_access: Estä pääsy kaikkiin resursseihin
sign_up_block: Uudet rekisteröitymiset eivät ole mahdollisia
sign_up_requires_approval: Uudet rekisteröitymiset edellyttävät hyväksyntääsi
severity: Valitse, mitä tapahtuu tämän IP-osoitteen pyynnöille
severity: Valitse, mitä tapahtuu tästä IP-osoitteesta tuleville pyynnöille
rule:
hint: Vapaaehtoinen. Anna yksityiskohtaisempia tietoja säännöstä
text: Kuvaile sääntöä tai edellytystä palvelimesi käyttäjille. Suosi tiivistä, yksinkertaista ilmaisua
@ -249,7 +249,7 @@ fi:
closed_registrations_message: Mukautettu viesti, kun rekisteröityminen ei ole saatavilla
content_cache_retention_period: Etäsisällön säilytysaika
custom_css: Mukautettu CSS
favicon: Suosikkikuvake
favicon: Sivustokuvake
mascot: Mukautettu maskotti (vanhentunut)
media_cache_retention_period: Mediasisällön välimuistin säilytysaika
peers_api_enabled: Julkaise löydettyjen palvelinten luettelo ohjelmointirajapinnassa

View file

@ -1 +1,6 @@
---
hi:
simple_form:
labels:
tag:
usable: पोस्ट को ये हैशटैग स्थानीय उपयोग करने दें

View file

@ -314,6 +314,7 @@ it:
listable: Permetti a questo hashtag di apparire nella directory dei profili
name: Hashtag
trendable: Permetti a questo hashtag di apparire nelle tendenze
usable: Permetti ai post di utilizzare questo hashtag localmente
user:
role: Ruolo
time_zone: Fuso orario

View file

@ -314,6 +314,7 @@ pt-PT:
listable: Permitir que esta etiqueta apareça em pesquisas e no diretório de perfis
name: Etiqueta
trendable: Permitir que esta etiqueta apareça em alta
usable: Permitir que as publicações usem esta hashtag localmente
user:
role: Cargo
time_zone: Fuso horário

View file

@ -203,6 +203,7 @@ ru:
setting_default_privacy: Видимость постов
setting_default_sensitive: Всегда отмечать медиафайлы как «деликатного характера»
setting_delete_modal: Всегда спрашивать перед удалении поста
setting_disable_hover_cards: Отключить предпросмотр профиля при наведении
setting_disable_swiping: Отключить анимацию смахивания
setting_display_media: Отображение медиафайлов
setting_display_media_default: По умолчанию

View file

@ -314,6 +314,7 @@ sq:
listable: Lejoje këtë hashtag të shfaqet në kërkime dhe në drejtori profilesh
name: Hashtag
trendable: Lejoje këtë hashtag të shfaqet në prirje
usable: Lejoji postimet të përdorin lokalisht këtë hashtag
user:
role: Rol
time_zone: Zonë kohore

View file

@ -314,6 +314,7 @@ vi:
listable: Cho phép xuất hiện trong tìm kiếm và đề xuất
name: Hashtag
trendable: Cho phép hashtag này lên xu hướng
usable: Cho phép dùng hashtag này khi soạn tút
user:
role: Vai trò
time_zone: Múi giờ

View file

@ -314,6 +314,7 @@ zh-CN:
listable: 允许这个话题标签在用户目录中显示
name: 话题标签
trendable: 允许在热门下显示此话题
usable: 允许本站嘟文使用此话题标签
user:
role: 角色
time_zone: 时区

View file

@ -880,7 +880,21 @@ sq:
action: Për më tepër hollësi, shihni këtu
message_html: "<strong>Depozita juaj e objekteve është e formësuar keq. Privatësia e përdoruesve tuaj është në rrezik.</strong>"
tags:
moderation:
not_usable: Të papërdorshme
pending_review: Në pritje të shqyrtimit
review_requested: U kërkua shqyrtim
reviewed: Shqyrtuar
title: Gjendje
unreviewed: Të pashqyrtuar
usable: Të përdorshëm
name: Emër
newest: Më të rejat
oldest: Më të vjetrat
reset: Riktheje te parazgjedhjet
review: Gjendje rishikimi
search: Kërkim
title: Hashtag-ë
updated_msg: Rregullimet për hashtag-ët u përditësuan me sukses
title: Administrim
trends:

View file

@ -885,7 +885,12 @@ sv:
action: Kolla här för mer information
message_html: "<strong>Din objektlagring är felkonfigurerad. Sekretessen för dina användare är i riskzonen.</strong>"
tags:
moderation:
title: Status
name: Namn
reset: Återställ
review: Granskningsstatus
search: Sök
updated_msg: Hashtagg-inställningarna har uppdaterats
title: Administration
trends:

View file

@ -871,7 +871,23 @@ vi:
action: Nhấn vào đây để biết thêm thông tin
message_html: "<strong>Lưu trữ đối tượng của bạn bị cấu hình sai. Có nguy cơ ảnh hưởng bảo mật của người dùng.</strong>"
tags:
moderation:
not_trendable: Không xu hướng
not_usable: Không được dùng
pending_review: Chờ duyệt
review_requested: Yêu cầu duyệt
reviewed: Đã duyệt
title: Trạng thái
trendable: Có thể xu hướng
unreviewed: Chưa duyệt
usable: Có thể dùng
name: Tên
newest: Mới nhất
oldest: Cũ nhất
reset: Đặt lại
review: Phê duyệt
search: Tìm kiếm
title: Hashtag
updated_msg: Hashtag đã được cập nhật thành công
title: Quản trị
trends:

View file

@ -871,7 +871,23 @@ zh-CN:
action: 点击这里查看更多信息
message_html: "<strong>您的对象存储空间配置错误,您用户的隐私处于危险中。</strong>"
tags:
moderation:
not_trendable: 不在趋势中显示
not_usable: 不可用
pending_review: 待审核
review_requested: 已请求审核
reviewed: 已审核
title: 状态
trendable: 可在趋势中显示
unreviewed: 未审核
usable: 可用
name: 名称
newest: 最新
oldest: 最早
reset: 重置
review: 审核状态
search: 搜索
title: 话题标签
updated_msg: 话题标签设置更新成功
title: 管理
trends:

View file

@ -65,7 +65,7 @@ module Mastodon
end
def user_agent
@user_agent ||= "#{HTTP::Request::USER_AGENT} (Mastodon/#{Version}; +http#{Rails.configuration.x.use_https ? 's' : ''}://#{Rails.configuration.x.web_domain}/)"
@user_agent ||= "Mastodon/#{Version} (#{HTTP::Request::USER_AGENT}; +http#{Rails.configuration.x.use_https ? 's' : ''}://#{Rails.configuration.x.web_domain}/)"
end
end
end

View file

@ -135,7 +135,7 @@ RSpec.describe 'Notifications' do
expect(response).to have_http_status(200)
expect(body_json_types.uniq).to eq ['mention']
expect(body_as_json[0][:page_min_id]).to_not be_nil
expect(body_as_json.dig(:notification_groups, 0, :page_min_id)).to_not be_nil
end
end
@ -147,7 +147,7 @@ RSpec.describe 'Notifications' do
notifications = user.account.notifications
expect(body_as_json.size)
expect(body_as_json[:notification_groups].size)
.to eq(params[:limit])
expect(response)
@ -161,7 +161,7 @@ RSpec.describe 'Notifications' do
end
def body_json_types
body_as_json.pluck(:type)
body_as_json[:notification_groups].pluck(:type)
end
end