From 1ee879a5ad095d23e844c1f849729705ede2c720 Mon Sep 17 00:00:00 2001 From: Soapbox Bot Date: Fri, 20 Oct 2023 00:07:16 +0000 Subject: [PATCH 001/115] Update Node.js to v21 --- .gitlab-ci.yml | 2 +- Dockerfile | 2 +- Dockerfile.dev | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index dbc2c6b3a..a70cded64 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,4 @@ -image: node:20 +image: node:21 variables: NODE_ENV: test diff --git a/Dockerfile b/Dockerfile index 2765f2053..fa790e7ad 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:20 as build +FROM node:21 as build WORKDIR /app COPY package.json . COPY yarn.lock . diff --git a/Dockerfile.dev b/Dockerfile.dev index 1e6056945..bb15e6d86 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -1,4 +1,4 @@ -FROM node:20 +FROM node:21 RUN apt-get update &&\ apt-get install -y inotify-tools &&\ From dd9a4dc6c4c024175d3a3dd7e32c5ef6f66e0fe3 Mon Sep 17 00:00:00 2001 From: Soapbox Bot Date: Fri, 27 Oct 2023 03:05:20 +0000 Subject: [PATCH 002/115] Update docker Docker tag to v24.0.7 --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index dbc2c6b3a..87389f7c4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -111,9 +111,9 @@ pages: docker: stage: deploy - image: docker:24.0.6 + image: docker:24.0.7 services: - - docker:24.0.6-dind + - docker:24.0.7-dind tags: - dind # https://medium.com/devops-with-valentine/how-to-build-a-docker-image-and-push-it-to-the-gitlab-container-registry-from-a-gitlab-ci-pipeline-acac0d1f26df From 68f66075f244d3bc6b34aa2b16aec78c9f08b219 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Fri, 27 Oct 2023 17:27:49 +0200 Subject: [PATCH 003/115] Hide hashtag follow toggle when unauthenticated MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- src/features/hashtag-timeline/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/features/hashtag-timeline/index.tsx b/src/features/hashtag-timeline/index.tsx index f5c21b5b9..27d8212ea 100644 --- a/src/features/hashtag-timeline/index.tsx +++ b/src/features/hashtag-timeline/index.tsx @@ -7,7 +7,7 @@ import { useHashtagStream } from 'soapbox/api/hooks'; import List, { ListItem } from 'soapbox/components/list'; import { Column, Toggle } from 'soapbox/components/ui'; import Timeline from 'soapbox/features/ui/components/timeline'; -import { useAppDispatch, useAppSelector, useFeatures } from 'soapbox/hooks'; +import { useAppDispatch, useAppSelector, useFeatures, useLoggedIn } from 'soapbox/hooks'; interface IHashtagTimeline { params?: { @@ -22,7 +22,7 @@ export const HashtagTimeline: React.FC = ({ params }) => { const dispatch = useAppDispatch(); const tag = useAppSelector((state) => state.tags.get(id)); const next = useAppSelector(state => state.timelines.get(`hashtag:${id}`)?.next); - + const { isLoggedIn } = useLoggedIn(); const handleLoadMore = (maxId: string) => { dispatch(expandHashtagTimeline(id, { url: next, maxId })); @@ -50,7 +50,7 @@ export const HashtagTimeline: React.FC = ({ params }) => { return ( - {features.followHashtags && ( + {features.followHashtags && isLoggedIn && ( } From b31df6dcfb3252553552b75b8f0e5bac23f23389 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sun, 29 Oct 2023 00:21:28 +0200 Subject: [PATCH 004/115] Support Iceshrimp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- src/utils/features.ts | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/utils/features.ts b/src/utils/features.ts index b7dadd51b..96f91f9c0 100644 --- a/src/utils/features.ts +++ b/src/utils/features.ts @@ -14,24 +14,30 @@ const overrides = custom('features'); /** Truthy array convenience function */ const any = (arr: Array): boolean => arr.some(Boolean); -/** - * Firefish, a fork of Misskey. Formerly known as Calckey. - * @see {@link https://joinfirefish.org/} - */ -export const FIREFISH = 'Firefish'; - /** * Ditto, a Nostr server with Mastodon API. * @see {@link https://gitlab.com/soapbox-pub/ditto} */ export const DITTO = 'Ditto'; +/** + * Firefish, a fork of Misskey. Formerly known as Calckey. + * @see {@link https://joinfirefish.org/} + */ +export const FIREFISH = 'Firefish'; + /** * Friendica, decentralized social platform implementing multiple federation protocols. * @see {@link https://friendi.ca/} */ export const FRIENDICA = 'Friendica'; +/** + * Iceshrimp, yet another Misskey fork. + * @see {@link https://iceshrimp.dev/} + */ +export const ICESHRIMP = 'Iceshrimp'; + /** * Mastodon, the software upon which this is all based. * @see {@link https://joinmastodon.org/} @@ -143,6 +149,7 @@ const getInstanceFeatures = (instance: Instance) => { */ accountLookup: any([ v.software === FIREFISH, + v.software === ICESHRIMP, v.software === MASTODON && gte(v.compatVersion, '3.4.0'), v.software === PLEROMA && gte(v.version, '2.4.50'), v.software === TAKAHE && gte(v.version, '0.6.1'), @@ -192,6 +199,7 @@ const getInstanceFeatures = (instance: Instance) => { * @see {@link https://docs.joinmastodon.org/methods/announcements/} */ announcements: any([ + v.software === ICESHRIMP, v.software === MASTODON && gte(v.compatVersion, '3.1.0'), v.software === PLEROMA && gte(v.version, '2.2.49'), v.software === TAKAHE && gte(v.version, '0.7.0'), @@ -230,6 +238,7 @@ const getInstanceFeatures = (instance: Instance) => { */ bookmarks: any([ v.software === FIREFISH, + v.software === ICESHRIMP, v.software === FRIENDICA, v.software === MASTODON && gte(v.compatVersion, '3.1.0'), v.software === PLEROMA && gte(v.version, '0.9.9'), @@ -319,6 +328,7 @@ const getInstanceFeatures = (instance: Instance) => { */ conversations: any([ v.software === FIREFISH, + v.software === ICESHRIMP, v.software === FRIENDICA, v.software === MASTODON && gte(v.compatVersion, '2.6.0'), v.software === PLEROMA && gte(v.version, '0.9.9'), @@ -359,6 +369,7 @@ const getInstanceFeatures = (instance: Instance) => { editProfile: any([ v.software === FIREFISH, v.software === FRIENDICA, + v.software === ICESHRIMP, v.software === MASTODON, v.software === MITRA, v.software === PIXELFED, @@ -374,6 +385,7 @@ const getInstanceFeatures = (instance: Instance) => { */ editStatuses: any([ v.software === FRIENDICA && gte(v.version, '2022.12.0'), + v.software === ICESHRIMP, v.software === MASTODON && gte(v.version, '3.5.0'), v.software === TAKAHE && gte(v.version, '0.8.0'), features.includes('editing'), @@ -444,6 +456,7 @@ const getInstanceFeatures = (instance: Instance) => { exposableReactions: any([ v.software === FIREFISH, v.software === FRIENDICA, + v.software === ICESHRIMP, v.software === MASTODON, v.software === TAKAHE && gte(v.version, '0.6.1'), v.software === TRUTHSOCIAL, @@ -628,6 +641,7 @@ const getInstanceFeatures = (instance: Instance) => { lists: any([ v.software === FIREFISH, v.software === FRIENDICA, + v.software === ICESHRIMP, v.software === MASTODON && gte(v.compatVersion, '2.1.0'), v.software === PLEROMA && gte(v.version, '0.9.9'), ]), @@ -683,6 +697,7 @@ const getInstanceFeatures = (instance: Instance) => { * @see PUT /api/v1/accounts/:id/mute */ mutesDuration: any([ + v.software === ICESHRIMP, v.software === PLEROMA && gte(v.version, '2.3.0'), v.software === MASTODON && gte(v.compatVersion, '3.3.0'), v.software === TAKAHE, @@ -715,6 +730,7 @@ const getInstanceFeatures = (instance: Instance) => { * @see GET /api/v1/notifications */ notificationsIncludeTypes: any([ + v.software === ICESHRIMP, v.software === MASTODON && gte(v.compatVersion, '3.5.0'), v.software === PLEROMA && gte(v.version, '2.4.50'), v.software === TAKAHE && gte(v.version, '0.6.2'), @@ -739,6 +755,7 @@ const getInstanceFeatures = (instance: Instance) => { */ polls: any([ v.software === FIREFISH, + v.software === ICESHRIMP, v.software === MASTODON && gte(v.version, '2.8.0'), v.software === PLEROMA, v.software === TAKAHE && gte(v.version, '0.8.0'), @@ -779,6 +796,7 @@ const getInstanceFeatures = (instance: Instance) => { publicTimeline: any([ v.software === FIREFISH, v.software === FRIENDICA, + v.software === ICESHRIMP, v.software === MASTODON, v.software === PLEROMA, v.software === TAKAHE, @@ -864,6 +882,7 @@ const getInstanceFeatures = (instance: Instance) => { * @see POST /api/v2/search */ searchFromAccount: any([ + v.software === ICESHRIMP, v.software === MASTODON && gte(v.version, '2.8.0'), v.software === PLEROMA && gte(v.version, '1.0.0'), ]), @@ -917,6 +936,7 @@ const getInstanceFeatures = (instance: Instance) => { */ suggestionsV2: any([ v.software === FRIENDICA, + v.software === ICESHRIMP, v.software === MASTODON && gte(v.compatVersion, '3.4.0'), v.software === TRUTHSOCIAL, features.includes('v2_suggestions'), @@ -933,6 +953,7 @@ const getInstanceFeatures = (instance: Instance) => { * @see GET /api/v1/trends/statuses */ trendingStatuses: any([ + v.software === ICESHRIMP, v.software === FRIENDICA && gte(v.version, '2022.12.0'), v.software === MASTODON && gte(v.compatVersion, '3.5.0'), ]), @@ -943,6 +964,7 @@ const getInstanceFeatures = (instance: Instance) => { */ trends: any([ v.software === FRIENDICA && gte(v.version, '2022.12.0'), + v.software === ICESHRIMP, v.software === MASTODON && gte(v.compatVersion, '3.0.0'), v.software === TRUTHSOCIAL, v.software === DITTO, From 1d3424e648bd24ce6bb0bfc483b7eec402bbaccb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sun, 29 Oct 2023 23:00:48 +0100 Subject: [PATCH 005/115] Display emoji reactions on glitch-soc and Iceshrimp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- src/actions/emoji-reacts.ts | 12 +-- src/components/status-action-bar.tsx | 9 +- src/components/status-action-button.tsx | 6 +- src/components/status-reaction-wrapper.tsx | 2 +- .../components/status-interaction-bar.tsx | 18 ++-- src/normalizers/status.ts | 18 +++- src/reducers/statuses.ts | 4 +- src/schemas/instance.ts | 3 + src/schemas/status.ts | 6 +- src/utils/emoji-reacts.test.ts | 64 ++++++-------- src/utils/emoji-reacts.ts | 83 ++++++------------- src/utils/features.ts | 7 ++ 12 files changed, 103 insertions(+), 129 deletions(-) diff --git a/src/actions/emoji-reacts.ts b/src/actions/emoji-reacts.ts index 764ed0139..1e8991824 100644 --- a/src/actions/emoji-reacts.ts +++ b/src/actions/emoji-reacts.ts @@ -1,4 +1,4 @@ -import { Map as ImmutableMap, List as ImmutableList } from 'immutable'; +import { List as ImmutableList } from 'immutable'; import { isLoggedIn } from 'soapbox/utils/auth'; @@ -8,7 +8,7 @@ import { importFetchedAccounts, importFetchedStatus } from './importer'; import { favourite, unfavourite } from './interactions'; import type { AppDispatch, RootState } from 'soapbox/store'; -import type { APIEntity, Status } from 'soapbox/types/entities'; +import type { APIEntity, EmojiReaction, Status } from 'soapbox/types/entities'; const EMOJI_REACT_REQUEST = 'EMOJI_REACT_REQUEST'; const EMOJI_REACT_SUCCESS = 'EMOJI_REACT_SUCCESS'; @@ -26,17 +26,17 @@ const noOp = () => () => new Promise(f => f(undefined)); const simpleEmojiReact = (status: Status, emoji: string, custom?: string) => (dispatch: AppDispatch) => { - const emojiReacts: ImmutableList> = status.pleroma.get('emoji_reactions') || ImmutableList(); + const emojiReacts: ImmutableList = status.reactions || ImmutableList(); if (emoji === '👍' && status.favourited) return dispatch(unfavourite(status)); - const undo = emojiReacts.filter(e => e.get('me') === true && e.get('name') === emoji).count() > 0; + const undo = emojiReacts.filter(e => e.me === true && e.name === emoji).count() > 0; if (undo) return dispatch(unEmojiReact(status, emoji)); return Promise.all([ ...emojiReacts - .filter((emojiReact) => emojiReact.get('me') === true) - .map(emojiReact => dispatch(unEmojiReact(status, emojiReact.get('name')))).toArray(), + .filter((emojiReact) => emojiReact.me === true) + .map(emojiReact => dispatch(unEmojiReact(status, emojiReact.name))).toArray(), status.favourited && dispatch(unfavourite(status)), ]).then(() => { if (emoji === '👍') { diff --git a/src/components/status-action-bar.tsx b/src/components/status-action-bar.tsx index aad3c1f82..b07550ed7 100644 --- a/src/components/status-action-bar.tsx +++ b/src/components/status-action-bar.tsx @@ -1,4 +1,3 @@ -import { List as ImmutableList } from 'immutable'; import React from 'react'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { useHistory, useRouteMatch } from 'react-router-dom'; @@ -626,15 +625,15 @@ const StatusActionBar: React.FC = ({ const reblogCount = status.reblogs_count; const favouriteCount = status.favourites_count; - const emojiReactCount = reduceEmoji( - (status.pleroma.get('emoji_reactions') || ImmutableList()) as ImmutableList, + const emojiReactCount = status.reactions ? reduceEmoji( + status.reactions, favouriteCount, status.favourited, allowedEmoji, - ).reduce((acc, cur) => acc + cur.get('count'), 0); + ).reduce((acc, cur) => acc + (cur.count || 0), 0) : undefined; const meEmojiReact = getReactForStatus(status, allowedEmoji); - const meEmojiName = meEmojiReact?.get('name') as keyof typeof reactMessages | undefined; + const meEmojiName = meEmojiReact?.name as keyof typeof reactMessages | undefined; const reactMessages = { '👍': messages.reactionLike, diff --git a/src/components/status-action-button.tsx b/src/components/status-action-button.tsx index 3dfe61939..aa87502ca 100644 --- a/src/components/status-action-button.tsx +++ b/src/components/status-action-button.tsx @@ -4,7 +4,7 @@ import React from 'react'; import { Text, Icon, Emoji } from 'soapbox/components/ui'; import { shortNumberFormat } from 'soapbox/utils/numbers'; -import type { Map as ImmutableMap } from 'immutable'; +import type { EmojiReaction } from 'soapbox/schemas'; const COLORS = { accent: 'accent', @@ -33,7 +33,7 @@ interface IStatusActionButton extends React.ButtonHTMLAttributes; + emoji?: EmojiReaction; text?: React.ReactNode; theme?: 'default' | 'inverse'; } @@ -45,7 +45,7 @@ const StatusActionButton = React.forwardRef - + ); } else { diff --git a/src/components/status-reaction-wrapper.tsx b/src/components/status-reaction-wrapper.tsx index f8e6129d1..c1d1224de 100644 --- a/src/components/status-reaction-wrapper.tsx +++ b/src/components/status-reaction-wrapper.tsx @@ -71,7 +71,7 @@ const StatusReactionWrapper: React.FC = ({ statusId, chi }; const handleClick: React.EventHandler = e => { - const meEmojiReact = getReactForStatus(status, soapboxConfig.allowedEmoji)?.get('name') || '👍'; + const meEmojiReact = getReactForStatus(status, soapboxConfig.allowedEmoji)?.name || '👍'; if (isUserTouching()) { if (ownAccount) { diff --git a/src/features/status/components/status-interaction-bar.tsx b/src/features/status/components/status-interaction-bar.tsx index 295d0f170..2e1809a22 100644 --- a/src/features/status/components/status-interaction-bar.tsx +++ b/src/features/status/components/status-interaction-bar.tsx @@ -1,6 +1,4 @@ -import clsx from 'clsx'; -import { List as ImmutableList } from 'immutable'; -import React from 'react'; +import clsx from 'clsx';import React from 'react'; import { FormattedMessage } from 'react-intl'; import { Link } from 'react-router-dom'; @@ -59,7 +57,7 @@ const StatusInteractionBar: React.FC = ({ status }): JSX. const getNormalizedReacts = () => { return reduceEmoji( - ImmutableList(status.pleroma.get('emoji_reactions') as any), + status.reactions, status.favourites_count, status.favourited, allowedEmoji, @@ -164,20 +162,22 @@ const StatusInteractionBar: React.FC = ({ status }): JSX. const getEmojiReacts = () => { const emojiReacts = getNormalizedReacts(); const count = emojiReacts.reduce((acc, cur) => ( - acc + cur.get('count') + acc + (cur.count || 0) ), 0); + const handleClick = features.emojiReacts ? handleOpenReactionsModal : handleOpenFavouritesModal; + if (count) { return ( - + {emojiReacts.take(3).map((e, i) => { return ( ); })} @@ -193,7 +193,7 @@ const StatusInteractionBar: React.FC = ({ status }): JSX. {getReposts()} {getQuotes()} - {features.emojiReacts ? getEmojiReacts() : getFavourites()} + {(features.emojiReacts || features.emojiReactsMastodon) ? getEmojiReacts() : getFavourites()} {getDislikes()} ); diff --git a/src/normalizers/status.ts b/src/normalizers/status.ts index ff1cb26aa..e621f210b 100644 --- a/src/normalizers/status.ts +++ b/src/normalizers/status.ts @@ -13,10 +13,10 @@ import { import { normalizeAttachment } from 'soapbox/normalizers/attachment'; import { normalizeEmoji } from 'soapbox/normalizers/emoji'; import { normalizeMention } from 'soapbox/normalizers/mention'; -import { accountSchema, cardSchema, groupSchema, pollSchema, tombstoneSchema } from 'soapbox/schemas'; +import { accountSchema, cardSchema, emojiReactionSchema, groupSchema, pollSchema, tombstoneSchema } from 'soapbox/schemas'; import { maybeFromJS } from 'soapbox/utils/normalizers'; -import type { Account, Attachment, Card, Emoji, Group, Mention, Poll, EmbeddedEntity } from 'soapbox/types/entities'; +import type { Account, Attachment, Card, Emoji, Group, Mention, Poll, EmbeddedEntity, EmojiReaction } from 'soapbox/types/entities'; export type StatusApprovalStatus = 'pending' | 'approval' | 'rejected'; export type StatusVisibility = 'public' | 'unlisted' | 'private' | 'direct' | 'self' | 'group'; @@ -69,6 +69,7 @@ export const StatusRecord = ImmutableRecord({ poll: null as EmbeddedEntity, quote: null as EmbeddedEntity, quotes_count: 0, + reactions: null as ImmutableList | null, reblog: null as EmbeddedEntity, reblogged: false, reblogs_count: 0, @@ -104,8 +105,8 @@ const normalizeMentions = (status: ImmutableMap) => { }); }; -// Normalize emojis -const normalizeEmojis = (entity: ImmutableMap) => { +// Normalize emoji reactions +const normalizeReactions = (entity: ImmutableMap) => { return entity.update('emojis', ImmutableList(), emojis => { return emojis.map(normalizeEmoji); }); @@ -218,6 +219,14 @@ const normalizeEvent = (status: ImmutableMap) => { } }; +// Normalize emojis +const normalizeEmojis = (status: ImmutableMap) => { + const reactions = status.getIn(['pleroma', 'emoji_reactions'], status.get('reactions')) as ImmutableList>; + if (reactions) { + status.set('reactions', ImmutableList(reactions.map(((reaction: ImmutableMap) => emojiReactionSchema.parse(reaction.toJS()))))); + } +}; + /** Rewrite `

` to empty string. */ const fixContent = (status: ImmutableMap) => { if (status.get('content') === '

') { @@ -275,6 +284,7 @@ export const normalizeStatus = (status: Record) => { fixQuote(status); fixSensitivity(status); normalizeEvent(status); + normalizeReactions(status); fixContent(status); normalizeFilterResults(status); normalizeDislikes(status); diff --git a/src/reducers/statuses.ts b/src/reducers/statuses.ts index a2f8941ad..37d7ec2ad 100644 --- a/src/reducers/statuses.ts +++ b/src/reducers/statuses.ts @@ -274,13 +274,13 @@ export default function statuses(state = initialState, action: AnyAction): State case EMOJI_REACT_REQUEST: return state .updateIn( - [action.status.id, 'pleroma', 'emoji_reactions'], + [action.status.id, 'reactions'], emojiReacts => simulateEmojiReact(emojiReacts as any, action.emoji, action.custom), ); case UNEMOJI_REACT_REQUEST: return state .updateIn( - [action.status.id, 'pleroma', 'emoji_reactions'], + [action.status.id, 'reactions'], emojiReacts => simulateUnEmojiReact(emojiReacts as any, action.emoji), ); case FAVOURITE_FAIL: diff --git a/src/schemas/instance.ts b/src/schemas/instance.ts index 4e55a7456..ee647c678 100644 --- a/src/schemas/instance.ts +++ b/src/schemas/instance.ts @@ -49,6 +49,9 @@ const configurationSchema = coerceObject({ max_options: z.number().optional().catch(undefined), min_expiration: z.number().optional().catch(undefined), }), + reactions: coerceObject({ + max_reactions: z.number().catch(0), + }), statuses: coerceObject({ max_characters: z.number().optional().catch(undefined), max_media_attachments: z.number().optional().catch(undefined), diff --git a/src/schemas/status.ts b/src/schemas/status.ts index 01169dcf1..cf66e4e3d 100644 --- a/src/schemas/status.ts +++ b/src/schemas/status.ts @@ -19,7 +19,6 @@ import { contentSchema, dateSchema, filteredArray, makeCustomEmojiMap } from './ import type { Resolve } from 'soapbox/utils/types'; const statusPleromaSchema = z.object({ - emoji_reactions: filteredArray(emojiReactionSchema), event: eventSchema.nullish().catch(undefined), quote: z.literal(null).catch(null), quote_visible: z.boolean().catch(true), @@ -51,6 +50,7 @@ const baseStatusSchema = z.object({ muted: z.coerce.boolean(), pinned: z.coerce.boolean(), pleroma: statusPleromaSchema.optional().catch(undefined), + reactions: filteredArray(emojiReactionSchema), poll: pollSchema.nullable().catch(null), quote: z.literal(null).catch(null), quotes_count: z.number().catch(0), @@ -131,16 +131,18 @@ const statusSchema = baseStatusSchema.extend({ reblog: embeddedStatusSchema, pleroma: statusPleromaSchema.extend({ quote: embeddedStatusSchema, + emoji_reactions: filteredArray(emojiReactionSchema), }).optional().catch(undefined), }).transform(({ pleroma, ...status }) => { return { ...status, event: pleroma?.event, quote: pleroma?.quote || status.quote || null, + reactions: pleroma?.emoji_reactions || status.reactions || null, // There's apparently no better way to do this... // Just trying to remove the `event` and `quote` keys from the object. pleroma: pleroma ? (() => { - const { event, quote, ...rest } = pleroma; + const { event, quote, emoji_reactions, ...rest } = pleroma; return rest; })() : undefined, }; diff --git a/src/utils/emoji-reacts.test.ts b/src/utils/emoji-reacts.test.ts index 38660fa13..af2c5c34b 100644 --- a/src/utils/emoji-reacts.test.ts +++ b/src/utils/emoji-reacts.test.ts @@ -1,11 +1,11 @@ -import { List as ImmutableList, Map as ImmutableMap, fromJS } from 'immutable'; +import { List as ImmutableList, fromJS } from 'immutable'; import { normalizeStatus } from 'soapbox/normalizers'; +import { emojiReactionSchema } from 'soapbox/schemas'; import { sortEmoji, mergeEmojiFavourites, - oneEmojiPerAccount, reduceEmoji, getReactForStatus, simulateEmojiReact, @@ -23,7 +23,7 @@ const ALLOWED_EMOJI = ImmutableList([ describe('sortEmoji', () => { describe('with an unsorted list of emoji', () => { - const emojiReacts = fromJS([ + const emojiReacts = ImmutableList([ { 'count': 7, 'me': true, 'name': '😃' }, { 'count': 7, 'me': true, 'name': '😯' }, { 'count': 3, 'me': true, 'name': '😢' }, @@ -31,7 +31,7 @@ describe('sortEmoji', () => { { 'count': 20, 'me': true, 'name': '👍' }, { 'count': 7, 'me': true, 'name': '😂' }, { 'count': 15, 'me': true, 'name': '❤' }, - ]) as ImmutableList>; + ].map((react) => emojiReactionSchema.parse(react))); it('sorts the emoji by count', () => { expect(sortEmoji(emojiReacts, ALLOWED_EMOJI)).toEqual(fromJS([ { 'count': 20, 'me': true, 'name': '👍' }, @@ -51,11 +51,11 @@ describe('mergeEmojiFavourites', () => { const favourited = true; describe('with existing 👍 reacts', () => { - const emojiReacts = fromJS([ + const emojiReacts = ImmutableList([ { 'count': 20, 'me': false, 'name': '👍', 'url': undefined }, { 'count': 15, 'me': false, 'name': '❤', 'url': undefined }, { 'count': 7, 'me': false, 'name': '😯', 'url': undefined }, - ]) as ImmutableList>; + ].map((react) => emojiReactionSchema.parse(react))); it('combines 👍 reacts with favourites', () => { expect(mergeEmojiFavourites(emojiReacts, favouritesCount, favourited)).toEqual(fromJS([ { 'count': 32, 'me': true, 'name': '👍', 'url': undefined }, @@ -66,10 +66,10 @@ describe('mergeEmojiFavourites', () => { }); describe('without existing 👍 reacts', () => { - const emojiReacts = fromJS([ + const emojiReacts = ImmutableList([ { 'count': 15, 'me': false, 'name': '❤' }, { 'count': 7, 'me': false, 'name': '😯' }, - ]) as ImmutableList>; + ].map((react) => emojiReactionSchema.parse(react))); it('adds 👍 reacts to the map equaling favourite count', () => { expect(mergeEmojiFavourites(emojiReacts, favouritesCount, favourited)).toEqual(fromJS([ { 'count': 15, 'me': false, 'name': '❤' }, @@ -88,7 +88,7 @@ describe('mergeEmojiFavourites', () => { describe('reduceEmoji', () => { describe('with a clusterfuck of emoji', () => { - const emojiReacts = fromJS([ + const emojiReacts = ImmutableList([ { 'count': 1, 'me': false, 'name': '😡' }, { 'count': 1, 'me': true, 'name': '🔪' }, { 'count': 7, 'me': true, 'name': '😯' }, @@ -99,7 +99,7 @@ describe('reduceEmoji', () => { { 'count': 15, 'me': true, 'name': '❤' }, { 'count': 1, 'me': false, 'name': '👀' }, { 'count': 1, 'me': false, 'name': '🍩' }, - ]) as ImmutableList>; + ].map((react) => emojiReactionSchema.parse(react))); it('sorts, filters, and combines emoji and favourites', () => { expect(reduceEmoji(emojiReacts, 7, true, ALLOWED_EMOJI)).toEqual(fromJS([ { 'count': 27, 'me': true, 'name': '👍' }, @@ -117,22 +117,6 @@ describe('reduceEmoji', () => { }); }); -describe('oneEmojiPerAccount', () => { - it('reduces to one react per account', () => { - const emojiReacts = fromJS([ - // Sorted - { 'count': 2, 'me': true, 'name': '👍', accounts: [{ id: '1' }, { id: '2' }] }, - { 'count': 2, 'me': true, 'name': '❤', accounts: [{ id: '1' }, { id: '2' }] }, - { 'count': 1, 'me': true, 'name': '😯', accounts: [{ id: '1' }] }, - { 'count': 1, 'me': false, 'name': '😂', accounts: [{ id: '3' }] }, - ]) as ImmutableList>; - expect(oneEmojiPerAccount(emojiReacts, '1')).toEqual(fromJS([ - { 'count': 2, 'me': true, 'name': '👍', accounts: [{ id: '1' }, { id: '2' }] }, - { 'count': 1, 'me': false, 'name': '😂', accounts: [{ id: '3' }] }, - ])); - }); -}); - describe('getReactForStatus', () => { it('returns a single owned react (including favourite) for the status', () => { const status = normalizeStatus(fromJS({ @@ -146,12 +130,12 @@ describe('getReactForStatus', () => { ], }, })); - expect(getReactForStatus(status, ALLOWED_EMOJI)?.get('name')).toEqual('❤'); + expect(getReactForStatus(status, ALLOWED_EMOJI)?.name).toEqual('❤'); }); it('returns a thumbs-up for a favourite', () => { const status = normalizeStatus(fromJS({ favourites_count: 1, favourited: true })); - expect(getReactForStatus(status)?.get('name')).toEqual('👍'); + expect(getReactForStatus(status)?.name).toEqual('👍'); }); it('returns undefined when a status has no reacts (or favourites)', () => { @@ -172,10 +156,10 @@ describe('getReactForStatus', () => { describe('simulateEmojiReact', () => { it('adds the emoji to the list', () => { - const emojiReacts = fromJS([ + const emojiReacts = ImmutableList([ { 'count': 2, 'me': false, 'name': '👍', 'url': undefined }, { 'count': 2, 'me': false, 'name': '❤', 'url': undefined }, - ]) as ImmutableList>; + ].map((react) => emojiReactionSchema.parse(react))); expect(simulateEmojiReact(emojiReacts, '❤')).toEqual(fromJS([ { 'count': 2, 'me': false, 'name': '👍', 'url': undefined }, { 'count': 3, 'me': true, 'name': '❤', 'url': undefined }, @@ -183,10 +167,10 @@ describe('simulateEmojiReact', () => { }); it('creates the emoji if it didn\'t already exist', () => { - const emojiReacts = fromJS([ + const emojiReacts = ImmutableList([ { 'count': 2, 'me': false, 'name': '👍', 'url': undefined }, { 'count': 2, 'me': false, 'name': '❤', 'url': undefined }, - ]) as ImmutableList>; + ].map((react) => emojiReactionSchema.parse(react))); expect(simulateEmojiReact(emojiReacts, '😯')).toEqual(fromJS([ { 'count': 2, 'me': false, 'name': '👍', 'url': undefined }, { 'count': 2, 'me': false, 'name': '❤', 'url': undefined }, @@ -195,10 +179,10 @@ describe('simulateEmojiReact', () => { }); it('adds a custom emoji to the list', () => { - const emojiReacts = fromJS([ + const emojiReacts = ImmutableList([ { 'count': 2, 'me': false, 'name': '👍', 'url': undefined }, { 'count': 2, 'me': false, 'name': '❤', 'url': undefined }, - ]) as ImmutableList>; + ].map((react) => emojiReactionSchema.parse(react))); expect(simulateEmojiReact(emojiReacts, 'soapbox', 'https://gleasonator.com/emoji/Gleasonator/soapbox.png')).toEqual(fromJS([ { 'count': 2, 'me': false, 'name': '👍', 'url': undefined }, { 'count': 2, 'me': false, 'name': '❤', 'url': undefined }, @@ -209,10 +193,10 @@ describe('simulateEmojiReact', () => { describe('simulateUnEmojiReact', () => { it('removes the emoji from the list', () => { - const emojiReacts = fromJS([ + const emojiReacts = ImmutableList([ { 'count': 2, 'me': false, 'name': '👍' }, { 'count': 3, 'me': true, 'name': '❤' }, - ]) as ImmutableList>; + ].map((react) => emojiReactionSchema.parse(react))); expect(simulateUnEmojiReact(emojiReacts, '❤')).toEqual(fromJS([ { 'count': 2, 'me': false, 'name': '👍' }, { 'count': 2, 'me': false, 'name': '❤' }, @@ -220,11 +204,11 @@ describe('simulateUnEmojiReact', () => { }); it('removes the emoji if it\'s the last one in the list', () => { - const emojiReacts = fromJS([ + const emojiReacts = ImmutableList([ { 'count': 2, 'me': false, 'name': '👍' }, { 'count': 2, 'me': false, 'name': '❤' }, { 'count': 1, 'me': true, 'name': '😯' }, - ]) as ImmutableList>; + ].map((react) => emojiReactionSchema.parse(react))); expect(simulateUnEmojiReact(emojiReacts, '😯')).toEqual(fromJS([ { 'count': 2, 'me': false, 'name': '👍' }, { 'count': 2, 'me': false, 'name': '❤' }, @@ -232,11 +216,11 @@ describe('simulateUnEmojiReact', () => { }); it ('removes custom emoji from the list', () => { - const emojiReacts = fromJS([ + const emojiReacts = ImmutableList([ { 'count': 2, 'me': false, 'name': '👍' }, { 'count': 2, 'me': false, 'name': '❤' }, { 'count': 1, 'me': true, 'name': 'soapbox', 'url': 'https://gleasonator.com/emoji/Gleasonator/soapbox.png' }, - ]) as ImmutableList>; + ].map((react) => emojiReactionSchema.parse(react))); expect(simulateUnEmojiReact(emojiReacts, 'soapbox')).toEqual(fromJS([ { 'count': 2, 'me': false, 'name': '👍' }, { 'count': 2, 'me': false, 'name': '❤' }, diff --git a/src/utils/emoji-reacts.ts b/src/utils/emoji-reacts.ts index 2fa83906b..559644bd7 100644 --- a/src/utils/emoji-reacts.ts +++ b/src/utils/emoji-reacts.ts @@ -1,9 +1,6 @@ -import { - Map as ImmutableMap, - List as ImmutableList, -} from 'immutable'; +import { List as ImmutableList } from 'immutable'; -import type { Me } from 'soapbox/types/soapbox'; +import { EmojiReaction, emojiReactionSchema } from 'soapbox/schemas'; // https://emojipedia.org/facebook // I've customized them. @@ -16,18 +13,16 @@ export const ALLOWED_EMOJI = ImmutableList([ '😩', ]); -type Account = ImmutableMap; -type EmojiReact = ImmutableMap; - -export const sortEmoji = (emojiReacts: ImmutableList, allowedEmoji: ImmutableList): ImmutableList => ( +export const sortEmoji = (emojiReacts: ImmutableList, allowedEmoji: ImmutableList): ImmutableList => ( emojiReacts .sortBy(emojiReact => - -(emojiReact.get('count') + Number(allowedEmoji.includes(emojiReact.get('name'))))) + -((emojiReact.count || 0) + Number(allowedEmoji.includes(emojiReact.name)))) ); -export const mergeEmojiFavourites = (emojiReacts = ImmutableList(), favouritesCount: number, favourited: boolean) => { +export const mergeEmojiFavourites = (emojiReacts: ImmutableList | null, favouritesCount: number, favourited: boolean) => { + if (!emojiReacts) return ImmutableList([emojiReactionSchema.parse({ count: favouritesCount, me: favourited, name: '👍' })]); if (!favouritesCount) return emojiReacts; - const likeIndex = emojiReacts.findIndex(emojiReact => emojiReact.get('name') === '👍'); + const likeIndex = emojiReacts.findIndex(emojiReact => emojiReact.name === '👍'); if (likeIndex > -1) { const likeCount = Number(emojiReacts.getIn([likeIndex, 'count'])); favourited = favourited || Boolean(emojiReacts.getIn([likeIndex, 'me'], false)); @@ -35,69 +30,43 @@ export const mergeEmojiFavourites = (emojiReacts = ImmutableList(), .setIn([likeIndex, 'count'], likeCount + favouritesCount) .setIn([likeIndex, 'me'], favourited); } else { - return emojiReacts.push(ImmutableMap({ count: favouritesCount, me: favourited, name: '👍' })); + return emojiReacts.push(emojiReactionSchema.parse({ count: favouritesCount, me: favourited, name: '👍' })); } }; -const hasMultiReactions = (emojiReacts: ImmutableList, account: Account): boolean => ( - emojiReacts.filter( - e => e.get('accounts').filter( - (a: Account) => a.get('id') === account.get('id'), - ).count() > 0, - ).count() > 1 -); - -const inAccounts = (accounts: ImmutableList, id: string): boolean => ( - accounts.filter(a => a.get('id') === id).count() > 0 -); - -export const oneEmojiPerAccount = (emojiReacts: ImmutableList, me: Me) => { - emojiReacts = emojiReacts.reverse(); - - return emojiReacts.reduce((acc, cur, idx) => { - const accounts = cur.get('accounts', ImmutableList()) - .filter((a: Account) => !hasMultiReactions(acc, a)); - - return acc.set(idx, cur.merge({ - accounts: accounts, - count: accounts.count(), - me: me ? inAccounts(accounts, me) : false, - })); - }, emojiReacts) - .filter(e => e.get('count') > 0) - .reverse(); -}; - -export const reduceEmoji = (emojiReacts: ImmutableList, favouritesCount: number, favourited: boolean, allowedEmoji = ALLOWED_EMOJI): ImmutableList => ( +export const reduceEmoji = (emojiReacts: ImmutableList | null, favouritesCount: number, favourited: boolean, allowedEmoji = ALLOWED_EMOJI): ImmutableList => ( sortEmoji( mergeEmojiFavourites(emojiReacts, favouritesCount, favourited), allowedEmoji, )); -export const getReactForStatus = (status: any, allowedEmoji = ALLOWED_EMOJI): EmojiReact | undefined => { +export const getReactForStatus = (status: any, allowedEmoji = ALLOWED_EMOJI): EmojiReaction | undefined => { + if (!status.reactions) return; + const result = reduceEmoji( - status.pleroma.get('emoji_reactions', ImmutableList()), + status.reactions, status.favourites_count || 0, status.favourited, allowedEmoji, - ).filter(e => e.get('me') === true) + ).filter(e => e.me === true) .get(0); - return typeof result?.get('name') === 'string' ? result : undefined; + return typeof result?.name === 'string' ? result : undefined; }; -export const simulateEmojiReact = (emojiReacts: ImmutableList, emoji: string, url?: string) => { - const idx = emojiReacts.findIndex(e => e.get('name') === emoji); +export const simulateEmojiReact = (emojiReacts: ImmutableList, emoji: string, url?: string) => { + const idx = emojiReacts.findIndex(e => e.name === emoji); const emojiReact = emojiReacts.get(idx); if (idx > -1 && emojiReact) { - return emojiReacts.set(idx, emojiReact.merge({ - count: emojiReact.get('count') + 1, + return emojiReacts.set(idx, emojiReactionSchema.parse({ + ...emojiReact, + count: (emojiReact.count || 0) + 1, me: true, url, })); } else { - return emojiReacts.push(ImmutableMap({ + return emojiReacts.push(emojiReactionSchema.parse({ count: 1, me: true, name: emoji, @@ -106,17 +75,17 @@ export const simulateEmojiReact = (emojiReacts: ImmutableList, emoji } }; -export const simulateUnEmojiReact = (emojiReacts: ImmutableList, emoji: string) => { +export const simulateUnEmojiReact = (emojiReacts: ImmutableList, emoji: string) => { const idx = emojiReacts.findIndex(e => - e.get('name') === emoji && e.get('me') === true); + e.name === emoji && e.me === true); const emojiReact = emojiReacts.get(idx); if (emojiReact) { - const newCount = emojiReact.get('count') - 1; + const newCount = (emojiReact.count || 1) - 1; if (newCount < 1) return emojiReacts.delete(idx); - return emojiReacts.set(idx, emojiReact.merge({ - count: emojiReact.get('count') - 1, + return emojiReacts.set(idx, emojiReactionSchema.parse({ + count: (emojiReact.count || 1) - 1, me: false, })); } else { diff --git a/src/utils/features.ts b/src/utils/features.ts index 96f91f9c0..d2aa11b2b 100644 --- a/src/utils/features.ts +++ b/src/utils/features.ts @@ -418,6 +418,13 @@ const getInstanceFeatures = (instance: Instance) => { */ emojiReacts: v.software === PLEROMA && gte(v.version, '2.0.0'), + /** + * Ability to add emoji reactions to a status available in Mastodon forks. + * @see POST /v1/statuses/:id/react/:emoji + * @see POST /v1/statuses/:id/unreact/:emoji + */ + emojiReactsMastodon: instance.configuration.reactions.max_reactions > 0, + /** * The backend allows only non-RGI ("Recommended for General Interchange") emoji reactions. * @see PUT /api/v1/pleroma/statuses/:id/reactions/:emoji From af41877a4e09f93624810664de50bc62e782af90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Tue, 31 Oct 2023 20:13:55 +0100 Subject: [PATCH 006/115] Always display poll option title MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- src/components/polls/poll-option.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/polls/poll-option.tsx b/src/components/polls/poll-option.tsx index f27a81e64..760945ff9 100644 --- a/src/components/polls/poll-option.tsx +++ b/src/components/polls/poll-option.tsx @@ -122,7 +122,7 @@ const PollOption: React.FC = (props): JSX.Element | null => { return (
{showResults ? ( -
+
Date: Wed, 1 Nov 2023 23:30:32 +0100 Subject: [PATCH 007/115] Fix federation modal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- src/actions/mrf.ts | 8 ++++---- .../ui/components/modals/edit-federation-modal.tsx | 11 ++++++----- src/utils/config-db.ts | 8 ++++---- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/actions/mrf.ts b/src/actions/mrf.ts index 359d7711f..509bdb8fc 100644 --- a/src/actions/mrf.ts +++ b/src/actions/mrf.ts @@ -1,4 +1,4 @@ -import { Map as ImmutableMap, Set as ImmutableSet } from 'immutable'; +import { Set as ImmutableSet } from 'immutable'; import ConfigDB from 'soapbox/utils/config-db'; @@ -7,9 +7,9 @@ import { fetchConfig, updateConfig } from './admin'; import type { MRFSimple } from 'soapbox/schemas/pleroma'; import type { AppDispatch, RootState } from 'soapbox/store'; -const simplePolicyMerge = (simplePolicy: MRFSimple, host: string, restrictions: ImmutableMap) => { +const simplePolicyMerge = (simplePolicy: MRFSimple, host: string, restrictions: Record) => { const entries = Object.entries(simplePolicy).map(([key, hosts]) => { - const isRestricted = restrictions.get(key); + const isRestricted = restrictions[key]; if (isRestricted) { return [key, ImmutableSet(hosts).add(host).toJS()]; @@ -21,7 +21,7 @@ const simplePolicyMerge = (simplePolicy: MRFSimple, host: string, restrictions: return Object.fromEntries(entries); }; -const updateMrf = (host: string, restrictions: ImmutableMap) => +const updateMrf = (host: string, restrictions: Record) => (dispatch: AppDispatch, getState: () => RootState) => dispatch(fetchConfig()) .then(() => { diff --git a/src/features/ui/components/modals/edit-federation-modal.tsx b/src/features/ui/components/modals/edit-federation-modal.tsx index 4b102e8ef..646439612 100644 --- a/src/features/ui/components/modals/edit-federation-modal.tsx +++ b/src/features/ui/components/modals/edit-federation-modal.tsx @@ -30,24 +30,25 @@ const EditFederationModal: React.FC = ({ host, onClose }) const getRemoteInstance = useCallback(makeGetRemoteInstance(), []); const remoteInstance = useAppSelector(state => getRemoteInstance(state, host)); - const [data, setData] = useState({} as any); + const [data, setData] = useState>({}); useEffect(() => { - setData(remoteInstance.get('federation')); + setData(remoteInstance.get('federation') as Record); }, [remoteInstance]); const handleDataChange = (key: string): React.ChangeEventHandler => { return ({ target }) => { - setData(data.set(key, target.checked)); + setData({ ...data, [key]: target.checked }); }; }; const handleMediaRemoval: React.ChangeEventHandler = ({ target: { checked } }) => { - const newData = data.merge({ + const newData = { + ...data, avatar_removal: checked, banner_removal: checked, media_removal: checked, - }); + }; setData(newData); }; diff --git a/src/utils/config-db.ts b/src/utils/config-db.ts index 5faf18163..4dbf3c163 100644 --- a/src/utils/config-db.ts +++ b/src/utils/config-db.ts @@ -9,7 +9,7 @@ import trimStart from 'lodash/trimStart'; import { type MRFSimple, mrfSimpleSchema } from 'soapbox/schemas/pleroma'; export type Config = ImmutableMap; -export type Policy = ImmutableMap; +export type Policy = Record; const find = ( configs: ImmutableList, @@ -40,15 +40,15 @@ const toSimplePolicy = (configs: ImmutableList): MRFSimple => { }; const fromSimplePolicy = (simplePolicy: Policy): ImmutableList => { - const mapper = (hosts: ImmutableList, key: string) => fromJS({ tuple: [`:${key}`, hosts.toJS()] }); + const mapper = ([key, hosts]: [key: string, hosts: ImmutableList]) => fromJS({ tuple: [`:${key}`, hosts] }); - const value = simplePolicy.map(mapper).toList(); + const value = Object.entries(simplePolicy).map(mapper); return ImmutableList([ ImmutableMap({ group: ':pleroma', key: ':mrf_simple', - value, + value: ImmutableList(value), }), ]); }; From f77aa7b4112982a2580feef9fd38e8e13e3945f2 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 13 Nov 2023 16:11:40 -0600 Subject: [PATCH 008/115] Fix parsing custom emoji reactions Fixes https://gitlab.com/soapbox-pub/soapbox/-/issues/1602 --- src/normalizers/status.ts | 9 ++++++--- src/schemas/emoji-reaction.ts | 17 ++++++++++++----- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/normalizers/status.ts b/src/normalizers/status.ts index e621f210b..9ae7933bc 100644 --- a/src/normalizers/status.ts +++ b/src/normalizers/status.ts @@ -14,6 +14,7 @@ import { normalizeAttachment } from 'soapbox/normalizers/attachment'; import { normalizeEmoji } from 'soapbox/normalizers/emoji'; import { normalizeMention } from 'soapbox/normalizers/mention'; import { accountSchema, cardSchema, emojiReactionSchema, groupSchema, pollSchema, tombstoneSchema } from 'soapbox/schemas'; +import { filteredArray } from 'soapbox/schemas/utils'; import { maybeFromJS } from 'soapbox/utils/normalizers'; import type { Account, Attachment, Card, Emoji, Group, Mention, Poll, EmbeddedEntity, EmojiReaction } from 'soapbox/types/entities'; @@ -219,11 +220,13 @@ const normalizeEvent = (status: ImmutableMap) => { } }; -// Normalize emojis +/** Normalize emojis. */ const normalizeEmojis = (status: ImmutableMap) => { - const reactions = status.getIn(['pleroma', 'emoji_reactions'], status.get('reactions')) as ImmutableList>; + const data = ImmutableList>(status.getIn(['pleroma', 'emoji_reactions']) || status.get('reactions')); + const reactions = filteredArray(emojiReactionSchema).parse(data.toJS()); + if (reactions) { - status.set('reactions', ImmutableList(reactions.map(((reaction: ImmutableMap) => emojiReactionSchema.parse(reaction.toJS()))))); + status.set('reactions', ImmutableList(reactions)); } }; diff --git a/src/schemas/emoji-reaction.ts b/src/schemas/emoji-reaction.ts index 56998c625..5f31658b1 100644 --- a/src/schemas/emoji-reaction.ts +++ b/src/schemas/emoji-reaction.ts @@ -2,15 +2,22 @@ import { z } from 'zod'; import { emojiSchema } from './utils'; -/** Pleroma emoji reaction. */ -const emojiReactionSchema = z.object({ - name: emojiSchema, +const baseEmojiReactionSchema = z.object({ count: z.number().nullable().catch(null), me: z.boolean().catch(false), - /** Akkoma custom emoji reaction. */ - url: z.string().url().optional().catch(undefined), + name: emojiSchema, + url: z.literal(undefined).catch(undefined), }); +const customEmojiReactionSchema = baseEmojiReactionSchema.extend({ + name: z.string(), + /** Akkoma custom emoji reaction. */ + url: z.string().url(), +}); + +/** Pleroma emoji reaction. */ +const emojiReactionSchema = baseEmojiReactionSchema.or(customEmojiReactionSchema); + type EmojiReaction = z.infer; export { emojiReactionSchema, type EmojiReaction }; \ No newline at end of file From 9154b638926e40a1b7632ee8be8a827dfc31adb3 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 14 Nov 2023 01:41:45 -0600 Subject: [PATCH 009/115] Fix emoji unreact Fixes https://gitlab.com/soapbox-pub/soapbox/-/issues/1616 --- src/utils/emoji-reacts.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/emoji-reacts.ts b/src/utils/emoji-reacts.ts index 559644bd7..8bbdc07b1 100644 --- a/src/utils/emoji-reacts.ts +++ b/src/utils/emoji-reacts.ts @@ -85,6 +85,7 @@ export const simulateUnEmojiReact = (emojiReacts: ImmutableList, const newCount = (emojiReact.count || 1) - 1; if (newCount < 1) return emojiReacts.delete(idx); return emojiReacts.set(idx, emojiReactionSchema.parse({ + ...emojiReact, count: (emojiReact.count || 1) - 1, me: false, })); From c7f9a9eb5693b5f3f824d88f8fc33e2d3f9dca53 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 14 Nov 2023 11:08:32 -0600 Subject: [PATCH 010/115] ComposeForm: get text from the editorRef instead of component state Fixes https://gitlab.com/soapbox-pub/soapbox/-/issues/1563 --- src/features/compose/components/compose-form.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/features/compose/components/compose-form.tsx b/src/features/compose/components/compose-form.tsx index 456dab69a..182707b68 100644 --- a/src/features/compose/components/compose-form.tsx +++ b/src/features/compose/components/compose-form.tsx @@ -1,5 +1,5 @@ import clsx from 'clsx'; -import { CLEAR_EDITOR_COMMAND, TextNode, type LexicalEditor } from 'lexical'; +import { CLEAR_EDITOR_COMMAND, TextNode, type LexicalEditor, $getRoot } from 'lexical'; import React, { Suspense, useCallback, useEffect, useRef, useState } from 'react'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { Link, useHistory } from 'react-router-dom'; @@ -96,13 +96,13 @@ const ComposeForm = ({ id, shouldCondense, autoFocus, clickab const anyMedia = compose.media_attachments.size > 0; const [composeFocused, setComposeFocused] = useState(false); - const [text, setText] = useState(compose.text); const firstRender = useRef(true); const formRef = useRef(null); const spoilerTextRef = useRef(null); const editorRef = useRef(null); + const text = editorRef.current?.getEditorState().read(() => $getRoot().getTextContent()) ?? ''; const { isDraggedOver } = useDraggedFiles(formRef); const getClickableArea = () => { @@ -297,7 +297,6 @@ const ComposeForm = ({ id, shouldCondense, autoFocus, clickab autoFocus={shouldAutoFocus} hasPoll={hasPoll} handleSubmit={handleSubmit} - onChange={setText} onFocus={handleComposeFocus} onPaste={onPaste} /> From cdb89ae8fdc17fdc707c4ce72a022995fbf621be Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 14 Nov 2023 14:41:35 -0600 Subject: [PATCH 011/115] Bring back NetworkError column --- src/features/ui/components/error-column.tsx | 45 +++++++++++++++++++ src/features/ui/util/react-router-helpers.tsx | 37 ++++++++------- src/utils/errors.ts | 9 +++- 3 files changed, 75 insertions(+), 16 deletions(-) create mode 100644 src/features/ui/components/error-column.tsx diff --git a/src/features/ui/components/error-column.tsx b/src/features/ui/components/error-column.tsx new file mode 100644 index 000000000..39964cca8 --- /dev/null +++ b/src/features/ui/components/error-column.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import { defineMessages, useIntl } from 'react-intl'; + +import { Column, Stack, Text, IconButton } from 'soapbox/components/ui'; +import { isNetworkError } from 'soapbox/utils/errors'; + +const messages = defineMessages({ + title: { id: 'bundle_column_error.title', defaultMessage: 'Network error' }, + body: { id: 'bundle_column_error.body', defaultMessage: 'Something went wrong while loading this page.' }, + retry: { id: 'bundle_column_error.retry', defaultMessage: 'Try again' }, +}); + +interface IErrorColumn { + error: Error; + onRetry?: () => void; +} + +const ErrorColumn: React.FC = ({ error, onRetry = () => location.reload() }) => { + const intl = useIntl(); + + const handleRetry = () => { + onRetry?.(); + }; + + if (!isNetworkError(error)) { + throw error; + } + + return ( + + + + + {intl.formatMessage(messages.body)} + + + ); +}; + +export default ErrorColumn; diff --git a/src/features/ui/util/react-router-helpers.tsx b/src/features/ui/util/react-router-helpers.tsx index ba1895ae4..92bbf28b4 100644 --- a/src/features/ui/util/react-router-helpers.tsx +++ b/src/features/ui/util/react-router-helpers.tsx @@ -1,4 +1,5 @@ -import React, { Suspense } from 'react'; +import React, { ComponentProps, Suspense } from 'react'; +import { ErrorBoundary } from 'react-error-boundary'; import { Redirect, Route, useHistory, RouteProps, RouteComponentProps, match as MatchType } from 'react-router-dom'; import { Layout } from 'soapbox/components/ui'; @@ -7,6 +8,7 @@ import { useOwnAccount, useSettings } from 'soapbox/hooks'; import ColumnForbidden from '../components/column-forbidden'; import ColumnLoading from '../components/column-loading'; import ColumnsArea from '../components/columns-area'; +import ErrorColumn from '../components/error-column'; type PageProps = { params?: MatchType['params']; @@ -46,24 +48,28 @@ const WrappedRoute: React.FC = ({ const renderComponent = ({ match }: RouteComponentProps) => { if (Page) { return ( - - - - {content} - - - + + + + + {content} + + + + ); } return ( - - - - {content} - - - + + + + + {content} + + + + ); }; @@ -79,6 +85,7 @@ const WrappedRoute: React.FC = ({ const renderLoading = () => renderWithLayout(); const renderForbidden = () => renderWithLayout(); + const renderError = (props: ComponentProps) => renderWithLayout(); const loginRedirect = () => { const actualUrl = encodeURIComponent(`${history.location.pathname}${history.location.search}`); diff --git a/src/utils/errors.ts b/src/utils/errors.ts index 7c8d81bd1..78f8db8bd 100644 --- a/src/utils/errors.ts +++ b/src/utils/errors.ts @@ -200,4 +200,11 @@ const httpErrorMessages: { code: number; name: string; description: string }[] = }, ]; -export { buildErrorMessage, httpErrorMessages }; +/** Whether the error is caused by a JS chunk failing to load. */ +function isNetworkError(error: unknown): boolean { + return error instanceof Error + && error.name === 'TypeError' + && error.message.startsWith('Failed to fetch dynamically imported module: '); +} + +export { buildErrorMessage, httpErrorMessages, isNetworkError }; From 54aa09c6b10f3a1b41adaf756a608e5201ad2d15 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 14 Nov 2023 14:47:04 -0600 Subject: [PATCH 012/115] Developers: fix /error/network route --- src/features/ui/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/ui/index.tsx b/src/features/ui/index.tsx index 59857d52f..20f25c4a8 100644 --- a/src/features/ui/index.tsx +++ b/src/features/ui/index.tsx @@ -329,7 +329,7 @@ const SwitchingColumnsArea: React.FC = ({ children }) => - Promise.reject())} content={children} /> + Promise.reject(new TypeError('Failed to fetch dynamically imported module: TEST')))} content={children} /> {hasCrypto && } From 1a32dc178b9015609a86bc18487f50d0feb44eb7 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 14 Nov 2023 15:17:33 -0600 Subject: [PATCH 013/115] WrappedRoute: allow navigating between pages to reset the ErrorBoundary --- src/features/ui/util/react-router-helpers.tsx | 75 +++++++++++++------ 1 file changed, 53 insertions(+), 22 deletions(-) diff --git a/src/features/ui/util/react-router-helpers.tsx b/src/features/ui/util/react-router-helpers.tsx index 92bbf28b4..0487ca825 100644 --- a/src/features/ui/util/react-router-helpers.tsx +++ b/src/features/ui/util/react-router-helpers.tsx @@ -1,6 +1,6 @@ -import React, { ComponentProps, Suspense } from 'react'; -import { ErrorBoundary } from 'react-error-boundary'; -import { Redirect, Route, useHistory, RouteProps, RouteComponentProps, match as MatchType } from 'react-router-dom'; +import React, { Suspense, useEffect, useRef } from 'react'; +import { ErrorBoundary, type FallbackProps } from 'react-error-boundary'; +import { Redirect, Route, useHistory, RouteProps, RouteComponentProps, match as MatchType, useLocation } from 'react-router-dom'; import { Layout } from 'soapbox/components/ui'; import { useOwnAccount, useSettings } from 'soapbox/hooks'; @@ -48,8 +48,8 @@ const WrappedRoute: React.FC = ({ const renderComponent = ({ match }: RouteComponentProps) => { if (Page) { return ( - - + + }> {content} @@ -61,8 +61,8 @@ const WrappedRoute: React.FC = ({ } return ( - - + + }> {content} @@ -73,20 +73,6 @@ const WrappedRoute: React.FC = ({ ); }; - const renderWithLayout = (children: JSX.Element) => ( - <> - - {children} - - - - - ); - - const renderLoading = () => renderWithLayout(); - const renderForbidden = () => renderWithLayout(); - const renderError = (props: ComponentProps) => renderWithLayout(); - const loginRedirect = () => { const actualUrl = encodeURIComponent(`${history.location.pathname}${history.location.search}`); localStorage.setItem('soapbox:redirect_uri', actualUrl); @@ -104,13 +90,58 @@ const WrappedRoute: React.FC = ({ if (!account) { return loginRedirect(); } else { - return renderForbidden(); + return ; } } return ; }; +interface IFallbackLayout { + children: JSX.Element; +} + +const FallbackLayout: React.FC = ({ children }) => ( + <> + + {children} + + + + +); + +const FallbackLoading: React.FC = () => ( + + + +); + +const FallbackForbidden: React.FC = () => ( + + + +); + +const FallbackError: React.FC = ({ error, resetErrorBoundary }) => { + const location = useLocation(); + const firstUpdate = useRef(true); + + useEffect(() => { + if (firstUpdate.current) { + firstUpdate.current = false; + } else { + resetErrorBoundary(); + } + }, [location]); + + return ( + + + + ); +}; + export { WrappedRoute, }; From 5c16747b0c462a17bd5baaf0572abbc5f3b6bc22 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 14 Nov 2023 15:27:48 -0600 Subject: [PATCH 014/115] yarn i18n --- src/locales/en.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/locales/en.json b/src/locales/en.json index 672e7cbfe..3299df485 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -198,6 +198,9 @@ "birthdays_modal.empty": "None of your friends have birthday today.", "boost_modal.combo": "You can press {combo} to skip this next time", "boost_modal.title": "Repost?", + "bundle_column_error.body": "Something went wrong while loading this page.", + "bundle_column_error.retry": "Try again", + "bundle_column_error.title": "Network error", "card.back.label": "Back", "chat.actions.send": "Send", "chat.failed_to_send": "Message failed to send.", From 4162808ce0c7c5596a8b5829fb80d354837f7b23 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 14 Nov 2023 15:53:57 -0600 Subject: [PATCH 015/115] Don't load GdprBanner unless configured --- src/components/gdpr-banner.tsx | 13 +++++-------- src/init/soapbox-mount.tsx | 15 +++++++++------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/components/gdpr-banner.tsx b/src/components/gdpr-banner.tsx index 73d90684e..bcd4ed303 100644 --- a/src/components/gdpr-banner.tsx +++ b/src/components/gdpr-banner.tsx @@ -3,7 +3,7 @@ import React, { useState } from 'react'; import { FormattedMessage } from 'react-intl'; import { Banner, Button, HStack, Stack, Text } from 'soapbox/components/ui'; -import { useAppSelector, useInstance, useSoapboxConfig } from 'soapbox/hooks'; +import { useInstance, useSoapboxConfig } from 'soapbox/hooks'; const acceptedGdpr = !!localStorage.getItem('soapbox:gdpr'); @@ -14,8 +14,7 @@ const GdprBanner: React.FC = () => { const [slideout, setSlideout] = useState(false); const instance = useInstance(); - const soapbox = useSoapboxConfig(); - const isLoggedIn = useAppSelector(state => !!state.me); + const { gdprUrl } = useSoapboxConfig(); const handleAccept = () => { localStorage.setItem('soapbox:gdpr', 'true'); @@ -23,9 +22,7 @@ const GdprBanner: React.FC = () => { setTimeout(() => setShown(true), 200); }; - const showBanner = soapbox.gdpr && !isLoggedIn && !shown; - - if (!showBanner) { + if (!shown) { return null; } @@ -47,8 +44,8 @@ const GdprBanner: React.FC = () => { - {soapbox.gdprUrl && ( - + {gdprUrl && ( + diff --git a/src/init/soapbox-mount.tsx b/src/init/soapbox-mount.tsx index 06d394293..213c50494 100644 --- a/src/init/soapbox-mount.tsx +++ b/src/init/soapbox-mount.tsx @@ -14,6 +14,7 @@ import { } from 'soapbox/features/ui/util/async-components'; import { useAppSelector, + useLoggedIn, useOwnAccount, useSoapboxConfig, } from 'soapbox/hooks'; @@ -27,13 +28,13 @@ const UI = React.lazy(() => import('soapbox/features/ui')); const SoapboxMount = () => { useCachedLocationHandler(); - const me = useAppSelector(state => state.me); + const { isLoggedIn } = useLoggedIn(); const { account } = useOwnAccount(); const soapboxConfig = useSoapboxConfig(); const needsOnboarding = useAppSelector(state => state.onboarding.needsOnboarding); const showOnboarding = account && needsOnboarding; - const { redirectRootNoLogin } = soapboxConfig; + const { redirectRootNoLogin, gdpr } = soapboxConfig; // @ts-ignore: I don't actually know what these should be, lol const shouldUpdateScroll = (prevRouterProps, { location }) => { @@ -46,7 +47,7 @@ const SoapboxMount = () => { - {(!me && redirectRootNoLogin) && ( + {(!isLoggedIn && redirectRootNoLogin) && ( )} @@ -73,9 +74,11 @@ const SoapboxMount = () => { - - - + {(gdpr && !isLoggedIn) && ( + + + + )}
Date: Tue, 14 Nov 2023 16:51:33 -0600 Subject: [PATCH 016/115] GdprBanner: fix inverted `shown` logic --- src/components/gdpr-banner.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/gdpr-banner.tsx b/src/components/gdpr-banner.tsx index bcd4ed303..288a5e421 100644 --- a/src/components/gdpr-banner.tsx +++ b/src/components/gdpr-banner.tsx @@ -22,7 +22,7 @@ const GdprBanner: React.FC = () => { setTimeout(() => setShown(true), 200); }; - if (!shown) { + if (shown) { return null; } From 04e68ebc94d3201fd7635fd2942ee59c5a7b2ab4 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 14 Nov 2023 17:57:08 -0600 Subject: [PATCH 017/115] Timeline: always insert new status IDs at the end --- src/reducers/timelines.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/reducers/timelines.ts b/src/reducers/timelines.ts index 021c02283..7b7dd274e 100644 --- a/src/reducers/timelines.ts +++ b/src/reducers/timelines.ts @@ -32,6 +32,7 @@ import { } from '../actions/timelines'; import type { AnyAction } from 'redux'; +import type { ImportPosition } from 'soapbox/entity-store/types'; import type { APIEntity, Status } from 'soapbox/types/entities'; const TRUNCATE_LIMIT = 40; @@ -93,6 +94,7 @@ const expandNormalizedTimeline = ( prev: string | undefined, isPartial: boolean, isLoadingRecent: boolean, + pos: ImportPosition = 'end', ) => { const newIds = getStatusIds(statuses); @@ -113,10 +115,10 @@ const expandNormalizedTimeline = ( if (!newIds.isEmpty()) { timeline.update('items', oldIds => { - if (newIds.first() > oldIds.first()!) { - return mergeStatusIds(oldIds, newIds); - } else { + if (pos === 'end') { return mergeStatusIds(newIds, oldIds); + } else { + return mergeStatusIds(oldIds, newIds); } }); } From 53b11ec175eab8d47ad24c219ff706a861e24be9 Mon Sep 17 00:00:00 2001 From: Poesty Li Date: Wed, 25 Oct 2023 12:17:10 +0000 Subject: [PATCH 018/115] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (1523 of 1523 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/zh_Hans/ --- src/locales/zh-CN.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/locales/zh-CN.json b/src/locales/zh-CN.json index 23e38bb5c..e23e377f5 100644 --- a/src/locales/zh-CN.json +++ b/src/locales/zh-CN.json @@ -164,6 +164,8 @@ "alert.unexpected.links.support": "支持", "alert.unexpected.message": "发生了意外错误。", "alert.unexpected.return_home": "回到主页", + "alert.unexpected.submit_feedback": "提交反馈", + "alert.unexpected.thanks": "感谢您的反馈!", "aliases.account.add": "创建别名", "aliases.account_label": "旧帐号:", "aliases.aliases_list_delete": "删除别名", From c45d219273217291a3e5a004ae79e9d9b3d331b6 Mon Sep 17 00:00:00 2001 From: Weblate Translation Memory Date: Wed, 1 Nov 2023 21:57:53 +0000 Subject: [PATCH 019/115] Translated using Weblate (Polish) Currently translated at 99.2% (1512 of 1523 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/pl/ --- src/locales/pl.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/locales/pl.json b/src/locales/pl.json index 311c043c6..8a2f564f8 100644 --- a/src/locales/pl.json +++ b/src/locales/pl.json @@ -230,6 +230,7 @@ "chat_message_list_intro.leave_chat.heading": "Opuść czat", "chat_message_list_intro.leave_chat.message": "Czy na pewno chcesz opuścić ten czat? Wiadomości zostaną dla Ciebie usunięte, a czat zniknie z Twojej skrzynki.", "chat_pane.blankslate.action": "Napisz do kogoś", + "chat_pane.blankslate.body": "Szukaj kogoś do rozpoczęcia rozmowy.", "chat_search.blankslate.body": "Szukaj kogoś do rozpoczęcia rozmowy.", "chat_search.blankslate.title": "Rozpocznij rozmowę", "chat_search.empty_results_blankslate.body": "Spróbuj znaleźć inną nazwę.", From b5bc20869d4d8b7b90c149ab58930207e7c5b0fd Mon Sep 17 00:00:00 2001 From: Eryk Michalak Date: Wed, 1 Nov 2023 21:57:44 +0000 Subject: [PATCH 020/115] Translated using Weblate (Polish) Currently translated at 99.2% (1512 of 1523 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/pl/ --- src/locales/pl.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/locales/pl.json b/src/locales/pl.json index 8a2f564f8..945d41394 100644 --- a/src/locales/pl.json +++ b/src/locales/pl.json @@ -164,6 +164,8 @@ "alert.unexpected.links.support": "Wsparcie techniczne", "alert.unexpected.message": "Wystąpił nieoczekiwany błąd.", "alert.unexpected.return_home": "Wróć na stronę główną", + "alert.unexpected.submit_feedback": "Prześlij opinię", + "alert.unexpected.thanks": "Dziękujemy za twoją opinię!", "aliases.account.add": "Utwórz alias", "aliases.account_label": "Stare konto:", "aliases.aliases_list_delete": "Odłącz alias", From c691b82cab517e884f71a64c9445beb38985de74 Mon Sep 17 00:00:00 2001 From: Eryk Michalak Date: Wed, 1 Nov 2023 21:58:06 +0000 Subject: [PATCH 021/115] Translated using Weblate (Polish) Currently translated at 99.4% (1515 of 1523 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/pl/ --- src/locales/pl.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/locales/pl.json b/src/locales/pl.json index 945d41394..64db3f00a 100644 --- a/src/locales/pl.json +++ b/src/locales/pl.json @@ -232,7 +232,7 @@ "chat_message_list_intro.leave_chat.heading": "Opuść czat", "chat_message_list_intro.leave_chat.message": "Czy na pewno chcesz opuścić ten czat? Wiadomości zostaną dla Ciebie usunięte, a czat zniknie z Twojej skrzynki.", "chat_pane.blankslate.action": "Napisz do kogoś", - "chat_pane.blankslate.body": "Szukaj kogoś do rozpoczęcia rozmowy.", + "chat_pane.blankslate.body": "Poszukaj kogoś do rozpoczęcia rozmowy.", "chat_search.blankslate.body": "Szukaj kogoś do rozpoczęcia rozmowy.", "chat_search.blankslate.title": "Rozpocznij rozmowę", "chat_search.empty_results_blankslate.body": "Spróbuj znaleźć inną nazwę.", @@ -309,6 +309,7 @@ "column.developers.service_worker": "Service Worker", "column.direct": "Wiadomości bezpośrednie", "column.directory": "Przeglądaj profile", + "column.dislikes": "Nie lubi", "column.domain_blocks": "Ukryte domeny", "column.edit_profile": "Edytuj profil", "column.event_map": "Lokalizacja wydarzenia", @@ -363,7 +364,7 @@ "column.notifications": "Powiadomienia", "column.pins": "Przypięte wpisy", "column.preferences": "Preferencje", - "column.public": "Globalna oś czasu", + "column.public": "Sfederowana oś czasu", "column.quotes": "Cytatu wpisu", "column.reactions": "Reakcje", "column.reblogs": "Podbicia", From a5e986668ebacf2d779029fb7c146f2233574edc Mon Sep 17 00:00:00 2001 From: Weblate Translation Memory Date: Wed, 1 Nov 2023 22:06:04 +0000 Subject: [PATCH 022/115] Translated using Weblate (Polish) Currently translated at 99.4% (1515 of 1523 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/pl/ --- src/locales/pl.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/locales/pl.json b/src/locales/pl.json index 64db3f00a..2e91a4e68 100644 --- a/src/locales/pl.json +++ b/src/locales/pl.json @@ -233,6 +233,7 @@ "chat_message_list_intro.leave_chat.message": "Czy na pewno chcesz opuścić ten czat? Wiadomości zostaną dla Ciebie usunięte, a czat zniknie z Twojej skrzynki.", "chat_pane.blankslate.action": "Napisz do kogoś", "chat_pane.blankslate.body": "Poszukaj kogoś do rozpoczęcia rozmowy.", + "chat_pane.blankslate.title": "Brak wiadomości", "chat_search.blankslate.body": "Szukaj kogoś do rozpoczęcia rozmowy.", "chat_search.blankslate.title": "Rozpocznij rozmowę", "chat_search.empty_results_blankslate.body": "Spróbuj znaleźć inną nazwę.", From d923e107b3881bf8174b4c8c51492d6de82f068f Mon Sep 17 00:00:00 2001 From: Ahmad Dakhlallah Date: Fri, 3 Nov 2023 20:21:38 +0000 Subject: [PATCH 023/115] Translated using Weblate (Arabic) Currently translated at 100.0% (1523 of 1523 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/ar/ --- src/locales/ar.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/locales/ar.json b/src/locales/ar.json index b09ef454b..942b79768 100644 --- a/src/locales/ar.json +++ b/src/locales/ar.json @@ -391,7 +391,7 @@ "compose_event.fields.description_label": "وصف الحدث", "compose_event.fields.description_placeholder": "الوصف", "compose_event.fields.end_time_label": "الحدث والتاريخ", - "compose_event.fields.end_time_placeholder": "الحدث ينتهي في…", + "compose_event.fields.end_time_placeholder": "ينتهي الحدث في…", "compose_event.fields.has_end_time": "الحدث له تاريخ إنتهاء", "compose_event.fields.location_label": "موقع الحدث", "compose_event.fields.name_label": "عنوان الحدث", From 45bbb43425cfdd93c418a2af5704d4b9ae64a9ce Mon Sep 17 00:00:00 2001 From: Ahmad Dakhlallah Date: Fri, 3 Nov 2023 20:43:51 +0000 Subject: [PATCH 024/115] Translated using Weblate (Arabic) Currently translated at 100.0% (1523 of 1523 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/ar/ --- src/locales/ar.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/locales/ar.json b/src/locales/ar.json index 942b79768..68b3d66e9 100644 --- a/src/locales/ar.json +++ b/src/locales/ar.json @@ -399,10 +399,10 @@ "compose_event.fields.start_time_label": "تاريخ بداية الحدث", "compose_event.fields.start_time_placeholder": "الحدث يبدأ في…", "compose_event.participation_requests.authorize": "تفويض", - "compose_event.participation_requests.authorize_success": "تم قبول المستخدم", + "compose_event.participation_requests.authorize_success": "قُبِل المستخدم", "compose_event.participation_requests.reject": "رفض", - "compose_event.participation_requests.reject_success": "تم رفض المستخدم", - "compose_event.reset_location": "حذف الموقع", + "compose_event.participation_requests.reject_success": "رُفِض المستخدم", + "compose_event.reset_location": "إعادة تعيين الموقع", "compose_event.submit_success": "تم إنشاء الحدث", "compose_event.tabs.edit": "تعديل التفاصيل", "compose_event.tabs.pending": "إدارة الطلبات", @@ -496,7 +496,7 @@ "confirmations.kick_from_group.confirm": "طرد", "confirmations.kick_from_group.message": "هل أنت متأكد أنك تريد طرد @ {name} من هذه المجموعة؟", "confirmations.leave_event.confirm": "الخروج من الحدث", - "confirmations.leave_event.message": "إذا كنت تريد إعادة الانضمام إلى الحدث ، فستتم مراجعة الطلب يدويًا مرة أخرى. هل انت متأكد انك تريد المتابعة؟", + "confirmations.leave_event.message": "إذا كنت تريد إعادة الانضمام إلى الحدث ، سيتم مراجعة الطلب يدويًا مرة أخرى. متأكد أنك تريد المتابعة؟", "confirmations.leave_group.confirm": "ترك", "confirmations.leave_group.heading": "مغادرة المجموعة", "confirmations.leave_group.message": "أنت على وشك مغادرة المجموعة هل تريد الاستمرار؟?", From a57725c18eddb68f6f1e740a007017d4dc4941cb Mon Sep 17 00:00:00 2001 From: Hassen Basdouri Date: Fri, 3 Nov 2023 20:46:59 +0000 Subject: [PATCH 025/115] Translated using Weblate (Arabic) Currently translated at 100.0% (1523 of 1523 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/ar/ --- src/locales/ar.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/locales/ar.json b/src/locales/ar.json index 68b3d66e9..deabd41b7 100644 --- a/src/locales/ar.json +++ b/src/locales/ar.json @@ -497,9 +497,9 @@ "confirmations.kick_from_group.message": "هل أنت متأكد أنك تريد طرد @ {name} من هذه المجموعة؟", "confirmations.leave_event.confirm": "الخروج من الحدث", "confirmations.leave_event.message": "إذا كنت تريد إعادة الانضمام إلى الحدث ، سيتم مراجعة الطلب يدويًا مرة أخرى. متأكد أنك تريد المتابعة؟", - "confirmations.leave_group.confirm": "ترك", + "confirmations.leave_group.confirm": "مغادرة", "confirmations.leave_group.heading": "مغادرة المجموعة", - "confirmations.leave_group.message": "أنت على وشك مغادرة المجموعة هل تريد الاستمرار؟?", + "confirmations.leave_group.message": "أنت على وشك مغادرة المجموعة هل تريد الاستمرار؟", "confirmations.mute.confirm": "كتم", "confirmations.mute.heading": "كتم @{name}", "confirmations.mute.message": "هل تود حقًا كتم {name}؟", From e41ddc4e1b8d7d49a92b8d6a1c01682d08619c22 Mon Sep 17 00:00:00 2001 From: Ahmad Dakhlallah Date: Fri, 3 Nov 2023 20:50:44 +0000 Subject: [PATCH 026/115] Translated using Weblate (Arabic) Currently translated at 100.0% (1523 of 1523 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/ar/ --- src/locales/ar.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/locales/ar.json b/src/locales/ar.json index deabd41b7..74887c807 100644 --- a/src/locales/ar.json +++ b/src/locales/ar.json @@ -499,7 +499,7 @@ "confirmations.leave_event.message": "إذا كنت تريد إعادة الانضمام إلى الحدث ، سيتم مراجعة الطلب يدويًا مرة أخرى. متأكد أنك تريد المتابعة؟", "confirmations.leave_group.confirm": "مغادرة", "confirmations.leave_group.heading": "مغادرة المجموعة", - "confirmations.leave_group.message": "أنت على وشك مغادرة المجموعة هل تريد الاستمرار؟", + "confirmations.leave_group.message": "أنت على وشك مغادرة المجموعة. هل تريد الاستمرار؟", "confirmations.mute.confirm": "كتم", "confirmations.mute.heading": "كتم @{name}", "confirmations.mute.message": "هل تود حقًا كتم {name}؟", @@ -617,7 +617,7 @@ "emoji_button.recent": "المُستخدمة حديثا", "emoji_button.search": "البحث…", "emoji_button.search_results": "نتائج البحث", - "emoji_button.skins_1": "الإفتراضي", + "emoji_button.skins_1": "الافتراضي", "emoji_button.skins_2": "فاتح", "emoji_button.skins_3": "ضوء المتوسط", "emoji_button.skins_4": "متوسط", @@ -637,7 +637,7 @@ "empty_column.bookmarks": "ليس لديك أي علامات ، ستظهر هنا عند اضافتها.", "empty_column.community": "لا توجد منشورات في الخط المحلي بعد. أكتب شيئا ما للعامة كبداية!", "empty_column.direct": "لم تتلقَ أي رسالة خاصة مباشرة بعد. ستعرض الرسائل المباشرة هنا في حال أرسلت أو تلقيت بعضها.", - "empty_column.dislikes": "لا أحد قام بعدم إعجاب هذا المنشور حتى الآن. عندما يفعل شخص ما ، سيظهرون هنا.", + "empty_column.dislikes": "لم يتفاعل أي شخص بعدم الإعجاب على هذا المنشور بعد. عندما يفعل شخص ما ، سيظهرون هنا.", "empty_column.domain_blocks": "ليس هناك نطاقات مخفية بعد.", "empty_column.event_participant_requests": "لا توجد طلبات معلقة للمشاركة في الحدث.", "empty_column.event_participants": "لم ينضم أحد إلى هذا الحدث حتى الآن. عندما يفعل شخص ما ، سوف يظهر هنا.", From a742b2ea191eeacd3f1bf9495d9307d942f0420b Mon Sep 17 00:00:00 2001 From: Hassen Basdouri Date: Fri, 3 Nov 2023 21:04:10 +0000 Subject: [PATCH 027/115] Translated using Weblate (Arabic) Currently translated at 100.0% (1523 of 1523 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/ar/ --- src/locales/ar.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/locales/ar.json b/src/locales/ar.json index 74887c807..ea8341791 100644 --- a/src/locales/ar.json +++ b/src/locales/ar.json @@ -686,7 +686,7 @@ "event.quote": "اقتباس الحدث", "event.reblog": "إعادة نشر الحدث", "event.show_on_map": "العرض على الخريطة", - "event.unreblog": "حدث لم يُعَدْ نشره", + "event.unreblog": "إلغاء نشر الحدث", "event.website": "روابط خارجية", "event_map.navigate": "التنقل", "events.create_event": "إنشاء حدث", From 2b7467a8bbae2fc50546c5c87a022435c2ed1507 Mon Sep 17 00:00:00 2001 From: Ahmad Dakhlallah Date: Fri, 3 Nov 2023 21:04:28 +0000 Subject: [PATCH 028/115] Translated using Weblate (Arabic) Currently translated at 100.0% (1523 of 1523 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/ar/ --- src/locales/ar.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/locales/ar.json b/src/locales/ar.json index ea8341791..026a85889 100644 --- a/src/locales/ar.json +++ b/src/locales/ar.json @@ -686,7 +686,7 @@ "event.quote": "اقتباس الحدث", "event.reblog": "إعادة نشر الحدث", "event.show_on_map": "العرض على الخريطة", - "event.unreblog": "إلغاء نشر الحدث", + "event.unreblog": "إلغاء مشاركة الحدث", "event.website": "روابط خارجية", "event_map.navigate": "التنقل", "events.create_event": "إنشاء حدث", From 8a55456c48460dd1c9268a13757b103266253d67 Mon Sep 17 00:00:00 2001 From: Ahmad Dakhlallah Date: Sat, 4 Nov 2023 14:01:38 +0000 Subject: [PATCH 029/115] Translated using Weblate (Arabic) Currently translated at 100.0% (1523 of 1523 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/ar/ --- src/locales/ar.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/locales/ar.json b/src/locales/ar.json index 026a85889..f482e01af 100644 --- a/src/locales/ar.json +++ b/src/locales/ar.json @@ -7,7 +7,7 @@ "account.birthday": "ولد في {date}", "account.birthday_today": "اليوم يوم ميلاد صاحب الحساب!", "account.block": "حظر @{name}", - "account.block_domain": "إخفاء كل ما يتعلق بالنطاق {domain}", + "account.block_domain": "إخفاء النطاق {domain}", "account.blocked": "محظور", "account.chat": "دردشة مع @{name}", "account.copy": "نسخ رابط الحساب", @@ -182,7 +182,7 @@ "app_create.results.explanation_title": "أُنشئ التطبيق بنجاح", "app_create.results.token_label": "رمز OAuth", "app_create.scopes_label": "آفاق", - "app_create.scopes_placeholder": "مثلاً: (قراءة كتابة متابعة)", + "app_create.scopes_placeholder": "مثلاً: 'read write follow'", "app_create.submit": "إنشاء تطبيق", "app_create.website_label": "الموقع", "auth.awaiting_approval": "حسابك ينتظر الموافقة", From 3b744d84d6fbff04e4219181baf81cd6fcfffecd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sat, 4 Nov 2023 08:05:45 +0000 Subject: [PATCH 030/115] Translated using Weblate (Polish) Currently translated at 99.4% (1515 of 1523 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/pl/ --- src/locales/pl.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/locales/pl.json b/src/locales/pl.json index 2e91a4e68..cd5f42705 100644 --- a/src/locales/pl.json +++ b/src/locales/pl.json @@ -84,7 +84,7 @@ "account_note.placeholder": "Nie wprowadzono opisu", "account_search.placeholder": "Szukaj konta", "actualStatus.edited": "Edytowano {date}", - "actualStatuses.quote_tombstone": "Wpis jest niedostępny", + "actualStatuses.quote_tombstone": "Wpis jest niedostępny.", "admin.announcements.action": "Utwórz ogłoszenie", "admin.announcements.all_day": "Cały dzień", "admin.announcements.delete": "Usuń", @@ -1395,7 +1395,7 @@ "status.group": "Napisano w {group}", "status.group_mod_delete": "Usuń wpis z grupy", "status.interactions.favourites": "{count, plural, one {Polubienie} few {Polubienia} other {Polubień}}", - "status.interactions.quotes": "{count, plural, one {cytat} few {cytaty} many {cytatów}}", + "status.interactions.quotes": "{count, plural, one {Cytat} few {Cytaty} other {Cytatów}}", "status.interactions.reblogs": "{count, plural, one {Podanie dalej} few {Podania dalej} other {Podań dalej}}", "status.load_more": "Załaduj więcej", "status.mention": "Wspomnij o @{name}", From 67a708b01ebb6b7e0d393b7103b00225b3bdb4d2 Mon Sep 17 00:00:00 2001 From: Ryan He Date: Wed, 8 Nov 2023 03:12:02 +0000 Subject: [PATCH 031/115] Translated using Weblate (Chinese (Traditional)) Currently translated at 74.6% (1137 of 1523 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/zh_Hant/ --- src/locales/zh-TW.json | 325 ++++++++++++++++++++++++++++------------- 1 file changed, 220 insertions(+), 105 deletions(-) diff --git a/src/locales/zh-TW.json b/src/locales/zh-TW.json index 03b6d97f6..daa7f2fcf 100644 --- a/src/locales/zh-TW.json +++ b/src/locales/zh-TW.json @@ -35,8 +35,8 @@ "account.media": "媒體", "account.member_since": "加入於 {date}", "account.mention": "提及", - "account.mute": "隱藏 @{name}", - "account.muted": "已隱藏", + "account.mute": "靜音 @{name}", + "account.muted": "已靜音", "account.never_active": "從未", "account.patron": "贊助人", "account.posts": "貼文", @@ -62,7 +62,7 @@ "account.unendorse": "不再於個人資料頁面推薦對方", "account.unendorse.success": "您已不再展示 @{acct}", "account.unfollow": "取消追蹤", - "account.unmute": "取消隱藏 @{name}", + "account.unmute": "取消靜音 @{name}", "account.unsubscribe": "取消訂閲 @{name}", "account.unsubscribe.failure": "取消訂閲此帳戶時發生錯誤。", "account.unsubscribe.success": "你已取消訂閲此帳戶。", @@ -126,7 +126,7 @@ "admin.reports.actions.view_status": "查看貼文", "admin.reports.empty_message": "沒有未處理的檢舉,如果有任何檢舉,它就會顯示在這裏。", "admin.reports.report_closed_message": "對 @{name} 的檢舉已關閉", - "admin.reports.report_title": "檢舉 {acct} 的帖文", + "admin.reports.report_title": "檢舉 {acct} 的貼文", "admin.software.backend": "後端", "admin.software.frontend": "前端", "admin.statuses.actions.delete_status": "刪除貼文", @@ -205,6 +205,13 @@ "chats.actions.report": "檢舉用戶", "chats.dividers.today": "今天", "chats.search_placeholder": "開始聊天…", + "colum.filters.expiration.1800": "30分鐘", + "colum.filters.expiration.21600": "6小時", + "colum.filters.expiration.3600": "1小時", + "colum.filters.expiration.43200": "12小時", + "colum.filters.expiration.604800": "1週", + "colum.filters.expiration.86400": "1天", + "colum.filters.expiration.never": "永不過期", "column.admin.awaiting_approval": "等待核准", "column.admin.dashboard": "控制台", "column.admin.moderation_log": "管理日誌", @@ -230,27 +237,38 @@ "column.directory": "發現更多", "column.domain_blocks": "隱藏的網域", "column.edit_profile": "編輯個人資料", + "column.event_map": "活動地點", + "column.event_participants": "活動參加者", + "column.events": "活動", "column.export_data": "匯出資料", "column.favourited_statuses": "按讚的貼文", "column.favourites": "按讚", "column.federation_restrictions": "聯邦限制", - "column.filters": "過濾詞", + "column.filters": "靜音的詞彙", + "column.filters.accounts": "帳號", "column.filters.add_new": "新增過濾詞", "column.filters.conversations": "聊天", - "column.filters.create_error": "新增過濾詞時出錯。", + "column.filters.create_error": "新增過濾器時出錯", "column.filters.delete": "刪除過濾詞", - "column.filters.delete_error": "刪除過濾詞時出錯。", + "column.filters.delete_error": "刪除過濾器時發生錯誤", "column.filters.drop_header": "丟棄而非隱藏", - "column.filters.drop_hint": "被丟棄的帖文會不可逆地消失,即使移除過濾詞之後也不會恢復", + "column.filters.drop_hint": "即使稍後刪除過濾器,過濾的貼文也將不可逆轉地消失", + "column.filters.edit": "編輯過濾器", "column.filters.expires": "過期時間", + "column.filters.hide_header": "完全隱藏", + "column.filters.hide_hint": "完全隱藏過濾的內容,而不是顯示警告", "column.filters.home_timeline": "主頁時間軸", - "column.filters.keyword": "關鍵詞", + "column.filters.keyword": "關鍵字或短語", + "column.filters.keywords": "關鍵字或短語", "column.filters.notifications": "通知", - "column.filters.public_timeline": "公共時間軸", - "column.filters.subheading_add_new": "新增過濾詞", + "column.filters.public_timeline": "公開時間軸", + "column.filters.subheading_add_new": "新增過濾器", + "column.filters.title": "標題", + "column.filters.whole_word": "整個詞", "column.follow_requests": "追蹤請求", "column.followers": "追蹤者", "column.following": "正在追蹤", + "column.group_blocked_members": "被禁止的成員", "column.home": "主頁", "column.import_data": "匯入資料", "column.info": "伺服器資訊", @@ -262,14 +280,14 @@ "column.mfa_disable_button": "停用", "column.mfa_setup": "同意並繼續", "column.migration": "帳戶遷移", - "column.mutes": "被隱藏的使用者", + "column.mutes": "被靜音的使用者", "column.notifications": "通知", "column.pins": "釘選的貼文", "column.preferences": "偏好設定", "column.public": "聯邦時間軸", "column.reactions": "心情回應", "column.reblogs": "轉帖", - "column.scheduled_statuses": "定時帖文", + "column.scheduled_statuses": "定時發文", "column.search": "搜尋", "column.settings_store": "設定儲存", "column.soapbox_config": "Soapbox設定", @@ -279,12 +297,37 @@ "common.cancel": "取消", "compare_history_modal.header": "編輯歷史", "compose.character_counter.title": "最大字符數: {maxChars}; 已使用 {chars}", - "compose.edit_success": "你的帖文已編輯", - "compose.invalid_schedule": "定時帖文只能設定在五分鐘後或更遲發送", - "compose.submit_success": "帖文已送出", - "compose_form.direct_message_warning": "這條帖文只有被提及的使用者才看得到。", - "compose_form.hashtag_warning": "由於這則帖文被設定成「不公開」,所以它將不會被列在任何主題標籤下。只有公開的帖文才能藉主題標籤找到。", - "compose_form.lock_disclaimer": "您的帳戶尚未{locked}。任何人都能追蹤您並看到您設定成只有追蹤者能看的帖文。", + "compose.edit_success": "你的貼文已編輯", + "compose.invalid_schedule": "您必須安排至少在5分鐘後發布貼文。", + "compose.submit_success": "您的貼文已發送!", + "compose_event.create": "新增", + "compose_event.edit_success": "您的活動已編輯", + "compose_event.fields.approval_required": "我想手動批准參與請求", + "compose_event.fields.banner_label": "活動封面", + "compose_event.fields.description_label": "活動說明", + "compose_event.fields.description_placeholder": "說明", + "compose_event.fields.end_time_label": "活動結束日期", + "compose_event.fields.end_time_placeholder": "活動結束於…", + "compose_event.fields.has_end_time": "活動有結束日期", + "compose_event.fields.location_label": "活動地點", + "compose_event.fields.name_label": "活動名稱", + "compose_event.fields.name_placeholder": "名稱", + "compose_event.fields.start_time_label": "活動開始日期", + "compose_event.fields.start_time_placeholder": "活動開始於…", + "compose_event.participation_requests.authorize": "授權", + "compose_event.participation_requests.authorize_success": "已許可參與的使用者", + "compose_event.participation_requests.reject": "拒絕", + "compose_event.participation_requests.reject_success": "被拒絕的使用者", + "compose_event.reset_location": "重設地點", + "compose_event.submit_success": "您的活動已建立", + "compose_event.tabs.edit": "編輯詳細內容", + "compose_event.tabs.pending": "管理請求", + "compose_event.update": "更新", + "compose_event.upload_banner": "上傳活動封面", + "compose_form.direct_message_warning": "這篇貼文只會發送給被提及的使用者。", + "compose_form.event_placeholder": "發佈到此活動", + "compose_form.hashtag_warning": "這篇貼文不會列出在任何主題標籤下,因為它是不公開的。只能透過主題標籤搜尋公開貼文。", + "compose_form.lock_disclaimer": "您的帳戶未{locked}。任何人都可以追蹤您並查看您的僅限追蹤者的貼文。", "compose_form.lock_disclaimer.lock": "上鎖", "compose_form.markdown.marked": "Markdown已啟用", "compose_form.markdown.unmarked": "Markdown已禁用", @@ -305,7 +348,7 @@ "compose_form.save_changes": "儲存變更", "compose_form.schedule": "定時發佈", "compose_form.scheduled_statuses.click_here": "點擊此處", - "compose_form.scheduled_statuses.message": "你有定時帖文, {click_here} 查看", + "compose_form.scheduled_statuses.message": "你有定時貼文, {click_here}查看。", "compose_form.spoiler.marked": "正文已隱藏到警告之後", "compose_form.spoiler.unmarked": "正文未被隱藏", "compose_form.spoiler_placeholder": "請在此處寫入警告訊息", @@ -316,39 +359,53 @@ "confirmations.admin.deactivate_user.heading": "禁用帳戶 @{acct}", "confirmations.admin.deactivate_user.message": "你確定要禁用帳戶 @{acct} 嗎?此操作不能撤回!", "confirmations.admin.delete_local_user.checkbox": "我確定我不再需要這個帳戶", - "confirmations.admin.delete_status.confirm": "刪除帖文", - "confirmations.admin.delete_status.heading": "刪除帖文", - "confirmations.admin.delete_status.message": "你確定要刪除帖文 @{acct} 嗎?此操作不能撤回!", + "confirmations.admin.delete_status.confirm": "刪除貼文", + "confirmations.admin.delete_status.heading": "刪除貼文", + "confirmations.admin.delete_status.message": "您即將刪除 @{acct} 的貼文。此操作無法撤回。", "confirmations.admin.delete_user.confirm": "刪除帳戶 @{name}", "confirmations.admin.delete_user.heading": "刪除帳戶 @{acct}", "confirmations.admin.delete_user.message": "你確定要刪除帳戶 @{acct}嗎?此操作不能撤回!", "confirmations.admin.mark_status_not_sensitive.confirm": "標記為不敏感", "confirmations.admin.mark_status_not_sensitive.heading": "標記為不敏感", - "confirmations.admin.mark_status_not_sensitive.message": "你要標記帳戶 @{acct} 的帖文為不敏感", - "confirmations.admin.mark_status_sensitive.confirm": "標記為敏感帖文", - "confirmations.admin.mark_status_sensitive.heading": "標記為敏感帖文", - "confirmations.admin.mark_status_sensitive.message": "你要標記帳戶 @{acct} 的帖文為敏感", + "confirmations.admin.mark_status_not_sensitive.message": "你要標記帳戶 @{acct} 的貼文為不敏感。", + "confirmations.admin.mark_status_sensitive.confirm": "標記為敏感貼文", + "confirmations.admin.mark_status_sensitive.heading": "標記為敏感貼文", + "confirmations.admin.mark_status_sensitive.message": "您要 @{acct} 發布的貼文標記為敏感。", "confirmations.admin.reject_user.confirm": "拒絕 @{name}", "confirmations.admin.reject_user.heading": "拒絕 @{acct}", "confirmations.admin.reject_user.message": "你正準備拒絕 @{acct} 的註冊請求。此操作不能撤銷。", "confirmations.block.block_and_report": "封鎖並檢舉", "confirmations.block.confirm": "封鎖", "confirmations.block.heading": "封鎖 @{name}", - "confirmations.block.message": "確定封鎖 {name} ?", + "confirmations.block.message": "您確定要封鎖 {name} 嗎?", + "confirmations.block_from_group.confirm": "禁止用戶", + "confirmations.block_from_group.heading": "禁止加入群組", + "confirmations.block_from_group.message": "您確定要禁止@{name}加入群組嗎?", + "confirmations.cancel_event_editing.heading": "取消編輯活動", + "confirmations.cancel_event_editing.message": "您確定要取消編輯此活動嗎?所有變更都將消失。", "confirmations.delete.confirm": "刪除", - "confirmations.delete.heading": "刪除帖文", - "confirmations.delete.message": "你確定要刪除這條帖文?", + "confirmations.delete.heading": "刪除貼文", + "confirmations.delete.message": "你確定要刪除這條貼文?", + "confirmations.delete_event.confirm": "刪除", + "confirmations.delete_event.heading": "刪除活動", + "confirmations.delete_event.message": "您確定要刪除此活動嗎?", "confirmations.delete_list.confirm": "刪除", "confirmations.delete_list.heading": "刪除列表", "confirmations.delete_list.message": "你確定要永久刪除這個列表?", "confirmations.domain_block.confirm": "隱藏整個網域", - "confirmations.domain_block.heading": "Block {domain}", - "confirmations.domain_block.message": "真的非常確定封鎖整個 {domain} 嗎?大部分情況下,你只需要封鎖或隱藏少數特定的人就能滿足需求了。你將不能在任何公開的時間軸及通知中看到那個網域的內容。你來自該網域的追蹤者也會被移除。", - "confirmations.mute.confirm": "隱藏", - "confirmations.mute.message": "確定隱藏 {name} ?", + "confirmations.domain_block.heading": "封鎖{domain}", + "confirmations.domain_block.message": "真的非常確定封鎖整個 {domain} 嗎?大部分情況下,你只需要封鎖或靜音少數特定的人就能滿足需求了。你將不能在任何公開的時間軸及通知中看到那個網域的內容。你來自該網域的追蹤者也會被移除。", + "confirmations.leave_event.confirm": "離開活動", + "confirmations.leave_event.message": "如果您想重新加入此活動,將再次對這項請求進行人工審核。您確定要繼續嗎?", + "confirmations.mute.confirm": "靜音", + "confirmations.mute.heading": "靜音 @{name}", + "confirmations.mute.message": "您確定要將 {name} 靜音嗎?", + "confirmations.mute_group.confirm": "靜音", + "confirmations.mute_group.heading": "靜音群組", + "confirmations.mute_group.message": "您要將該群組靜音。你想繼續嗎?", "confirmations.redraft.confirm": "刪除並重新編輯", "confirmations.redraft.heading": "刪除並重新編輯", - "confirmations.redraft.message": "確定刪掉這則帖文並重新編輯嗎?將會失去這則帖文的轉帖及收藏,且回覆這則的帖文將會變成獨立的帖文。", + "confirmations.redraft.message": "確定刪掉這則貼文並重新編輯嗎?將會失去這則貼文的轉貼及收藏,且回覆這則的貼文將會變成獨立的貼文。", "confirmations.register.needs_approval": "你的帳戶正在被管理員審核中,請等待一會", "confirmations.register.needs_approval.header": "需要審核", "confirmations.register.needs_confirmation": "我們已經發送了指引到你的電郵 {email} 中,請檢查收件箱並點擊鏈接以繼續。", @@ -358,8 +415,8 @@ "confirmations.reply.confirm": "回覆", "confirmations.reply.message": "現在回覆將蓋掉您目前正在撰寫的訊息。是否仍要回覆?", "confirmations.scheduled_status_delete.confirm": "取消", - "confirmations.scheduled_status_delete.heading": "取消帖文定時發佈", - "confirmations.scheduled_status_delete.message": "你確定要取消這篇帖文定時發佈嗎?", + "confirmations.scheduled_status_delete.heading": "取消貼文定時發布", + "confirmations.scheduled_status_delete.message": "你確定要取消這篇貼文定時發布嗎?", "confirmations.unfollow.confirm": "取消追蹤", "crypto_donate.explanation_box.message": "{siteTitle} 接受用戶向以下錢包地址捐贈任意數量的數字資產。你的抖內會令我們做得更好!", "crypto_donate.explanation_box.title": "發起數字貨幣捐贈", @@ -392,13 +449,13 @@ "directory.new_arrivals": "新增訪客", "directory.recently_active": "最近活動", "edit_email.placeholder": "me@example.com", - "edit_federation.followers_only": "對追蹤者以外的用戶隱藏帖文", + "edit_federation.followers_only": "對追蹤者以外的使用者隱藏貼文", "edit_federation.force_nsfw": "將附件強制標記為敏感內容", "edit_federation.media_removal": "去除媒體", "edit_federation.reject": "拒絕所有資訊交互", "edit_federation.save": "儲存", "edit_federation.success": "{host} 聯邦設定已儲存", - "edit_federation.unlisted": "將帖文強制標記移出公共時間軸", + "edit_federation.unlisted": "將貼文強制標記移出公共時間軸", "edit_password.header": "修改密碼", "edit_profile.error": "個人資料更新失敗", "edit_profile.fields.accepts_email_list_label": "訂閲電子郵件列表", @@ -430,7 +487,7 @@ "edit_profile.hints.stranger_notifications": "僅顯示來自您追蹤的人的通知", "edit_profile.save": "儲存", "edit_profile.success": "個人資料已儲存", - "embed.instructions": "要嵌入此帖文,請將以下程式碼貼進你的網站。", + "embed.instructions": "要嵌入此貼文,請將以下程式碼貼進你的網站。", "emoji_button.activity": "活動", "emoji_button.custom": "自訂", "emoji_button.flags": "旗標", @@ -445,49 +502,70 @@ "emoji_button.search_results": "搜尋結果", "emoji_button.symbols": "符號", "emoji_button.travel": "旅遊與地點", - "empty_column.account_blocked": "你被 @{accountUsername} 封鎖了", + "empty_column.account_blocked": "你被 @{accountUsername} 封鎖了。", "empty_column.account_favourited_statuses": "他還沒有按讚任何貼文", - "empty_column.account_timeline": "這裡還沒有帖文!", + "empty_column.account_timeline": "這裡還沒有貼文!", "empty_column.account_unavailable": "無法取得個人資料", "empty_column.aliases": "你還沒有設定任何別名", "empty_column.aliases.suggestions": "暫時沒有可用的帳戶建議", "empty_column.blocks": "你還沒有封鎖任何使用者。", - "empty_column.bookmarks": "你還沒有任何書籤收藏,一旦你開始將帖文加入書籤,它將會在這裡顯示", + "empty_column.bookmarks": "你還沒有任何書籤收藏,一旦你開始將貼文加入書籤,它將會在這裡顯示。", "empty_column.community": "本地時間軸是空的。快公開發佈些文搶頭香啊!", "empty_column.direct": "您還沒有任何私訊。當您私訊別人或收到私訊時,它將於此顯示。", "empty_column.domain_blocks": "尚未隱藏任何網域。", - "empty_column.favourited_statuses": "你還沒收藏任何帖文。這裡將會顯示你收藏的帖文。", - "empty_column.favourites": "還沒有人收藏這則帖文。這裡將會顯示被收藏的帖文。", - "empty_column.filters": "你還未有添加任何過濾詞。", + "empty_column.event_participant_requests": "沒有待處理的活動參與請求。", + "empty_column.event_participants": "尚未有人參加此活動。當有人這麼做時,他們就會出現在這裡。", + "empty_column.favourited_statuses": "你還沒收藏任何貼文。這裡將會顯示你收藏的貼文。", + "empty_column.favourites": "還沒有人收藏這則貼文。這裡將會顯示被收藏的貼文。", + "empty_column.filters": "您還沒有創建任何靜音詞。", "empty_column.follow_recommendations": "目前似乎暫時沒有推薦訊息,你可以嘗試搜尋用戶或者瀏覽熱門標籤。", "empty_column.follow_requests": "您尚未收到任何追蹤請求。這裡將會顯示收到的追蹤請求。", + "empty_column.group_blocks": "該群組尚未禁止任何使用者。", "empty_column.hashtag": "這個主題標籤下什麼也沒有。", "empty_column.home": "您的首頁時間軸是空的!前往 {public} 或使用搜尋功能來認識其他人。", "empty_column.home.local_tab": "{site_title} 本站時間軸", - "empty_column.list": "這份名單還沒有東西。當此名單的成員發佈了新的帖文時,它們就會顯示於此。", + "empty_column.list": "這份名單還沒有東西。當此名單的成員發佈了新的貼文時,它們就會顯示於此。", "empty_column.lists": "你還沒有建立任何名單。這裡將會顯示你所建立的名單。", - "empty_column.mutes": "你尚未隱藏任何使用者。", + "empty_column.mutes": "您尚未將任何使用者靜音。", "empty_column.notifications": "您尚未收到任何通知,和別人互動開啟對話吧。", - "empty_column.public": "這裡什麼都沒有!嘗試寫些公開的帖文,或著自己追蹤其他伺服器的使用者後就會有帖文出現了", + "empty_column.notifications_filtered": "您還沒有任何此類通知。", + "empty_column.public": "這裡什麼都沒有!嘗試寫些公開的貼文,或著追蹤其他伺服器的使用者後就會出現了", "empty_column.remote": "這裡什麼都沒有! 關注本站或者其他站點的成員,就會有用戶出現在這裡。", - "empty_column.scheduled_statuses": "暫時沒有定時帖文。當你發佈定時帖文後,它們會顯示在這裡。", + "empty_column.scheduled_statuses": "暫時沒有定時貼文。當你發佈定時貼文後,它們會顯示在這裡。", "empty_column.search.accounts": "沒有匹配的帳戶 \"{term}\"", "empty_column.search.hashtags": "沒有匹配的標籤 \"{term}\"", - "empty_column.search.statuses": "沒有匹配的帖文 \"{term}\"", + "empty_column.search.statuses": "沒有匹配的貼文 \"{term}\"", "empty_column.test": "測試時間軸是空的", + "event.banner": "活動封面", + "event.copy": "複製活動的網址", + "event.date": "日期", + "event.description": "說明", + "event.discussion.empty": "尚未有人對此事件發表評論。當有人這樣做時,他們就會出現在這裡。", + "event.export_ics": "匯出到您的日曆", + "event.external": "查看 {domain} 上的活動", + "event.location": "地點", + "event.manage": "管理", + "event.organized_by": "組織者:{name}", + "event.show_on_map": "在地圖上顯示", + "event.website": "外部連結", + "events.create_event": "新增活動", + "events.joined_events": "已加入的活動", + "events.joined_events.empty": "您還沒有參加任何活動。", + "events.recent_events": "最近的活動", + "events.recent_events.empty": "還沒有公開活動。", "export_data.actions.export": "匯出", "export_data.actions.export_blocks": "匯出封鎖名單", "export_data.actions.export_follows": "匯出追蹤名單", - "export_data.actions.export_mutes": "匯出隱藏名單", + "export_data.actions.export_mutes": "匯出靜音名單", "export_data.blocks_label": "封鎖", "export_data.follows_label": "追蹤", "export_data.hints.blocks": "匯出封鎖名單為CSV檔案", "export_data.hints.follows": "匯出追蹤名單為CSV檔案", - "export_data.hints.mutes": "匯出隱藏名單為CSV檔案", - "export_data.mutes_label": "隱藏", + "export_data.hints.mutes": "匯出靜音名單為CSV檔案", + "export_data.mutes_label": "靜音", "export_data.success.blocks": "封鎖名單匯出成功", "export_data.success.followers": "追蹤名單匯出成功", - "export_data.success.mutes": "隱藏名單匯出成功", + "export_data.success.mutes": "靜音名單匯出成功", "federation_restriction.federated_timeline_removal": "從聯邦宇宙時間軸移除", "federation_restriction.followers_only": "僅追蹤者可見", "federation_restriction.full_media_removal": "完全移除媒體", @@ -498,20 +576,34 @@ "federation_restrictions.explanation_box.title": "實例相關政策", "federation_restrictions.not_disclosed_message": "{siteTitle} 沒有通過API向聯邦宇宙公開限制。", "fediverse_tab.explanation_box.dismiss": "不再顯示", - "fediverse_tab.explanation_box.explanation": "{site_title} 是聯邦宇宙的一份子, 一個由數個站點組成的社交網路集合。你在這裏看到的帖文來自於其他站點。你可以自由地與他們打交道,或者封鎖任何你不喜歡的站點。第二個 @ 符號後的完整帳戶名表示帖文來自哪個站點。要想只看到 {site_title} 的帖文, 請瀏覽 {local} 。", + "fediverse_tab.explanation_box.explanation": "{site_title} 是聯邦宇宙的一份子, 一個由數個站點組成的社交網路集合。你在這裏看到的貼文來自於其他站點。你可以自由地與他們打交道,或者封鎖任何你不喜歡的站點。第二個 @ 符號後的完整帳戶名表示貼文來自哪個站點。要想只看到 {site_title} 的帖文, 請瀏覽 {local} 。", "fediverse_tab.explanation_box.title": "什麼是聯邦宇宙?", "feed_suggestions.heading": "建議的個人資料", "feed_suggestions.view_all": "檢視全部", "filters.added": "過濾器已添加。", "filters.context_header": "過濾器場景", "filters.context_hint": "一個或多個應用至過濾器的條件", + "filters.create_filter": "建立過濾器", "filters.filters_list_context_label": "過濾器場景:", "filters.filters_list_drop": "丟棄", + "filters.filters_list_expired": "已過期", "filters.filters_list_hide": "隱藏", - "filters.removed": "過濾器已移除", + "filters.filters_list_hide_completely": "隱藏內容", + "filters.filters_list_phrases_label": "關鍵字或短語:", + "filters.filters_list_warn": "顯示警告", + "filters.removed": "過濾器已移除。", "follow_request.authorize": "授權", "follow_request.reject": "拒絕", "getting_started.open_source_notice": "{code_name} 是開源軟體。你可以在 GitLab {code_link} (v{code_version}) 上貢獻或是回報問題。", + "group.group_mod_block": "禁止加入群組", + "group.group_mod_block.success": "@{name} 已被封鎖", + "group.group_mod_unblock": "取消封鎖", + "group.mute.label": "靜音", + "group.mute.long_label": "靜音群組", + "group.mute.success": "將群組設為靜音", + "group.unmute.label": "取消靜音", + "group.unmute.long_label": "取消群組靜音", + "group.unmute.success": "取消群組靜音", "header.login.label": "登入", "header.register.label": "註冊", "home.column_settings.show_reblogs": "顯示轉帖", @@ -521,27 +613,33 @@ "import_data.actions.import": "匯入", "import_data.actions.import_blocks": "匯入封鎖名單", "import_data.actions.import_follows": "匯入追蹤名單", - "import_data.actions.import_mutes": "匯入隱藏名單", + "import_data.actions.import_mutes": "匯入靜音名單", "import_data.blocks_label": "封鎖帳戶", "import_data.follows_label": "追蹤帳戶", "import_data.hints.blocks": "上載包含封鎖帳戶名單的CSV檔案", "import_data.hints.follows": "上載包含追蹤帳戶名單的CSV檔案", - "import_data.hints.mutes": "上載包含隱藏帳戶名單的CSV檔案", - "import_data.mutes_label": "隱藏帳戶", + "import_data.hints.mutes": "上載包含靜音帳戶名單的CSV檔案", + "import_data.mutes_label": "靜音", "import_data.success.blocks": "封鎖帳戶名單已匯入", "import_data.success.followers": "追蹤帳戶名單已匯入", - "import_data.success.mutes": "隱藏帳戶名單已匯入", + "import_data.success.mutes": "靜音帳戶名單已匯入", "input.password.hide_password": "隱藏密碼", "input.password.show_password": "顯示密碼", "intervals.full.days": "{number} 天", "intervals.full.hours": "{number} 小時", "intervals.full.minutes": "{number} 分鐘", + "join_event.hint": "您可以告訴主辦單位為什麼想參加本次活動:", + "join_event.join": "請求加入", + "join_event.placeholder": "給主辦單位的留言", + "join_event.request_success": "已請求參加活動", + "join_event.success": "已參加活動", + "join_event.title": "參加活動", "keyboard_shortcuts.back": "返回上一頁", "keyboard_shortcuts.blocked": "開啟「封鎖使用者」名單", "keyboard_shortcuts.boost": "轉帖", "keyboard_shortcuts.compose": "將焦點移至撰寫文字區塊", "keyboard_shortcuts.down": "往下移動名單項目", - "keyboard_shortcuts.enter": "檢視帖文", + "keyboard_shortcuts.enter": "檢視貼文", "keyboard_shortcuts.favourite": "收藏", "keyboard_shortcuts.favourites": "開啟收藏名單", "keyboard_shortcuts.heading": "鍵盤快速鍵", @@ -549,11 +647,11 @@ "keyboard_shortcuts.hotkey": "快速鍵", "keyboard_shortcuts.legend": "顯示此名單", "keyboard_shortcuts.mention": "提及作者", - "keyboard_shortcuts.muted": "開啟隱藏使用者名單", + "keyboard_shortcuts.muted": "開啟靜音使用者名單", "keyboard_shortcuts.my_profile": "開啟個人資料頁面", "keyboard_shortcuts.notifications": "開啟通知欄", "keyboard_shortcuts.open_media": "開啟媒體", - "keyboard_shortcuts.pinned": "開啟釘選的帖文名單", + "keyboard_shortcuts.pinned": "開啟釘選的貼文名單", "keyboard_shortcuts.profile": "開啟作者的個人資料頁面", "keyboard_shortcuts.react": "心情回應", "keyboard_shortcuts.reply": "回覆", @@ -561,7 +659,7 @@ "keyboard_shortcuts.search": "將焦點移至搜尋框", "keyboard_shortcuts.toggle_hidden": "顯示/隱藏在內容警告之後的正文", "keyboard_shortcuts.toggle_sensitivity": "顯示 / 隱藏媒體", - "keyboard_shortcuts.toot": "開始發出新帖文", + "keyboard_shortcuts.toot": "開始發出新貼文", "keyboard_shortcuts.unfocus": "取消輸入文字區塊 / 搜尋的焦點", "keyboard_shortcuts.up": "往上移動名單項目", "landing_page_modal.download": "下載", @@ -629,15 +727,18 @@ "moderation_overlay.contact": "聯絡", "moderation_overlay.hide": "隱藏內容", "moderation_overlay.show": "顯示內容", - "moderation_overlay.subtitle": "此帖文已發送至站務以供審核,目前只允許本人查看。如你認為該消息有誤,請聯絡站務", + "moderation_overlay.subtitle": "此貼文已發送至站務以供審核,目前只允許本人查看。如你認為該消息有誤,請聯絡站務。", "moderation_overlay.title": "內容正被審核中", + "mute_modal.auto_expire": "自動過期靜音?", + "mute_modal.duration": "期間", "mute_modal.hide_notifications": "隱藏來自這個帳戶的通知?", + "mutes.empty.groups": "您尚未將任何群組靜音。", "navbar.login.action": "登入", "navbar.login.forgot_password": "忘記密碼?", "navbar.login.password.label": "密碼", "navbar.login.username.placeholder": "郵箱地址或帳戶名稱", "navigation.chats": "聊天", - "navigation.compose": "發佈新帖文", + "navigation.compose": "發佈新貼文", "navigation.dashboard": "控制台", "navigation.developers": "開發者", "navigation.direct_messages": "私人訊息", @@ -647,24 +748,29 @@ "navigation_bar.account_aliases": "帳戶別名", "navigation_bar.account_migration": "帳戶遷移", "navigation_bar.blocks": "封鎖使用者", - "navigation_bar.compose": "撰寫新帖文", + "navigation_bar.compose": "撰寫新貼文", "navigation_bar.compose_direct": "發送私人訊息", - "navigation_bar.compose_edit": "編輯帖文", - "navigation_bar.compose_quote": "引用帖文", - "navigation_bar.compose_reply": "回覆帖文", + "navigation_bar.compose_edit": "編輯貼文", + "navigation_bar.compose_event": "管理活動", + "navigation_bar.compose_quote": "引用貼文", + "navigation_bar.compose_reply": "回覆貼文", + "navigation_bar.create_event": "新增活動", "navigation_bar.domain_blocks": "隱藏的網域", "navigation_bar.favourites": "收藏", - "navigation_bar.filters": "隱藏", + "navigation_bar.filters": "過濾器", "navigation_bar.follow_requests": "追蹤請求", "navigation_bar.import_data": "匯入資料", "navigation_bar.in_reply_to": "回覆", "navigation_bar.invites": "邀請", "navigation_bar.logout": "登出", - "navigation_bar.mutes": "隱藏的使用者", + "navigation_bar.mutes": "靜音", "navigation_bar.preferences": "偏好設定", "navigation_bar.profile_directory": "發現更多帳戶", "navigation_bar.soapbox_config": "Soapbox配置", - "notification.favourite": "{name} 讚了你的帖文", + "new_event_panel.action": "新增活動", + "new_event_panel.subtitle": "找不到您要找的東西?安排您自己的活動。", + "new_event_panel.title": "新增活動", + "notification.favourite": "{name} 讚了你的貼文", "notification.follow": "{name} 追蹤了你", "notification.follow_request": "{name} 請求追蹤你", "notification.mention": "{name} 提到了你", @@ -673,15 +779,18 @@ "notification.name": "{link}{others}", "notification.others": " + {count} 其他通知", "notification.pleroma:chat_mention": "{name} 給你發送了訊息", - "notification.pleroma:emoji_reaction": "{name} 用表情回應了你的帖文", + "notification.pleroma:emoji_reaction": "{name} 用表情回應了你的貼文", + "notification.pleroma:event_reminder": "您正在參加的活動即將開始", + "notification.pleroma:participation_accepted": "您已獲準參加活動", + "notification.pleroma:participation_request": "{name}想要參加您的活動", "notification.poll": "你參與的一項投票已經結束", - "notification.reblog": "{name} 轉帖了你的帖文", + "notification.reblog": "{name} 轉貼了你的貼文", "notification.status": "{name} 剛剛發帖", - "notification.update": "{name} 編輯了你參與互動的帖文", + "notification.update": "{name} 編輯了你參與互動的貼文", "notification.user_approved": "歡迎來到 {instance}!", "notifications.filter.all": "全部", - "notifications.filter.boosts": "轉帖", - "notifications.filter.emoji_reacts": "Emoji心情回應", + "notifications.filter.boosts": "轉貼", + "notifications.filter.emoji_reacts": "表情符號回應", "notifications.filter.favourites": "最愛", "notifications.filter.follows": "追蹤的使用者", "notifications.filter.mentions": "提及", @@ -716,7 +825,7 @@ "patron.donate": "抖內", "patron.title": "籌集目標", "pinned_accounts.title": "{name} 的釘選", - "pinned_statuses.none": "沒有釘選的帖文", + "pinned_statuses.none": "沒有釘選的貼文", "poll.choose_multiple": "盡情選擇你所感興趣的", "poll.closed": "已關閉", "poll.non_anonymous": "公共投票", @@ -730,15 +839,15 @@ "poll_button.add_poll": "發起投票", "poll_button.remove_poll": "移除投票", "preferences.fields.auto_play_gif_label": "自動播放GIF", - "preferences.fields.autoload_more_label": "滾動至時間軸底部自動載入更多帖文", + "preferences.fields.autoload_more_label": "滾動至時間軸底部自動載入更多貼文", "preferences.fields.autoload_timelines_label": "滾動至時間軸頂部自動載入更多新帖", "preferences.fields.boost_modal_label": "轉帖前顯示確認提示", "preferences.fields.content_type_label": "預設貼文格式", - "preferences.fields.delete_modal_label": "刪除帖文前顯示確認提示", + "preferences.fields.delete_modal_label": "刪除貼文前顯示確認提示", "preferences.fields.display_media.default": "隱藏被標記為敏感內容的媒體", "preferences.fields.display_media.hide_all": "始終隱藏所有媒體", "preferences.fields.display_media.show_all": "始終顯示所有媒體", - "preferences.fields.expand_spoilers_label": "始終展開標有內容警告的帖文", + "preferences.fields.expand_spoilers_label": "始終展開標有內容警告的貼文", "preferences.fields.language_label": "語言", "preferences.fields.media_display_label": "媒體顯示", "preferences.fields.preserve_spoilers_label": "回覆時保留內容警告", @@ -758,6 +867,7 @@ "privacy.unlisted.short": "所有人", "profile_dropdown.add_account": "新增已有帳戶", "profile_dropdown.logout": "登出 @{acct}", + "profile_dropdown.switch_account": "切換帳戶", "profile_dropdown.theme": "主題", "profile_fields_panel.title": "個人資料字段", "reactions.all": "全部", @@ -797,8 +907,9 @@ "remote_instance.unpin_host": "取消釘選 {host}", "remote_interaction.account_placeholder": "輸入您想採取行動的帳戶 (格式:帳戶名@網域)", "remote_interaction.divider": "或", + "remote_interaction.event_join_title": "遠距參加活動", "remote_interaction.favourite": "按讚", - "remote_interaction.favourite_title": "遠端按讚一條帖文", + "remote_interaction.favourite_title": "遠端按讚一條貼文", "remote_interaction.follow": "開始追蹤", "remote_interaction.follow_title": "遠端追蹤 {user}", "remote_interaction.poll_vote": "投票", @@ -814,7 +925,7 @@ "reply_mentions.account.remove": "從提及名單中移除", "reply_mentions.more": "添加 {count} 個", "reply_mentions.reply": "回覆 {accounts}{more}", - "reply_mentions.reply_empty": "回覆帖文", + "reply_mentions.reply_empty": "回覆貼文", "report.block": "封鎖帳戶 {target}", "report.block_hint": "你是否要封鎖這個帳戶呢?", "report.confirmation.content": "如果我們發現此帳戶確實違反了 {link} ,我們會採取進一步的措施", @@ -844,8 +955,9 @@ "search.action": "搜尋 “{query}”", "search.placeholder": "搜尋", "search_results.accounts": "使用者", + "search_results.filter_message": "您正在搜尋來自 @{acct} 的貼文。", "search_results.hashtags": "主題標籤", - "search_results.statuses": "帖文", + "search_results.statuses": "貼文", "security.codes.fail": "恢復代碼錯誤", "security.confirm.fail": "密碼錯誤,請重試。", "security.delete_account.fail": "帳戶刪除失敗", @@ -872,6 +984,7 @@ "settings.configure_mfa": "設定多重要素驗證 (MFA)", "settings.delete_account": "刪除帳戶", "settings.edit_profile": "編輯個人資料", + "settings.mutes": "靜音", "settings.other": "Other options", "settings.preferences": "首選項", "settings.profile": "個人資料", @@ -900,6 +1013,7 @@ "soapbox_config.greentext_label": "啟用greentext支援", "soapbox_config.headings.advanced": "進階", "soapbox_config.headings.cryptocurrency": "數字貨幣", + "soapbox_config.headings.events": "活動", "soapbox_config.headings.navigation": "導航列", "soapbox_config.headings.options": "選項", "soapbox_config.headings.theme": "主題", @@ -919,29 +1033,29 @@ "soapbox_config.saved": "Soapbox配置已儲存!", "soapbox_config.verified_can_edit_name_label": "允許經過驗證的用戶編輯自己的顯示名稱。", "status.admin_account": "開啟 @{name} 的管理介面", - "status.admin_status": "在管理介面開啟此帖文", + "status.admin_status": "在管理介面開啟此貼文", "status.bookmark": "書籤", "status.bookmarked": "書籤已添加", "status.cancel_reblog_private": "取消轉帖", - "status.cannot_reblog": "這篇帖文無法被轉載", + "status.cannot_reblog": "這篇貼文無法被轉載", "status.chat": "和 @{name} 聊天", - "status.copy": "將連結複製到帖文中", + "status.copy": "將連結複製到貼文中", "status.delete": "刪除", "status.detailed_status": "對話的詳細內容", "status.direct": "發送私訊給 @{name}", "status.edit": "編輯", "status.embed": "嵌入", - "status.external": "View post on {domain}", + "status.external": "查看 {domain} 上的貼文", "status.favourite": "最愛", "status.filtered": "已過濾", "status.load_more": "載入更多", "status.mention": "提到 @{name}", "status.more": "更多", - "status.mute_conversation": "隱藏對話", - "status.open": "展開帖文", + "status.mute_conversation": "靜音對話", + "status.open": "展開貼文", "status.pin": "釘選到個人資料頁", - "status.pinned": "釘選的帖文", - "status.quote": "引用帖文", + "status.pinned": "釘選的貼文", + "status.quote": "引用貼文", "status.reactions.cry": "傷心", "status.reactions.empty": "尚未有人回應心情", "status.reactions.heart": "愛", @@ -956,24 +1070,25 @@ "status.reblogs.empty": "還沒有人轉帖。如果有,會顯示在這裡。", "status.redraft": "刪除 & 編輯", "status.remove_account_from_group": "將帳戶移出群組", - "status.remove_post_from_group": "將帖文移出群組", + "status.remove_post_from_group": "將貼文移出群組", "status.reply": "回覆", "status.replyAll": "回覆所有人", "status.report": "檢舉 @{name}", "status.sensitive_warning": "敏感內容", "status.sensitive_warning.subtitle": "這則貼文可能含有不宜觀看的消息", "status.share": "分享", - "status.show_less_all": "減少顯示這類帖文", - "status.show_more_all": "顯示更多這類帖文", - "status.title": "帖文", + "status.show_filter_reason": "無論如何都顯示", + "status.show_less_all": "減少顯示這類貼文", + "status.show_more_all": "顯示更多這類貼文", + "status.title": "貼文詳情", "status.title_direct": "私訊", "status.unbookmark": "移除書籤", "status.unbookmarked": "書籤已移除", - "status.unmute_conversation": "解除此對話的隱藏", + "status.unmute_conversation": "取消靜音對話", "status.unpin": "解除釘選", - "status_list.queue_label": "點選查看 {count} 個新帖文", - "statuses.quote_tombstone": "帖文不可用", - "statuses.tombstone": "部分帖文不可見", + "status_list.queue_label": "點選查看 {count} 個新貼文", + "statuses.quote_tombstone": "貼文不可用", + "statuses.tombstone": "部分貼文不可見", "streamfield.add": "新增", "streamfield.remove": "移除", "suggestions.dismiss": "關閉建議", @@ -985,7 +1100,7 @@ "tabs_bar.dashboard": "控制台", "tabs_bar.fediverse": "聯邦宇宙", "tabs_bar.home": "主頁", - "tabs_bar.local": "Local", + "tabs_bar.local": "本地", "tabs_bar.more": "更多", "tabs_bar.notifications": "通知", "tabs_bar.profile": "個人資料", @@ -1025,9 +1140,9 @@ "video.expand": "展開影片", "video.fullscreen": "全螢幕", "video.hide": "隱藏影片", - "video.mute": "隱藏", + "video.mute": "靜音音效", "video.pause": "暫停", "video.play": "播放", - "video.unmute": "解除隱藏", + "video.unmute": "取消靜音音效", "who_to_follow.title": "推薦追蹤" } From 125412dd029a5d809e9fd874625956cbc26ca7b2 Mon Sep 17 00:00:00 2001 From: Ahmad Dakhlallah Date: Sat, 11 Nov 2023 13:28:18 +0000 Subject: [PATCH 032/115] Translated using Weblate (Arabic) Currently translated at 100.0% (1523 of 1523 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/ar/ --- src/locales/ar.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/locales/ar.json b/src/locales/ar.json index f482e01af..e674d96c1 100644 --- a/src/locales/ar.json +++ b/src/locales/ar.json @@ -378,7 +378,7 @@ "column_forbidden.body": "ليست لديك الصلاحيات للدخول إلى هذه الصفحة.", "column_forbidden.title": "محظور", "common.cancel": "إلغاء", - "compare_history_modal.header": "تعديل السِّجل", + "compare_history_modal.header": "سِجلّ التعديلات", "compose.character_counter.title": "مُستخدم {chars} حرف من أصل {maxChars} {maxChars, plural, one {حروف} other {حروف}}", "compose.edit_success": "تم تعديل المنشور", "compose.invalid_schedule": "يجب عليك جدولة منشور بمدة لا تقل عن 5 دقائق.", From dd8370a78b795c3d6acdeed38bfd0be69b11ba6e Mon Sep 17 00:00:00 2001 From: Ryan He Date: Mon, 13 Nov 2023 03:53:45 +0000 Subject: [PATCH 033/115] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (1523 of 1523 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/zh_Hant/ --- src/locales/zh-TW.json | 953 ++++++++++++++++++++++++++++------------- 1 file changed, 665 insertions(+), 288 deletions(-) diff --git a/src/locales/zh-TW.json b/src/locales/zh-TW.json index daa7f2fcf..ac6739bc3 100644 --- a/src/locales/zh-TW.json +++ b/src/locales/zh-TW.json @@ -1,8 +1,8 @@ { "about.also_available": "其他版本:", "accordion.collapse": "收起", - "accordion.expand": "展开", - "account.add_or_remove_from_list": "從名單中新增或移除", + "accordion.expand": "展開", + "account.add_or_remove_from_list": "從清單中新增或移除", "account.badges.bot": "機器人", "account.birthday": "出生於 {date}", "account.birthday_today": "今天是你的生日!", @@ -17,20 +17,20 @@ "account.edit_profile": "編輯個人資料", "account.endorse": "在個人資料推薦對方", "account.endorse.success": "你正在你的個人資料中展示 @{acct}", - "account.familiar_followers": "被 {accounts} 追蹤", - "account.familiar_followers.empty": "您認識的人沒有追蹤{name}。", - "account.familiar_followers.more": "你追蹤了 {count} 位其他用戶", - "account.follow": "追蹤", - "account.followers": "追蹤者", - "account.followers.empty": "尚沒有人追蹤這位使用者。", - "account.follows": "正在追蹤", - "account.follows.empty": "這位使用者尚未追蹤任何使用者。", - "account.follows_you": "追蹤了你", + "account.familiar_followers": "被 {accounts} 追隨", + "account.familiar_followers.empty": "您認識的人沒有追隨{name}。", + "account.familiar_followers.more": "你追隨了 {count} 位用戶", + "account.follow": "追隨", + "account.followers": "追隨者", + "account.followers.empty": "尚未有人追隨此用戶。", + "account.follows": "正在追隨", + "account.follows.empty": "這位使用者尚未追隨任何使用者。", + "account.follows_you": "追隨你", "account.header.alt": "個人資料標頭", "account.hide_reblogs": "隱藏來自 @{name} 的轉貼", "account.last_status": "最後活動", "account.link_verified_on": "已在 {date} 檢查此連結的擁有者權限", - "account.locked_info": "此帳戶的隱私狀態被設成鎖定。帳號擁有者會手動審核追蹤此帳號的人。", + "account.locked_info": "此帳戶的隱私狀態被設成鎖定。帳號擁有者會手動審核追隨此帳號的人。", "account.login": "登入", "account.media": "媒體", "account.member_since": "加入於 {date}", @@ -44,10 +44,10 @@ "account.profile": "個人資料", "account.profile_external": "在 {domain} 查看個人資料", "account.register": "註冊", - "account.remote_follow": "遠端追蹤", - "account.remove_from_followers": "移除此追蹤者", + "account.remote_follow": "遠端追隨", + "account.remove_from_followers": "移除此追隨者", "account.report": "檢舉 @{name}", - "account.requested": "正在等待核准。按一下取消追蹤請求", + "account.requested": "正在等待核准。按一下取消追隨請求", "account.requested_small": "等待核准", "account.rss_feed": "訂閱 RSS 來源", "account.search": "搜尋關於 @{name} 的內容", @@ -61,7 +61,7 @@ "account.unblock_domain": "取消隱藏 {domain}", "account.unendorse": "不再於個人資料頁面推薦對方", "account.unendorse.success": "您已不再展示 @{acct}", - "account.unfollow": "取消追蹤", + "account.unfollow": "取消追隨", "account.unmute": "取消靜音 @{name}", "account.unsubscribe": "取消訂閲 @{name}", "account.unsubscribe.failure": "取消訂閲此帳戶時發生錯誤。", @@ -73,7 +73,7 @@ "account_moderation_modal.fields.badges": "客製化徽章", "account_moderation_modal.fields.deactivate": "關閉帳號", "account_moderation_modal.fields.delete": "刪除帳號", - "account_moderation_modal.fields.suggested": "建議追蹤的人", + "account_moderation_modal.fields.suggested": "建議追隨的人", "account_moderation_modal.fields.verified": "已驗證帳戶", "account_moderation_modal.info.id": "ID: {id}", "account_moderation_modal.roles.admin": "管理員", @@ -95,7 +95,7 @@ "admin.dashboard.registration_mode.approval_hint": "使用者可以註冊,但他們的帳戶只有在管理員批准後才會啟用。", "admin.dashboard.registration_mode.approval_label": "需要審核", "admin.dashboard.registration_mode.closed_hint": "沒有人可以註冊。您仍然可以邀請其他人。", - "admin.dashboard.registration_mode.closed_label": "私密", + "admin.dashboard.registration_mode.closed_label": "已關閉", "admin.dashboard.registration_mode.open_hint": "任何人都可以加入。", "admin.dashboard.registration_mode.open_label": "公開", "admin.dashboard.registration_mode_label": "註冊模式", @@ -105,7 +105,7 @@ "admin.dashcounters.retention_label": "使用者留存", "admin.dashcounters.status_count_label": "總貼文數", "admin.dashcounters.user_count_label": "使用者總數", - "admin.dashwidgets.email_list_header": "電郵列表", + "admin.dashwidgets.email_list_header": "電子郵件清單", "admin.dashwidgets.software_header": "軟體版本", "admin.edit_announcement.created": "已建立公告", "admin.edit_announcement.deleted": "公告已刪除", @@ -119,7 +119,7 @@ "admin.edit_announcement.fields.start_time_placeholder": "公告開始日期:", "admin.edit_announcement.save": "儲存", "admin.edit_announcement.updated": "公告已編輯", - "admin.latest_accounts_panel.more": "點擊展開 {count} 個帳戶", + "admin.latest_accounts_panel.more": "點擊展開 {count, plural, one {# account} other {# accounts}}", "admin.latest_accounts_panel.title": "最近加入的帳戶", "admin.moderation_log.empty_message": "你還沒有進行任何管理,如果有任何操作,操作歷史就會顯示在這裏。", "admin.reports.actions.close": "關閉檢舉", @@ -138,14 +138,14 @@ "admin.theme.title": "主題", "admin.user_index.empty": "找不到使用者。", "admin.user_index.search_input_placeholder": "你正在找誰?", - "admin.users.actions.deactivate_user": "禁用帳戶 @{name}", - "admin.users.actions.delete_user": "刪除帳戶 @{name}", - "admin.users.actions.demote_to_moderator_message": "@{acct} 被降級為站務", + "admin.users.actions.deactivate_user": "停用 @{name}", + "admin.users.actions.delete_user": "刪除 @{name}", + "admin.users.actions.demote_to_moderator_message": "@{acct} 被降級為審查員", "admin.users.actions.demote_to_user_message": "@{acct} 被降級為普通用戶", "admin.users.actions.promote_to_admin_message": "@{acct} 被升級為管理員", "admin.users.actions.promote_to_moderator_message": "@{acct} 被升級為審查員", "admin.users.badges_saved_message": "自訂徽章已更新。", - "admin.users.remove_donor_message": "@{acct} 被移除出捐贈者名單", + "admin.users.remove_donor_message": "@{acct} 被移除出捐贈者清單", "admin.users.set_donor_message": "@{acct} 被設為捐贈者", "admin.users.user_deactivated_message": "@{acct} 被停權", "admin.users.user_deleted_message": "@{acct} 被刪除了", @@ -163,11 +163,11 @@ "alert.unexpected.links.status": "狀態", "alert.unexpected.links.support": "支援", "alert.unexpected.message": "發生了非預期的錯誤。", - "alert.unexpected.return_home": "回到主頁", + "alert.unexpected.return_home": "回到首頁", "alert.unexpected.submit_feedback": "提交回應", "alert.unexpected.thanks": "感謝您的回饋意見!", "aliases.account.add": "創建別名", - "aliases.account_label": "原帳戶:", + "aliases.account_label": "原帳戶:", "aliases.aliases_list_delete": "刪除別名", "aliases.search": "搜尋原帳戶", "aliases.success.add": "帳戶別名創建成功", @@ -175,7 +175,7 @@ "announcements.title": "公告", "app_create.name_label": "應用名稱", "app_create.name_placeholder": "例如 'Soapbox'", - "app_create.redirect_uri_label": "重定向網域", + "app_create.redirect_uri_label": "重定向網址", "app_create.restart": "創建另一個", "app_create.results.app_label": "應用", "app_create.results.explanation_text": "您已成功創建一個新應用及其令牌,請複製密鑰等資訊,離開本頁面後這些資訊將不會再次顯示。", @@ -187,23 +187,94 @@ "app_create.website_label": "網站", "auth.awaiting_approval": "您的帳戶正在等待批准", "auth.invalid_credentials": "無效的帳戶名稱或密碼", - "auth.logged_out": "您已登出", + "auth.logged_out": "您已登出。", "authorize.success": "已被批准", "backups.actions.create": "創建備份", - "backups.empty_message": "找不到備份 {action}", + "backups.empty_message": "找不到備份。 {action}", "backups.empty_message.action": "現在創建嗎?", "backups.pending": "等待備份", "badge_input.placeholder": "輸入徽章…", "birthday_panel.title": "生日", "birthdays_modal.empty": "你的朋友今天都沒過生日。", "boost_modal.combo": "下次您可以按 {combo} 跳過", - "boost_modal.title": "重新發布?", + "boost_modal.title": "轉發?", "card.back.label": "返回", + "chat.actions.send": "送出", + "chat.failed_to_send": "訊息發送失敗。", + "chat.input.placeholder": "輸入訊息", + "chat.new_message.title": "新的訊息", + "chat.page_settings.accepting_messages.label": "允許其他使用者與您開始新的聊天", + "chat.page_settings.play_sounds.label": "收到訊息時播放聲音", + "chat.page_settings.preferences": "偏好設定", "chat.page_settings.privacy": "隱私", - "chats.actions.delete": "刪除訊息", + "chat.page_settings.submit": "儲存", + "chat.page_settings.title": "訊息設定", + "chat.retry": "重試?", + "chat.welcome.accepting_messages.label": "允許其他使用者與您開始新的聊天", + "chat.welcome.notice": "您可以稍後變更這些設定。", + "chat.welcome.submit": "儲存並繼續", + "chat.welcome.subtitle": "與其他使用者透過直接訊息交流。", + "chat.welcome.title": "歡迎來到{br}聊天室!", + "chat_composer.unblock": "取消封鎖", + "chat_list_item.blocked_you": "該使用者已封鎖您", + "chat_list_item.blocking": "您已封鎖使用者", + "chat_message_list.blocked": "您封鎖了此使用者", + "chat_message_list.blockedBy": "您被封鎖了", + "chat_message_list.network_failure.action": "再試一次", + "chat_message_list.network_failure.subtitle": "我們遇到了網路故障。", + "chat_message_list.network_failure.title": "糟糕!", + "chat_message_list_intro.actions.accept": "接受", + "chat_message_list_intro.actions.leave_chat": "離開聊天室", + "chat_message_list_intro.actions.message_lifespan": "早於 {day,plural,one {# day} other {# days}} 的訊息將會被刪除。", + "chat_message_list_intro.actions.report": "檢舉", + "chat_message_list_intro.intro": "想和你聊天", + "chat_message_list_intro.leave_chat.confirm": "離開聊天室", + "chat_message_list_intro.leave_chat.heading": "離開聊天室", + "chat_message_list_intro.leave_chat.message": "您確定要離開此聊天室嗎?將為您刪除訊息,並且此聊天室將從您的收件匣中刪除。", + "chat_pane.blankslate.action": "發訊息給某人", + "chat_pane.blankslate.body": "搜尋您想聊天的對象。", + "chat_pane.blankslate.title": "尚未收到任何訊息", + "chat_search.blankslate.body": "搜尋您想聊天的對象。", + "chat_search.blankslate.title": "開始聊天", + "chat_search.empty_results_blankslate.body": "嘗試搜尋其他名稱。", + "chat_search.empty_results_blankslate.title": "未找到符合的名稱", + "chat_search.placeholder": "輸入名稱", + "chat_search.title": "訊息", + "chat_settings.auto_delete.14days": "14天", + "chat_settings.auto_delete.2minutes": "2分鐘", + "chat_settings.auto_delete.30days": "30天", + "chat_settings.auto_delete.7days": "7天", + "chat_settings.auto_delete.90days": "90天", + "chat_settings.auto_delete.days": "{day, plural, one {# day} other {# days}}", + "chat_settings.auto_delete.hint": "已發送的訊息將在選定的期間後自動刪除", + "chat_settings.auto_delete.label": "自動刪除訊息", + "chat_settings.block.confirm": "封鎖", + "chat_settings.block.heading": "封鎖@{acct}", + "chat_settings.block.message": "封鎖將阻止此使用者直接向您發送訊息並查看您的內容。您可以在之後解除封鎖。", + "chat_settings.leave.confirm": "離開聊天室", + "chat_settings.leave.heading": "離開聊天室", + "chat_settings.leave.message": "您確定要離開此聊天室嗎?將為您刪除訊息,並且此聊天室將從您的收件匣中刪除。", + "chat_settings.options.block_user": "封鎖@{acct}", + "chat_settings.options.leave_chat": "離開聊天室", + "chat_settings.options.report_user": "檢舉@{acct}", + "chat_settings.options.unblock_user": "取消封鎖@{acct}", + "chat_settings.title": "聊天室詳情", + "chat_settings.unblock.confirm": "取消封鎖", + "chat_settings.unblock.heading": "取消封鎖@{acct}", + "chat_settings.unblock.message": "取消封鎖將允許此使用者直接向您發送訊息並查看您的內容。", + "chat_window.auto_delete_label": "{day,plural,one {# day} other {# days}}後自動刪除", + "chat_window.auto_delete_tooltip": "聊天訊息設定為發送後 {day,plural,one {# day} other {# days}}後自動刪除。", + "chats.actions.copy": "複製", + "chats.actions.delete": "刪除兩者", + "chats.actions.deleteForMe": "只刪除我的", "chats.actions.more": "更多選項", - "chats.actions.report": "檢舉用戶", + "chats.actions.report": "檢舉", "chats.dividers.today": "今天", + "chats.main.blankslate.new_chat": "發訊息給某人", + "chats.main.blankslate.subtitle": "搜尋您想聊天的對象", + "chats.main.blankslate.title": "尚未收到任何訊息", + "chats.main.blankslate_with_chats.subtitle": "從您開啟的聊天室中選擇一個或建立新訊息。", + "chats.main.blankslate_with_chats.title": "選擇聊天室", "chats.search_placeholder": "開始聊天…", "colum.filters.expiration.1800": "30分鐘", "colum.filters.expiration.21600": "6小時", @@ -212,8 +283,11 @@ "colum.filters.expiration.604800": "1週", "colum.filters.expiration.86400": "1天", "colum.filters.expiration.never": "永不過期", + "column.admin.announcements": "公告", "column.admin.awaiting_approval": "等待核准", + "column.admin.create_announcement": "新增公告", "column.admin.dashboard": "控制台", + "column.admin.edit_announcement": "編輯公告", "column.admin.moderation_log": "管理日誌", "column.admin.reports": "檢舉", "column.admin.reports.menu.moderation_log": "管理日誌", @@ -231,18 +305,21 @@ "column.bookmarks": "書籤", "column.chats": "聊天", "column.community": "本站時間軸", - "column.crypto_donate": "數字貨幣捐贈", + "column.crypto_donate": "捐贈加密貨幣", "column.developers": "開發者", + "column.developers.service_worker": "Service Worker", "column.direct": "私訊", "column.directory": "發現更多", + "column.dislikes": "不喜歡", "column.domain_blocks": "隱藏的網域", "column.edit_profile": "編輯個人資料", "column.event_map": "活動地點", "column.event_participants": "活動參加者", "column.events": "活動", "column.export_data": "匯出資料", - "column.favourited_statuses": "按讚的貼文", - "column.favourites": "按讚", + "column.familiar_followers": "您認識的追隨 {name} 的人", + "column.favourited_statuses": "最愛的貼文", + "column.favourites": "最愛", "column.federation_restrictions": "聯邦限制", "column.filters": "靜音的詞彙", "column.filters.accounts": "帳號", @@ -257,7 +334,7 @@ "column.filters.expires": "過期時間", "column.filters.hide_header": "完全隱藏", "column.filters.hide_hint": "完全隱藏過濾的內容,而不是顯示警告", - "column.filters.home_timeline": "主頁時間軸", + "column.filters.home_timeline": "首頁時間軸", "column.filters.keyword": "關鍵字或短語", "column.filters.keywords": "關鍵字或短語", "column.filters.notifications": "通知", @@ -265,16 +342,20 @@ "column.filters.subheading_add_new": "新增過濾器", "column.filters.title": "標題", "column.filters.whole_word": "整個詞", - "column.follow_requests": "追蹤請求", - "column.followers": "追蹤者", - "column.following": "正在追蹤", + "column.follow_requests": "追隨請求", + "column.followed_tags": "已關注的主題標籤", + "column.followers": "追隨者", + "column.following": "正在追隨", "column.group_blocked_members": "被禁止的成員", + "column.group_pending_requests": "待處理的請求", + "column.groups": "群組", "column.home": "主頁", "column.import_data": "匯入資料", "column.info": "伺服器資訊", - "column.lists": "名單", + "column.lists": "清單", + "column.manage_group": "管理群組", "column.mentions": "提及", - "column.mfa": "兩步驟驗證", + "column.mfa": "多因素驗證", "column.mfa_cancel": "取消", "column.mfa_confirm_button": "確認", "column.mfa_disable_button": "停用", @@ -285,8 +366,10 @@ "column.pins": "釘選的貼文", "column.preferences": "偏好設定", "column.public": "聯邦時間軸", + "column.quotes": "引用貼文", "column.reactions": "心情回應", - "column.reblogs": "轉帖", + "column.reblogs": "轉發", + "column.registration": "註冊", "column.scheduled_statuses": "定時發文", "column.search": "搜尋", "column.settings_store": "設定儲存", @@ -296,9 +379,10 @@ "column_forbidden.title": "無權訪問", "common.cancel": "取消", "compare_history_modal.header": "編輯歷史", - "compose.character_counter.title": "最大字符數: {maxChars}; 已使用 {chars}", + "compose.character_counter.title": "使用了 {maxChars} {maxChars, plural, one {character} other {characters}} 中的 {chars}", "compose.edit_success": "你的貼文已編輯", "compose.invalid_schedule": "您必須安排至少在5分鐘後發布貼文。", + "compose.reply_group_indicator.message": "發佈到 {groupLink}", "compose.submit_success": "您的貼文已發送!", "compose_event.create": "新增", "compose_event.edit_success": "您的活動已編輯", @@ -327,7 +411,7 @@ "compose_form.direct_message_warning": "這篇貼文只會發送給被提及的使用者。", "compose_form.event_placeholder": "發佈到此活動", "compose_form.hashtag_warning": "這篇貼文不會列出在任何主題標籤下,因為它是不公開的。只能透過主題標籤搜尋公開貼文。", - "compose_form.lock_disclaimer": "您的帳戶未{locked}。任何人都可以追蹤您並查看您的僅限追蹤者的貼文。", + "compose_form.lock_disclaimer": "您的帳戶未{locked}。任何人都可以追隨您並查看您的僅限追隨者的貼文。", "compose_form.lock_disclaimer.lock": "上鎖", "compose_form.markdown.marked": "Markdown已啟用", "compose_form.markdown.unmarked": "Markdown已禁用", @@ -342,7 +426,7 @@ "compose_form.poll.remove_option": "移除此選擇", "compose_form.poll.switch_to_multiple": "投票改為多選", "compose_form.poll.switch_to_single": "投票改為單選", - "compose_form.poll_placeholder": "添加投票主題...", + "compose_form.poll_placeholder": "添加投票主題…", "compose_form.publish": "發佈", "compose_form.publish_loud": "{publish}!", "compose_form.save_changes": "儲存變更", @@ -354,23 +438,27 @@ "compose_form.spoiler_placeholder": "請在此處寫入警告訊息", "compose_form.spoiler_remove": "移除敏感內容", "compose_form.spoiler_title": "敏感內容", + "compose_group.share_to_followers": "與我的追隨者分享", "confirmation_modal.cancel": "取消", - "confirmations.admin.deactivate_user.confirm": "禁用帳戶 @{name}", - "confirmations.admin.deactivate_user.heading": "禁用帳戶 @{acct}", - "confirmations.admin.deactivate_user.message": "你確定要禁用帳戶 @{acct} 嗎?此操作不能撤回!", - "confirmations.admin.delete_local_user.checkbox": "我確定我不再需要這個帳戶", + "confirmations.admin.deactivate_user.confirm": "停用帳戶 @{name}", + "confirmations.admin.deactivate_user.heading": "停用帳戶 @{acct}", + "confirmations.admin.deactivate_user.message": "您即將停用@{acct}。停用使用者是一個可逆的操作。", + "confirmations.admin.delete_announcement.confirm": "刪除", + "confirmations.admin.delete_announcement.heading": "刪除公告", + "confirmations.admin.delete_announcement.message": "您確定要刪除此公告嗎?", + "confirmations.admin.delete_local_user.checkbox": "我知道我即將刪除本地用戶。", "confirmations.admin.delete_status.confirm": "刪除貼文", "confirmations.admin.delete_status.heading": "刪除貼文", "confirmations.admin.delete_status.message": "您即將刪除 @{acct} 的貼文。此操作無法撤回。", "confirmations.admin.delete_user.confirm": "刪除帳戶 @{name}", "confirmations.admin.delete_user.heading": "刪除帳戶 @{acct}", - "confirmations.admin.delete_user.message": "你確定要刪除帳戶 @{acct}嗎?此操作不能撤回!", - "confirmations.admin.mark_status_not_sensitive.confirm": "標記為不敏感", - "confirmations.admin.mark_status_not_sensitive.heading": "標記為不敏感", + "confirmations.admin.delete_user.message": "您即將刪除@{acct}。這是無法挽回的破壞性行為。", + "confirmations.admin.mark_status_not_sensitive.confirm": "標記貼文為不敏感", + "confirmations.admin.mark_status_not_sensitive.heading": "標記貼文為不敏感。", "confirmations.admin.mark_status_not_sensitive.message": "你要標記帳戶 @{acct} 的貼文為不敏感。", "confirmations.admin.mark_status_sensitive.confirm": "標記為敏感貼文", "confirmations.admin.mark_status_sensitive.heading": "標記為敏感貼文", - "confirmations.admin.mark_status_sensitive.message": "您要 @{acct} 發布的貼文標記為敏感。", + "confirmations.admin.mark_status_sensitive.message": "您將 @{acct} 發布的貼文標記為敏感。", "confirmations.admin.reject_user.confirm": "拒絕 @{name}", "confirmations.admin.reject_user.heading": "拒絕 @{acct}", "confirmations.admin.reject_user.message": "你正準備拒絕 @{acct} 的註冊請求。此操作不能撤銷。", @@ -381,6 +469,12 @@ "confirmations.block_from_group.confirm": "禁止用戶", "confirmations.block_from_group.heading": "禁止加入群組", "confirmations.block_from_group.message": "您確定要禁止@{name}加入群組嗎?", + "confirmations.cancel.confirm": "丟棄", + "confirmations.cancel.heading": "丟棄貼文", + "confirmations.cancel.message": "您確定要取消建立此貼文嗎?", + "confirmations.cancel_editing.confirm": "取消編輯", + "confirmations.cancel_editing.heading": "取消貼文編輯", + "confirmations.cancel_editing.message": "您確定要取消編輯此貼文嗎?所有變更都將消失。", "confirmations.cancel_event_editing.heading": "取消編輯活動", "confirmations.cancel_event_editing.message": "您確定要取消編輯此活動嗎?所有變更都將消失。", "confirmations.delete.confirm": "刪除", @@ -389,14 +483,23 @@ "confirmations.delete_event.confirm": "刪除", "confirmations.delete_event.heading": "刪除活動", "confirmations.delete_event.message": "您確定要刪除此活動嗎?", + "confirmations.delete_from_group.message": "您確定要刪除@{name}的貼文嗎?", + "confirmations.delete_group.confirm": "刪除", + "confirmations.delete_group.heading": "刪除群組", + "confirmations.delete_group.message": "您確定要刪除此群組嗎?這是無法撤銷的永久性操作。", "confirmations.delete_list.confirm": "刪除", "confirmations.delete_list.heading": "刪除列表", "confirmations.delete_list.message": "你確定要永久刪除這個列表?", "confirmations.domain_block.confirm": "隱藏整個網域", "confirmations.domain_block.heading": "封鎖{domain}", - "confirmations.domain_block.message": "真的非常確定封鎖整個 {domain} 嗎?大部分情況下,你只需要封鎖或靜音少數特定的人就能滿足需求了。你將不能在任何公開的時間軸及通知中看到那個網域的內容。你來自該網域的追蹤者也會被移除。", + "confirmations.domain_block.message": "您真的確定要封鎖整個 {domain} 嗎?在大多數情況下,一些有針對性的阻止或靜音就足夠了,也是更好的選擇。您將不會在任何公開時間軸或通知中看到來自該網域的內容。", + "confirmations.kick_from_group.confirm": "踢出群組", + "confirmations.kick_from_group.message": "您確定要將 @{name} 從此群組中踢出嗎?", "confirmations.leave_event.confirm": "離開活動", "confirmations.leave_event.message": "如果您想重新加入此活動,將再次對這項請求進行人工審核。您確定要繼續嗎?", + "confirmations.leave_group.confirm": "退出", + "confirmations.leave_group.heading": "退出群組", + "confirmations.leave_group.message": "你即將退出群組。你想繼續嗎?", "confirmations.mute.confirm": "靜音", "confirmations.mute.heading": "靜音 @{name}", "confirmations.mute.message": "您確定要將 {name} 靜音嗎?", @@ -405,30 +508,36 @@ "confirmations.mute_group.message": "您要將該群組靜音。你想繼續嗎?", "confirmations.redraft.confirm": "刪除並重新編輯", "confirmations.redraft.heading": "刪除並重新編輯", - "confirmations.redraft.message": "確定刪掉這則貼文並重新編輯嗎?將會失去這則貼文的轉貼及收藏,且回覆這則的貼文將會變成獨立的貼文。", - "confirmations.register.needs_approval": "你的帳戶正在被管理員審核中,請等待一會", + "confirmations.redraft.message": "確定刪掉這則貼文並重新編輯嗎?將會失去這則貼文的轉發及最愛,且回覆這則的貼文將會變成獨立的貼文。", + "confirmations.register.needs_approval": "您的帳戶將由管理員手動批准。我們會審核您的詳細訊息,請耐心等待。", "confirmations.register.needs_approval.header": "需要審核", "confirmations.register.needs_confirmation": "我們已經發送了指引到你的電郵 {email} 中,請檢查收件箱並點擊鏈接以繼續。", "confirmations.register.needs_confirmation.header": "需要確認", "confirmations.remove_from_followers.confirm": "刪除", - "confirmations.remove_from_followers.message": "確定要從你的追蹤者中移走 {name} 嗎?", + "confirmations.remove_from_followers.message": "確定要從你的追隨者中移除 {name} 嗎?", "confirmations.reply.confirm": "回覆", "confirmations.reply.message": "現在回覆將蓋掉您目前正在撰寫的訊息。是否仍要回覆?", + "confirmations.revoke_session.confirm": "撤銷", + "confirmations.revoke_session.heading": "撤銷當前的登入狀態", + "confirmations.revoke_session.message": "您即將撤銷當前的登入狀態。您將被登出。", "confirmations.scheduled_status_delete.confirm": "取消", "confirmations.scheduled_status_delete.heading": "取消貼文定時發布", "confirmations.scheduled_status_delete.message": "你確定要取消這篇貼文定時發布嗎?", - "confirmations.unfollow.confirm": "取消追蹤", - "crypto_donate.explanation_box.message": "{siteTitle} 接受用戶向以下錢包地址捐贈任意數量的數字資產。你的抖內會令我們做得更好!", - "crypto_donate.explanation_box.title": "發起數字貨幣捐贈", + "confirmations.unfollow.confirm": "取消追隨", + "copy.success": "已複製到剪貼簿!", + "crypto_donate.explanation_box.message": "{siteTitle} 接受加密貨幣捐款。您可以將捐款寄至以下任何地址。感謝您的支持!", + "crypto_donate.explanation_box.title": "發送加密貨幣捐款", "crypto_donate_panel.actions.view": "點擊查看 {count} {count, plural, one {wallet} other {wallets}}", - "crypto_donate_panel.heading": "捐贈數字貨幣", - "crypto_donate_panel.intro.message": "{siteTitle} 接受用戶捐贈數字貨幣。感謝你的支持!", - "datepicker.day": "Day", + "crypto_donate_panel.heading": "捐贈加密貨幣", + "crypto_donate_panel.intro.message": "{siteTitle} 接受加密貨幣捐贈來資助我們的服務。感謝您的支持!", + "datepicker.day": "日", "datepicker.hint": "設定發送時間…", + "datepicker.month": "月", "datepicker.next_month": "下個月", "datepicker.next_year": "明年", "datepicker.previous_month": "上個月", "datepicker.previous_year": "去年", + "datepicker.year": "年", "developers.challenge.answer_label": "回答", "developers.challenge.answer_placeholder": "你的回答", "developers.challenge.fail": "回答錯誤", @@ -440,30 +549,34 @@ "developers.navigation.intentional_error_label": "觸發錯誤", "developers.navigation.leave_developers_label": "退出開發者", "developers.navigation.network_error_label": "網路錯誤", + "developers.navigation.service_worker_label": "Service Worker", "developers.navigation.settings_store_label": "設置儲存", + "developers.navigation.show_toast": "Trigger Toast", "developers.navigation.test_timeline_label": "測試時間軸", - "developers.settings_store.hint": "可以在此處直接編輯您的用戶設置。 當心!編輯此部分可能會破壞您的帳戶,您只能通過 API 恢復。", + "developers.settings_store.advanced": "進階設定", + "developers.settings_store.hint": "可以在此處直接編輯您的使用者設定。當心!編輯此部分可能會破壞您的帳戶,並且您只能透過 API 進行還原。", "direct.search_placeholder": "發送私信給…", "directory.federated": "來自已知聯邦宇宙", "directory.local": "僅來自 {domain}", "directory.new_arrivals": "新增訪客", "directory.recently_active": "最近活動", + "edit_email.header": "更改電子郵件", "edit_email.placeholder": "me@example.com", - "edit_federation.followers_only": "對追蹤者以外的使用者隱藏貼文", + "edit_federation.followers_only": "對追隨者以外的使用者隱藏貼文", "edit_federation.force_nsfw": "將附件強制標記為敏感內容", "edit_federation.media_removal": "去除媒體", "edit_federation.reject": "拒絕所有資訊交互", "edit_federation.save": "儲存", "edit_federation.success": "{host} 聯邦設定已儲存", - "edit_federation.unlisted": "將貼文強制標記移出公共時間軸", + "edit_federation.unlisted": "強制貼文不公開", "edit_password.header": "修改密碼", "edit_profile.error": "個人資料更新失敗", - "edit_profile.fields.accepts_email_list_label": "訂閲電子郵件列表", + "edit_profile.fields.accepts_email_list_label": "訂閲電子報", "edit_profile.fields.bio_label": "簡介", "edit_profile.fields.bio_placeholder": "介紹一下自己", "edit_profile.fields.birthday_label": "生日", "edit_profile.fields.birthday_placeholder": "你的生日", - "edit_profile.fields.bot_label": "這是一個機械人帳戶", + "edit_profile.fields.bot_label": "這是一個機器人帳戶", "edit_profile.fields.discoverable_label": "公開自己", "edit_profile.fields.display_name_label": "顯示名稱", "edit_profile.fields.display_name_placeholder": "你的名稱", @@ -478,109 +591,137 @@ "edit_profile.fields.website_label": "網站", "edit_profile.fields.website_placeholder": "顯示連結", "edit_profile.header": "編輯個人資料", - "edit_profile.hints.accepts_email_list": "接收新聞和推廣電郵", - "edit_profile.hints.bot": "此帳戶主要執行自動化操作,可能不受用戶控制", + "edit_profile.hints.accepts_email_list": "選擇接收新聞和行銷更新。", + "edit_profile.hints.bot": "該帳戶主要執行自動操作,可能不會受到監控", "edit_profile.hints.discoverable": "在配置文件目錄中顯示帳戶並允許外部服務索引", - "edit_profile.hints.hide_network": "您追蹤的人和追蹤您的人不會顯示在您的個人資料中", - "edit_profile.hints.locked": "需要您手動批准追蹤請求", - "edit_profile.hints.meta_fields": "你能在個人資料頁面上最多顯示 {count} 行自定義列", - "edit_profile.hints.stranger_notifications": "僅顯示來自您追蹤的人的通知", + "edit_profile.hints.hide_network": "您追隨的人和追隨您的人不會顯示在您的個人資料中", + "edit_profile.hints.locked": "需要您手動批准追隨請求", + "edit_profile.hints.meta_fields": "您的個人資料上最多可以顯示{count, plural, one {# custom field} other {# custom fields}}。", + "edit_profile.hints.stranger_notifications": "僅顯示來自您追隨的人的通知", "edit_profile.save": "儲存", - "edit_profile.success": "個人資料已儲存", + "edit_profile.success": "您的個人資料已成功儲存!", + "email_confirmation.success": "您的電子郵件已被確認!", "embed.instructions": "要嵌入此貼文,請將以下程式碼貼進你的網站。", "emoji_button.activity": "活動", + "emoji_button.add_custom": "新增自訂表情符號", "emoji_button.custom": "自訂", "emoji_button.flags": "旗標", "emoji_button.food": "飲食", "emoji_button.label": "插入表情符號", "emoji_button.nature": "大自然", - "emoji_button.not_found": "啊就沒這表情符號吼!! (╯°□°)╯︵ ┻━┻", + "emoji_button.not_found": "未找到表情符號。", "emoji_button.objects": "物件", - "emoji_button.people": "使用者", + "emoji_button.oh_no": "喔不!", + "emoji_button.people": "人們", + "emoji_button.pick": "選擇一個表情符號…", "emoji_button.recent": "最常使用", "emoji_button.search": "搜尋…", "emoji_button.search_results": "搜尋結果", + "emoji_button.skins_1": "預設", + "emoji_button.skins_2": "淺色", + "emoji_button.skins_3": "中等淺色", + "emoji_button.skins_4": "中等", + "emoji_button.skins_5": "中等深色", + "emoji_button.skins_6": "深色", + "emoji_button.skins_choose": "選擇預設底色", "emoji_button.symbols": "符號", "emoji_button.travel": "旅遊與地點", "empty_column.account_blocked": "你被 @{accountUsername} 封鎖了。", - "empty_column.account_favourited_statuses": "他還沒有按讚任何貼文", + "empty_column.account_favourited_statuses": "該用戶還沒有任何最愛的貼文。", "empty_column.account_timeline": "這裡還沒有貼文!", "empty_column.account_unavailable": "無法取得個人資料", - "empty_column.aliases": "你還沒有設定任何別名", - "empty_column.aliases.suggestions": "暫時沒有可用的帳戶建議", + "empty_column.admin.announcements": "還沒有發布任何公告。", + "empty_column.aliases": "您尚未建立任何帳戶別名。", + "empty_column.aliases.suggestions": "沒有針對所提供的期限的帳戶建議。", "empty_column.blocks": "你還沒有封鎖任何使用者。", - "empty_column.bookmarks": "你還沒有任何書籤收藏,一旦你開始將貼文加入書籤,它將會在這裡顯示。", + "empty_column.bookmarks": "你還沒有任何書籤,一旦你開始將貼文加入書籤,它將會在這裡顯示。", "empty_column.community": "本地時間軸是空的。快公開發佈些文搶頭香啊!", "empty_column.direct": "您還沒有任何私訊。當您私訊別人或收到私訊時,它將於此顯示。", + "empty_column.dislikes": "還沒有人不喜歡這篇文章。當有人這麼做時,他們就會出現在這裡。", "empty_column.domain_blocks": "尚未隱藏任何網域。", "empty_column.event_participant_requests": "沒有待處理的活動參與請求。", "empty_column.event_participants": "尚未有人參加此活動。當有人這麼做時,他們就會出現在這裡。", - "empty_column.favourited_statuses": "你還沒收藏任何貼文。這裡將會顯示你收藏的貼文。", - "empty_column.favourites": "還沒有人收藏這則貼文。這裡將會顯示被收藏的貼文。", + "empty_column.favourited_statuses": "您還沒有任何最愛的貼文。當你這麼做時,它就會出現在這裡。", + "empty_column.favourites": "還沒有人最愛這篇貼文。當有人這麼做時,他們就會出現在這裡。", "empty_column.filters": "您還沒有創建任何靜音詞。", "empty_column.follow_recommendations": "目前似乎暫時沒有推薦訊息,你可以嘗試搜尋用戶或者瀏覽熱門標籤。", - "empty_column.follow_requests": "您尚未收到任何追蹤請求。這裡將會顯示收到的追蹤請求。", + "empty_column.follow_requests": "您尚未收到任何追隨請求。這裡將會顯示收到的追隨請求。", + "empty_column.followed_tags": "您尚未關注任何主題標籤。", + "empty_column.group": "此群組還沒有貼文。", "empty_column.group_blocks": "該群組尚未禁止任何使用者。", + "empty_column.group_membership_requests": "該群組沒有待處理的成員資格請求。", "empty_column.hashtag": "這個主題標籤下什麼也沒有。", - "empty_column.home": "您的首頁時間軸是空的!前往 {public} 或使用搜尋功能來認識其他人。", - "empty_column.home.local_tab": "{site_title} 本站時間軸", - "empty_column.list": "這份名單還沒有東西。當此名單的成員發佈了新的貼文時,它們就會顯示於此。", - "empty_column.lists": "你還沒有建立任何名單。這裡將會顯示你所建立的名單。", + "empty_column.home": "或者您可以造訪 {public} 來開始並結識其他使用者。", + "empty_column.home.local_tab": "{site_title} 分頁", + "empty_column.home.subtitle": "一旦您追隨其他用戶,{siteTitle} 就會變得更有趣。", + "empty_column.home.title": "您還沒有追隨任何人", + "empty_column.list": "此列表中還沒有任何內容。當此列表的成員創建新貼文時,他們將出現在此處。", + "empty_column.lists": "你還沒有建立任何列表。這裡將會顯示你所建立的列表。", "empty_column.mutes": "您尚未將任何使用者靜音。", "empty_column.notifications": "您尚未收到任何通知,和別人互動開啟對話吧。", "empty_column.notifications_filtered": "您還沒有任何此類通知。", - "empty_column.public": "這裡什麼都沒有!嘗試寫些公開的貼文,或著追蹤其他伺服器的使用者後就會出現了", - "empty_column.remote": "這裡什麼都沒有! 關注本站或者其他站點的成員,就會有用戶出現在這裡。", + "empty_column.public": "這裡什麼都沒有!嘗試寫些公開的貼文,或著追隨其他伺服器的使用者後就會出現了", + "empty_column.quotes": "這篇文章尚未被引用。", + "empty_column.remote": "這裡什麼都沒有! 追隨本站或者其他站點的成員,就會有貼文出現在這裡。", "empty_column.scheduled_statuses": "暫時沒有定時貼文。當你發佈定時貼文後,它們會顯示在這裡。", "empty_column.search.accounts": "沒有匹配的帳戶 \"{term}\"", "empty_column.search.hashtags": "沒有匹配的標籤 \"{term}\"", "empty_column.search.statuses": "沒有匹配的貼文 \"{term}\"", - "empty_column.test": "測試時間軸是空的", + "empty_column.test": "測試時間軸是空的。", "event.banner": "活動封面", "event.copy": "複製活動的網址", "event.date": "日期", "event.description": "說明", - "event.discussion.empty": "尚未有人對此事件發表評論。當有人這樣做時,他們就會出現在這裡。", + "event.discussion.empty": "尚未有人對此活動發表評論。當有人這樣做時,他們就會出現在這裡。", "event.export_ics": "匯出到您的日曆", "event.external": "查看 {domain} 上的活動", + "event.join_state.accept": "進行中的", + "event.join_state.empty": "參與", + "event.join_state.pending": "等待審核", + "event.join_state.rejected": "進行中的", "event.location": "地點", "event.manage": "管理", "event.organized_by": "組織者:{name}", + "event.participants": "{count} {rawCount, plural, one {person} other {people}} 正在進行", + "event.quote": "引用活動", + "event.reblog": "轉發活動", "event.show_on_map": "在地圖上顯示", + "event.unreblog": "取消轉發活動", "event.website": "外部連結", + "event_map.navigate": "導航", "events.create_event": "新增活動", "events.joined_events": "已加入的活動", "events.joined_events.empty": "您還沒有參加任何活動。", "events.recent_events": "最近的活動", "events.recent_events.empty": "還沒有公開活動。", "export_data.actions.export": "匯出", - "export_data.actions.export_blocks": "匯出封鎖名單", - "export_data.actions.export_follows": "匯出追蹤名單", - "export_data.actions.export_mutes": "匯出靜音名單", + "export_data.actions.export_blocks": "匯出封鎖清單", + "export_data.actions.export_follows": "匯出追隨清單", + "export_data.actions.export_mutes": "匯出靜音清單", "export_data.blocks_label": "封鎖", - "export_data.follows_label": "追蹤", - "export_data.hints.blocks": "匯出封鎖名單為CSV檔案", - "export_data.hints.follows": "匯出追蹤名單為CSV檔案", - "export_data.hints.mutes": "匯出靜音名單為CSV檔案", + "export_data.follows_label": "追隨", + "export_data.hints.blocks": "取得包含被封鎖帳戶清單的 CSV 文件", + "export_data.hints.follows": "取得包含追隨帳戶清單的 CSV 文件", + "export_data.hints.mutes": "取得包含靜音帳戶清單的 CSV 文件", "export_data.mutes_label": "靜音", - "export_data.success.blocks": "封鎖名單匯出成功", - "export_data.success.followers": "追蹤名單匯出成功", - "export_data.success.mutes": "靜音名單匯出成功", + "export_data.success.blocks": "封鎖清單匯出成功", + "export_data.success.followers": "追隨清單匯出成功", + "export_data.success.mutes": "靜音清單匯出成功", "federation_restriction.federated_timeline_removal": "從聯邦宇宙時間軸移除", - "federation_restriction.followers_only": "僅追蹤者可見", + "federation_restriction.followers_only": "僅追隨者可見", "federation_restriction.full_media_removal": "完全移除媒體", "federation_restriction.media_nsfw": "附件標註為 NSFW", "federation_restriction.partial_media_removal": "部分移除媒體", "federation_restrictions.empty_message": "{siteTitle} 沒有限制任何實例", "federation_restrictions.explanation_box.message": "通常情況下,聯邦宇宙上的伺服器可以自由通訊。然而 {siteTitle} 對以下伺服器實施了限制", "federation_restrictions.explanation_box.title": "實例相關政策", - "federation_restrictions.not_disclosed_message": "{siteTitle} 沒有通過API向聯邦宇宙公開限制。", + "federation_restrictions.not_disclosed_message": "{siteTitle} 不透過 API 揭露聯合限制。", "fediverse_tab.explanation_box.dismiss": "不再顯示", - "fediverse_tab.explanation_box.explanation": "{site_title} 是聯邦宇宙的一份子, 一個由數個站點組成的社交網路集合。你在這裏看到的貼文來自於其他站點。你可以自由地與他們打交道,或者封鎖任何你不喜歡的站點。第二個 @ 符號後的完整帳戶名表示貼文來自哪個站點。要想只看到 {site_title} 的帖文, 請瀏覽 {local} 。", + "fediverse_tab.explanation_box.explanation": "{site_title} 是聯邦宇宙的一份子, 一個由數個站點組成的社交網路集合。你在這裏看到的貼文來自於其他站點。你可以自由地與他們打交道,或者封鎖任何你不喜歡的站點。第二個 @ 符號後的完整帳戶名表示貼文來自哪個站點。要想只看到 {site_title} 的貼文, 請瀏覽 {local} 。", "fediverse_tab.explanation_box.title": "什麼是聯邦宇宙?", - "feed_suggestions.heading": "建議的個人資料", + "feed_suggestions.heading": "建議的使用者", "feed_suggestions.view_all": "檢視全部", - "filters.added": "過濾器已添加。", + "filters.added": "已添加過濾器。", "filters.context_header": "過濾器場景", "filters.context_hint": "一個或多個應用至過濾器的條件", "filters.create_filter": "建立過濾器", @@ -592,37 +733,136 @@ "filters.filters_list_phrases_label": "關鍵字或短語:", "filters.filters_list_warn": "顯示警告", "filters.removed": "過濾器已移除。", + "followRecommendations.heading": "建議的使用者", "follow_request.authorize": "授權", "follow_request.reject": "拒絕", - "getting_started.open_source_notice": "{code_name} 是開源軟體。你可以在 GitLab {code_link} (v{code_version}) 上貢獻或是回報問題。", + "gdpr.accept": "接受", + "gdpr.learn_more": "了解更多", + "gdpr.message": "{siteTitle} 使用 cookie,這對於網站的運作至關重要。", + "gdpr.title": "{siteTitle} 使用 cookie", + "generic.saved": "已儲存", + "getting_started.open_source_notice": "{code_name} 是開源軟體。您可以在 {code_link} (v{code_version}) 上貢獻或回報問題。", + "group.banned.message": "您已被禁止加入 {group}", + "group.cancel_request": "取消請求", + "group.delete.success": "群組刪除成功", + "group.deleted.message": "此群組已被刪除。", + "group.demote.user.success": "@{name} 現已成為會員", + "group.group_mod_authorize.fail": "無法批准@{name}", "group.group_mod_block": "禁止加入群組", "group.group_mod_block.success": "@{name} 已被封鎖", + "group.group_mod_demote": "刪除 {role} 角色", + "group.group_mod_kick": "從群組踢出@{name}", + "group.group_mod_kick.success": "已將 @{name} 從群組踢出", + "group.group_mod_promote_mod": "分配 {role} 角色", + "group.group_mod_reject.fail": "拒絕 @{name} 失敗", "group.group_mod_unblock": "取消封鎖", + "group.group_mod_unblock.success": "將 @{name} 從群組解禁", + "group.header.alt": "群組標題", + "group.join.private": "請求加入", + "group.join.public": "加入群組", + "group.join.request_success": "請求已發送給群組所有者", + "group.join.success": "已成功加入群組!", + "group.leave": "退出群組", + "group.leave.label": "退出", + "group.leave.success": "退出群組", + "group.manage": "管理群組", + "group.member.admin.limit.summary": "您可以為群組指派最多{count, plural, one {admin} other {admins}}。", + "group.member.admin.limit.title": "已達到管理員額上限", "group.mute.label": "靜音", "group.mute.long_label": "靜音群組", "group.mute.success": "將群組設為靜音", + "group.popover.action": "查看群組", + "group.popover.summary": "您必須是該群組的成員才能回覆此貼文。", + "group.popover.title": "需要成員資格", + "group.privacy.locked": "私人的", + "group.privacy.locked.full": "私人群組", + "group.privacy.locked.info": "可發現的。使用者可以在申請獲得批准後加入。", + "group.privacy.public": "公開的", + "group.privacy.public.full": "公開群組", + "group.privacy.public.info": "可發現的。任何人都可以加入。", + "group.private.message": "內容僅對群組成員可見", + "group.promote.admin.confirmation.message": "您確定要將管理員角色指派給@{name}嗎?", + "group.promote.admin.confirmation.title": "分配管理員角色", + "group.promote.admin.success": "@{name} 現在是管理員", + "group.report.label": "檢舉", + "group.role.admin": "管理員", + "group.role.owner": "擁有者", + "group.share.label": "分享", + "group.tabs.all": "全部", + "group.tabs.media": "媒體", + "group.tabs.members": "成員", + "group.tabs.tags": "主題", + "group.tags.empty": "此群組中還沒有主題。", + "group.tags.hidden.success": "主題被標記為隱藏", + "group.tags.hide": "隱藏主題", + "group.tags.hint": "最多增加 3 個關鍵字,作為小組討論的核心主題。", + "group.tags.label": "標籤", + "group.tags.pin": "置頂主題", + "group.tags.pin.success": "已置頂!", + "group.tags.show": "顯示主題", + "group.tags.total": "貼文總數", + "group.tags.unpin": "取消置頂主題", + "group.tags.unpin.success": "取消置頂!", + "group.tags.visible.success": "主題標記為可見", "group.unmute.label": "取消靜音", "group.unmute.long_label": "取消群組靜音", "group.unmute.success": "取消群組靜音", + "group.update.success": "群組已成功儲存", + "group.upload_avatar": "上傳頭像", + "group.upload_banner": "上傳圖片", + "group.upload_banner.title": "上傳背景圖片", + "groups.discover.popular.empty": "目前無法取得熱門群組。請稍後再回來查看。", + "groups.discover.popular.show_more": "顯示更多", + "groups.discover.popular.title": "熱門群組", + "groups.discover.search.error.subtitle": "請稍後再試。", + "groups.discover.search.error.title": "發生錯誤", + "groups.discover.search.no_results.subtitle": "嘗試搜尋另一個群組。", + "groups.discover.search.no_results.title": "未找到任何結果", + "groups.discover.search.placeholder": "搜尋", + "groups.discover.search.recent_searches.blankslate.subtitle": "搜尋群組名稱、主題或關鍵字", + "groups.discover.search.recent_searches.blankslate.title": "沒有最近的搜索", + "groups.discover.search.recent_searches.clear_all": "清除全部", + "groups.discover.search.recent_searches.title": "最近的搜尋", + "groups.discover.search.results.groups": "群組", + "groups.discover.search.results.member_count": "{members, plural, one {member} other {members}}", + "groups.discover.suggested.empty": "目前無法取得建議的群組。請稍後再回來查看。", + "groups.discover.suggested.show_more": "顯示更多", + "groups.discover.suggested.title": "為您推薦", + "groups.discover.tags.empty": "目前無法取得熱門主題。請稍後再回來查看。", + "groups.discover.tags.show_more": "顯示更多", + "groups.discover.tags.title": "瀏覽主題", + "groups.discovery.tags.no_of_groups": "群組數量", + "groups.empty.subtitle": "開始發掘可以加入的群組或建立自己的群組。", + "groups.empty.title": "還沒有群組", + "groups.pending.count": "{number, plural, one {# pending request} other {# pending requests}}", + "groups.pending.empty.subtitle": "您目前沒有待處理的請求。", + "groups.pending.empty.title": "沒有待處理的請求", + "groups.pending.label": "待處理的請求", + "groups.popular.label": "推薦的群組", + "groups.search.placeholder": "搜尋我的群組", + "groups.suggested.label": "推薦的群組", + "groups.tags.title": "瀏覽主題", + "hashtag.follow": "關注主題標籤", "header.login.label": "登入", "header.register.label": "註冊", - "home.column_settings.show_reblogs": "顯示轉帖", + "home.column_settings.show_reblogs": "顯示轉發", "home.column_settings.show_replies": "顯示回覆", "icon_button.icons": "圖示", "icon_button.label": "選取圖示", "import_data.actions.import": "匯入", - "import_data.actions.import_blocks": "匯入封鎖名單", - "import_data.actions.import_follows": "匯入追蹤名單", - "import_data.actions.import_mutes": "匯入靜音名單", + "import_data.actions.import_blocks": "匯入封鎖清單", + "import_data.actions.import_follows": "匯入追隨清單", + "import_data.actions.import_mutes": "匯入靜音清單", "import_data.blocks_label": "封鎖帳戶", - "import_data.follows_label": "追蹤帳戶", - "import_data.hints.blocks": "上載包含封鎖帳戶名單的CSV檔案", - "import_data.hints.follows": "上載包含追蹤帳戶名單的CSV檔案", - "import_data.hints.mutes": "上載包含靜音帳戶名單的CSV檔案", + "import_data.follows_label": "追隨帳戶", + "import_data.hints.blocks": "包含被封鎖帳戶清單的 CSV 文件", + "import_data.hints.follows": "包含追隨帳戶清單的 CSV 文件", + "import_data.hints.mutes": "包含靜音帳戶清單的 CSV 文件", "import_data.mutes_label": "靜音", - "import_data.success.blocks": "封鎖帳戶名單已匯入", - "import_data.success.followers": "追蹤帳戶名單已匯入", - "import_data.success.mutes": "靜音帳戶名單已匯入", + "import_data.success.blocks": "封鎖帳戶清單已匯入", + "import_data.success.followers": "追隨帳戶清單已匯入", + "import_data.success.mutes": "靜音帳戶清單已匯入", + "input.copy": "複製", "input.password.hide_password": "隱藏密碼", "input.password.show_password": "顯示密碼", "intervals.full.days": "{number} 天", @@ -635,89 +875,128 @@ "join_event.success": "已參加活動", "join_event.title": "參加活動", "keyboard_shortcuts.back": "返回上一頁", - "keyboard_shortcuts.blocked": "開啟「封鎖使用者」名單", - "keyboard_shortcuts.boost": "轉帖", + "keyboard_shortcuts.blocked": "開啟封鎖的使用者清單", + "keyboard_shortcuts.boost": "轉發", "keyboard_shortcuts.compose": "將焦點移至撰寫文字區塊", - "keyboard_shortcuts.down": "往下移動名單項目", - "keyboard_shortcuts.enter": "檢視貼文", - "keyboard_shortcuts.favourite": "收藏", - "keyboard_shortcuts.favourites": "開啟收藏名單", + "keyboard_shortcuts.down": "在清單中向下移動", + "keyboard_shortcuts.enter": "開啟貼文", + "keyboard_shortcuts.favourite": "加入最愛", + "keyboard_shortcuts.favourites": "開啟最愛清單", "keyboard_shortcuts.heading": "鍵盤快速鍵", "keyboard_shortcuts.home": "開啟首頁時間軸", "keyboard_shortcuts.hotkey": "快速鍵", - "keyboard_shortcuts.legend": "顯示此名單", + "keyboard_shortcuts.legend": "顯示此圖例", "keyboard_shortcuts.mention": "提及作者", - "keyboard_shortcuts.muted": "開啟靜音使用者名單", + "keyboard_shortcuts.muted": "開啟靜音使用者清單", "keyboard_shortcuts.my_profile": "開啟個人資料頁面", "keyboard_shortcuts.notifications": "開啟通知欄", "keyboard_shortcuts.open_media": "開啟媒體", - "keyboard_shortcuts.pinned": "開啟釘選的貼文名單", + "keyboard_shortcuts.pinned": "開啟釘選的貼文清單", "keyboard_shortcuts.profile": "開啟作者的個人資料頁面", "keyboard_shortcuts.react": "心情回應", "keyboard_shortcuts.reply": "回覆", - "keyboard_shortcuts.requests": "開啟追蹤請求名單", + "keyboard_shortcuts.requests": "開啟追隨請求清單", "keyboard_shortcuts.search": "將焦點移至搜尋框", "keyboard_shortcuts.toggle_hidden": "顯示/隱藏在內容警告之後的正文", - "keyboard_shortcuts.toggle_sensitivity": "顯示 / 隱藏媒體", - "keyboard_shortcuts.toot": "開始發出新貼文", + "keyboard_shortcuts.toggle_sensitivity": "顯示/隱藏媒體", + "keyboard_shortcuts.toot": "開始一個新貼文", "keyboard_shortcuts.unfocus": "取消輸入文字區塊 / 搜尋的焦點", - "keyboard_shortcuts.up": "往上移動名單項目", + "keyboard_shortcuts.up": "在列表中向上移動", "landing_page_modal.download": "下載", "landing_page_modal.helpCenter": "支援中心", "lightbox.close": "關閉", + "lightbox.expand": "展開", + "lightbox.minimize": "最小化", "lightbox.next": "下一步", "lightbox.previous": "上一步", "lightbox.view_context": "檢視內文", - "list.click_to_add": "點擊新增帳戶到名單", - "list_adder.header_title": "從名單中添加或刪除帳戶", - "lists.account.add": "新增至名單", - "lists.account.remove": "從名單中移除", - "lists.delete": "刪除名單", - "lists.edit": "編輯名單", + "list.click_to_add": "點擊新增帳戶到清單", + "list_adder.header_title": "從清單中添加或刪除帳戶", + "lists.account.add": "新增至清單", + "lists.account.remove": "從清單中移除", + "lists.delete": "刪除清單", + "lists.edit": "編輯清單", "lists.edit.submit": "變更標題", - "lists.new.create": "新增名單", - "lists.new.create_title": "新增名單", - "lists.new.save_title": "儲存名單", - "lists.new.title_placeholder": "新名單標題", - "lists.search": "搜尋您追蹤的使用者", - "lists.subheading": "您的名單", + "lists.new.create": "新增清單", + "lists.new.create_title": "新增清單", + "lists.new.save_title": "儲存清單", + "lists.new.title_placeholder": "新清單標題", + "lists.search": "在您追隨的人中搜尋", + "lists.subheading": "您的清單", "loading_indicator.label": "讀取中...", + "location_search.placeholder": "查找地址", + "login.fields.email_label": "電子郵件地址", "login.fields.instance_label": "實例", "login.fields.instance_placeholder": "example.com", - "login.fields.otp_code_hint": "輸入兩步驟驗證應用程式裏的代碼,或者輸入恢復代碼", + "login.fields.otp_code_hint": "輸入您的手機應用程式產生的雙因素代碼或使用您的恢復代碼之一", "login.fields.otp_code_label": "兩步驟驗證代碼:", "login.fields.password_placeholder": "密碼", "login.fields.username_label": "電郵地址或帳戶名稱", "login.log_in": "登入", - "login.otp_log_in": "兩步驟驗證登入", - "login.otp_log_in.fail": "兩步驟驗證代號無效,請重新輸入", + "login.otp_log_in": "一次性密碼登入", + "login.otp_log_in.fail": "密碼無效,請重新輸入。", "login.reset_password_hint": "登入遇到了問題?", "login.sign_in": "登入", + "login_external.errors.instance_fail": "實例傳回錯誤。", + "login_external.errors.network_fail": "連線失敗。是瀏覽器擴充功能阻止了嗎?", "login_form.header": "登入", - "media_panel.empty_message": "未找到媒體", + "manage_group.blocked_members": "被禁止的成員", + "manage_group.confirmation.copy": "複製連結", + "manage_group.confirmation.info_1": "作為該群組的擁有者,您可以指派管理人員、刪除貼文等等。", + "manage_group.confirmation.info_2": "發布群組的第一篇貼文並開始對話。", + "manage_group.confirmation.info_3": "與朋友、家人和追隨者分享您的新群組,以增加其成員數量。", + "manage_group.confirmation.share": "分享這個群組", + "manage_group.confirmation.title": "一切就緒!", + "manage_group.create": "建立群組", + "manage_group.delete_group": "刪除群組", + "manage_group.done": "完成", + "manage_group.edit_group": "編輯群組", + "manage_group.fields.cannot_change_hint": "建立群組後無法變更。", + "manage_group.fields.description_label": "說明", + "manage_group.fields.description_placeholder": "說明", + "manage_group.fields.hashtag_placeholder": "新增主題", + "manage_group.fields.name_help": "建立群組後無法變更。", + "manage_group.fields.name_label": "群組名稱(必填)", + "manage_group.fields.name_label_optional": "群組名稱", + "manage_group.fields.name_placeholder": "群組名稱", + "manage_group.get_started": "讓我們開始吧!", + "manage_group.next": "下一步", + "manage_group.pending_requests": "待處理的請求", + "manage_group.privacy.hint": "這些設定以後無法變更。", + "manage_group.privacy.label": "隱私設定", + "manage_group.privacy.private.hint": "可發現的。使用者可以在申請獲得批准後加入。", + "manage_group.privacy.private.label": "私人(需要所有者批准)", + "manage_group.privacy.public.hint": "可發現的。任何人都可以加入。", + "manage_group.privacy.public.label": "公開的", + "manage_group.tagline": "群組根據共同興趣將您與其他人聯繫起來。", + "media_panel.empty_message": "沒有找到媒體。", "media_panel.title": "媒體", "mfa.confirm.success_message": "多重要素驗證 (MFA) 已啟用", "mfa.disable.success_message": "多重要素驗證 (MFA) 已停用", - "mfa.mfa_disable_enter_password": "輸入當前密碼以停用兩步驟驗證:", - "mfa.mfa_setup.code_hint": "輸入兩步驟驗證應用程式裏的代碼", + "mfa.disabled": "已停用", + "mfa.enabled": "已啟用", + "mfa.mfa_disable_enter_password": "輸入您目前的密碼以停用雙因素認證。", + "mfa.mfa_setup.code_hint": "輸入雙因素應用程式中的代碼。", "mfa.mfa_setup.code_placeholder": "代碼", - "mfa.mfa_setup.password_hint": "輸入當前密碼以確認你的身份", + "mfa.mfa_setup.password_hint": "輸入您目前的密碼以確認您的身分。", "mfa.mfa_setup.password_placeholder": "密碼", - "mfa.mfa_setup_scan_description": "請使用 Google Authenticator 或其他應用程式來掃描 QR 碼。啟用兩步驟驗證後,在登入時你需要提供該應用程式生成的代碼", - "mfa.mfa_setup_scan_title": "如果你無法掃描 QR 碼,請手動輸入下列文本:", - "mfa.mfa_setup_verify_title": "啟用", - "mfa.otp_enabled_description": "您已成功啟用兩步驟驗證", - "mfa.otp_enabled_title": "兩步驟驗證已啟用", + "mfa.mfa_setup_scan_description": "使用雙因素應用程式掃描此二維碼或輸入文字鍵。", + "mfa.mfa_setup_scan_title": "掃描", + "mfa.mfa_setup_verify_title": "驗證", + "mfa.otp_enabled_description": "您已透過一次性密碼啟用雙因素認證。", + "mfa.otp_enabled_title": "一次性密碼已啟用", "mfa.setup_recoverycodes": "恢復代碼", - "mfa.setup_warning": "請將你的恢復代碼記在安全的地方或寫在紙上,建議與個人資訊分開存放,以便在丟失兩步驟驗證應用程式時可以恢復你的帳戶。", - "migration.fields.acct.label": "新帳戶的帳戶名稱", + "mfa.setup_warning": "寫下這些恢復代碼或將它們保存在安全的地方 - 否則您將不會再看到它們。如果您無法存取雙因素驗證應用程式和恢復代碼,您的帳戶將被鎖定。", + "migration.fields.acct.label": "新帳戶的完整名稱", "migration.fields.acct.placeholder": "帳戶名稱@網域", "migration.fields.confirm_password.label": "當前密碼", - "migration.hint": "你的追蹤者將被轉移到新帳戶,除此之外其他資料將不會被轉移。要執行遷移,您需要先{link}你的新帳戶", + "migration.hint": "這會將您的追隨者轉移到新帳戶。不會移動其他資料。要執行遷移,您需要先在新帳戶上{link}。", + "migration.hint.cooldown_period": "如果您遷移帳戶,您將在 {cooldownPeriod, plural, one {one day} other {the next # days}} 內無法移轉帳戶。", "migration.hint.link": "新建一個帳戶別名", "migration.move_account.fail": "帳戶遷移失敗。", + "migration.move_account.fail.cooldown_period": "您最近遷移了您的帳戶。請稍後再試。", "migration.move_account.success": "帳戶遷移成功了!", - "migration.submit": "遷移關注者", + "migration.submit": "遷移追隨者", "missing_description_modal.cancel": "取消", "missing_description_modal.continue": "發佈", "missing_description_modal.description": "仍然繼續發佈嗎?", @@ -734,11 +1013,13 @@ "mute_modal.hide_notifications": "隱藏來自這個帳戶的通知?", "mutes.empty.groups": "您尚未將任何群組靜音。", "navbar.login.action": "登入", + "navbar.login.email.placeholder": "電子郵件地址", "navbar.login.forgot_password": "忘記密碼?", "navbar.login.password.label": "密碼", - "navbar.login.username.placeholder": "郵箱地址或帳戶名稱", + "navbar.login.username.placeholder": "電子郵件或使用者名稱", "navigation.chats": "聊天", "navigation.compose": "發佈新貼文", + "navigation.compose_group": "發文到群組", "navigation.dashboard": "控制台", "navigation.developers": "開發者", "navigation.direct_messages": "私人訊息", @@ -752,13 +1033,20 @@ "navigation_bar.compose_direct": "發送私人訊息", "navigation_bar.compose_edit": "編輯貼文", "navigation_bar.compose_event": "管理活動", + "navigation_bar.compose_group": "發文到群組", + "navigation_bar.compose_group_reply": "回覆群組貼文", "navigation_bar.compose_quote": "引用貼文", "navigation_bar.compose_reply": "回覆貼文", "navigation_bar.create_event": "新增活動", + "navigation_bar.create_group": "建立群組", + "navigation_bar.create_group.private": "建立私人群組", + "navigation_bar.create_group.public": "建立公開群組", "navigation_bar.domain_blocks": "隱藏的網域", - "navigation_bar.favourites": "收藏", + "navigation_bar.edit_group": "編輯群組", + "navigation_bar.favourites": "最愛", "navigation_bar.filters": "過濾器", - "navigation_bar.follow_requests": "追蹤請求", + "navigation_bar.follow_requests": "追隨請求", + "navigation_bar.followed_tags": "已關注的主題標籤", "navigation_bar.import_data": "匯入資料", "navigation_bar.in_reply_to": "回覆", "navigation_bar.invites": "邀請", @@ -770,44 +1058,59 @@ "new_event_panel.action": "新增活動", "new_event_panel.subtitle": "找不到您要找的東西?安排您自己的活動。", "new_event_panel.title": "新增活動", - "notification.favourite": "{name} 讚了你的貼文", - "notification.follow": "{name} 追蹤了你", - "notification.follow_request": "{name} 請求追蹤你", + "new_group_panel.action": "建立群組", + "new_group_panel.subtitle": "找不到想要的內容?建立您自己的私人或公共群組。", + "new_group_panel.title": "建立群組", + "notification.favourite": "{name} 最愛了你的貼文", + "notification.follow": "{name} 追隨了你", + "notification.follow_request": "{name} 請求追隨你", + "notification.group_favourite": "{name} 最愛您的群組貼文", + "notification.group_reblog": "{name} 轉發了您的群組貼文", "notification.mention": "{name} 提到了你", "notification.mentioned": "{name} 提到了你", "notification.move": "{name} 移動到了 {targetName}", "notification.name": "{link}{others}", - "notification.others": " + {count} 其他通知", - "notification.pleroma:chat_mention": "{name} 給你發送了訊息", + "notification.others": "+ {count, plural, one {# other} other {# others}}", + "notification.pleroma:chat_mention": "{name} 發送了訊息給你", "notification.pleroma:emoji_reaction": "{name} 用表情回應了你的貼文", "notification.pleroma:event_reminder": "您正在參加的活動即將開始", "notification.pleroma:participation_accepted": "您已獲準參加活動", "notification.pleroma:participation_request": "{name}想要參加您的活動", "notification.poll": "你參與的一項投票已經結束", - "notification.reblog": "{name} 轉貼了你的貼文", - "notification.status": "{name} 剛剛發帖", + "notification.reblog": "{name} 轉發了你的貼文", + "notification.status": "{name} 剛剛發文", "notification.update": "{name} 編輯了你參與互動的貼文", "notification.user_approved": "歡迎來到 {instance}!", "notifications.filter.all": "全部", "notifications.filter.boosts": "轉貼", "notifications.filter.emoji_reacts": "表情符號回應", "notifications.filter.favourites": "最愛", - "notifications.filter.follows": "追蹤的使用者", + "notifications.filter.follows": "追隨的使用者", "notifications.filter.mentions": "提及", "notifications.filter.polls": "投票結果", - "notifications.filter.statuses": "來自追蹤的人的更新", + "notifications.filter.statuses": "來自追隨的人的更新", "notifications.group": "{count} 條通知", "notifications.queue_label": "點擊查看 {count} 條新通知", "oauth_consumer.tooltip": "通過 {provider} 登入", "oauth_consumers.title": "更多登入方式", "onboarding.avatar.subtitle": "祝你玩得開心!", "onboarding.avatar.title": "設定你的頭像", + "onboarding.bio.hint": "最多 500 個字", + "onboarding.bio.placeholder": "向世界介紹一下自己…", + "onboarding.display_name.label": "顯示名稱", + "onboarding.display_name.placeholder": "例如:約翰史密斯", "onboarding.display_name.subtitle": "你可以稍後更改", "onboarding.display_name.title": "設定你的顯示名稱", "onboarding.done": "完成", - "onboarding.fediverse.next": "Next", + "onboarding.error": "發生意外錯誤。請重試或跳過此步驟。", + "onboarding.fediverse.its_you": "這是你!其他人可以使用您的完整 @帳號名稱 從其他伺服器追隨您。", + "onboarding.fediverse.message": "聯邦宇宙是一個由成千上萬個獨立經營的社群媒體網站(又稱「伺服器」)組成的社群網路。您可以追隨大多數其他聯邦宇宙伺服器上的用戶,喜歡、轉發和回覆貼文,因為他們可以與{siteTitle}進行交流。", + "onboarding.fediverse.next": "下一步", + "onboarding.fediverse.other_instances": "瀏覽時間軸時,請注意第二個 @ 符號後面的完整用戶名,以了解貼文來自哪個伺服器。", + "onboarding.fediverse.title": "{siteTitle}只是聯邦宇宙的一部分", + "onboarding.fediverse.trailer": "由於它是分散式的,任何人都可以運行自己的伺服器,因此聯邦宇宙具有彈性和開放性。如果您選擇加入另一個伺服器或建立自己的伺服器,您可以與相同的人互動,並在相同的社交圖譜上繼續前進。", "onboarding.finished.message": "我們很高興歡迎您加入我們的社區! 點擊下面的按鈕,讓我們開始吧!", - "onboarding.finished.title": "新手教程完成", + "onboarding.finished.title": "新手教學完成", "onboarding.header.subtitle": "這將顯示在你個人資料的上方。", "onboarding.header.title": "選擇封面圖片", "onboarding.next": "下一步", @@ -817,19 +1120,20 @@ "onboarding.skip": "現在跳過", "onboarding.suggestions.subtitle": "以下是幾個受歡迎的帳戶,你可能會喜歡", "onboarding.suggestions.title": "推薦帳戶", - "onboarding.view_feed": "檢視列表", - "password_reset.confirmation": "請查閲確認電郵", - "password_reset.fields.username_placeholder": "電郵地址或帳戶名稱", - "password_reset.header": "Reset Password", + "onboarding.view_feed": "檢視時間軸", + "password_reset.confirmation": "檢查您的電子郵件以進行確認。", + "password_reset.fields.email_placeholder": "電子郵件地址", + "password_reset.fields.username_placeholder": "電子郵件或使用者名稱", + "password_reset.header": "重設密碼", "password_reset.reset": "重設密碼", - "patron.donate": "抖內", + "patron.donate": "捐贈", "patron.title": "籌集目標", "pinned_accounts.title": "{name} 的釘選", - "pinned_statuses.none": "沒有釘選的貼文", - "poll.choose_multiple": "盡情選擇你所感興趣的", + "pinned_statuses.none": "沒有釘選的貼文。", + "poll.choose_multiple": "想選多少就選多少。", "poll.closed": "已關閉", - "poll.non_anonymous": "公共投票", - "poll.non_anonymous.label": "其他的實例可能可以見到你投票的選擇", + "poll.non_anonymous": "公開投票", + "poll.non_anonymous.label": "其他實例可能會顯示您投票的選項", "poll.refresh": "重新整理", "poll.total_people": "還有 {count} 人", "poll.total_votes": "投票", @@ -840,31 +1144,43 @@ "poll_button.remove_poll": "移除投票", "preferences.fields.auto_play_gif_label": "自動播放GIF", "preferences.fields.autoload_more_label": "滾動至時間軸底部自動載入更多貼文", - "preferences.fields.autoload_timelines_label": "滾動至時間軸頂部自動載入更多新帖", - "preferences.fields.boost_modal_label": "轉帖前顯示確認提示", + "preferences.fields.autoload_timelines_label": "滾動至時間軸頂部自動載入更多新貼文", + "preferences.fields.boost_modal_label": "轉發前顯示確認提示", "preferences.fields.content_type_label": "預設貼文格式", "preferences.fields.delete_modal_label": "刪除貼文前顯示確認提示", + "preferences.fields.demetricator_label": "使用數據採集器", + "preferences.fields.demo_hint": "使用預設的 Soapbox 標誌和配色方案。對於截圖很有用。", + "preferences.fields.demo_label": "展示模式", "preferences.fields.display_media.default": "隱藏被標記為敏感內容的媒體", "preferences.fields.display_media.hide_all": "始終隱藏所有媒體", "preferences.fields.display_media.show_all": "始終顯示所有媒體", "preferences.fields.expand_spoilers_label": "始終展開標有內容警告的貼文", - "preferences.fields.language_label": "語言", - "preferences.fields.media_display_label": "媒體顯示", + "preferences.fields.language_label": "界面語言", + "preferences.fields.media_display_label": "敏感內容", + "preferences.fields.missing_description_modal_label": "在發送無媒體描述的貼文前顯示確認對話框", "preferences.fields.preserve_spoilers_label": "回覆時保留內容警告", "preferences.fields.privacy_label": "預設貼文隱私", - "preferences.fields.theme": "主題", + "preferences.fields.reduce_motion_label": "減少動畫中的運動", + "preferences.fields.system_font_label": "使用系統預設字型", + "preferences.fields.theme": "佈景主題", + "preferences.fields.underline_links_label": "永遠顯示貼文中連結的底線", + "preferences.fields.unfollow_modal_label": "在取消追隨某人之前顯示確認對話框", + "preferences.hints.demetricator": "透過隱藏網站上的所有數字來減少社群媒體焦慮。", + "preferences.notifications.advanced": "顯示所有通知類別", "preferences.options.content_type_markdown": "Markdown", "preferences.options.content_type_plaintext": "純文字", - "preferences.options.privacy_public": "Public", + "preferences.options.privacy_followers_only": "僅限追隨者", + "preferences.options.privacy_public": "公開", + "preferences.options.privacy_unlisted": "不公開", "privacy.change": "調整隱私狀態", "privacy.direct.long": "只有被提到的使用者能看到", "privacy.direct.short": "僅被提及的使用者", - "privacy.private.long": "只有追蹤你的使用者能看到", - "privacy.private.short": "僅追蹤者", - "privacy.public.long": "所有人可見,出現在公共時間軸上", - "privacy.public.short": "公共時間軸", - "privacy.unlisted.long": "公開,但不會顯示在公共時間軸", - "privacy.unlisted.short": "所有人", + "privacy.private.long": "只有追隨你的使用者能看到", + "privacy.private.short": "僅追隨者", + "privacy.public.long": "所有人可見,出現在公開時間軸上", + "privacy.public.short": "公開時間軸", + "privacy.unlisted.long": "不會顯示在公開時間軸", + "privacy.unlisted.short": "不公開", "profile_dropdown.add_account": "新增已有帳戶", "profile_dropdown.logout": "登出 @{acct}", "profile_dropdown.switch_account": "切換帳戶", @@ -873,84 +1189,97 @@ "reactions.all": "全部", "regeneration_indicator.label": "載入中…", "regeneration_indicator.sublabel": "你的主頁時間軸正在準備中!", - "register_invite.lead": "填寫下列表單以註冊帳戶", + "register_invite.lead": "填寫下列表單以註冊帳戶。", "register_invite.title": "你已被邀請加入 {siteTitle}!", - "registration.agreement": "我同意本站用戶條款 {tos}.", + "registration.agreement": "我同意{tos}。", "registration.captcha.hint": "點擊圖像以重載驗證碼", - "registration.captcha.placeholder": "輸入照片中顯示的文字", - "registration.closed_message": "{instance} 公開註冊暫時關閉", - "registration.closed_title": "暫停註冊", + "registration.captcha.placeholder": "輸入圖片中顯示的文字", + "registration.closed_message": "{instance} 不接受新成員", + "registration.closed_title": "已關閉註冊", "registration.confirmation_modal.close": "關閉", "registration.fields.confirm_placeholder": "再次輸入密碼", - "registration.fields.email_placeholder": "電郵地址", + "registration.fields.email_placeholder": "電子郵件地址", "registration.fields.password_placeholder": "密碼", - "registration.fields.username_hint": "只能使用英文字母、數字和下橫線", - "registration.fields.username_placeholder": "帳戶名稱", - "registration.newsletter": "訂閲我們的新聞郵件", - "registration.password_mismatch": "密碼不匹配", - "registration.reason": "你為什麼想要註冊本站?", - "registration.reason_hint": "認真填寫將能加快你通過註冊的速度", + "registration.fields.username_hint": "只允許使用字母、數字和底線。", + "registration.fields.username_placeholder": "使用者名稱", + "registration.newsletter": "訂閱電子報。", + "registration.password_mismatch": "密碼不一致。", + "registration.reason": "你為什麼想要加入本站?", + "registration.reason_hint": "這將有助於我們審查您的申請", "registration.sign_up": "註冊", - "registration.tos": "用戶條款", - "registration.username_unavailable": "帳戶名稱已被使用", + "registration.tos": "服務條款", + "registration.username_unavailable": "使用者名稱已被使用。", + "reject.success": "被拒絕", "relative_time.days": "{number}天", "relative_time.hours": "{number}小時", - "relative_time.just_now": "剛剛", + "relative_time.just_now": "現在", "relative_time.minutes": "{number}分", "relative_time.seconds": "{number}秒", "remote_instance.edit_federation": "編輯聯邦設定", "remote_instance.federation_panel.heading": "聯邦限制", - "remote_instance.federation_panel.no_restrictions_message": "{siteTitle} 未對 {host} 採取限制措施", - "remote_instance.federation_panel.restricted_message": "{siteTitle} 完全封鎖了 {host}", - "remote_instance.federation_panel.some_restrictions_message": "{siteTitle} 對 {host} 實施了部分限制", + "remote_instance.federation_panel.no_restrictions_message": "{siteTitle} 未對 {host} 施加任何限制。", + "remote_instance.federation_panel.restricted_message": "{siteTitle} 封鎖來自 {host} 的所有活動。", + "remote_instance.federation_panel.some_restrictions_message": "{siteTitle} 對 {host} 設定了一些限制。", "remote_instance.pin_host": "釘選 {host}", "remote_instance.unpin_host": "取消釘選 {host}", - "remote_interaction.account_placeholder": "輸入您想採取行動的帳戶 (格式:帳戶名@網域)", + "remote_interaction.account_placeholder": "輸入您想要執行操作的使用者名稱@網域", + "remote_interaction.dislike": "繼續不喜歡", + "remote_interaction.dislike_title": "遠端不喜歡某個貼文", "remote_interaction.divider": "或", + "remote_interaction.event_join": "繼續加入", "remote_interaction.event_join_title": "遠距參加活動", - "remote_interaction.favourite": "按讚", - "remote_interaction.favourite_title": "遠端按讚一條貼文", - "remote_interaction.follow": "開始追蹤", - "remote_interaction.follow_title": "遠端追蹤 {user}", + "remote_interaction.favourite": "最愛", + "remote_interaction.favourite_title": "遠端最愛一條貼文", + "remote_interaction.follow": "開始追隨", + "remote_interaction.follow_title": "遠端追隨 {user}", "remote_interaction.poll_vote": "投票", "remote_interaction.poll_vote_title": "遠端參與投票", - "remote_interaction.reblog": "轉帖", - "remote_interaction.reblog_title": "遠端轉帖", + "remote_interaction.reblog": "繼續轉發", + "remote_interaction.reblog_title": "遠端轉發貼文", "remote_interaction.reply": "回覆", "remote_interaction.reply_title": "遠端回覆", - "remote_interaction.user_not_found_error": "找不到該帳戶", - "remote_timeline.filter_message": "你正在查看 {instance} 的時間軸", + "remote_interaction.user_not_found_error": "找不到指定的使用者", + "remote_timeline.filter_message": "您正在查看 {instance} 的時間軸。", "reply_indicator.cancel": "取消", - "reply_mentions.account.add": "添加到提及名單", - "reply_mentions.account.remove": "從提及名單中移除", + "reply_mentions.account.add": "添加到提及", + "reply_mentions.account.remove": "從提及移除", "reply_mentions.more": "添加 {count} 個", "reply_mentions.reply": "回覆 {accounts}{more}", + "reply_mentions.reply.hoverable": "正在回覆 {accounts}", "reply_mentions.reply_empty": "回覆貼文", - "report.block": "封鎖帳戶 {target}", + "report.block": "封鎖{target}", "report.block_hint": "你是否要封鎖這個帳戶呢?", - "report.confirmation.content": "如果我們發現此帳戶確實違反了 {link} ,我們會採取進一步的措施", - "report.confirmation.title": "感謝你提交的檢舉", + "report.chatMessage.context": "在檢舉使用者的訊息時,所選訊息之前和之後的五個訊息將轉給我們的審核團隊,以了解相關情況。", + "report.chatMessage.title": "檢舉訊息", + "report.confirmation.content": "如果我們發現此{entity}違反了{link},我們將就此事採取進一步行動。", + "report.confirmation.entity.account": "帳號", + "report.confirmation.entity.group": "群組", + "report.confirmation.title": "感謝你提交的檢舉。", "report.done": "完成", "report.forward": "轉寄到 {target}", - "report.forward_hint": "這個帳戶屬於其他站點。要像該站點發送匿名的檢舉訊息嗎?", + "report.forward_hint": "該帳戶來自另一台伺服器。也將檢舉報告副本寄到那裡嗎?", + "report.group.title": "檢舉群組", "report.next": "下一步", "report.otherActions.addAdditional": "你還想為你的檢舉添加更多狀態嗎?", "report.otherActions.addMore": "添加更多", - "report.otherActions.furtherActions": "進一步措施:", + "report.otherActions.furtherActions": "進一步措施:", "report.otherActions.hideAdditional": "隱藏額外狀態", "report.otherActions.otherStatuses": "包含其他狀態?", "report.placeholder": "更多訊息", - "report.reason.blankslate": "你已移除選中的所有狀態", + "report.previous": "上一步", + "report.reason.blankslate": "您已移除所選擇的所有狀態。", "report.reason.title": "檢舉原因", "report.submit": "送出", "report.target": "檢舉 {target}", "reset_password.fail": "令牌已過期,請重試", "reset_password.header": "設定新的密碼", - "reset_password.password.label": "Password", + "reset_password.password.label": "密碼", + "reset_password.password.placeholder": "佔位符", + "save": "儲存", "schedule.post_time": "發佈時間", - "schedule.remove": "取消發佈", - "schedule_button.add_schedule": "定時發佈", - "schedule_button.remove_schedule": "取消定時發佈", + "schedule.remove": "取消排程", + "schedule_button.add_schedule": "安排稍後發布", + "schedule_button.remove_schedule": "立即發布", "scheduled_status.cancel": "取消", "search.action": "搜尋 “{query}”", "search.placeholder": "搜尋", @@ -958,42 +1287,47 @@ "search_results.filter_message": "您正在搜尋來自 @{acct} 的貼文。", "search_results.hashtags": "主題標籤", "search_results.statuses": "貼文", - "security.codes.fail": "恢復代碼錯誤", + "security.codes.fail": "取得恢復代碼失敗", "security.confirm.fail": "密碼錯誤,請重試。", "security.delete_account.fail": "帳戶刪除失敗", "security.delete_account.success": "帳戶刪除成功", "security.disable.fail": "密碼錯誤,請重試。", - "security.fields.email.label": "電郵地址", - "security.fields.new_password.label": "輸入新密碼", - "security.fields.old_password.label": "輸入原密碼", + "security.fields.email.label": "電子郵件地址", + "security.fields.new_password.label": "新密碼", + "security.fields.old_password.label": "目前密碼", "security.fields.password.label": "密碼", "security.fields.password_confirmation.label": "再次輸入新密碼", "security.headers.delete": "刪除帳戶", "security.headers.tokens": "會話", - "security.qr.fail": "加載密鑰失敗", + "security.qr.fail": "無法取得設定密鑰", "security.submit": "儲存變更", "security.submit.delete": "刪除帳戶", - "security.text.delete": "要刪除您的帳戶,請輸入您的密碼。注意:這是無法撤消的永久性操作!您的帳戶將從該服務器中銷毀,並將向其他服務器發送刪除請求。但你的資訊不一定會在其他站點上立即刪除。", + "security.text.delete": "若要刪除您的帳戶,請輸入您的密碼,然後按一下「刪除帳戶」。這是無法撤銷的永久性操作。您的帳戶將從此伺服器被銷毀,並且刪除請求將發送到其他伺服器。不保證所有伺服器都會清除您的帳戶。", + "security.text.delete.local": "若要刪除您的帳戶,請輸入您的密碼,然後按一下「刪除帳戶」。這是無法撤銷的永久性操作。", "security.tokens.revoke": "撤銷", - "security.update_email.fail": "更新電郵地址失敗", - "security.update_email.success": "電郵地址已更新", - "security.update_password.fail": "更新密碼失敗", - "security.update_password.success": "密碼已更新", - "settings.change_email": "更改電郵地址", + "security.update_email.fail": "更新電子郵件失敗。", + "security.update_email.success": "電子郵件已成功更新。", + "security.update_password.fail": "更新密碼失敗。", + "security.update_password.success": "密碼已成功更新。", + "settings.account_migration": "遷移帳戶", + "settings.blocks": "封鎖", + "settings.change_email": "更改電子郵件", "settings.change_password": "更改密碼", "settings.configure_mfa": "設定多重要素驗證 (MFA)", "settings.delete_account": "刪除帳戶", "settings.edit_profile": "編輯個人資料", + "settings.messages.label": "允許其他使用者與您開始新的聊天", "settings.mutes": "靜音", - "settings.other": "Other options", - "settings.preferences": "首選項", + "settings.other": "其他選項", + "settings.preferences": "偏好設定", + "settings.privacy": "隱私", "settings.profile": "個人資料", "settings.save.success": "你的設定已儲存", "settings.security": "安全性", "settings.sessions": "活動會話", "settings.settings": "設定", "shared.tos": "服務條款", - "signup_panel.subtitle": "註冊以參與討論", + "signup_panel.subtitle": "註冊以參與討論。", "signup_panel.title": "初來乍到 {site_title} 嗎?", "site_preview.preview": "預覽", "soapbox_config.authenticated_profile_hint": "用戶必須登錄才能查看用戶個人資料上的回覆和媒體。", @@ -1003,114 +1337,157 @@ "soapbox_config.crypto_address.meta_fields.note_placeholder": "備註 (可選)", "soapbox_config.crypto_address.meta_fields.ticker_placeholder": "幣種", "soapbox_config.crypto_donate_panel_limit.meta_fields.limit_placeholder": "在主頁數字貨幣小部件中顯示的數量", + "soapbox_config.cta_label": "如果未通過驗證,則顯示號召性用語面板", "soapbox_config.custom_css.meta_fields.url_placeholder": "URL", - "soapbox_config.display_fqn_label": "顯示本站帳戶的網域 (如 @帳戶名稱@網域) ", - "soapbox_config.fields.crypto_addresses_label": "數字貨幣地址", - "soapbox_config.fields.home_footer_fields_label": "主頁頁眉", - "soapbox_config.fields.logo_label": "Logo", - "soapbox_config.fields.promo_panel_fields_label": "時間軸頁底", - "soapbox_config.fields.theme_label": "默認主題", + "soapbox_config.display_fqn_label": "顯示本站帳戶的網域(例如@user@domain)。", + "soapbox_config.feed_injection_hint": "在時間軸加入額外內容,例如推薦的使用者。", + "soapbox_config.feed_injection_label": "插入內容", + "soapbox_config.fields.crypto_addresses_label": "加密貨幣位址", + "soapbox_config.fields.edit_theme_label": "編輯佈景主題", + "soapbox_config.fields.home_footer_fields_label": "主頁頁腳項目", + "soapbox_config.fields.logo_label": "標識", + "soapbox_config.fields.promo_panel_fields_label": "宣傳面板項目", + "soapbox_config.fields.theme_label": "預設佈景主題", "soapbox_config.greentext_label": "啟用greentext支援", "soapbox_config.headings.advanced": "進階", - "soapbox_config.headings.cryptocurrency": "數字貨幣", + "soapbox_config.headings.cryptocurrency": "加密貨幣", "soapbox_config.headings.events": "活動", "soapbox_config.headings.navigation": "導航列", "soapbox_config.headings.options": "選項", - "soapbox_config.headings.theme": "主題", - "soapbox_config.hints.crypto_addresses": "添加加密貨幣地址,以便您網站的用戶可以向您捐款。請注意順序,同時您必須使用小寫的幣種代碼。", - "soapbox_config.hints.home_footer_fields": "您可以在靜態頁面的頁腳顯示自定義鏈接(如about)。", - "soapbox_config.hints.logo": "SVG. 最多 2 MB。 將顯示到 50px 高度,保持縱橫比", - "soapbox_config.hints.promo_panel_fields": "您可以在時間線頁面的右側面板上顯示自定義鏈接。", - "soapbox_config.hints.promo_panel_icons.link": "Soapbox圖示", + "soapbox_config.headings.theme": "佈景主題", + "soapbox_config.hints.crypto_addresses": "新增加密貨幣地址,以便您網站的用戶可以向您捐款。順序很重要,而且您必須使用小寫的幣種代碼。", + "soapbox_config.hints.home_footer_fields": "您可以在靜態頁面的頁腳上顯示自訂連結", + "soapbox_config.hints.logo": "SVG。最多 2 MB。將顯示為 50px 高度,保持寬高比", + "soapbox_config.hints.promo_panel_fields": "您可以在時間軸頁面的右側面板上顯示自訂連結。", + "soapbox_config.hints.promo_panel_icons.link": "Soapbox圖示列表", "soapbox_config.home_footer.meta_fields.label_placeholder": "標籤", "soapbox_config.home_footer.meta_fields.url_placeholder": "URL", + "soapbox_config.media_preview_hint": "有些後端提供了媒體的最佳化版本,以便在時間軸中顯示。但是如果不進行額外配置,這些預覽影像可能會太小。", + "soapbox_config.media_preview_label": "首選縮圖預覽媒體", "soapbox_config.promo_panel.meta_fields.icon_placeholder": "圖示", "soapbox_config.promo_panel.meta_fields.label_placeholder": "標籤", "soapbox_config.promo_panel.meta_fields.url_placeholder": "URL", - "soapbox_config.raw_json_hint": "直接編輯設置數據。 直接對 JSON 文件進行的更改將覆蓋上面的表單字段。 單擊保存以應用您的更改。", - "soapbox_config.raw_json_label": "高級: 編輯原始JSON", + "soapbox_config.raw_json_hint": "直接編輯設定資料。直接對 JSON 檔案進行的變更將覆蓋上面的表單欄位。點擊“儲存”以應用您的更改。", + "soapbox_config.raw_json_invalid": "是無效的", + "soapbox_config.raw_json_label": "進階:編輯原始 JSON 數據", + "soapbox_config.redirect_root_no_login_hint": "使用者未登入時重定向首頁的路徑。", + "soapbox_config.redirect_root_no_login_label": "重定向首頁", "soapbox_config.save": "儲存更改", "soapbox_config.saved": "Soapbox配置已儲存!", + "soapbox_config.sentry_dsn_hint": "用於錯誤報告的 DSN URL。與 Sentry 和 GlitchTip 配合使用。", + "soapbox_config.sentry_dsn_label": "Sentry DSN", + "soapbox_config.tile_server_attribution_label": "地圖圖塊歸屬", + "soapbox_config.tile_server_label": "地圖圖塊伺服器", "soapbox_config.verified_can_edit_name_label": "允許經過驗證的用戶編輯自己的顯示名稱。", "status.admin_account": "開啟 @{name} 的管理介面", "status.admin_status": "在管理介面開啟此貼文", + "status.approval.pending": "等待批准", + "status.approval.rejected": "被拒絕", "status.bookmark": "書籤", - "status.bookmarked": "書籤已添加", - "status.cancel_reblog_private": "取消轉帖", - "status.cannot_reblog": "這篇貼文無法被轉載", + "status.bookmarked": "已加到書籤。", + "status.cancel_reblog_private": "取消轉發", + "status.cannot_reblog": "這篇貼文無法被轉發", "status.chat": "和 @{name} 聊天", - "status.copy": "將連結複製到貼文中", + "status.copy": "複製貼文網址", "status.delete": "刪除", "status.detailed_status": "對話的詳細內容", "status.direct": "發送私訊給 @{name}", + "status.disabled_replies.group_membership": "只有群組成員才能回覆", + "status.disfavourite": "不喜歡", "status.edit": "編輯", - "status.embed": "嵌入", + "status.embed": "嵌入貼文", "status.external": "查看 {domain} 上的貼文", "status.favourite": "最愛", "status.filtered": "已過濾", + "status.group": "發布到{group}", + "status.group_mod_delete": "從群組中刪除貼文", + "status.interactions.dislikes": "{count, plural, one {Dislike} other {Dislikes}}", + "status.interactions.favourites": "{count, plural, one {Like} other {Likes}}", + "status.interactions.quotes": "{count, plural, one {Quote} other {Quotes}}", + "status.interactions.reblogs": "{count, plural, one {Repost} other {Reposts}}", "status.load_more": "載入更多", "status.mention": "提到 @{name}", "status.more": "更多", "status.mute_conversation": "靜音對話", "status.open": "展開貼文", "status.pin": "釘選到個人資料頁", + "status.pin_to_group": "釘選到群組", + "status.pin_to_group.success": "已釘選到群組!", "status.pinned": "釘選的貼文", "status.quote": "引用貼文", "status.reactions.cry": "傷心", - "status.reactions.empty": "尚未有人回應心情", + "status.reactions.empty": "尚未有人對這篇文章作出反應。當有人這麼做時,他們就會出現在這裡。", "status.reactions.heart": "愛", "status.reactions.laughing": "哈哈哈", - "status.reactions.like": "讚哦", + "status.reactions.like": "喜歡", "status.reactions.open_mouth": "哇!", "status.reactions.weary": "疲憊", "status.read_more": "閱讀更多", - "status.reblog": "轉帖", - "status.reblog_private": "轉帖給原有追蹤者", - "status.reblogged_by": "{name} 轉帖了", - "status.reblogs.empty": "還沒有人轉帖。如果有,會顯示在這裡。", - "status.redraft": "刪除 & 編輯", - "status.remove_account_from_group": "將帳戶移出群組", - "status.remove_post_from_group": "將貼文移出群組", + "status.reblog": "轉發", + "status.reblog_private": "轉發給原有追隨者", + "status.reblogged_by": "{name} 轉發了", + "status.reblogged_by_with_group": "{name} 轉發自 {group}", + "status.reblogs.empty": "還沒有人轉發。如果有,會顯示在這裡。", + "status.redraft": "刪除並重新編輯", + "status.remove_account_from_group": "從群組中刪除帳戶", + "status.remove_post_from_group": "從群組中刪除貼文", "status.reply": "回覆", "status.replyAll": "回覆所有人", "status.report": "檢舉 @{name}", "status.sensitive_warning": "敏感內容", - "status.sensitive_warning.subtitle": "這則貼文可能含有不宜觀看的消息", + "status.sensitive_warning.subtitle": "此內容可能不適用於所有人。", "status.share": "分享", "status.show_filter_reason": "無論如何都顯示", "status.show_less_all": "減少顯示這類貼文", "status.show_more_all": "顯示更多這類貼文", + "status.show_original": "顯示原本的", "status.title": "貼文詳情", "status.title_direct": "私訊", + "status.translate": "翻譯", + "status.translated_from_with": "使用 {provider} 從 {lang} 翻譯而來", "status.unbookmark": "移除書籤", - "status.unbookmarked": "書籤已移除", + "status.unbookmarked": "書籤已刪除。", "status.unmute_conversation": "取消靜音對話", "status.unpin": "解除釘選", + "status.unpin_to_group": "取消釘選於群組", "status_list.queue_label": "點選查看 {count} 個新貼文", - "statuses.quote_tombstone": "貼文不可用", - "statuses.tombstone": "部分貼文不可見", + "statuses.quote_tombstone": "貼文不可用。", + "statuses.tombstone": "一個或多個貼文不可用。", "streamfield.add": "新增", "streamfield.remove": "移除", "suggestions.dismiss": "關閉建議", - "sw.restart": "Restart", + "sw.restart": "重新啟動", "sw.state.active": "Active", - "sw.status": "Status", + "sw.state.loading": "載入中…", + "sw.state.unavailable": "不可用", + "sw.state.unknown": "未知", + "sw.state.waiting": "等待中", + "sw.status": "狀態", "sw.url": "Script URL", "tabs_bar.all": "全部", "tabs_bar.dashboard": "控制台", "tabs_bar.fediverse": "聯邦宇宙", - "tabs_bar.home": "主頁", + "tabs_bar.groups": "群組", + "tabs_bar.home": "首頁", "tabs_bar.local": "本地", "tabs_bar.more": "更多", "tabs_bar.notifications": "通知", "tabs_bar.profile": "個人資料", "tabs_bar.search": "搜尋", "tabs_bar.settings": "設定", + "textarea.counter.label": "剩餘 {count} 個字", + "theme_editor.Reset": "重設", + "theme_editor.export": "匯出佈景主題", + "theme_editor.import": "匯入佈景主題", + "theme_editor.import_success": "已成功匯入佈景主題!", + "theme_editor.restore": "還原預設佈景主題", + "theme_editor.save": "儲存佈景主題", + "theme_editor.saved": "佈景主題已更新!", "theme_toggle.dark": "深色", "theme_toggle.light": "淺色", "theme_toggle.system": "系統", "thread_login.login": "登入", - "thread_login.message": "加入 {siteTitle} 以獲取完整資訊", + "thread_login.message": "加入 {siteTitle} 以獲取完整的故事和詳細資訊。", "thread_login.signup": "註冊", "thread_login.title": "繼續這個對話", "time_remaining.days": "剩餘{number, plural, one {# 天數} other {# 天數}}", @@ -1122,7 +1499,7 @@ "trends.count_by_accounts": "{count} 位使用者在討論", "trends.title": "趨勢", "trendsPanel.viewAll": "顯示全部", - "unauthorized_modal.text": "你需要登入才能繼續", + "unauthorized_modal.text": "您需要登入才能執行此操作。", "unauthorized_modal.title": "註冊 {site_title} 帳戶", "upload_button.label": "上傳媒體檔案 (JPEG, PNG, GIF, WebM, MP4, MOV)", "upload_error.image_size_limit": "圖片超出當前文件大小限制 ({limit})", @@ -1135,7 +1512,7 @@ "upload_form.undo": "刪除", "upload_progress.label": "上傳中...", "video.close": "關閉影片", - "video.download": "下載", + "video.download": "下載檔案", "video.exit_fullscreen": "退出全螢幕", "video.expand": "展開影片", "video.fullscreen": "全螢幕", @@ -1144,5 +1521,5 @@ "video.pause": "暫停", "video.play": "播放", "video.unmute": "取消靜音音效", - "who_to_follow.title": "推薦追蹤" + "who_to_follow.title": "推薦追隨" } From 5a408f0ea93a2471b8439406a2a64e217061b5cf Mon Sep 17 00:00:00 2001 From: Ahmad Dakhlallah Date: Mon, 13 Nov 2023 11:38:23 +0000 Subject: [PATCH 034/115] Translated using Weblate (Arabic) Currently translated at 100.0% (1523 of 1523 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/ar/ --- src/locales/ar.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/locales/ar.json b/src/locales/ar.json index e674d96c1..81a68b2c1 100644 --- a/src/locales/ar.json +++ b/src/locales/ar.json @@ -734,7 +734,7 @@ "filters.filters_list_warn": "ترشيح العرض", "filters.removed": "حُذف المُرشِّح.", "followRecommendations.heading": "الحسابات المقترحة", - "follow_request.authorize": "ترخيص بالوصول", + "follow_request.authorize": "السماح بالمتابعة", "follow_request.reject": "رفض", "gdpr.accept": "الموافقة", "gdpr.learn_more": "معرفة المزيد", From cf23fd087612f6077079ee87806d00e7a7308155 Mon Sep 17 00:00:00 2001 From: Ryan He Date: Mon, 13 Nov 2023 08:16:10 +0000 Subject: [PATCH 035/115] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (1523 of 1523 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/zh_Hant/ --- src/locales/zh-TW.json | 90 +++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/src/locales/zh-TW.json b/src/locales/zh-TW.json index ac6739bc3..41e38ff06 100644 --- a/src/locales/zh-TW.json +++ b/src/locales/zh-TW.json @@ -30,7 +30,7 @@ "account.hide_reblogs": "隱藏來自 @{name} 的轉貼", "account.last_status": "最後活動", "account.link_verified_on": "已在 {date} 檢查此連結的擁有者權限", - "account.locked_info": "此帳戶的隱私狀態被設成鎖定。帳號擁有者會手動審核追隨此帳號的人。", + "account.locked_info": "該帳戶的隱私狀態設定為鎖定。所有者會手動審核誰可以追隨他們。", "account.login": "登入", "account.media": "媒體", "account.member_since": "加入於 {date}", @@ -71,9 +71,9 @@ "account_moderation_modal.admin_fe": "在 AdminFE 中開啟", "account_moderation_modal.fields.account_role": "管理人員等級", "account_moderation_modal.fields.badges": "客製化徽章", - "account_moderation_modal.fields.deactivate": "關閉帳號", - "account_moderation_modal.fields.delete": "刪除帳號", - "account_moderation_modal.fields.suggested": "建議追隨的人", + "account_moderation_modal.fields.deactivate": "停用帳戶", + "account_moderation_modal.fields.delete": "刪除帳戶", + "account_moderation_modal.fields.suggested": "設置為建議追隨的帳戶", "account_moderation_modal.fields.verified": "已驗證帳戶", "account_moderation_modal.info.id": "ID: {id}", "account_moderation_modal.roles.admin": "管理員", @@ -109,7 +109,7 @@ "admin.dashwidgets.software_header": "軟體版本", "admin.edit_announcement.created": "已建立公告", "admin.edit_announcement.deleted": "公告已刪除", - "admin.edit_announcement.fields.all_day_hint": "勾選後,僅顯示時間範圍內的日期", + "admin.edit_announcement.fields.all_day_hint": "啟用後,僅顯示時間範圍內的日期", "admin.edit_announcement.fields.all_day_label": "全天的活動", "admin.edit_announcement.fields.content_label": "內容", "admin.edit_announcement.fields.content_placeholder": "公告內容", @@ -119,7 +119,7 @@ "admin.edit_announcement.fields.start_time_placeholder": "公告開始日期:", "admin.edit_announcement.save": "儲存", "admin.edit_announcement.updated": "公告已編輯", - "admin.latest_accounts_panel.more": "點擊展開 {count, plural, one {# account} other {# accounts}}", + "admin.latest_accounts_panel.more": "點擊展開 {count} 個帳戶", "admin.latest_accounts_panel.title": "最近加入的帳戶", "admin.moderation_log.empty_message": "你還沒有進行任何管理,如果有任何操作,操作歷史就會顯示在這裏。", "admin.reports.actions.close": "關閉檢舉", @@ -225,7 +225,7 @@ "chat_message_list.network_failure.title": "糟糕!", "chat_message_list_intro.actions.accept": "接受", "chat_message_list_intro.actions.leave_chat": "離開聊天室", - "chat_message_list_intro.actions.message_lifespan": "早於 {day,plural,one {# day} other {# days}} 的訊息將會被刪除。", + "chat_message_list_intro.actions.message_lifespan": "早於 {day} 天的訊息將會被刪除。", "chat_message_list_intro.actions.report": "檢舉", "chat_message_list_intro.intro": "想和你聊天", "chat_message_list_intro.leave_chat.confirm": "離開聊天室", @@ -245,7 +245,7 @@ "chat_settings.auto_delete.30days": "30天", "chat_settings.auto_delete.7days": "7天", "chat_settings.auto_delete.90days": "90天", - "chat_settings.auto_delete.days": "{day, plural, one {# day} other {# days}}", + "chat_settings.auto_delete.days": "{day} 天", "chat_settings.auto_delete.hint": "已發送的訊息將在選定的期間後自動刪除", "chat_settings.auto_delete.label": "自動刪除訊息", "chat_settings.block.confirm": "封鎖", @@ -262,8 +262,8 @@ "chat_settings.unblock.confirm": "取消封鎖", "chat_settings.unblock.heading": "取消封鎖@{acct}", "chat_settings.unblock.message": "取消封鎖將允許此使用者直接向您發送訊息並查看您的內容。", - "chat_window.auto_delete_label": "{day,plural,one {# day} other {# days}}後自動刪除", - "chat_window.auto_delete_tooltip": "聊天訊息設定為發送後 {day,plural,one {# day} other {# days}}後自動刪除。", + "chat_window.auto_delete_label": "{day} 天後自動刪除", + "chat_window.auto_delete_tooltip": "聊天訊息設定為發送 {day} 天後自動刪除。", "chats.actions.copy": "複製", "chats.actions.delete": "刪除兩者", "chats.actions.deleteForMe": "只刪除我的", @@ -322,7 +322,7 @@ "column.favourites": "最愛", "column.federation_restrictions": "聯邦限制", "column.filters": "靜音的詞彙", - "column.filters.accounts": "帳號", + "column.filters.accounts": "帳戶", "column.filters.add_new": "新增過濾詞", "column.filters.conversations": "聊天", "column.filters.create_error": "新增過濾器時出錯", @@ -379,10 +379,10 @@ "column_forbidden.title": "無權訪問", "common.cancel": "取消", "compare_history_modal.header": "編輯歷史", - "compose.character_counter.title": "使用了 {maxChars} {maxChars, plural, one {character} other {characters}} 中的 {chars}", + "compose.character_counter.title": "已輸入{chars}字元,最多可輸入{maxChars}", "compose.edit_success": "你的貼文已編輯", "compose.invalid_schedule": "您必須安排至少在5分鐘後發布貼文。", - "compose.reply_group_indicator.message": "發佈到 {groupLink}", + "compose.reply_group_indicator.message": "發布到 {groupLink}", "compose.submit_success": "您的貼文已發送!", "compose_event.create": "新增", "compose_event.edit_success": "您的活動已編輯", @@ -409,7 +409,7 @@ "compose_event.update": "更新", "compose_event.upload_banner": "上傳活動封面", "compose_form.direct_message_warning": "這篇貼文只會發送給被提及的使用者。", - "compose_form.event_placeholder": "發佈到此活動", + "compose_form.event_placeholder": "發布到此活動", "compose_form.hashtag_warning": "這篇貼文不會列出在任何主題標籤下,因為它是不公開的。只能透過主題標籤搜尋公開貼文。", "compose_form.lock_disclaimer": "您的帳戶未{locked}。任何人都可以追隨您並查看您的僅限追隨者的貼文。", "compose_form.lock_disclaimer.lock": "上鎖", @@ -427,10 +427,10 @@ "compose_form.poll.switch_to_multiple": "投票改為多選", "compose_form.poll.switch_to_single": "投票改為單選", "compose_form.poll_placeholder": "添加投票主題…", - "compose_form.publish": "發佈", + "compose_form.publish": "發布", "compose_form.publish_loud": "{publish}!", "compose_form.save_changes": "儲存變更", - "compose_form.schedule": "定時發佈", + "compose_form.schedule": "定時發布", "compose_form.scheduled_statuses.click_here": "點擊此處", "compose_form.scheduled_statuses.message": "你有定時貼文, {click_here}查看。", "compose_form.spoiler.marked": "正文已隱藏到警告之後", @@ -527,7 +527,7 @@ "copy.success": "已複製到剪貼簿!", "crypto_donate.explanation_box.message": "{siteTitle} 接受加密貨幣捐款。您可以將捐款寄至以下任何地址。感謝您的支持!", "crypto_donate.explanation_box.title": "發送加密貨幣捐款", - "crypto_donate_panel.actions.view": "點擊查看 {count} {count, plural, one {wallet} other {wallets}}", + "crypto_donate_panel.actions.view": "點擊查看 {count} 個錢包", "crypto_donate_panel.heading": "捐贈加密貨幣", "crypto_donate_panel.intro.message": "{siteTitle} 接受加密貨幣捐贈來資助我們的服務。感謝您的支持!", "datepicker.day": "日", @@ -577,10 +577,10 @@ "edit_profile.fields.birthday_label": "生日", "edit_profile.fields.birthday_placeholder": "你的生日", "edit_profile.fields.bot_label": "這是一個機器人帳戶", - "edit_profile.fields.discoverable_label": "公開自己", + "edit_profile.fields.discoverable_label": "允許帳戶探索", "edit_profile.fields.display_name_label": "顯示名稱", "edit_profile.fields.display_name_placeholder": "你的名稱", - "edit_profile.fields.hide_network_label": "隱藏網路狀態", + "edit_profile.fields.hide_network_label": "隱藏社交關係", "edit_profile.fields.location_label": "地點", "edit_profile.fields.location_placeholder": "地點", "edit_profile.fields.locked_label": "鎖定帳戶", @@ -596,7 +596,7 @@ "edit_profile.hints.discoverable": "在配置文件目錄中顯示帳戶並允許外部服務索引", "edit_profile.hints.hide_network": "您追隨的人和追隨您的人不會顯示在您的個人資料中", "edit_profile.hints.locked": "需要您手動批准追隨請求", - "edit_profile.hints.meta_fields": "您的個人資料上最多可以顯示{count, plural, one {# custom field} other {# custom fields}}。", + "edit_profile.hints.meta_fields": "您的個人資料上最多可以顯示{count}個自訂欄位。", "edit_profile.hints.stranger_notifications": "僅顯示來自您追隨的人的通知", "edit_profile.save": "儲存", "edit_profile.success": "您的個人資料已成功儲存!", @@ -635,7 +635,7 @@ "empty_column.aliases.suggestions": "沒有針對所提供的期限的帳戶建議。", "empty_column.blocks": "你還沒有封鎖任何使用者。", "empty_column.bookmarks": "你還沒有任何書籤,一旦你開始將貼文加入書籤,它將會在這裡顯示。", - "empty_column.community": "本地時間軸是空的。快公開發佈些文搶頭香啊!", + "empty_column.community": "本地時間軸是空的。快公開發布些貼文搶頭香啊!", "empty_column.direct": "您還沒有任何私訊。當您私訊別人或收到私訊時,它將於此顯示。", "empty_column.dislikes": "還沒有人不喜歡這篇文章。當有人這麼做時,他們就會出現在這裡。", "empty_column.domain_blocks": "尚未隱藏任何網域。", @@ -663,7 +663,7 @@ "empty_column.public": "這裡什麼都沒有!嘗試寫些公開的貼文,或著追隨其他伺服器的使用者後就會出現了", "empty_column.quotes": "這篇文章尚未被引用。", "empty_column.remote": "這裡什麼都沒有! 追隨本站或者其他站點的成員,就會有貼文出現在這裡。", - "empty_column.scheduled_statuses": "暫時沒有定時貼文。當你發佈定時貼文後,它們會顯示在這裡。", + "empty_column.scheduled_statuses": "暫時沒有定時貼文。當你發布定時貼文後,它們會顯示在這裡。", "empty_column.search.accounts": "沒有匹配的帳戶 \"{term}\"", "empty_column.search.hashtags": "沒有匹配的標籤 \"{term}\"", "empty_column.search.statuses": "沒有匹配的貼文 \"{term}\"", @@ -682,7 +682,7 @@ "event.location": "地點", "event.manage": "管理", "event.organized_by": "組織者:{name}", - "event.participants": "{count} {rawCount, plural, one {person} other {people}} 正在進行", + "event.participants": "{count} 個用戶正在進行", "event.quote": "引用活動", "event.reblog": "轉發活動", "event.show_on_map": "在地圖上顯示", @@ -766,7 +766,7 @@ "group.leave.label": "退出", "group.leave.success": "退出群組", "group.manage": "管理群組", - "group.member.admin.limit.summary": "您可以為群組指派最多{count, plural, one {admin} other {admins}}。", + "group.member.admin.limit.summary": "您可以為群組指派最多{count}位管理員。", "group.member.admin.limit.title": "已達到管理員額上限", "group.mute.label": "靜音", "group.mute.long_label": "靜音群組", @@ -824,7 +824,7 @@ "groups.discover.search.recent_searches.clear_all": "清除全部", "groups.discover.search.recent_searches.title": "最近的搜尋", "groups.discover.search.results.groups": "群組", - "groups.discover.search.results.member_count": "{members, plural, one {member} other {members}}", + "groups.discover.search.results.member_count": "{members} 位成員", "groups.discover.suggested.empty": "目前無法取得建議的群組。請稍後再回來查看。", "groups.discover.suggested.show_more": "顯示更多", "groups.discover.suggested.title": "為您推薦", @@ -834,7 +834,7 @@ "groups.discovery.tags.no_of_groups": "群組數量", "groups.empty.subtitle": "開始發掘可以加入的群組或建立自己的群組。", "groups.empty.title": "還沒有群組", - "groups.pending.count": "{number, plural, one {# pending request} other {# pending requests}}", + "groups.pending.count": "{number} 個待處理的請求", "groups.pending.empty.subtitle": "您目前沒有待處理的請求。", "groups.pending.empty.title": "沒有待處理的請求", "groups.pending.label": "待處理的請求", @@ -991,16 +991,16 @@ "migration.fields.acct.placeholder": "帳戶名稱@網域", "migration.fields.confirm_password.label": "當前密碼", "migration.hint": "這會將您的追隨者轉移到新帳戶。不會移動其他資料。要執行遷移,您需要先在新帳戶上{link}。", - "migration.hint.cooldown_period": "如果您遷移帳戶,您將在 {cooldownPeriod, plural, one {one day} other {the next # days}} 內無法移轉帳戶。", + "migration.hint.cooldown_period": "如果您遷移帳戶,您將在未來 {cooldownPeriod} 天內無法再次移轉帳戶。", "migration.hint.link": "新建一個帳戶別名", "migration.move_account.fail": "帳戶遷移失敗。", "migration.move_account.fail.cooldown_period": "您最近遷移了您的帳戶。請稍後再試。", "migration.move_account.success": "帳戶遷移成功了!", "migration.submit": "遷移追隨者", "missing_description_modal.cancel": "取消", - "missing_description_modal.continue": "發佈", - "missing_description_modal.description": "仍然繼續發佈嗎?", - "missing_description_modal.text": "附件沒有提供描述。仍然繼續發佈嗎?", + "missing_description_modal.continue": "發布", + "missing_description_modal.description": "仍然繼續發布嗎?", + "missing_description_modal.text": "附件沒有提供描述。仍然繼續發布嗎?", "missing_indicator.label": "找不到", "missing_indicator.sublabel": "找不到此資源", "moderation_overlay.contact": "聯絡", @@ -1018,7 +1018,7 @@ "navbar.login.password.label": "密碼", "navbar.login.username.placeholder": "電子郵件或使用者名稱", "navigation.chats": "聊天", - "navigation.compose": "發佈新貼文", + "navigation.compose": "發布新貼文", "navigation.compose_group": "發文到群組", "navigation.dashboard": "控制台", "navigation.developers": "開發者", @@ -1070,7 +1070,7 @@ "notification.mentioned": "{name} 提到了你", "notification.move": "{name} 移動到了 {targetName}", "notification.name": "{link}{others}", - "notification.others": "+ {count, plural, one {# other} other {# others}}", + "notification.others": "+ {count} 其他通知", "notification.pleroma:chat_mention": "{name} 發送了訊息給你", "notification.pleroma:emoji_reaction": "{name} 用表情回應了你的貼文", "notification.pleroma:event_reminder": "您正在參加的活動即將開始", @@ -1103,7 +1103,7 @@ "onboarding.display_name.title": "設定你的顯示名稱", "onboarding.done": "完成", "onboarding.error": "發生意外錯誤。請重試或跳過此步驟。", - "onboarding.fediverse.its_you": "這是你!其他人可以使用您的完整 @帳號名稱 從其他伺服器追隨您。", + "onboarding.fediverse.its_you": "這是你!其他人可以使用您的完整 @帳戶名稱 從其他伺服器追隨您。", "onboarding.fediverse.message": "聯邦宇宙是一個由成千上萬個獨立經營的社群媒體網站(又稱「伺服器」)組成的社群網路。您可以追隨大多數其他聯邦宇宙伺服器上的用戶,喜歡、轉發和回覆貼文,因為他們可以與{siteTitle}進行交流。", "onboarding.fediverse.next": "下一步", "onboarding.fediverse.other_instances": "瀏覽時間軸時,請注意第二個 @ 符號後面的完整用戶名,以了解貼文來自哪個伺服器。", @@ -1252,7 +1252,7 @@ "report.chatMessage.context": "在檢舉使用者的訊息時,所選訊息之前和之後的五個訊息將轉給我們的審核團隊,以了解相關情況。", "report.chatMessage.title": "檢舉訊息", "report.confirmation.content": "如果我們發現此{entity}違反了{link},我們將就此事採取進一步行動。", - "report.confirmation.entity.account": "帳號", + "report.confirmation.entity.account": "帳戶", "report.confirmation.entity.group": "群組", "report.confirmation.title": "感謝你提交的檢舉。", "report.done": "完成", @@ -1276,7 +1276,7 @@ "reset_password.password.label": "密碼", "reset_password.password.placeholder": "佔位符", "save": "儲存", - "schedule.post_time": "發佈時間", + "schedule.post_time": "發布時間", "schedule.remove": "取消排程", "schedule_button.add_schedule": "安排稍後發布", "schedule_button.remove_schedule": "立即發布", @@ -1330,8 +1330,8 @@ "signup_panel.subtitle": "註冊以參與討論。", "signup_panel.title": "初來乍到 {site_title} 嗎?", "site_preview.preview": "預覽", - "soapbox_config.authenticated_profile_hint": "用戶必須登錄才能查看用戶個人資料上的回覆和媒體。", - "soapbox_config.authenticated_profile_label": "個人資料需要授權才能查看", + "soapbox_config.authenticated_profile_hint": "用戶必須登入才能查看用戶個人資料上的回覆和媒體。", + "soapbox_config.authenticated_profile_label": "個人資料需要登入才能查看", "soapbox_config.copyright_footer.meta_fields.label_placeholder": "版權頁底", "soapbox_config.crypto_address.meta_fields.address_placeholder": "地址", "soapbox_config.crypto_address.meta_fields.note_placeholder": "備註 (可選)", @@ -1383,7 +1383,7 @@ "status.admin_status": "在管理介面開啟此貼文", "status.approval.pending": "等待批准", "status.approval.rejected": "被拒絕", - "status.bookmark": "書籤", + "status.bookmark": "加到書籤", "status.bookmarked": "已加到書籤。", "status.cancel_reblog_private": "取消轉發", "status.cannot_reblog": "這篇貼文無法被轉發", @@ -1402,9 +1402,9 @@ "status.group": "發布到{group}", "status.group_mod_delete": "從群組中刪除貼文", "status.interactions.dislikes": "{count, plural, one {Dislike} other {Dislikes}}", - "status.interactions.favourites": "{count, plural, one {Like} other {Likes}}", - "status.interactions.quotes": "{count, plural, one {Quote} other {Quotes}}", - "status.interactions.reblogs": "{count, plural, one {Repost} other {Reposts}}", + "status.interactions.favourites": "{count} 個喜歡", + "status.interactions.quotes": "{count} 個引用", + "status.interactions.reblogs": "{count} 個轉發", "status.load_more": "載入更多", "status.mention": "提到 @{name}", "status.more": "更多", @@ -1490,11 +1490,11 @@ "thread_login.message": "加入 {siteTitle} 以獲取完整的故事和詳細資訊。", "thread_login.signup": "註冊", "thread_login.title": "繼續這個對話", - "time_remaining.days": "剩餘{number, plural, one {# 天數} other {# 天數}}", - "time_remaining.hours": "剩餘{number, plural, one {# 小時} other {# 小時}}", - "time_remaining.minutes": "剩餘{number, plural, one {# 分鐘} other {# 分鐘}}", + "time_remaining.days": "剩餘 {number} 天", + "time_remaining.hours": "剩餘 {number} 小時", + "time_remaining.minutes": "剩餘 {number} 分鐘", "time_remaining.moments": "剩餘時間", - "time_remaining.seconds": "剩餘 {number, plural, one {# 秒} other {# 秒}}", + "time_remaining.seconds": "剩餘 {number} 秒", "toast.view": "檢視", "trends.count_by_accounts": "{count} 位使用者在討論", "trends.title": "趨勢", From b82c8625fb2c4a1dde86ceefd2d4bb4c36e26e1c Mon Sep 17 00:00:00 2001 From: Ryan He Date: Tue, 14 Nov 2023 06:15:34 +0000 Subject: [PATCH 036/115] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (1523 of 1523 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/zh_Hant/ --- src/locales/zh-TW.json | 78 +++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/src/locales/zh-TW.json b/src/locales/zh-TW.json index 41e38ff06..716d6cbae 100644 --- a/src/locales/zh-TW.json +++ b/src/locales/zh-TW.json @@ -10,13 +10,13 @@ "account.block_domain": "隱藏來自 {domain} 的所有內容", "account.blocked": "已封鎖", "account.chat": "和 @{name} 聊天", - "account.copy": "複製個人資料網址", + "account.copy": "複製個人檔案網址", "account.deactivated": "帳戶已被停權", "account.direct": "傳私訊給 @{name}", "account.domain_blocked": "隱藏網域", - "account.edit_profile": "編輯個人資料", - "account.endorse": "在個人資料推薦對方", - "account.endorse.success": "你正在你的個人資料中展示 @{acct}", + "account.edit_profile": "編輯個人檔案", + "account.endorse": "在個人檔案推薦對方", + "account.endorse.success": "你正在你的個人檔案中展示 @{acct}", "account.familiar_followers": "被 {accounts} 追隨", "account.familiar_followers.empty": "您認識的人沒有追隨{name}。", "account.familiar_followers.more": "你追隨了 {count} 位用戶", @@ -26,7 +26,7 @@ "account.follows": "正在追隨", "account.follows.empty": "這位使用者尚未追隨任何使用者。", "account.follows_you": "追隨你", - "account.header.alt": "個人資料標頭", + "account.header.alt": "個人檔案標頭", "account.hide_reblogs": "隱藏來自 @{name} 的轉貼", "account.last_status": "最後活動", "account.link_verified_on": "已在 {date} 檢查此連結的擁有者權限", @@ -41,8 +41,8 @@ "account.patron": "贊助人", "account.posts": "貼文", "account.posts_with_replies": "貼文與回覆", - "account.profile": "個人資料", - "account.profile_external": "在 {domain} 查看個人資料", + "account.profile": "個人檔案", + "account.profile_external": "在 {domain} 查看個人檔案", "account.register": "註冊", "account.remote_follow": "遠端追隨", "account.remove_from_followers": "移除此追隨者", @@ -52,14 +52,14 @@ "account.rss_feed": "訂閱 RSS 來源", "account.search": "搜尋關於 @{name} 的內容", "account.search_self": "搜尋你的貼文", - "account.share": "分享 @{name} 的個人資料", + "account.share": "分享 @{name} 的個人檔案", "account.show_reblogs": "顯示 @{name} 的轉貼", "account.subscribe": "訂閲 @{name}", "account.subscribe.failure": "嘗試訂閱此帳戶時發生錯誤。", "account.subscribe.success": "您已訂閱此帳戶。", "account.unblock": "取消封鎖 @{name}", "account.unblock_domain": "取消隱藏 {domain}", - "account.unendorse": "不再於個人資料頁面推薦對方", + "account.unendorse": "不再於個人檔案頁面推薦對方", "account.unendorse.success": "您已不再展示 @{acct}", "account.unfollow": "取消追隨", "account.unmute": "取消靜音 @{name}", @@ -250,7 +250,7 @@ "chat_settings.auto_delete.label": "自動刪除訊息", "chat_settings.block.confirm": "封鎖", "chat_settings.block.heading": "封鎖@{acct}", - "chat_settings.block.message": "封鎖將阻止此使用者直接向您發送訊息並查看您的內容。您可以在之後解除封鎖。", + "chat_settings.block.message": "封鎖將阻止此使用者直接向您發送訊息與查看您的內容。您可以在之後解除封鎖。", "chat_settings.leave.confirm": "離開聊天室", "chat_settings.leave.heading": "離開聊天室", "chat_settings.leave.message": "您確定要離開此聊天室嗎?將為您刪除訊息,並且此聊天室將從您的收件匣中刪除。", @@ -261,7 +261,7 @@ "chat_settings.title": "聊天室詳情", "chat_settings.unblock.confirm": "取消封鎖", "chat_settings.unblock.heading": "取消封鎖@{acct}", - "chat_settings.unblock.message": "取消封鎖將允許此使用者直接向您發送訊息並查看您的內容。", + "chat_settings.unblock.message": "取消封鎖將允許此使用者直接向您發送訊息與查看您的內容。", "chat_window.auto_delete_label": "{day} 天後自動刪除", "chat_window.auto_delete_tooltip": "聊天訊息設定為發送 {day} 天後自動刪除。", "chats.actions.copy": "複製", @@ -309,10 +309,10 @@ "column.developers": "開發者", "column.developers.service_worker": "Service Worker", "column.direct": "私訊", - "column.directory": "發現更多", + "column.directory": "瀏覽個人檔案", "column.dislikes": "不喜歡", "column.domain_blocks": "隱藏的網域", - "column.edit_profile": "編輯個人資料", + "column.edit_profile": "編輯個人檔案", "column.event_map": "活動地點", "column.event_participants": "活動參加者", "column.events": "活動", @@ -570,10 +570,10 @@ "edit_federation.success": "{host} 聯邦設定已儲存", "edit_federation.unlisted": "強制貼文不公開", "edit_password.header": "修改密碼", - "edit_profile.error": "個人資料更新失敗", + "edit_profile.error": "個人檔案更新失敗", "edit_profile.fields.accepts_email_list_label": "訂閲電子報", "edit_profile.fields.bio_label": "簡介", - "edit_profile.fields.bio_placeholder": "介紹一下自己", + "edit_profile.fields.bio_placeholder": "向我們介紹你自己。", "edit_profile.fields.birthday_label": "生日", "edit_profile.fields.birthday_placeholder": "你的生日", "edit_profile.fields.bot_label": "這是一個機器人帳戶", @@ -581,25 +581,25 @@ "edit_profile.fields.display_name_label": "顯示名稱", "edit_profile.fields.display_name_placeholder": "你的名稱", "edit_profile.fields.hide_network_label": "隱藏社交關係", - "edit_profile.fields.location_label": "地點", - "edit_profile.fields.location_placeholder": "地點", + "edit_profile.fields.location_label": "位置", + "edit_profile.fields.location_placeholder": "你的所在位置,例如地球", "edit_profile.fields.locked_label": "鎖定帳戶", "edit_profile.fields.meta_fields.content_placeholder": "內容", "edit_profile.fields.meta_fields.label_placeholder": "標籤", - "edit_profile.fields.meta_fields_label": "個人資料自定義列", + "edit_profile.fields.meta_fields_label": "個人檔案額外欄位", "edit_profile.fields.stranger_notifications_label": "封鎖來自陌生人的通知", "edit_profile.fields.website_label": "網站", "edit_profile.fields.website_placeholder": "顯示連結", - "edit_profile.header": "編輯個人資料", + "edit_profile.header": "編輯個人檔案", "edit_profile.hints.accepts_email_list": "選擇接收新聞和行銷更新。", "edit_profile.hints.bot": "該帳戶主要執行自動操作,可能不會受到監控", - "edit_profile.hints.discoverable": "在配置文件目錄中顯示帳戶並允許外部服務索引", - "edit_profile.hints.hide_network": "您追隨的人和追隨您的人不會顯示在您的個人資料中", + "edit_profile.hints.discoverable": "在個人檔案目錄中顯示帳戶並允許外部服務建立索引", + "edit_profile.hints.hide_network": "您追隨的人和追隨您的人不會顯示在您的個人檔案中", "edit_profile.hints.locked": "需要您手動批准追隨請求", - "edit_profile.hints.meta_fields": "您的個人資料上最多可以顯示{count}個自訂欄位。", + "edit_profile.hints.meta_fields": "您的個人檔案上最多可以顯示{count}個自訂欄位。", "edit_profile.hints.stranger_notifications": "僅顯示來自您追隨的人的通知", "edit_profile.save": "儲存", - "edit_profile.success": "您的個人資料已成功儲存!", + "edit_profile.success": "您的個人檔案已成功儲存!", "email_confirmation.success": "您的電子郵件已被確認!", "embed.instructions": "要嵌入此貼文,請將以下程式碼貼進你的網站。", "emoji_button.activity": "活動", @@ -629,7 +629,7 @@ "empty_column.account_blocked": "你被 @{accountUsername} 封鎖了。", "empty_column.account_favourited_statuses": "該用戶還沒有任何最愛的貼文。", "empty_column.account_timeline": "這裡還沒有貼文!", - "empty_column.account_unavailable": "無法取得個人資料", + "empty_column.account_unavailable": "無法取得個人檔案", "empty_column.admin.announcements": "還沒有發布任何公告。", "empty_column.aliases": "您尚未建立任何帳戶別名。", "empty_column.aliases.suggestions": "沒有針對所提供的期限的帳戶建議。", @@ -719,7 +719,7 @@ "fediverse_tab.explanation_box.dismiss": "不再顯示", "fediverse_tab.explanation_box.explanation": "{site_title} 是聯邦宇宙的一份子, 一個由數個站點組成的社交網路集合。你在這裏看到的貼文來自於其他站點。你可以自由地與他們打交道,或者封鎖任何你不喜歡的站點。第二個 @ 符號後的完整帳戶名表示貼文來自哪個站點。要想只看到 {site_title} 的貼文, 請瀏覽 {local} 。", "fediverse_tab.explanation_box.title": "什麼是聯邦宇宙?", - "feed_suggestions.heading": "建議的使用者", + "feed_suggestions.heading": "推薦的個人檔案", "feed_suggestions.view_all": "檢視全部", "filters.added": "已添加過濾器。", "filters.context_header": "過濾器場景", @@ -733,7 +733,7 @@ "filters.filters_list_phrases_label": "關鍵字或短語:", "filters.filters_list_warn": "顯示警告", "filters.removed": "過濾器已移除。", - "followRecommendations.heading": "建議的使用者", + "followRecommendations.heading": "推薦的個人檔案", "follow_request.authorize": "授權", "follow_request.reject": "拒絕", "gdpr.accept": "接受", @@ -888,11 +888,11 @@ "keyboard_shortcuts.legend": "顯示此圖例", "keyboard_shortcuts.mention": "提及作者", "keyboard_shortcuts.muted": "開啟靜音使用者清單", - "keyboard_shortcuts.my_profile": "開啟個人資料頁面", + "keyboard_shortcuts.my_profile": "開啟個人檔案頁面", "keyboard_shortcuts.notifications": "開啟通知欄", "keyboard_shortcuts.open_media": "開啟媒體", "keyboard_shortcuts.pinned": "開啟釘選的貼文清單", - "keyboard_shortcuts.profile": "開啟作者的個人資料頁面", + "keyboard_shortcuts.profile": "開啟作者的個人檔案頁面", "keyboard_shortcuts.react": "心情回應", "keyboard_shortcuts.reply": "回覆", "keyboard_shortcuts.requests": "開啟追隨請求清單", @@ -1053,7 +1053,7 @@ "navigation_bar.logout": "登出", "navigation_bar.mutes": "靜音", "navigation_bar.preferences": "偏好設定", - "navigation_bar.profile_directory": "發現更多帳戶", + "navigation_bar.profile_directory": "個人檔案目錄", "navigation_bar.soapbox_config": "Soapbox配置", "new_event_panel.action": "新增活動", "new_event_panel.subtitle": "找不到您要找的東西?安排您自己的活動。", @@ -1111,7 +1111,7 @@ "onboarding.fediverse.trailer": "由於它是分散式的,任何人都可以運行自己的伺服器,因此聯邦宇宙具有彈性和開放性。如果您選擇加入另一個伺服器或建立自己的伺服器,您可以與相同的人互動,並在相同的社交圖譜上繼續前進。", "onboarding.finished.message": "我們很高興歡迎您加入我們的社區! 點擊下面的按鈕,讓我們開始吧!", "onboarding.finished.title": "新手教學完成", - "onboarding.header.subtitle": "這將顯示在你個人資料的上方。", + "onboarding.header.subtitle": "這將顯示在你個人檔案的上方。", "onboarding.header.title": "選擇封面圖片", "onboarding.next": "下一步", "onboarding.note.subtitle": "你可以稍後更改", @@ -1184,8 +1184,8 @@ "profile_dropdown.add_account": "新增已有帳戶", "profile_dropdown.logout": "登出 @{acct}", "profile_dropdown.switch_account": "切換帳戶", - "profile_dropdown.theme": "主題", - "profile_fields_panel.title": "個人資料字段", + "profile_dropdown.theme": "佈景主題", + "profile_fields_panel.title": "額外欄位", "reactions.all": "全部", "regeneration_indicator.label": "載入中…", "regeneration_indicator.sublabel": "你的主頁時間軸正在準備中!", @@ -1315,13 +1315,13 @@ "settings.change_password": "更改密碼", "settings.configure_mfa": "設定多重要素驗證 (MFA)", "settings.delete_account": "刪除帳戶", - "settings.edit_profile": "編輯個人資料", + "settings.edit_profile": "編輯個人檔案", "settings.messages.label": "允許其他使用者與您開始新的聊天", "settings.mutes": "靜音", "settings.other": "其他選項", "settings.preferences": "偏好設定", "settings.privacy": "隱私", - "settings.profile": "個人資料", + "settings.profile": "個人檔案", "settings.save.success": "你的設定已儲存", "settings.security": "安全性", "settings.sessions": "活動會話", @@ -1330,8 +1330,8 @@ "signup_panel.subtitle": "註冊以參與討論。", "signup_panel.title": "初來乍到 {site_title} 嗎?", "site_preview.preview": "預覽", - "soapbox_config.authenticated_profile_hint": "用戶必須登入才能查看用戶個人資料上的回覆和媒體。", - "soapbox_config.authenticated_profile_label": "個人資料需要登入才能查看", + "soapbox_config.authenticated_profile_hint": "用戶必須登入才能查看用戶個人檔案上的回覆和媒體。", + "soapbox_config.authenticated_profile_label": "個人檔案需要登入才能查看", "soapbox_config.copyright_footer.meta_fields.label_placeholder": "版權頁底", "soapbox_config.crypto_address.meta_fields.address_placeholder": "地址", "soapbox_config.crypto_address.meta_fields.note_placeholder": "備註 (可選)", @@ -1410,7 +1410,7 @@ "status.more": "更多", "status.mute_conversation": "靜音對話", "status.open": "展開貼文", - "status.pin": "釘選到個人資料頁", + "status.pin": "釘選到個人檔案", "status.pin_to_group": "釘選到群組", "status.pin_to_group.success": "已釘選到群組!", "status.pinned": "釘選的貼文", @@ -1448,7 +1448,7 @@ "status.unbookmark": "移除書籤", "status.unbookmarked": "書籤已刪除。", "status.unmute_conversation": "取消靜音對話", - "status.unpin": "解除釘選", + "status.unpin": "在個人檔案解除釘選", "status.unpin_to_group": "取消釘選於群組", "status_list.queue_label": "點選查看 {count} 個新貼文", "statuses.quote_tombstone": "貼文不可用。", @@ -1472,7 +1472,7 @@ "tabs_bar.local": "本地", "tabs_bar.more": "更多", "tabs_bar.notifications": "通知", - "tabs_bar.profile": "個人資料", + "tabs_bar.profile": "個人檔案", "tabs_bar.search": "搜尋", "tabs_bar.settings": "設定", "textarea.counter.label": "剩餘 {count} 個字", From a3155f345ce6252c8c839b700b5f45d3e5258209 Mon Sep 17 00:00:00 2001 From: Ryan He Date: Tue, 14 Nov 2023 06:59:42 +0000 Subject: [PATCH 037/115] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (1523 of 1523 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/zh_Hant/ --- src/locales/zh-TW.json | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/locales/zh-TW.json b/src/locales/zh-TW.json index 716d6cbae..c5addc289 100644 --- a/src/locales/zh-TW.json +++ b/src/locales/zh-TW.json @@ -712,8 +712,8 @@ "federation_restriction.full_media_removal": "完全移除媒體", "federation_restriction.media_nsfw": "附件標註為 NSFW", "federation_restriction.partial_media_removal": "部分移除媒體", - "federation_restrictions.empty_message": "{siteTitle} 沒有限制任何實例", - "federation_restrictions.explanation_box.message": "通常情況下,聯邦宇宙上的伺服器可以自由通訊。然而 {siteTitle} 對以下伺服器實施了限制", + "federation_restrictions.empty_message": "{siteTitle} 未限制任何實例。", + "federation_restrictions.explanation_box.message": "通常情況下,聯邦宇宙上的伺服器可以自由通訊。然而 {siteTitle} 對以下伺服器實施了限制。", "federation_restrictions.explanation_box.title": "實例相關政策", "federation_restrictions.not_disclosed_message": "{siteTitle} 不透過 API 揭露聯合限制。", "fediverse_tab.explanation_box.dismiss": "不再顯示", @@ -923,7 +923,7 @@ "lists.new.title_placeholder": "新清單標題", "lists.search": "在您追隨的人中搜尋", "lists.subheading": "您的清單", - "loading_indicator.label": "讀取中...", + "loading_indicator.label": "讀取中…", "location_search.placeholder": "查找地址", "login.fields.email_label": "電子郵件地址", "login.fields.instance_label": "實例", @@ -995,7 +995,7 @@ "migration.hint.link": "新建一個帳戶別名", "migration.move_account.fail": "帳戶遷移失敗。", "migration.move_account.fail.cooldown_period": "您最近遷移了您的帳戶。請稍後再試。", - "migration.move_account.success": "帳戶遷移成功了!", + "migration.move_account.success": "帳戶遷移成功了。", "migration.submit": "遷移追隨者", "missing_description_modal.cancel": "取消", "missing_description_modal.continue": "發布", @@ -1093,13 +1093,13 @@ "notifications.queue_label": "點擊查看 {count} 條新通知", "oauth_consumer.tooltip": "通過 {provider} 登入", "oauth_consumers.title": "更多登入方式", - "onboarding.avatar.subtitle": "祝你玩得開心!", + "onboarding.avatar.subtitle": "盡情享受吧。", "onboarding.avatar.title": "設定你的頭像", "onboarding.bio.hint": "最多 500 個字", "onboarding.bio.placeholder": "向世界介紹一下自己…", "onboarding.display_name.label": "顯示名稱", "onboarding.display_name.placeholder": "例如:約翰史密斯", - "onboarding.display_name.subtitle": "你可以稍後更改", + "onboarding.display_name.subtitle": "你可以稍後更改它。", "onboarding.display_name.title": "設定你的顯示名稱", "onboarding.done": "完成", "onboarding.error": "發生意外錯誤。請重試或跳過此步驟。", @@ -1109,16 +1109,16 @@ "onboarding.fediverse.other_instances": "瀏覽時間軸時,請注意第二個 @ 符號後面的完整用戶名,以了解貼文來自哪個伺服器。", "onboarding.fediverse.title": "{siteTitle}只是聯邦宇宙的一部分", "onboarding.fediverse.trailer": "由於它是分散式的,任何人都可以運行自己的伺服器,因此聯邦宇宙具有彈性和開放性。如果您選擇加入另一個伺服器或建立自己的伺服器,您可以與相同的人互動,並在相同的社交圖譜上繼續前進。", - "onboarding.finished.message": "我們很高興歡迎您加入我們的社區! 點擊下面的按鈕,讓我們開始吧!", + "onboarding.finished.message": "我們非常歡迎您加入我們的社群!點擊下面的按鈕開始吧。", "onboarding.finished.title": "新手教學完成", "onboarding.header.subtitle": "這將顯示在你個人檔案的上方。", "onboarding.header.title": "選擇封面圖片", "onboarding.next": "下一步", - "onboarding.note.subtitle": "你可以稍後更改", + "onboarding.note.subtitle": "你可以稍後更改它。", "onboarding.note.title": "簡短地介紹下自己", "onboarding.saving": "儲存中…", "onboarding.skip": "現在跳過", - "onboarding.suggestions.subtitle": "以下是幾個受歡迎的帳戶,你可能會喜歡", + "onboarding.suggestions.subtitle": "以下是您可能喜歡的一些最受歡迎的帳戶。", "onboarding.suggestions.title": "推薦帳戶", "onboarding.view_feed": "檢視時間軸", "password_reset.confirmation": "檢查您的電子郵件以進行確認。", @@ -1271,7 +1271,7 @@ "report.reason.title": "檢舉原因", "report.submit": "送出", "report.target": "檢舉 {target}", - "reset_password.fail": "令牌已過期,請重試", + "reset_password.fail": "令牌已過期,請重試。", "reset_password.header": "設定新的密碼", "reset_password.password.label": "密碼", "reset_password.password.placeholder": "佔位符", @@ -1289,8 +1289,8 @@ "search_results.statuses": "貼文", "security.codes.fail": "取得恢復代碼失敗", "security.confirm.fail": "密碼錯誤,請重試。", - "security.delete_account.fail": "帳戶刪除失敗", - "security.delete_account.success": "帳戶刪除成功", + "security.delete_account.fail": "帳戶刪除失敗。", + "security.delete_account.success": "帳戶刪除成功。", "security.disable.fail": "密碼錯誤,請重試。", "security.fields.email.label": "電子郵件地址", "security.fields.new_password.label": "新密碼", @@ -1298,7 +1298,7 @@ "security.fields.password.label": "密碼", "security.fields.password_confirmation.label": "再次輸入新密碼", "security.headers.delete": "刪除帳戶", - "security.headers.tokens": "會話", + "security.headers.tokens": "登入狀態", "security.qr.fail": "無法取得設定密鑰", "security.submit": "儲存變更", "security.submit.delete": "刪除帳戶", @@ -1322,9 +1322,9 @@ "settings.preferences": "偏好設定", "settings.privacy": "隱私", "settings.profile": "個人檔案", - "settings.save.success": "你的設定已儲存", + "settings.save.success": "您的偏好設定已儲存!", "settings.security": "安全性", - "settings.sessions": "活動會話", + "settings.sessions": "管理登入狀態", "settings.settings": "設定", "shared.tos": "服務條款", "signup_panel.subtitle": "註冊以參與討論。", @@ -1401,10 +1401,10 @@ "status.filtered": "已過濾", "status.group": "發布到{group}", "status.group_mod_delete": "從群組中刪除貼文", - "status.interactions.dislikes": "{count, plural, one {Dislike} other {Dislikes}}", + "status.interactions.dislikes": "{count} 個不喜歡", "status.interactions.favourites": "{count} 個喜歡", "status.interactions.quotes": "{count} 個引用", - "status.interactions.reblogs": "{count} 個轉發", + "status.interactions.reblogs": "個轉發", "status.load_more": "載入更多", "status.mention": "提到 @{name}", "status.more": "更多", @@ -1420,7 +1420,7 @@ "status.reactions.heart": "愛", "status.reactions.laughing": "哈哈哈", "status.reactions.like": "喜歡", - "status.reactions.open_mouth": "哇!", + "status.reactions.open_mouth": "哇", "status.reactions.weary": "疲憊", "status.read_more": "閱讀更多", "status.reblog": "轉發", @@ -1510,7 +1510,7 @@ "upload_form.description": "為視障人士增加文字說明", "upload_form.preview": "預覽", "upload_form.undo": "刪除", - "upload_progress.label": "上傳中...", + "upload_progress.label": "上傳中…", "video.close": "關閉影片", "video.download": "下載檔案", "video.exit_fullscreen": "退出全螢幕", From 898c2700f74ba9f3fbbcc3d05dc49ed111346a77 Mon Sep 17 00:00:00 2001 From: Ryan He Date: Tue, 14 Nov 2023 07:21:31 +0000 Subject: [PATCH 038/115] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (1523 of 1523 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/zh_Hant/ --- src/locales/zh-TW.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/locales/zh-TW.json b/src/locales/zh-TW.json index c5addc289..42a443b4b 100644 --- a/src/locales/zh-TW.json +++ b/src/locales/zh-TW.json @@ -304,7 +304,7 @@ "column.blocks": "封鎖的使用者", "column.bookmarks": "書籤", "column.chats": "聊天", - "column.community": "本站時間軸", + "column.community": "本地時間軸", "column.crypto_donate": "捐贈加密貨幣", "column.developers": "開發者", "column.developers.service_worker": "Service Worker", @@ -1136,10 +1136,10 @@ "poll.non_anonymous.label": "其他實例可能會顯示您投票的選項", "poll.refresh": "重新整理", "poll.total_people": "還有 {count} 人", - "poll.total_votes": "投票", + "poll.total_votes": "{count} 票", "poll.vote": "投票", "poll.voted": "你投票給了這個選項", - "poll.votes": "投票", + "poll.votes": "{votes, plural, one {# vote} other {# votes}}", "poll_button.add_poll": "發起投票", "poll_button.remove_poll": "移除投票", "preferences.fields.auto_play_gif_label": "自動播放GIF", @@ -1337,7 +1337,7 @@ "soapbox_config.crypto_address.meta_fields.note_placeholder": "備註 (可選)", "soapbox_config.crypto_address.meta_fields.ticker_placeholder": "幣種", "soapbox_config.crypto_donate_panel_limit.meta_fields.limit_placeholder": "在主頁數字貨幣小部件中顯示的數量", - "soapbox_config.cta_label": "如果未通過驗證,則顯示號召性用語面板", + "soapbox_config.cta_label": "如果未通過驗證,則顯示行動呼籲面板", "soapbox_config.custom_css.meta_fields.url_placeholder": "URL", "soapbox_config.display_fqn_label": "顯示本站帳戶的網域(例如@user@domain)。", "soapbox_config.feed_injection_hint": "在時間軸加入額外內容,例如推薦的使用者。", From 8ba328d96bfad6c150a7ef6d16f520b3f0666740 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 20 Nov 2023 13:45:52 -0600 Subject: [PATCH 039/115] Prevent a new ServiceWorker from being installed after the page loads --- src/main.tsx | 3 ++- src/utils/sw.ts | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main.tsx b/src/main.tsx index 1ef21a493..05c38cf73 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -25,11 +25,12 @@ import './styles/tailwind.css'; import './precheck'; import ready from './ready'; -import { registerSW } from './utils/sw'; +import { registerSW, lockSW } from './utils/sw'; if (BuildConfig.NODE_ENV === 'production') { printConsoleWarning(); registerSW('/sw.js'); + lockSW(); } ready(() => { diff --git a/src/utils/sw.ts b/src/utils/sw.ts index 931c5b60c..692b1ab0f 100644 --- a/src/utils/sw.ts +++ b/src/utils/sw.ts @@ -7,6 +7,15 @@ function registerSW(path: string) { } } +/** Prevent a new ServiceWorker from being installed. */ +function lockSW() { + if ('serviceWorker' in navigator) { + navigator.serviceWorker.register = () => { + throw new Error('ServiceWorker already registered.'); + }; + } +} + /** Unregister the ServiceWorker */ // https://stackoverflow.com/a/49771828/8811886 const unregisterSW = async(): Promise => { @@ -22,4 +31,5 @@ const unregisterSW = async(): Promise => { export { registerSW, unregisterSW, + lockSW, }; \ No newline at end of file From df020e425399fd7223d7ff4b7514ca1bdcb741c8 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 20 Nov 2023 14:22:48 -0600 Subject: [PATCH 040/115] ServiceWorker: don't wait for window.onload before registering the worker --- src/utils/sw.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/utils/sw.ts b/src/utils/sw.ts index 692b1ab0f..b5e49c860 100644 --- a/src/utils/sw.ts +++ b/src/utils/sw.ts @@ -1,9 +1,7 @@ /** Register the ServiceWorker. */ function registerSW(path: string) { if ('serviceWorker' in navigator) { - window.addEventListener('load', () => { - navigator.serviceWorker.register(path, { scope: '/' }); - }); + navigator.serviceWorker.register(path, { scope: '/' }); } } From d293c9d9006df3ea729da5b513c1bf38345f4c40 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 20 Nov 2023 15:38:05 -0600 Subject: [PATCH 041/115] Add PowWorker to mine Nostr events off the main thread --- package.json | 1 + src/workers.ts | 9 +++++++++ src/workers/pow.worker.ts | 10 ++++++++++ yarn.lock | 5 +++++ 4 files changed, 25 insertions(+) create mode 100644 src/workers.ts create mode 100644 src/workers/pow.worker.ts diff --git a/package.json b/package.json index d90340b7f..a6cfd4f56 100644 --- a/package.json +++ b/package.json @@ -99,6 +99,7 @@ "bowser": "^2.11.0", "browserslist": "^4.16.6", "clsx": "^2.0.0", + "comlink": "^4.4.1", "core-js": "^3.27.2", "cryptocurrency-icons": "^0.18.1", "cssnano": "^6.0.0", diff --git a/src/workers.ts b/src/workers.ts new file mode 100644 index 000000000..098aaa15c --- /dev/null +++ b/src/workers.ts @@ -0,0 +1,9 @@ +import * as Comlink from 'comlink'; + +import type { PowWorker } from './workers/pow.worker'; + +const powWorker = Comlink.wrap( + new Worker(new URL('./workers/pow.worker.ts', import.meta.url), { type: 'module' }), +); + +export { powWorker }; \ No newline at end of file diff --git a/src/workers/pow.worker.ts b/src/workers/pow.worker.ts new file mode 100644 index 000000000..dcfb948e5 --- /dev/null +++ b/src/workers/pow.worker.ts @@ -0,0 +1,10 @@ +import * as Comlink from 'comlink'; +import { nip13, type UnsignedEvent } from 'nostr-tools'; + +export const PowWorker = { + mine(event: UnsignedEvent, difficulty: number) { + return nip13.minePow(event, difficulty); + }, +}; + +Comlink.expose(PowWorker); \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 1d7fefcf3..a2d4c7e5d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3566,6 +3566,11 @@ combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" +comlink@^4.4.1: + version "4.4.1" + resolved "https://registry.yarnpkg.com/comlink/-/comlink-4.4.1.tgz#e568b8e86410b809e8600eb2cf40c189371ef981" + integrity sha512-+1dlx0aY5Jo1vHy/tSsIGpSkN4tS9rZSW8FIhG0JH/crs9wwweswIo/POr451r7bZww3hFbPAKnTpimzL/mm4Q== + commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" From 016198c3014d642e16c7d8d105b2b37a10bfa9e4 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 20 Nov 2023 17:52:37 -0600 Subject: [PATCH 042/115] Sign NIP-46 events with proof-of-work --- src/api/hooks/nostr/useSignerStream.ts | 2 +- src/features/nostr/sign.ts | 15 +++++++++++++-- src/schemas/nostr.ts | 7 ++++++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/api/hooks/nostr/useSignerStream.ts b/src/api/hooks/nostr/useSignerStream.ts index 6780351c8..216c3a8e3 100644 --- a/src/api/hooks/nostr/useSignerStream.ts +++ b/src/api/hooks/nostr/useSignerStream.ts @@ -36,7 +36,7 @@ function useSignerStream() { const respMsg = { id: reqMsg.data.id, - result: await signEvent(reqMsg.data.params[0]), + result: await signEvent(reqMsg.data.params[0], reqMsg.data.params[1]), }; const respEvent = await signEvent({ diff --git a/src/features/nostr/sign.ts b/src/features/nostr/sign.ts index 5a9b72082..8158d734d 100644 --- a/src/features/nostr/sign.ts +++ b/src/features/nostr/sign.ts @@ -7,6 +7,8 @@ import { nip04 as _nip04, } from 'nostr-tools'; +import { powWorker } from 'soapbox/workers'; + /** localStorage key for the Nostr private key (if not using NIP-07). */ const LOCAL_KEY = 'soapbox:nostr:privateKey'; @@ -28,9 +30,18 @@ async function getPublicKey(): Promise { return window.nostr ? window.nostr.getPublicKey() : _getPublicKey(getPrivateKey()); } +interface SignEventOpts { + pow?: number; +} + /** Sign an event with NIP-07, or the locally generated key. */ -async function signEvent(event: EventTemplate): Promise> { - return window.nostr ? window.nostr.signEvent(event) as Promise> : finishEvent(event, getPrivateKey()) ; +async function signEvent(template: EventTemplate, opts: SignEventOpts = {}): Promise> { + if (opts.pow) { + const event = await powWorker.mine({ ...template, pubkey: await getPublicKey() }, opts.pow) as Omit, 'sig'>; + return window.nostr ? window.nostr.signEvent(event) as Promise> : finishEvent(event, getPrivateKey()) ; + } else { + return window.nostr ? window.nostr.signEvent(template) as Promise> : finishEvent(template, getPrivateKey()) ; + } } /** Crypto function with NIP-07, or the local key. */ diff --git a/src/schemas/nostr.ts b/src/schemas/nostr.ts index 1dcd0c466..03e93d12f 100644 --- a/src/schemas/nostr.ts +++ b/src/schemas/nostr.ts @@ -24,11 +24,16 @@ const eventSchema = eventTemplateSchema.extend({ /** Nostr event schema that also verifies the event's signature. */ const signedEventSchema = eventSchema.refine(verifySignature); +/** NIP-46 signer options. */ +const signEventOptsSchema = z.object({ + pow: z.number().int().nonnegative(), +}); + /** NIP-46 signer request. */ const connectRequestSchema = z.object({ id: z.string(), method: z.literal('sign_event'), - params: z.tuple([eventTemplateSchema]), + params: z.tuple([eventTemplateSchema]).or(z.tuple([eventTemplateSchema, signEventOptsSchema])), }); export { nostrIdSchema, kindSchema, eventSchema, signedEventSchema, connectRequestSchema }; \ No newline at end of file From c138e2ee094031177ff502c7e1d50fa6ba40e22d Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 22 Nov 2023 13:21:02 -0600 Subject: [PATCH 043/115] NIP-46: fix parsing request message for sign_event --- src/schemas/nostr.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/schemas/nostr.ts b/src/schemas/nostr.ts index 03e93d12f..e8aa80e9e 100644 --- a/src/schemas/nostr.ts +++ b/src/schemas/nostr.ts @@ -27,7 +27,7 @@ const signedEventSchema = eventSchema.refine(verifySignature); /** NIP-46 signer options. */ const signEventOptsSchema = z.object({ pow: z.number().int().nonnegative(), -}); +}).partial(); /** NIP-46 signer request. */ const connectRequestSchema = z.object({ From 2e1282bc2d4b6e89a5dbd7d679cebf8c6589a672 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 22 Nov 2023 22:20:19 -0600 Subject: [PATCH 044/115] Render a Game Boy player for GB/GBC attachments --- package.json | 1 + src/components/gameboy.tsx | 47 ++++++++++++++++++++++++++++++++ src/components/media-gallery.tsx | 24 ++++++++++++---- yarn.lock | 26 +++++++++++++++++- 4 files changed, 92 insertions(+), 6 deletions(-) create mode 100644 src/components/gameboy.tsx diff --git a/package.json b/package.json index a6cfd4f56..b6144c5e9 100644 --- a/package.json +++ b/package.json @@ -174,6 +174,7 @@ "vite-plugin-html": "^3.2.0", "vite-plugin-require": "^1.1.10", "vite-plugin-static-copy": "^0.17.0", + "wasmboy": "^0.7.1", "wicg-inert": "^3.1.1", "zod": "^3.21.4" }, diff --git a/src/components/gameboy.tsx b/src/components/gameboy.tsx new file mode 100644 index 000000000..ec6617304 --- /dev/null +++ b/src/components/gameboy.tsx @@ -0,0 +1,47 @@ +import React, { useEffect, useRef } from 'react'; +// @ts-ignore No types available +import { WasmBoy } from 'wasmboy'; + +interface IGameboy extends React.CanvasHTMLAttributes { + /** URL to the ROM. */ + src: string; +} + +/** Component to display a playable Gameboy emulator. */ +const Gameboy: React.FC = ({ src, ...rest }) => { + const canvas = useRef(null); + + async function init() { + await WasmBoy.config(WasmBoyOptions, canvas.current!); + await WasmBoy.loadROM(src); + await WasmBoy.play(); + } + + useEffect(() => { + init(); + }, []); + + return ( + + ); +}; + +const WasmBoyOptions = { + headless: false, + useGbcWhenOptional: true, + isAudioEnabled: false, + frameSkip: 1, + audioBatchProcessing: true, + timersBatchProcessing: false, + audioAccumulateSamples: true, + graphicsBatchProcessing: false, + graphicsDisableScanlineRendering: false, + tileRendering: true, + tileCaching: true, + gameboyFPSCap: 60, + updateGraphicsCallback: false, + updateAudioCallback: false, + saveStateCallback: false, +}; + +export { Gameboy }; \ No newline at end of file diff --git a/src/components/media-gallery.tsx b/src/components/media-gallery.tsx index 0d8e48683..2cf8ee139 100644 --- a/src/components/media-gallery.tsx +++ b/src/components/media-gallery.tsx @@ -12,6 +12,8 @@ import { truncateFilename } from 'soapbox/utils/media'; import { isIOS } from '../is-mobile'; import { isPanoramic, isPortrait, isNonConformingRatio, minimumAspectRatio, maximumAspectRatio } from '../utils/media-aspect-ratio'; +import { Gameboy } from './gameboy'; + import type { Property } from 'csstype'; import type { List as ImmutableList } from 'immutable'; @@ -141,8 +143,22 @@ const Item: React.FC = ({ } let thumbnail: React.ReactNode = ''; + const ext = attachment.url.split('.').pop()?.toLowerCase(); - if (attachment.type === 'unknown') { + if (attachment.type === 'unknown' && ['gb', 'gbc'].includes(ext!)) { + return ( +
1, + })} + key={attachment.id} + style={{ position, float, left, top, right, bottom, height, width: `${width}%` }} + > + +
+ ); + } else if (attachment.type === 'unknown') { const filename = truncateFilename(attachment.url, MAX_FILENAME_LENGTH); const attachmentIcon = ( = ({
); } else if (attachment.type === 'audio') { - const ext = attachment.url.split('.').pop()?.toUpperCase(); thumbnail = (
= ({ title={attachment.description} > - {ext} + {ext} ); } else if (attachment.type === 'video') { - const ext = attachment.url.split('.').pop()?.toUpperCase(); thumbnail = ( = ({ > - {ext} + {ext} ); } diff --git a/yarn.lock b/yarn.lock index a2d4c7e5d..79e9ac9e2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3108,6 +3108,10 @@ at-least-node@^1.0.0: resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== +"audiobuffer-to-wav@git+https://github.com/torch2424/audiobuffer-to-wav.git#es-module-rollup": + version "1.0.0" + resolved "git+https://github.com/torch2424/audiobuffer-to-wav.git#8878a20c5cc7e457b113dabfb1781ad4178f9c62" + autoprefixer@^10.4.15: version "10.4.15" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.15.tgz#a1230f4aeb3636b89120b34a1f513e2f6834d530" @@ -5197,6 +5201,11 @@ iconv-lite@0.6.3: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" +idb@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/idb/-/idb-2.1.3.tgz#7b295fa1a46ab7851e42dd85543a271435f87fee" + integrity sha512-1He6QAuavrD38HCiJasi4lEEK87Y22ldFuM+ZHkp433n4Fd5jXjWKutClYFp8w4mgx3zgrjnWxL8dpjMzcQ+WQ== + idb@^7.0.1: version "7.1.1" resolved "https://registry.yarnpkg.com/idb/-/idb-7.1.1.tgz#d910ded866d32c7ced9befc5bfdf36f572ced72b" @@ -7138,7 +7147,7 @@ quick-lru@^5.1.1: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== -raf@^3.1.0: +raf@^3.1.0, raf@^3.4.0: version "3.4.1" resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA== @@ -7709,6 +7718,11 @@ responselike@^2.0.0: dependencies: lowercase-keys "^2.0.0" +responsive-gamepad@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/responsive-gamepad/-/responsive-gamepad-1.1.0.tgz#0173d05199e3c41c09f3b1b9fa8eb811dad8e585" + integrity sha512-njsJuKvany9eYjywXm8iorTeXeAAPqwMNaRWOo8jlh0iQboXgGPf6Z6bLGntELrfU+vR94jTPJYRW0Zzb2gaRA== + restore-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" @@ -9040,6 +9054,16 @@ warning@^4.0.0, warning@^4.0.1, warning@^4.0.2: dependencies: loose-envify "^1.0.0" +wasmboy@^0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/wasmboy/-/wasmboy-0.7.1.tgz#5bbf0f0f386f8e9ea322a611689b889f9c3495d2" + integrity sha512-qgA3bIFAqioYs8kYXtsanIvedgZlZQf382zs3gNlZHIItsAnRzV70/Vp6cJxbK4FyaiG58ah8/g7OW3orrs9Lg== + dependencies: + audiobuffer-to-wav "git+https://github.com/torch2424/audiobuffer-to-wav.git#es-module-rollup" + idb "^2.1.3" + raf "^3.4.0" + responsive-gamepad "1.1.0" + watchpack@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" From 2e7b773bb5b370067514b9a97f33e7149a6eb464 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 22 Nov 2023 22:39:45 -0600 Subject: [PATCH 045/115] Gameboy: release keyboard when canvas isn't focused --- src/components/gameboy.tsx | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/components/gameboy.tsx b/src/components/gameboy.tsx index ec6617304..c3a67b3d4 100644 --- a/src/components/gameboy.tsx +++ b/src/components/gameboy.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef } from 'react'; +import React, { useCallback, useEffect, useRef } from 'react'; // @ts-ignore No types available import { WasmBoy } from 'wasmboy'; @@ -8,21 +8,39 @@ interface IGameboy extends React.CanvasHTMLAttributes { } /** Component to display a playable Gameboy emulator. */ -const Gameboy: React.FC = ({ src, ...rest }) => { +const Gameboy: React.FC = ({ src, onFocus, onBlur, ...rest }) => { const canvas = useRef(null); async function init() { await WasmBoy.config(WasmBoyOptions, canvas.current!); await WasmBoy.loadROM(src); await WasmBoy.play(); + + if (document.activeElement !== canvas.current) { + await WasmBoy.disableDefaultJoypad(); + } } + const handleFocus: React.FocusEventHandler = useCallback(() => { + WasmBoy.enableDefaultJoypad(); + }, []); + + const handleBlur: React.FocusEventHandler = useCallback(() => { + WasmBoy.disableDefaultJoypad(); + }, []); + useEffect(() => { init(); }, []); return ( - + ); }; From f7c624483ec2e034055c33f8fad04453f9234568 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 22 Nov 2023 22:44:23 -0600 Subject: [PATCH 046/115] Gameboy: improve remounting --- src/components/gameboy.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/gameboy.tsx b/src/components/gameboy.tsx index c3a67b3d4..7c9773fc5 100644 --- a/src/components/gameboy.tsx +++ b/src/components/gameboy.tsx @@ -16,7 +16,9 @@ const Gameboy: React.FC = ({ src, onFocus, onBlur, ...rest }) => { await WasmBoy.loadROM(src); await WasmBoy.play(); - if (document.activeElement !== canvas.current) { + if (document.activeElement === canvas.current) { + await WasmBoy.enableDefaultJoypad(); + } else { await WasmBoy.disableDefaultJoypad(); } } @@ -31,6 +33,11 @@ const Gameboy: React.FC = ({ src, onFocus, onBlur, ...rest }) => { useEffect(() => { init(); + + return () => { + WasmBoy.pause(); + WasmBoy.disableDefaultJoypad(); + }; }, []); return ( From 0bb50f492e5555963016b095dc14d9e792a063c3 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 22 Nov 2023 22:49:27 -0600 Subject: [PATCH 047/115] Lazy-load the Gameboy component --- src/components/gameboy.tsx | 2 +- src/components/media-gallery.tsx | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/components/gameboy.tsx b/src/components/gameboy.tsx index 7c9773fc5..775386080 100644 --- a/src/components/gameboy.tsx +++ b/src/components/gameboy.tsx @@ -69,4 +69,4 @@ const WasmBoyOptions = { saveStateCallback: false, }; -export { Gameboy }; \ No newline at end of file +export default Gameboy; \ No newline at end of file diff --git a/src/components/media-gallery.tsx b/src/components/media-gallery.tsx index 2cf8ee139..198fee48a 100644 --- a/src/components/media-gallery.tsx +++ b/src/components/media-gallery.tsx @@ -1,5 +1,5 @@ import clsx from 'clsx'; -import React, { useState, useRef, useLayoutEffect } from 'react'; +import React, { useState, useRef, useLayoutEffect, Suspense } from 'react'; import Blurhash from 'soapbox/components/blurhash'; import Icon from 'soapbox/components/icon'; @@ -12,11 +12,11 @@ import { truncateFilename } from 'soapbox/utils/media'; import { isIOS } from '../is-mobile'; import { isPanoramic, isPortrait, isNonConformingRatio, minimumAspectRatio, maximumAspectRatio } from '../utils/media-aspect-ratio'; -import { Gameboy } from './gameboy'; - import type { Property } from 'csstype'; import type { List as ImmutableList } from 'immutable'; +const Gameboy = React.lazy(() => import('./gameboy')); + const ATTACHMENT_LIMIT = 4; const MAX_FILENAME_LENGTH = 45; @@ -155,7 +155,9 @@ const Item: React.FC = ({ key={attachment.id} style={{ position, float, left, top, right, bottom, height, width: `${width}%` }} > - + }> + +
); } else if (attachment.type === 'unknown') { From 3b17bef9e5c69f3dab9261ec5580d89be847dc40 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 24 Nov 2023 17:16:51 -0600 Subject: [PATCH 048/115] Switch to my fork of wasmboy --- package.json | 2 +- src/components/gameboy.tsx | 4 ++-- yarn.lock | 20 ++++++++++---------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index b6144c5e9..8484a627a 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "@reduxjs/toolkit": "^1.8.1", "@sentry/browser": "^7.74.1", "@sentry/react": "^7.74.1", + "@soapbox.pub/wasmboy": "^0.8.0", "@tabler/icons": "^2.0.0", "@tailwindcss/aspect-ratio": "^0.4.2", "@tailwindcss/forms": "^0.5.3", @@ -174,7 +175,6 @@ "vite-plugin-html": "^3.2.0", "vite-plugin-require": "^1.1.10", "vite-plugin-static-copy": "^0.17.0", - "wasmboy": "^0.7.1", "wicg-inert": "^3.1.1", "zod": "^3.21.4" }, diff --git a/src/components/gameboy.tsx b/src/components/gameboy.tsx index 775386080..47d8e060a 100644 --- a/src/components/gameboy.tsx +++ b/src/components/gameboy.tsx @@ -1,6 +1,6 @@ -import React, { useCallback, useEffect, useRef } from 'react'; // @ts-ignore No types available -import { WasmBoy } from 'wasmboy'; +import { WasmBoy } from '@soapbox.pub/wasmboy'; +import React, { useCallback, useEffect, useRef } from 'react'; interface IGameboy extends React.CanvasHTMLAttributes { /** URL to the ROM. */ diff --git a/yarn.lock b/yarn.lock index 79e9ac9e2..08b18ba00 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2100,6 +2100,16 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== +"@soapbox.pub/wasmboy@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@soapbox.pub/wasmboy/-/wasmboy-0.8.0.tgz#ca7e86b9c144af44530223536fdbcd29930953b1" + integrity sha512-feecE/YHmE7RdKe5IWzTCeLSaO3gF2XtHqAZWZ31YGzm0Fc8vAxuZC2Tyt0lrKRsS7rEs2L1SxT9oYAiEJcOZA== + dependencies: + audiobuffer-to-wav "git+https://github.com/torch2424/audiobuffer-to-wav.git#es-module-rollup" + idb "^2.1.3" + raf "^3.4.0" + responsive-gamepad "1.1.0" + "@surma/rollup-plugin-off-main-thread@^2.2.3": version "2.2.3" resolved "https://registry.yarnpkg.com/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz#ee34985952ca21558ab0d952f00298ad2190c053" @@ -9054,16 +9064,6 @@ warning@^4.0.0, warning@^4.0.1, warning@^4.0.2: dependencies: loose-envify "^1.0.0" -wasmboy@^0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/wasmboy/-/wasmboy-0.7.1.tgz#5bbf0f0f386f8e9ea322a611689b889f9c3495d2" - integrity sha512-qgA3bIFAqioYs8kYXtsanIvedgZlZQf382zs3gNlZHIItsAnRzV70/Vp6cJxbK4FyaiG58ah8/g7OW3orrs9Lg== - dependencies: - audiobuffer-to-wav "git+https://github.com/torch2424/audiobuffer-to-wav.git#es-module-rollup" - idb "^2.1.3" - raf "^3.4.0" - responsive-gamepad "1.1.0" - watchpack@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" From 33b2d19cd04465a6e26f0f0d726e04371c5742d9 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 24 Nov 2023 18:36:37 -0600 Subject: [PATCH 049/115] vite: don't optimize wasmboy in dev (fixes devserver) --- vite.config.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/vite.config.ts b/vite.config.ts index 4f93c42d3..273ebb87b 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -12,7 +12,7 @@ import { VitePWA } from 'vite-plugin-pwa'; import vitePluginRequire from 'vite-plugin-require'; import { viteStaticCopy } from 'vite-plugin-static-copy'; -export default defineConfig({ +export default defineConfig(({ command }) => ({ build: { assetsDir: 'packs', assetsInlineLimit: 0, @@ -29,6 +29,9 @@ export default defineConfig({ server: { port: 3036, }, + optimizeDeps: { + exclude: command === 'serve' ? ['@soapbox.pub/wasmboy'] : [], + }, plugins: [ checker({ typescript: true }), // @ts-ignore @@ -100,7 +103,7 @@ export default defineConfig({ environment: 'jsdom', setupFiles: 'src/jest/test-setup.ts', }, -}); +})); /** Return file as string, or return empty string if the file isn't found. */ function readFileContents(path: string) { From 5ee2c8a23c0196903536c19a436bc0819920688c Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 24 Nov 2023 20:54:24 -0600 Subject: [PATCH 050/115] Gameboy: render the canvas inside a container div --- src/components/gameboy.tsx | 29 ++++++++++++++++++++--------- src/components/media-gallery.tsx | 2 +- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/components/gameboy.tsx b/src/components/gameboy.tsx index 47d8e060a..e7bbe9309 100644 --- a/src/components/gameboy.tsx +++ b/src/components/gameboy.tsx @@ -1,14 +1,19 @@ // @ts-ignore No types available import { WasmBoy } from '@soapbox.pub/wasmboy'; +import clsx from 'clsx'; import React, { useCallback, useEffect, useRef } from 'react'; -interface IGameboy extends React.CanvasHTMLAttributes { +interface IGameboy extends Pick, 'onFocus' | 'onBlur'> { + /** Classname of the outer `
`. */ + className?: string; /** URL to the ROM. */ src: string; + /** Aspect ratio of the canvas. */ + aspect?: 'normal' | 'stretched'; } /** Component to display a playable Gameboy emulator. */ -const Gameboy: React.FC = ({ src, onFocus, onBlur, ...rest }) => { +const Gameboy: React.FC = ({ className, src, aspect = 'normal', onFocus, onBlur, ...rest }) => { const canvas = useRef(null); async function init() { @@ -41,13 +46,19 @@ const Gameboy: React.FC = ({ src, onFocus, onBlur, ...rest }) => { }, []); return ( - +
+ +
); }; diff --git a/src/components/media-gallery.tsx b/src/components/media-gallery.tsx index 198fee48a..db7bfd1d6 100644 --- a/src/components/media-gallery.tsx +++ b/src/components/media-gallery.tsx @@ -156,7 +156,7 @@ const Item: React.FC = ({ style={{ position, float, left, top, right, bottom, height, width: `${width}%` }} > }> - +
); From 269636471072617354509fb5aacf92123fe71834 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 24 Nov 2023 21:39:59 -0600 Subject: [PATCH 051/115] Gameboy: add controls and a pause buttom --- src/components/gameboy.tsx | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/components/gameboy.tsx b/src/components/gameboy.tsx index e7bbe9309..50ba4b08b 100644 --- a/src/components/gameboy.tsx +++ b/src/components/gameboy.tsx @@ -1,7 +1,9 @@ // @ts-ignore No types available import { WasmBoy } from '@soapbox.pub/wasmboy'; import clsx from 'clsx'; -import React, { useCallback, useEffect, useRef } from 'react'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; + +import { IconButton } from './ui'; interface IGameboy extends Pick, 'onFocus' | 'onBlur'> { /** Classname of the outer `
`. */ @@ -16,10 +18,12 @@ interface IGameboy extends Pick, ' const Gameboy: React.FC = ({ className, src, aspect = 'normal', onFocus, onBlur, ...rest }) => { const canvas = useRef(null); + const [paused, setPaused] = useState(false); + async function init() { await WasmBoy.config(WasmBoyOptions, canvas.current!); await WasmBoy.loadROM(src); - await WasmBoy.play(); + await play(); if (document.activeElement === canvas.current) { await WasmBoy.enableDefaultJoypad(); @@ -36,6 +40,18 @@ const Gameboy: React.FC = ({ className, src, aspect = 'normal', onFocu WasmBoy.disableDefaultJoypad(); }, []); + const pause = async () => { + await WasmBoy.pause(); + setPaused(true); + }; + + const play = async () => { + await WasmBoy.play(); + setPaused(false); + }; + + const togglePaused = () => paused ? play() : pause(); + useEffect(() => { init(); @@ -46,7 +62,7 @@ const Gameboy: React.FC = ({ className, src, aspect = 'normal', onFocu }, []); return ( -
+
= ({ className, src, aspect = 'normal', onFocu onBlur={onBlur ?? handleBlur} {...rest} /> + +
+ +
); }; From 48db472af57fe0e9e96b785e993203c6799ed68e Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 24 Nov 2023 21:58:04 -0600 Subject: [PATCH 052/115] Gameboy: add audio control, but it doesn't work correctly --- src/components/gameboy.tsx | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/components/gameboy.tsx b/src/components/gameboy.tsx index 50ba4b08b..e19977730 100644 --- a/src/components/gameboy.tsx +++ b/src/components/gameboy.tsx @@ -19,6 +19,7 @@ const Gameboy: React.FC = ({ className, src, aspect = 'normal', onFocu const canvas = useRef(null); const [paused, setPaused] = useState(false); + const [muted, setMuted] = useState(true); async function init() { await WasmBoy.config(WasmBoyOptions, canvas.current!); @@ -52,6 +53,11 @@ const Gameboy: React.FC = ({ className, src, aspect = 'normal', onFocu const togglePaused = () => paused ? play() : pause(); + const unmute = async () => { + await WasmBoy.resumeAudioContext(); + setMuted(false); + }; + useEffect(() => { init(); @@ -75,12 +81,17 @@ const Gameboy: React.FC = ({ className, src, aspect = 'normal', onFocu {...rest} /> -
+
+
); @@ -89,7 +100,7 @@ const Gameboy: React.FC = ({ className, src, aspect = 'normal', onFocu const WasmBoyOptions = { headless: false, useGbcWhenOptional: true, - isAudioEnabled: false, + isAudioEnabled: true, frameSkip: 1, audioBatchProcessing: true, timersBatchProcessing: false, From 4d840e02905154c6ce4207f07fbbe75b9ba4667d Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 24 Nov 2023 22:15:25 -0600 Subject: [PATCH 053/115] Gameboy: add a fullscreen button --- src/components/gameboy.tsx | 45 ++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/src/components/gameboy.tsx b/src/components/gameboy.tsx index e19977730..2edb52065 100644 --- a/src/components/gameboy.tsx +++ b/src/components/gameboy.tsx @@ -3,9 +3,11 @@ import { WasmBoy } from '@soapbox.pub/wasmboy'; import clsx from 'clsx'; import React, { useCallback, useEffect, useRef, useState } from 'react'; +import { exitFullscreen, isFullscreen, requestFullscreen } from 'soapbox/features/ui/util/fullscreen'; + import { IconButton } from './ui'; -interface IGameboy extends Pick, 'onFocus' | 'onBlur'> { +interface IGameboy extends Pick, 'onFocus' | 'onBlur'> { /** Classname of the outer `
`. */ className?: string; /** URL to the ROM. */ @@ -16,10 +18,12 @@ interface IGameboy extends Pick, ' /** Component to display a playable Gameboy emulator. */ const Gameboy: React.FC = ({ className, src, aspect = 'normal', onFocus, onBlur, ...rest }) => { + const node = useRef(null); const canvas = useRef(null); const [paused, setPaused] = useState(false); const [muted, setMuted] = useState(true); + const [fullscreen, setFullscreen] = useState(false); async function init() { await WasmBoy.config(WasmBoyOptions, canvas.current!); @@ -33,14 +37,18 @@ const Gameboy: React.FC = ({ className, src, aspect = 'normal', onFocu } } - const handleFocus: React.FocusEventHandler = useCallback(() => { + const handleFocus: React.FocusEventHandler = useCallback(() => { WasmBoy.enableDefaultJoypad(); }, []); - const handleBlur: React.FocusEventHandler = useCallback(() => { + const handleBlur: React.FocusEventHandler = useCallback(() => { WasmBoy.disableDefaultJoypad(); }, []); + const handleFullscreenChange = useCallback(() => { + setFullscreen(isFullscreen()); + }, []); + const pause = async () => { await WasmBoy.pause(); setPaused(true); @@ -58,6 +66,14 @@ const Gameboy: React.FC = ({ className, src, aspect = 'normal', onFocu setMuted(false); }; + const toggleFullscreen = () => { + if (isFullscreen()) { + exitFullscreen(); + } else if (node.current) { + requestFullscreen(node.current); + } + }; + useEffect(() => { init(); @@ -67,17 +83,27 @@ const Gameboy: React.FC = ({ className, src, aspect = 'normal', onFocu }; }, []); + useEffect(() => { + document.addEventListener('fullscreenchange', handleFullscreenChange, true); + return () => { + document.removeEventListener('fullscreenchange', handleFullscreenChange, true); + }; + }, []); + return ( -
+
@@ -92,6 +118,11 @@ const Gameboy: React.FC = ({ className, src, aspect = 'normal', onFocu onClick={unmute} src={muted ? require('@tabler/icons/volume-3.svg') : require('@tabler/icons/volume.svg')} /> +
); From a317152e3f007d1520d81a0d5d827561ee1aee93 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 24 Nov 2023 22:28:29 -0600 Subject: [PATCH 054/115] Gameboy: tap the canvas to show/hide controls --- src/components/gameboy.tsx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/components/gameboy.tsx b/src/components/gameboy.tsx index 2edb52065..d5e371e4d 100644 --- a/src/components/gameboy.tsx +++ b/src/components/gameboy.tsx @@ -24,6 +24,7 @@ const Gameboy: React.FC = ({ className, src, aspect = 'normal', onFocu const [paused, setPaused] = useState(false); const [muted, setMuted] = useState(true); const [fullscreen, setFullscreen] = useState(false); + const [showControls, setShowControls] = useState(true); async function init() { await WasmBoy.config(WasmBoyOptions, canvas.current!); @@ -49,6 +50,10 @@ const Gameboy: React.FC = ({ className, src, aspect = 'normal', onFocu setFullscreen(isFullscreen()); }, []); + const handleCanvasClick = useCallback(() => { + setShowControls(!showControls); + }, [showControls]); + const pause = async () => { await WasmBoy.pause(); setPaused(true); @@ -100,6 +105,7 @@ const Gameboy: React.FC = ({ className, src, aspect = 'normal', onFocu > = ({ className, src, aspect = 'normal', onFocu {...rest} /> -
+
Date: Fri, 24 Nov 2023 22:39:42 -0600 Subject: [PATCH 055/115] Gameboy: focus the div after entering fullscreen --- src/components/gameboy.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/gameboy.tsx b/src/components/gameboy.tsx index d5e371e4d..457aeb74c 100644 --- a/src/components/gameboy.tsx +++ b/src/components/gameboy.tsx @@ -95,11 +95,17 @@ const Gameboy: React.FC = ({ className, src, aspect = 'normal', onFocu }; }, []); + useEffect(() => { + if (fullscreen) { + node.current?.focus(); + } + }, [fullscreen]); + return (
From 5aa69c917f3c39959c17a859227e5d7d47248ccd Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 24 Nov 2023 23:18:15 -0600 Subject: [PATCH 056/115] Gameboy: make mute button work properly --- src/components/gameboy.tsx | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/components/gameboy.tsx b/src/components/gameboy.tsx index 457aeb74c..bc8197fd1 100644 --- a/src/components/gameboy.tsx +++ b/src/components/gameboy.tsx @@ -7,6 +7,8 @@ import { exitFullscreen, isFullscreen, requestFullscreen } from 'soapbox/feature import { IconButton } from './ui'; +let gainNode: GainNode | undefined; + interface IGameboy extends Pick, 'onFocus' | 'onBlur'> { /** Classname of the outer `
`. */ className?: string; @@ -65,11 +67,7 @@ const Gameboy: React.FC = ({ className, src, aspect = 'normal', onFocu }; const togglePaused = () => paused ? play() : pause(); - - const unmute = async () => { - await WasmBoy.resumeAudioContext(); - setMuted(false); - }; + const toggleMuted = () => setMuted(!muted); const toggleFullscreen = () => { if (isFullscreen()) { @@ -101,6 +99,12 @@ const Gameboy: React.FC = ({ className, src, aspect = 'normal', onFocu } }, [fullscreen]); + useEffect(() => { + if (gainNode) { + gainNode.gain.value = muted ? 0 : 1; + } + }, [gainNode, muted]); + return (
= ({ className, src, aspect = 'normal', onFocu /> { + gainNode = gainNode ?? audioContext.createGain(); + audioBufferSourceNode.connect(gainNode); + return gainNode; + }, saveStateCallback: false, }; From dd1e1aca82054cea9c2c2fc3a09ef864fa51f910 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 24 Nov 2023 23:39:17 -0600 Subject: [PATCH 057/115] MediaGallery: fix cursor over Gameboy component --- src/components/media-gallery.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/media-gallery.tsx b/src/components/media-gallery.tsx index db7bfd1d6..368afc6e4 100644 --- a/src/components/media-gallery.tsx +++ b/src/components/media-gallery.tsx @@ -156,7 +156,7 @@ const Item: React.FC = ({ style={{ position, float, left, top, right, bottom, height, width: `${width}%` }} > }> - +
); From c754a52d88612ae78911f9654d0f1d439717a715 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 25 Nov 2023 00:25:22 -0600 Subject: [PATCH 058/115] Gameboy: add download button --- src/components/gameboy.tsx | 55 ++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/src/components/gameboy.tsx b/src/components/gameboy.tsx index bc8197fd1..946d056e8 100644 --- a/src/components/gameboy.tsx +++ b/src/components/gameboy.tsx @@ -5,7 +5,7 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; import { exitFullscreen, isFullscreen, requestFullscreen } from 'soapbox/features/ui/util/fullscreen'; -import { IconButton } from './ui'; +import { HStack, IconButton } from './ui'; let gainNode: GainNode | undefined; @@ -77,6 +77,10 @@ const Gameboy: React.FC = ({ className, src, aspect = 'normal', onFocu } }; + const handleDownload = () => { + window.open(src); + }; + useEffect(() => { init(); @@ -123,27 +127,38 @@ const Gameboy: React.FC = ({ className, src, aspect = 'normal', onFocu {...rest} /> -
- - - -
+ + + + + + + + + +
); }; From b95bd0e533e6d85ffb9dc7e6c53bcc887adb31f6 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 25 Nov 2023 00:39:29 -0600 Subject: [PATCH 059/115] Gameboy: fix button styles in light mode --- src/components/gameboy.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/gameboy.tsx b/src/components/gameboy.tsx index 946d056e8..234b62097 100644 --- a/src/components/gameboy.tsx +++ b/src/components/gameboy.tsx @@ -135,11 +135,13 @@ const Gameboy: React.FC = ({ className, src, aspect = 'normal', onFocu > = ({ className, src, aspect = 'normal', onFocu Date: Sun, 26 Nov 2023 19:38:56 -0600 Subject: [PATCH 060/115] Upgrade Lexical to v0.12.4 --- package.json | 14 +-- yarn.lock | 247 ++++++++++++++++++++++++++------------------------- 2 files changed, 131 insertions(+), 130 deletions(-) diff --git a/package.json b/package.json index 8484a627a..f0d261939 100644 --- a/package.json +++ b/package.json @@ -50,12 +50,12 @@ "@fontsource/roboto-mono": "^5.0.0", "@fontsource/tajawal": "^5.0.8", "@gamestdio/websocket": "^0.3.2", - "@lexical/clipboard": "^0.12.2", - "@lexical/hashtag": "^0.12.2", - "@lexical/link": "^0.12.2", - "@lexical/react": "^0.12.2", - "@lexical/selection": "^0.12.2", - "@lexical/utils": "^0.12.2", + "@lexical/clipboard": "^0.12.4", + "@lexical/hashtag": "^0.12.4", + "@lexical/link": "^0.12.4", + "@lexical/react": "^0.12.4", + "@lexical/selection": "^0.12.4", + "@lexical/utils": "^0.12.4", "@popperjs/core": "^2.11.5", "@reach/combobox": "^0.18.0", "@reach/menu-button": "^0.18.0", @@ -119,7 +119,7 @@ "intl-messageformat": "10.5.4", "intl-pluralrules": "^2.0.0", "leaflet": "^1.8.0", - "lexical": "^0.12.2", + "lexical": "^0.12.4", "line-awesome": "^1.3.0", "localforage": "^1.10.0", "lodash": "^4.7.11", diff --git a/yarn.lock b/yarn.lock index 08b18ba00..418841fbc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1639,159 +1639,160 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@lexical/clipboard@0.12.2", "@lexical/clipboard@^0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@lexical/clipboard/-/clipboard-0.12.2.tgz#cfa74da178673624ecd835eb9449545885cbefc7" - integrity sha512-RldmfZquuJJJCJ5WquCyoJ1/eZ+AnNgdksqvd+G+Yn/GyJl/+O3dnHM0QVaDSPvh/PynLFcCtz/57ySLo2kQxQ== +"@lexical/clipboard@0.12.4", "@lexical/clipboard@^0.12.4": + version "0.12.4" + resolved "https://registry.yarnpkg.com/@lexical/clipboard/-/clipboard-0.12.4.tgz#b9c3a38ab98a67c678ee80238036a166d3161491" + integrity sha512-kFR+UdhtLCMTQgZCyDmYzp2yjPFMNpUZ4TaRjuRBpCRFYwKMlgie4p1J4VJm6sT23kkAFZtVjOfp+gDEYnPHRQ== dependencies: - "@lexical/html" "0.12.2" - "@lexical/list" "0.12.2" - "@lexical/selection" "0.12.2" - "@lexical/utils" "0.12.2" + "@lexical/html" "0.12.4" + "@lexical/list" "0.12.4" + "@lexical/selection" "0.12.4" + "@lexical/utils" "0.12.4" -"@lexical/code@0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@lexical/code/-/code-0.12.2.tgz#2484511cb9c3688bb85f477d448444250939986d" - integrity sha512-w2JeJdnMUtYnC/Fx78sL3iJBt9Ug8pFSDOcI9ay/BkMQFQV8oqq1iyuLLBBJSG4FAM8b2DXrVdGklRQ+jTfTVw== +"@lexical/code@0.12.4": + version "0.12.4" + resolved "https://registry.yarnpkg.com/@lexical/code/-/code-0.12.4.tgz#aa91cf1b070e012b359e9ba023ef880ed8c7fec0" + integrity sha512-pX7rJCjbjCl6VdOPl2hl/UkjP3iPPyCQgH2VQ+WlXapDd+0uZ54nPL1MKCCaFUZocHPmOmSRKKGUp6K2CNiqzg== dependencies: - "@lexical/utils" "0.12.2" + "@lexical/utils" "0.12.4" prismjs "^1.27.0" -"@lexical/dragon@0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@lexical/dragon/-/dragon-0.12.2.tgz#0ae209449a7ebe57c078584e28edb1b7354ecf99" - integrity sha512-Mt8NLzTOt+VgQtc2DKDbHBwKeRlvKqbLqRIMYUVk60gol+YV7NpVBsP1PAMuYYjrTQLhlckBSC32H1SUHZRavA== +"@lexical/dragon@0.12.4": + version "0.12.4" + resolved "https://registry.yarnpkg.com/@lexical/dragon/-/dragon-0.12.4.tgz#dc9961abf31a7e5a40db1b81e07a290ccdca93a5" + integrity sha512-7DaXdQ/5GJ8HRpPYr2+SjaUi912tG9L6ukg9IglG1t51lWGxqLx2chW17tp50XDTtY05w9VnoMaxtgsuCN5Pmg== -"@lexical/hashtag@0.12.2", "@lexical/hashtag@^0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@lexical/hashtag/-/hashtag-0.12.2.tgz#d9c0f872b4a662b0393b289fa84515ec2c7cd624" - integrity sha512-2vYzIu5Ldf+eYdUrNA2m80c3N3MF3vJ0fIJzpl5QyX8OdViggEWl1bh+lKtw1Ju0H0CUyDIXdDLZ2apW3WDkTA== +"@lexical/hashtag@0.12.4", "@lexical/hashtag@^0.12.4": + version "0.12.4" + resolved "https://registry.yarnpkg.com/@lexical/hashtag/-/hashtag-0.12.4.tgz#95e2dced69dd0378c567c855e834492f367d7a86" + integrity sha512-iCxQRBZmgwAV6kypmxtWg7HVhBC7PKclmqLNaLDLoKBm+keEXpKnGB5iEtgK/tCMiwkzrg+wGcrw5qi+YjvM9Q== dependencies: - "@lexical/utils" "0.12.2" + "@lexical/utils" "0.12.4" -"@lexical/history@0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@lexical/history/-/history-0.12.2.tgz#6870871c8120468a213e47c5b303f5b1dd378cba" - integrity sha512-PM/EDjnUyBPMWh1UiYb7T+FLbvTk14HwUWLXvZxn72S6Kj8ExH/PfLbWZWLCFL8RfzvbP407VwfSN8S0bF5H6g== +"@lexical/history@0.12.4": + version "0.12.4" + resolved "https://registry.yarnpkg.com/@lexical/history/-/history-0.12.4.tgz#bb97c6a079d57ea446f40d7de647e9ee5c7f63cd" + integrity sha512-XLbSSr9FueAxuKHo4LBi+lZNVAEReNNDCt4MM2Ol8UZhWPlpNskSB/sECYEEQ6/ItlzgtnKyKWjfDFBHRWvC2g== dependencies: - "@lexical/utils" "0.12.2" + "@lexical/utils" "0.12.4" -"@lexical/html@0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@lexical/html/-/html-0.12.2.tgz#6df09c362688b666da0f474d132d889415dbae8a" - integrity sha512-LWUO6OKhDtDZa9X1spHAqzsp+4EF01exis4cz5H9y2sHi7EofogXnRCadZ+fa07NVwPVTZWsStkk5qdSe/NEzg== +"@lexical/html@0.12.4": + version "0.12.4" + resolved "https://registry.yarnpkg.com/@lexical/html/-/html-0.12.4.tgz#25dd678d3d2bb735fc23340867bfe87e66248495" + integrity sha512-RD/n9n1eCuTZtLaTEI3wuUDlJjCn6j+/0c9GvzqLKhNz9f+E5zMVExhzTT4cZQh5WXbzGFNlwC/cuOtaM3wODg== dependencies: - "@lexical/selection" "0.12.2" + "@lexical/selection" "0.12.4" + "@lexical/utils" "0.12.4" -"@lexical/link@0.12.2", "@lexical/link@^0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@lexical/link/-/link-0.12.2.tgz#33bf3ecdd98c2b27b2bdd67a8885649e1f528fc2" - integrity sha512-etOIONa7uyRDmwg8GN52kDlf8thD2Zk1LOFLeocHWz1V8fe3i2unGUek5s/rNPkc6ynpPpNsHdN1VEghOLCCmw== +"@lexical/link@0.12.4", "@lexical/link@^0.12.4": + version "0.12.4" + resolved "https://registry.yarnpkg.com/@lexical/link/-/link-0.12.4.tgz#364628ae06396cd0182c978efaa9e66d77b34758" + integrity sha512-gmEs0GJGDhgwV1x0IrO7Br2GCALijZLIayGWoLAgYiXZee4WZpvjbngZuC6yghYBhrme6muPRMG2sLMwV2cWiQ== dependencies: - "@lexical/utils" "0.12.2" + "@lexical/utils" "0.12.4" -"@lexical/list@0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@lexical/list/-/list-0.12.2.tgz#7afdd13026f936144ff93d40382f21924e8e6908" - integrity sha512-3CyWtYQC+IlK4cK/oiD8Uz1gSXD8UcKGOF2vVsDXkMU06O6zvHNmHZOnVJqA0JVNgZAoR9dMR1fi2xd4iuCAiw== +"@lexical/list@0.12.4": + version "0.12.4" + resolved "https://registry.yarnpkg.com/@lexical/list/-/list-0.12.4.tgz#f57fe71ff599e298569722e0364c26a5cf417082" + integrity sha512-qxwRIz+4Aj2u2fzyGPo86vX+1ebwCnamppr/c5ZWuqpRTWtYDWjq5LQKIwAvZBxCzPdtP5jzwyZ6VYWQXYW4Kg== dependencies: - "@lexical/utils" "0.12.2" + "@lexical/utils" "0.12.4" -"@lexical/mark@0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@lexical/mark/-/mark-0.12.2.tgz#bfcfffc9f74505e5a6160679812b3d6bafea9c78" - integrity sha512-ub+37PDfmThsqAWipRTrwqpgE+83ckqJ5C3mKQUBZvhZfVZW1rEUXZnKjFh2Q3eZK6iT7zVgoVJWJS9ZgEEyag== +"@lexical/mark@0.12.4": + version "0.12.4" + resolved "https://registry.yarnpkg.com/@lexical/mark/-/mark-0.12.4.tgz#dfe221143d9d2c006b680d88ab2cba281bfb7a45" + integrity sha512-NFFk/3AFFJARjsth8wd5HdeW8XhcaECoQ8wwnJ4fRZzgN0lu3ZSiq+CuVm0NRN5xA5KoUT6sfIQqGOzIPfvdsw== dependencies: - "@lexical/utils" "0.12.2" + "@lexical/utils" "0.12.4" -"@lexical/markdown@0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@lexical/markdown/-/markdown-0.12.2.tgz#b11559590e8684525d4a11d2d78108c3498896b9" - integrity sha512-F2jTFtBp7Q+yoA11BeUOEcxhROzW+HUhUGdsn20pSLhuxsWRj3oUuryWFeNKFofpzTCVoqU6dwpaMNMI2mL/sQ== +"@lexical/markdown@0.12.4": + version "0.12.4" + resolved "https://registry.yarnpkg.com/@lexical/markdown/-/markdown-0.12.4.tgz#ca492a9c76ce7d24e49a51603f770fdfe23d0b51" + integrity sha512-cOk0dkafyvQI4DMwwMfkP329bRVfyhXcVF3dcRiydl6ZIgqOrj/EMi+C0qxQkcqg0MO26Rky6LLJ4vQi6AgJDg== dependencies: - "@lexical/code" "0.12.2" - "@lexical/link" "0.12.2" - "@lexical/list" "0.12.2" - "@lexical/rich-text" "0.12.2" - "@lexical/text" "0.12.2" - "@lexical/utils" "0.12.2" + "@lexical/code" "0.12.4" + "@lexical/link" "0.12.4" + "@lexical/list" "0.12.4" + "@lexical/rich-text" "0.12.4" + "@lexical/text" "0.12.4" + "@lexical/utils" "0.12.4" -"@lexical/offset@0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@lexical/offset/-/offset-0.12.2.tgz#9e4a36508790de1d643d4328986c5c3a2d847de0" - integrity sha512-rZLZXfOBmpmM8A2UZsX3cr/CQYw5F/ou67AbaKI0WImb5sjnIgICZqzu9VFUnkKlVNUurEpplV3UG3D1YYh1OQ== +"@lexical/offset@0.12.4": + version "0.12.4" + resolved "https://registry.yarnpkg.com/@lexical/offset/-/offset-0.12.4.tgz#00c0020a98e32216bd6f119949d3a3bd64b4b139" + integrity sha512-6fjXCx+YD1TMl6GFL4wowhBgbIg+UX3j2OOXh3F7WEp3SDvzoJsJ6F7xRctrHQbluCITM3oDwOyHa1J0m5lrFg== -"@lexical/overflow@0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@lexical/overflow/-/overflow-0.12.2.tgz#b21ba828d6f02e99456d05df6c1d2771fb82aceb" - integrity sha512-UgE5j3ukO6qRFRpH4T7m/DvnodE9nCtImD7QinyGdsTa0hi5xlRnl0FUo605vH+vz7xEsUNAGwQXYPX9Sc/vig== +"@lexical/overflow@0.12.4": + version "0.12.4" + resolved "https://registry.yarnpkg.com/@lexical/overflow/-/overflow-0.12.4.tgz#3e7725e356044a5c9a7a80e53edc23cddf026da9" + integrity sha512-mEWgVukoOgcyDruHvzk1amy9jgGDVXFYiPn20ykxgrVQz6XEpq+lfyic/BUnN4toNR8p6jc/Yxi2lF1ELCU0Kg== -"@lexical/plain-text@0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@lexical/plain-text/-/plain-text-0.12.2.tgz#87c51de239190d9202122a62aeaae04cb2477cda" - integrity sha512-Lcg6+ngRnX70//kz34azYhID3bvW66HSHCfu5UPhCXT+vQ/Jkd/InhRKajBwWXpaJxMM1huoi3sjzVDb3luNtw== +"@lexical/plain-text@0.12.4": + version "0.12.4" + resolved "https://registry.yarnpkg.com/@lexical/plain-text/-/plain-text-0.12.4.tgz#10ef4d56e1569e0d8ad1bc12569cffd736414957" + integrity sha512-osbqOyt19oFG0kTbV71jxxCdgnUqNYW6QXIIaS1SwcCN/N1CdFZ0sNpjPkHIFx9AdZ/Tmi4u9SNFUo16DjvThA== -"@lexical/react@^0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@lexical/react/-/react-0.12.2.tgz#336805af7a3d8e69d5b0ef3d0efd7bd4cd8f29fb" - integrity sha512-ZBUvf5xmhiYWBw8pPrhYmLAEwFWrbF/cd15y76TUKD9l/2zDwwPs6nJQxBzfz3ei65r2/nnavLDV8W3QfvxfUA== +"@lexical/react@^0.12.4": + version "0.12.4" + resolved "https://registry.yarnpkg.com/@lexical/react/-/react-0.12.4.tgz#4c53c32d8575dff685334b116e5a2bdf19a34da5" + integrity sha512-tz4ebqJ++YP/Y6FCjk5aU3bvgrps8+i9abqvaaNCSzSQavI0qHtdS7EGy4S9qyO6qKuthXcOGIQxGTweRTkDsA== dependencies: - "@lexical/clipboard" "0.12.2" - "@lexical/code" "0.12.2" - "@lexical/dragon" "0.12.2" - "@lexical/hashtag" "0.12.2" - "@lexical/history" "0.12.2" - "@lexical/link" "0.12.2" - "@lexical/list" "0.12.2" - "@lexical/mark" "0.12.2" - "@lexical/markdown" "0.12.2" - "@lexical/overflow" "0.12.2" - "@lexical/plain-text" "0.12.2" - "@lexical/rich-text" "0.12.2" - "@lexical/selection" "0.12.2" - "@lexical/table" "0.12.2" - "@lexical/text" "0.12.2" - "@lexical/utils" "0.12.2" - "@lexical/yjs" "0.12.2" + "@lexical/clipboard" "0.12.4" + "@lexical/code" "0.12.4" + "@lexical/dragon" "0.12.4" + "@lexical/hashtag" "0.12.4" + "@lexical/history" "0.12.4" + "@lexical/link" "0.12.4" + "@lexical/list" "0.12.4" + "@lexical/mark" "0.12.4" + "@lexical/markdown" "0.12.4" + "@lexical/overflow" "0.12.4" + "@lexical/plain-text" "0.12.4" + "@lexical/rich-text" "0.12.4" + "@lexical/selection" "0.12.4" + "@lexical/table" "0.12.4" + "@lexical/text" "0.12.4" + "@lexical/utils" "0.12.4" + "@lexical/yjs" "0.12.4" react-error-boundary "^3.1.4" -"@lexical/rich-text@0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@lexical/rich-text/-/rich-text-0.12.2.tgz#9ef44e54777fc222ac8df344adb0d7428c784b25" - integrity sha512-igsEuv7CwBOAj5c8jeE41cnx6zkhI/Bkbu4W7shT6S6lNA/3cnyZpAMlgixwyK5RoqjGRCT+IJK5l6yBxQfNkw== +"@lexical/rich-text@0.12.4": + version "0.12.4" + resolved "https://registry.yarnpkg.com/@lexical/rich-text/-/rich-text-0.12.4.tgz#545a1d6bd88e930c572d17fe504a8796f6af0c9d" + integrity sha512-gWMDmdRRFPk00JfQv52650qcpjTN6oBrrYwBydYvEG8WTC8o1k8qEOZaOFja6GElPt0520dpyvcWHTlIL0jv3Q== -"@lexical/selection@0.12.2", "@lexical/selection@^0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@lexical/selection/-/selection-0.12.2.tgz#87e30b953b02923d1691f61d5189eb1be81a19ae" - integrity sha512-h+g3oOnihHKIyLTyG6uLCEVR/DmUEVdCcZO1iAoGsuW7nwWiWNPWj6oZ3Cw5J1Mk5u62DHnkkVDQsVSZbAwmtg== +"@lexical/selection@0.12.4", "@lexical/selection@^0.12.4": + version "0.12.4" + resolved "https://registry.yarnpkg.com/@lexical/selection/-/selection-0.12.4.tgz#756922edbf42f3cb0bd6f99239d77ba2615c859c" + integrity sha512-9lJt9PBJW7lWYiPDo/PGl2nZ6NrdYaDBidEoMNhyusPjeBEr35z4Hm0qWUhDrPDQPhK2i1oBw6nZa94bxuS9Lw== -"@lexical/table@0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@lexical/table/-/table-0.12.2.tgz#59be2fd0413a9125017bb119aa950050bf92717b" - integrity sha512-tiAmTq6RKHDVER9v589Ajm9/RL+WTF1WschrH6HHVCtil6cfJfTJeJ+MF45+XEzB9fkqy2LfrScAfWxqLjVePA== +"@lexical/table@0.12.4": + version "0.12.4" + resolved "https://registry.yarnpkg.com/@lexical/table/-/table-0.12.4.tgz#b40426de069b7e962e95e38f2ff1bc10ca649388" + integrity sha512-Lyy6y1HOQqzU8O2cH5Zhzek46B0UU7NceM2fJKM7qiBSuxY/nE0BzkFq0xDk3x5W+vhXob6Z32sJSNFImtuqKw== dependencies: - "@lexical/utils" "0.12.2" + "@lexical/utils" "0.12.4" -"@lexical/text@0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@lexical/text/-/text-0.12.2.tgz#623f8a9a56606e202febf4af80cfb5cf2da2a530" - integrity sha512-HyuIGuQvVi5djJKKBf+jYEBjK+0Eo9cKHf6WS7dlFozuCZvcCQEJkFy2yceWOwIVk+f2kptVQ5uO7aiZHExH2A== +"@lexical/text@0.12.4": + version "0.12.4" + resolved "https://registry.yarnpkg.com/@lexical/text/-/text-0.12.4.tgz#65ba9620492d673cd68c8380725d4e4fe845e603" + integrity sha512-r/7402eCf6C/7BqUNR7ZLZQQjsE62wjeuf0rFeW1ulOpwiti/dFn1o+EsCb0hvNeHPzfGgRC+FuDT9KSEKu7Ig== -"@lexical/utils@0.12.2", "@lexical/utils@^0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@lexical/utils/-/utils-0.12.2.tgz#b8325f1a1a0d043fd2b40d59cd00c4d7c038474b" - integrity sha512-xW4y4l2Yd37+qLwkBvBGyzsKCA9wnh1ljphBJeR2vreT193i2gaIwuku2ZKlER14VHw4192qNJF7vUoAEmwurQ== +"@lexical/utils@0.12.4", "@lexical/utils@^0.12.4": + version "0.12.4" + resolved "https://registry.yarnpkg.com/@lexical/utils/-/utils-0.12.4.tgz#83ed97d31201e1b911cfa38b940909c3cca41d77" + integrity sha512-ColV11ANBY6deT7CdGwP4lzv3pb5caFfFLcVKdGDMMJSUYFQ5l69aZvDP2qWWnNqzGLb+AJSunMd142wWc5LGg== dependencies: - "@lexical/list" "0.12.2" - "@lexical/selection" "0.12.2" - "@lexical/table" "0.12.2" + "@lexical/list" "0.12.4" + "@lexical/selection" "0.12.4" + "@lexical/table" "0.12.4" -"@lexical/yjs@0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@lexical/yjs/-/yjs-0.12.2.tgz#c0bebe1795ecb7e68d88d255dcbfcaa02740539d" - integrity sha512-OPJhkJD1Mp9W80mfLzASTB3OFWFMzJteUYA+eSyDgiX9zNi1VGxAqmIITTkDvnCMa+qvw4EfhGeGezpjx6Og4A== +"@lexical/yjs@0.12.4": + version "0.12.4" + resolved "https://registry.yarnpkg.com/@lexical/yjs/-/yjs-0.12.4.tgz#ea986b66932558062bab2ccc1b46c34c0260ea3e" + integrity sha512-qtCiABugE1CiZ7K5iFfQnB1KqfWtLyiRK0nxAaSxuZzQTO4+Kh3WDh7ULppPa53Sf3pKpw8Sq2XB4AXP6csbkg== dependencies: - "@lexical/offset" "0.12.2" + "@lexical/offset" "0.12.4" "@mdn/browser-compat-data@^5.2.34", "@mdn/browser-compat-data@^5.3.13": version "5.3.16" @@ -5894,10 +5895,10 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -lexical@^0.12.2: - version "0.12.2" - resolved "https://registry.yarnpkg.com/lexical/-/lexical-0.12.2.tgz#68535e145715d5788374495c9ee0420e417d792b" - integrity sha512-Kxavd+ETjxtVwG/hvPd6WZfXD44sLOKe9Vlkwxy7lBQ1qZArS+rZfs+u5iXwXe6tX9f2PIM0u3RHsrCEDDE0fw== +lexical@^0.12.4: + version "0.12.4" + resolved "https://registry.yarnpkg.com/lexical/-/lexical-0.12.4.tgz#1f38d40eb1b5bdcf30a79864027bf7443de52fb5" + integrity sha512-giNrnp45H6P4IHFhkKaHEPTF+bKLBWdEIDL/FGjRZf+to7l7TORIBk/23Zdchzt/VGgKGWu950EOvGh53gkVMQ== li@^1.3.0: version "1.3.0" From 889c2658ba9b4c88b4e0680db2be2fc8181e31d1 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 27 Nov 2023 14:20:36 -0600 Subject: [PATCH 061/115] ComposeForm: refactor canSubmit so it works correctly in more scenarios --- .../compose/components/compose-form.tsx | 40 +++++++------------ 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/src/features/compose/components/compose-form.tsx b/src/features/compose/components/compose-form.tsx index 182707b68..72acd166e 100644 --- a/src/features/compose/components/compose-form.tsx +++ b/src/features/compose/components/compose-form.tsx @@ -101,18 +101,20 @@ const ComposeForm = ({ id, shouldCondense, autoFocus, clickab const formRef = useRef(null); const spoilerTextRef = useRef(null); const editorRef = useRef(null); + const { isDraggedOver } = useDraggedFiles(formRef); const text = editorRef.current?.getEditorState().read(() => $getRoot().getTextContent()) ?? ''; - const { isDraggedOver } = useDraggedFiles(formRef); + const fulltext = [spoilerText, countableText(text)].join(''); + + const isEmpty = !(fulltext.trim() || anyMedia); + const condensed = shouldCondense && !isDraggedOver && !composeFocused && isEmpty && !isUploading; + const shouldAutoFocus = autoFocus && !showSearch && !isMobile(window.innerWidth); + const canSubmit = !isSubmitting && !isUploading && !isChangingUpload && !isEmpty && length(fulltext) <= maxTootChars; const getClickableArea = () => { return clickableAreaRef ? clickableAreaRef.current : formRef.current; }; - const isEmpty = () => { - return !(text || spoilerText || anyMedia); - }; - const isClickOutside = (e: MouseEvent | React.MouseEvent) => { return ![ // List of elements that shouldn't collapse the composer when clicked @@ -125,10 +127,10 @@ const ComposeForm = ({ id, shouldCondense, autoFocus, clickab }; const handleClick = useCallback((e: MouseEvent | React.MouseEvent) => { - if (isEmpty() && isClickOutside(e)) { + if (isEmpty && isClickOutside(e)) { handleClickOutside(); } - }, []); + }, [isEmpty]); const handleClickOutside = () => { setComposeFocused(false); @@ -139,20 +141,12 @@ const ComposeForm = ({ id, shouldCondense, autoFocus, clickab }; const handleSubmit = (e?: React.FormEvent) => { + if (!canSubmit) return; + e?.preventDefault(); + dispatch(changeCompose(id, text)); - - // Submit disabled: - const fulltext = [spoilerText, countableText(text)].join(''); - - if (e) { - e.preventDefault(); - } - - if (isSubmitting || isUploading || isChangingUpload || length(fulltext) > maxTootChars || (fulltext.length !== 0 && fulltext.trim().length === 0 && !anyMedia)) { - return; - } - dispatch(submitCompose(id, { history })); + editorRef.current?.dispatchCommand(CLEAR_EDITOR_COMMAND, undefined); }; @@ -215,12 +209,6 @@ const ComposeForm = ({ id, shouldCondense, autoFocus, clickab ), [features, id]); - const condensed = shouldCondense && !isDraggedOver && !composeFocused && isEmpty() && !isUploading; - const disabled = isSubmitting; - const countedText = [spoilerText, countableText(text)].join(''); - const disabledButton = disabled || isUploading || isChangingUpload || length(countedText) > maxTootChars || (countedText.length !== 0 && countedText.trim().length === 0 && !anyMedia); - const shouldAutoFocus = autoFocus && !showSearch && !isMobile(window.innerWidth); - const composeModifiers = !condensed && ( @@ -323,7 +311,7 @@ const ComposeForm = ({ id, shouldCondense, autoFocus, clickab )} -
From fd19fa9e5bca113ec76ead9f1c387d02764bf2a2 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 27 Nov 2023 14:56:42 -0600 Subject: [PATCH 062/115] FocusPlugin: refactor the useEffect for sanity --- src/features/compose/editor/plugins/focus-plugin.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/features/compose/editor/plugins/focus-plugin.tsx b/src/features/compose/editor/plugins/focus-plugin.tsx index 65b567683..8a076f199 100644 --- a/src/features/compose/editor/plugins/focus-plugin.tsx +++ b/src/features/compose/editor/plugins/focus-plugin.tsx @@ -11,10 +11,6 @@ export const FOCUS_EDITOR_COMMAND: LexicalCommand = createCommand(); const FocusPlugin: React.FC = ({ autoFocus }) => { const [editor] = useLexicalComposerContext(); - const focus = () => { - editor.dispatchCommand(FOCUS_EDITOR_COMMAND, undefined); - }; - useEffect(() => editor.registerCommand(FOCUS_EDITOR_COMMAND, () => { editor.focus( () => { @@ -29,8 +25,10 @@ const FocusPlugin: React.FC = ({ autoFocus }) => { }, COMMAND_PRIORITY_NORMAL)); useEffect(() => { - if (autoFocus) focus(); - }, []); + if (autoFocus) { + editor.dispatchCommand(FOCUS_EDITOR_COMMAND, undefined); + } + }, [autoFocus, editor]); return null; }; From 54dff2131f92d689dcec704a8d47af21ef545c5e Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 27 Nov 2023 14:57:16 -0600 Subject: [PATCH 063/115] ComposeForm: do autoFocus on mobile --- src/features/compose/components/compose-form.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/features/compose/components/compose-form.tsx b/src/features/compose/components/compose-form.tsx index 72acd166e..adc3b0571 100644 --- a/src/features/compose/components/compose-form.tsx +++ b/src/features/compose/components/compose-form.tsx @@ -18,7 +18,6 @@ import { Button, HStack, Stack } from 'soapbox/components/ui'; import EmojiPickerDropdown from 'soapbox/features/emoji/containers/emoji-picker-dropdown-container'; import { ComposeEditor } from 'soapbox/features/ui/util/async-components'; import { useAppDispatch, useAppSelector, useCompose, useDraggedFiles, useFeatures, useInstance, usePrevious } from 'soapbox/hooks'; -import { isMobile } from 'soapbox/is-mobile'; import QuotedStatusContainer from '../containers/quoted-status-container'; import ReplyIndicatorContainer from '../containers/reply-indicator-container'; @@ -108,7 +107,7 @@ const ComposeForm = ({ id, shouldCondense, autoFocus, clickab const isEmpty = !(fulltext.trim() || anyMedia); const condensed = shouldCondense && !isDraggedOver && !composeFocused && isEmpty && !isUploading; - const shouldAutoFocus = autoFocus && !showSearch && !isMobile(window.innerWidth); + const shouldAutoFocus = autoFocus && !showSearch; const canSubmit = !isSubmitting && !isUploading && !isChangingUpload && !isEmpty && length(fulltext) <= maxTootChars; const getClickableArea = () => { From e426f7213018d394458c98e5f51010eaebeb6c5e Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 27 Nov 2023 15:00:39 -0600 Subject: [PATCH 064/115] ComposeForm: disable submit when there is no editorRef --- src/features/compose/components/compose-form.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/compose/components/compose-form.tsx b/src/features/compose/components/compose-form.tsx index adc3b0571..45771dd94 100644 --- a/src/features/compose/components/compose-form.tsx +++ b/src/features/compose/components/compose-form.tsx @@ -108,7 +108,7 @@ const ComposeForm = ({ id, shouldCondense, autoFocus, clickab const isEmpty = !(fulltext.trim() || anyMedia); const condensed = shouldCondense && !isDraggedOver && !composeFocused && isEmpty && !isUploading; const shouldAutoFocus = autoFocus && !showSearch; - const canSubmit = !isSubmitting && !isUploading && !isChangingUpload && !isEmpty && length(fulltext) <= maxTootChars; + const canSubmit = !!editorRef.current && !isSubmitting && !isUploading && !isChangingUpload && !isEmpty && length(fulltext) <= maxTootChars; const getClickableArea = () => { return clickableAreaRef ? clickableAreaRef.current : formRef.current; From 3333db75ba004f4abd779068b82f5f4eb110dcf5 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 28 Nov 2023 12:35:48 -0600 Subject: [PATCH 065/115] account.tsx: add space between action --- src/components/account.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/account.tsx b/src/components/account.tsx index ad4766ecd..cca7f47ce 100644 --- a/src/components/account.tsx +++ b/src/components/account.tsx @@ -187,7 +187,7 @@ const Account = ({ return (
- + Date: Fri, 17 Nov 2023 16:10:14 +0000 Subject: [PATCH 066/115] Translated using Weblate (Chinese (Traditional)) Currently translated at 99.8% (1523 of 1526 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/zh_Hant/ --- src/locales/zh-TW.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/locales/zh-TW.json b/src/locales/zh-TW.json index 42a443b4b..d6ab4fda3 100644 --- a/src/locales/zh-TW.json +++ b/src/locales/zh-TW.json @@ -717,7 +717,7 @@ "federation_restrictions.explanation_box.title": "實例相關政策", "federation_restrictions.not_disclosed_message": "{siteTitle} 不透過 API 揭露聯合限制。", "fediverse_tab.explanation_box.dismiss": "不再顯示", - "fediverse_tab.explanation_box.explanation": "{site_title} 是聯邦宇宙的一份子, 一個由數個站點組成的社交網路集合。你在這裏看到的貼文來自於其他站點。你可以自由地與他們打交道,或者封鎖任何你不喜歡的站點。第二個 @ 符號後的完整帳戶名表示貼文來自哪個站點。要想只看到 {site_title} 的貼文, 請瀏覽 {local} 。", + "fediverse_tab.explanation_box.explanation": "{site_title} 是聯邦宇宙的一部分,是一個由數千個獨立社群媒體網站(又稱「伺服器」)組成的社群網路。您在此處看到的貼文來自第三方伺服器。您可以自由地與他們互動或封鎖任何您不喜歡的伺服器。請注意完整用戶名中第二個@符號後面代表貼文來自哪個伺服器。要僅查看 {site_title} 的貼文,請查看「本地」時間軸。", "fediverse_tab.explanation_box.title": "什麼是聯邦宇宙?", "feed_suggestions.heading": "推薦的個人檔案", "feed_suggestions.view_all": "檢視全部", From 9680a304b99cc1ce1b55822d3a99f58d5a91aba7 Mon Sep 17 00:00:00 2001 From: jonnysemon Date: Sun, 19 Nov 2023 17:44:05 +0000 Subject: [PATCH 067/115] Translated using Weblate (Arabic) Currently translated at 100.0% (1526 of 1526 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/ar/ --- src/locales/ar.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/locales/ar.json b/src/locales/ar.json index 81a68b2c1..8329ca2ca 100644 --- a/src/locales/ar.json +++ b/src/locales/ar.json @@ -198,6 +198,8 @@ "birthdays_modal.empty": "ليس لأصدقائك يوم ميلاد اليوم.", "boost_modal.combo": "يمكنك الضغط على {combo} لتخطي هذا في المرة القادمة", "boost_modal.title": "إعادة نشر؟", + "bundle_column_error.body": "حدث خطأ ما أثناء تحميل هذه الصفحة.", + "bundle_column_error.retry": "حاول مجددًا", "card.back.label": "العودة", "chat.actions.send": "إرسال", "chat.failed_to_send": "فشل ارسال الرسالة.", From 3acdb7a839efb833e0060f6f56bbf26a0e1b8324 Mon Sep 17 00:00:00 2001 From: Weblate Translation Memory Date: Sun, 19 Nov 2023 17:44:12 +0000 Subject: [PATCH 068/115] Translated using Weblate (Arabic) Currently translated at 100.0% (1526 of 1526 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/ar/ --- src/locales/ar.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/locales/ar.json b/src/locales/ar.json index 8329ca2ca..db87c7c2d 100644 --- a/src/locales/ar.json +++ b/src/locales/ar.json @@ -200,6 +200,7 @@ "boost_modal.title": "إعادة نشر؟", "bundle_column_error.body": "حدث خطأ ما أثناء تحميل هذه الصفحة.", "bundle_column_error.retry": "حاول مجددًا", + "bundle_column_error.title": "خطأ في الشبكة", "card.back.label": "العودة", "chat.actions.send": "إرسال", "chat.failed_to_send": "فشل ارسال الرسالة.", From e9fa21158f8515c8f5e14a67eadaab62355df150 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=95=E3=81=95=E3=81=8F=E3=82=89=E3=82=8A?= Date: Tue, 21 Nov 2023 10:57:22 +0000 Subject: [PATCH 069/115] Translated using Weblate (Japanese) Currently translated at 74.3% (1134 of 1526 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/ja/ --- src/locales/ja.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/locales/ja.json b/src/locales/ja.json index 6b1d782a9..9843e393d 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -10,6 +10,7 @@ "account.block_domain": "{domain}全体を非表示", "account.blocked": "ブロック済み", "account.chat": "@{name}さんとチャット", + "account.copy": "プロフィールへのリンクをコピー", "account.deactivated": "非アクティブ化", "account.direct": "@{name}さんにダイレクトメッセージ", "account.domain_blocked": "ドメイン非表示", @@ -82,6 +83,11 @@ "account_search.placeholder": "アカウントを検索", "actualStatus.edited": "{date}に編集済", "actualStatuses.quote_tombstone": "Post is unavailable.", + "admin.announcements.action": "アナウンスを作成", + "admin.announcements.delete": "削除", + "admin.announcements.edit": "編集", + "admin.announcements.ends_at": "終了日時:", + "admin.announcements.starts_at": "開始日時:", "admin.awaiting_approval.empty_message": "There is nobody waiting for approval. When a new user signs up, you can review them here.", "admin.dashboard.registration_mode.approval_hint": "Users can sign up, but their account only gets activated when an admin approves it.", "admin.dashboard.registration_mode.approval_label": "Approval Required", @@ -98,6 +104,12 @@ "admin.dashcounters.user_count_label": "total users", "admin.dashwidgets.email_list_header": "Email list", "admin.dashwidgets.software_header": "Software", + "admin.edit_announcement.created": "アナウンスが作成されました", + "admin.edit_announcement.deleted": "アナウンスを削除しました", + "admin.edit_announcement.fields.all_day_label": "終日", + "admin.edit_announcement.fields.content_label": "内容", + "admin.edit_announcement.fields.content_placeholder": "アナウンスの内容", + "admin.edit_announcement.fields.end_time_label": "終了日", "admin.latest_accounts_panel.more": "クリックして {count} 人のおすすめユーザーを表示", "admin.latest_accounts_panel.title": "Latest Accounts", "admin.moderation_log.empty_message": "You have not performed any moderation actions yet. When you do, a history will be shown here.", From 4d8e87bad758d7e7da2d1755d0a2914dbe66adb5 Mon Sep 17 00:00:00 2001 From: Ryan He Date: Thu, 23 Nov 2023 03:52:07 +0000 Subject: [PATCH 070/115] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (1526 of 1526 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/zh_Hant/ --- src/locales/zh-TW.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/locales/zh-TW.json b/src/locales/zh-TW.json index d6ab4fda3..e46a0d9a0 100644 --- a/src/locales/zh-TW.json +++ b/src/locales/zh-TW.json @@ -198,6 +198,9 @@ "birthdays_modal.empty": "你的朋友今天都沒過生日。", "boost_modal.combo": "下次您可以按 {combo} 跳過", "boost_modal.title": "轉發?", + "bundle_column_error.body": "載入此頁面時出現問題。", + "bundle_column_error.retry": "再試一次", + "bundle_column_error.title": "網路錯誤", "card.back.label": "返回", "chat.actions.send": "送出", "chat.failed_to_send": "訊息發送失敗。", From 642483eb9f652da4b2cc934b9573376a63678b62 Mon Sep 17 00:00:00 2001 From: Soapbox Bot Date: Tue, 5 Dec 2023 00:15:22 +0000 Subject: [PATCH 071/115] Update dependency @types/react-motion to ^0.0.39 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f0d261939..3406e21cc 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "@types/react-datepicker": "^4.4.2", "@types/react-dom": "^18.0.10", "@types/react-helmet": "^6.1.5", - "@types/react-motion": "^0.0.36", + "@types/react-motion": "^0.0.39", "@types/react-router-dom": "^5.3.3", "@types/react-sparklines": "^1.7.2", "@types/react-swipeable-views": "^0.13.1", diff --git a/yarn.lock b/yarn.lock index 418841fbc..6c1756f60 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2456,10 +2456,10 @@ dependencies: "@types/react" "*" -"@types/react-motion@^0.0.36": - version "0.0.36" - resolved "https://registry.yarnpkg.com/@types/react-motion/-/react-motion-0.0.36.tgz#ec543b671f95e2e9b7abd50d7d31d3820ab03310" - integrity sha512-ATFMhp+A+kNxjvKK3bHPS9tO0wBuFg/zgLCc9vmzBYaNj87U839fpXWsB/OS0kDslMYp1Lg9xM/9hdPD81Ooeg== +"@types/react-motion@^0.0.39": + version "0.0.39" + resolved "https://registry.yarnpkg.com/@types/react-motion/-/react-motion-0.0.39.tgz#f282ecc026b988e7524e222217304df708de2d14" + integrity sha512-FqQcamh3FED6A4CVL39fmZMHQ4B3v1C7lenxwqDAtENO+p+xuOXHCTOpxh632qdGTPeqHVhN7oeClhNijgpOPg== dependencies: "@types/react" "*" From 96d6801af92c8436fa24bc760d11d82b7a6a294a Mon Sep 17 00:00:00 2001 From: Soapbox Bot Date: Tue, 5 Dec 2023 00:15:38 +0000 Subject: [PATCH 072/115] Update dependency intl-messageformat to v10.5.8 --- package.json | 2 +- yarn.lock | 47 +++++++++++++++++++++++++++++++++++------------ 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index f0d261939..57a708d8a 100644 --- a/package.json +++ b/package.json @@ -116,7 +116,7 @@ "immer": "^10.0.0", "immutable": "^4.2.1", "intersection-observer": "^0.12.2", - "intl-messageformat": "10.5.4", + "intl-messageformat": "10.5.8", "intl-pluralrules": "^2.0.0", "leaflet": "^1.8.0", "lexical": "^0.12.4", diff --git a/yarn.lock b/yarn.lock index 418841fbc..9106a192b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1442,6 +1442,14 @@ "@formatjs/intl-localematcher" "0.4.2" tslib "^2.4.0" +"@formatjs/ecma402-abstract@1.18.0": + version "1.18.0" + resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.18.0.tgz#e2120e7101020140661b58430a7ff4262705a2f2" + integrity sha512-PEVLoa3zBevWSCZzPIM/lvPCi8P5l4G+NXQMc/CjEiaCWgyHieUoo0nM7Bs0n/NbuQ6JpXEolivQ9pKSBHaDlA== + dependencies: + "@formatjs/intl-localematcher" "0.5.2" + tslib "^2.4.0" + "@formatjs/fast-memoize@2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-2.2.0.tgz#33bd616d2e486c3e8ef4e68c99648c196887802b" @@ -1458,13 +1466,13 @@ "@formatjs/icu-skeleton-parser" "1.6.2" tslib "^2.4.0" -"@formatjs/icu-messageformat-parser@2.7.0": - version "2.7.0" - resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.7.0.tgz#9b13f2710a3b4efddfeb544480f684f27a53483b" - integrity sha512-7uqC4C2RqOaBQtcjqXsSpGRYVn+ckjhNga5T/otFh6MgxRrCJQqvjfbrGLpX1Lcbxdm5WH3Z2WZqt1+Tm/cn/Q== +"@formatjs/icu-messageformat-parser@2.7.3": + version "2.7.3" + resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.7.3.tgz#c8c95e7c9f8141bdb93bea0e92e4fcace19d3c9f" + integrity sha512-X/jy10V9S/vW+qlplqhMUxR8wErQ0mmIYSq4mrjpjDl9mbuGcCILcI1SUYkL5nlM4PJqpc0KOS0bFkkJNPxYRw== dependencies: - "@formatjs/ecma402-abstract" "1.17.2" - "@formatjs/icu-skeleton-parser" "1.6.2" + "@formatjs/ecma402-abstract" "1.18.0" + "@formatjs/icu-skeleton-parser" "1.7.0" tslib "^2.4.0" "@formatjs/icu-skeleton-parser@1.6.2": @@ -1475,6 +1483,14 @@ "@formatjs/ecma402-abstract" "1.17.2" tslib "^2.4.0" +"@formatjs/icu-skeleton-parser@1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.7.0.tgz#796938d6d0ba8fc75bb9edee038d1350bfee32cb" + integrity sha512-Cfdo/fgbZzpN/jlN/ptQVe0lRHora+8ezrEeg2RfrNjyp+YStwBy7cqDY8k5/z2LzXg6O0AdzAV91XS0zIWv+A== + dependencies: + "@formatjs/ecma402-abstract" "1.18.0" + tslib "^2.4.0" + "@formatjs/intl-displaynames@6.5.2": version "6.5.2" resolved "https://registry.yarnpkg.com/@formatjs/intl-displaynames/-/intl-displaynames-6.5.2.tgz#b14ffd0962d5b5cfd71457efc389f0bca83a00db" @@ -1500,6 +1516,13 @@ dependencies: tslib "^2.4.0" +"@formatjs/intl-localematcher@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.5.2.tgz#5fcf029fd218905575e5080fa33facdcb623d532" + integrity sha512-txaaE2fiBMagLrR4jYhxzFO6wEdEG4TPMqrzBAcbr4HFUYzH/YC+lg6OIzKCHm8WgDdyQevxbAAV1OgcXctuGw== + dependencies: + tslib "^2.4.0" + "@formatjs/intl@2.9.3": version "2.9.3" resolved "https://registry.yarnpkg.com/@formatjs/intl/-/intl-2.9.3.tgz#e570c4b1afb173dfb1f80a42624425dde9841329" @@ -5322,14 +5345,14 @@ intl-messageformat@10.5.3: "@formatjs/icu-messageformat-parser" "2.6.2" tslib "^2.4.0" -intl-messageformat@10.5.4: - version "10.5.4" - resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-10.5.4.tgz#7b212b083f1b354d7e282518e78057e025134af9" - integrity sha512-z+hrFdiJ/heRYlzegrdFYqU1m/KOMOVMqNilIArj+PbsuU8TNE7v4TWdQgSoxlxbT4AcZH3Op3/Fu15QTp+W1w== +intl-messageformat@10.5.8: + version "10.5.8" + resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-10.5.8.tgz#7184da425f360a53a5483a6194e16d666b011fc0" + integrity sha512-NRf0jpBWV0vd671G5b06wNofAN8tp7WWDogMZyaU8GUAsmbouyvgwmFJI7zLjfAMpm3zK+vSwRP3jzaoIcMbaA== dependencies: - "@formatjs/ecma402-abstract" "1.17.2" + "@formatjs/ecma402-abstract" "1.18.0" "@formatjs/fast-memoize" "2.2.0" - "@formatjs/icu-messageformat-parser" "2.7.0" + "@formatjs/icu-messageformat-parser" "2.7.3" tslib "^2.4.0" intl-pluralrules@^2.0.0: From 6406e77601377c43998dc47561db922b61c6304c Mon Sep 17 00:00:00 2001 From: Soapbox Bot Date: Tue, 5 Dec 2023 01:01:28 +0000 Subject: [PATCH 073/115] Update dependency vite-plugin-pwa to ^0.17.0 --- package.json | 2 +- yarn.lock | 21 ++++++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 4196b7e5a..c60e9e1c0 100644 --- a/package.json +++ b/package.json @@ -211,7 +211,7 @@ "stylelint-config-standard-scss": "^11.0.0", "tailwindcss": "^3.3.3", "vite-plugin-checker": "^0.6.2", - "vite-plugin-pwa": "^0.16.5", + "vite-plugin-pwa": "^0.17.0", "vitest": "^0.34.4" }, "resolutions": { diff --git a/yarn.lock b/yarn.lock index c368aa66d..d73e3e974 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4682,6 +4682,17 @@ fast-glob@^3.2.11, fast-glob@^3.2.12, fast-glob@^3.2.5, fast-glob@^3.2.7, fast-g merge2 "^1.3.0" micromatch "^4.0.4" +fast-glob@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -8920,13 +8931,13 @@ vite-plugin-html@^3.2.0: node-html-parser "^5.3.3" pathe "^0.2.0" -vite-plugin-pwa@^0.16.5: - version "0.16.5" - resolved "https://registry.yarnpkg.com/vite-plugin-pwa/-/vite-plugin-pwa-0.16.5.tgz#863ae3ffe0a7b1183da94e4b5cf6966878c30308" - integrity sha512-Ahol4dwhMP2UHPQXkllSlXbihOaDFnvBIDPmAxoSZ1EObBUJGP4CMRyCyAVkIHjd6/H+//vH0DM2ON+XxHr81g== +vite-plugin-pwa@^0.17.0: + version "0.17.3" + resolved "https://registry.yarnpkg.com/vite-plugin-pwa/-/vite-plugin-pwa-0.17.3.tgz#eab6ab2950012e483ab6959172a15c796fd0d1e3" + integrity sha512-ilOs0mGxIxKQN3FZYX8pys5DmY/wI9A6oojlY5rrd7mAxCVcSbtjDVAhm62C+3Ww6KQrNr/jmiRUCplC8AsaBw== dependencies: debug "^4.3.4" - fast-glob "^3.3.1" + fast-glob "^3.3.2" pretty-bytes "^6.1.1" workbox-build "^7.0.0" workbox-window "^7.0.0" From f55aa6933fa37c0fc45015c1d2956b206da2a1ac Mon Sep 17 00:00:00 2001 From: Soapbox Bot Date: Tue, 5 Dec 2023 02:01:17 +0000 Subject: [PATCH 074/115] Update dependency html-react-parser to v5 --- package.json | 2 +- yarn.lock | 58 ++++++++++++++++++++++++++-------------------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/package.json b/package.json index c60e9e1c0..1a0fe603f 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "escape-html": "^1.0.3", "exifr": "^7.1.3", "graphemesplit": "^2.4.4", - "html-react-parser": "^4.2.2", + "html-react-parser": "^5.0.0", "http-link-header": "^1.0.2", "immer": "^10.0.0", "immutable": "^4.2.1", diff --git a/yarn.lock b/yarn.lock index d73e3e974..14aec6750 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5141,10 +5141,10 @@ hosted-git-info@^4.0.1: dependencies: lru-cache "^6.0.0" -html-dom-parser@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/html-dom-parser/-/html-dom-parser-4.0.0.tgz#dc382fbbc9306f8c9b5aae4e3f2822e113a48709" - integrity sha512-TUa3wIwi80f5NF8CVWzkopBVqVAtlawUzJoLwVLHns0XSJGynss4jiY0mTWpiDOsuyw+afP+ujjMgRh9CoZcXw== +html-dom-parser@5.0.4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/html-dom-parser/-/html-dom-parser-5.0.4.tgz#2941a762317d088e747db31c8cf290987ec30a55" + integrity sha512-azy8THLKd4Ar0OVJpEgX+MSjYvKdNDWlGiRBIlovMqEQYMAnLLXBhhiSwjylDD3RDdcCYT8Utg6uoRDeLHUyHg== dependencies: domhandler "5.0.3" htmlparser2 "9.0.0" @@ -5169,15 +5169,15 @@ html-minifier-terser@^6.1.0: relateurl "^0.2.7" terser "^5.10.0" -html-react-parser@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/html-react-parser/-/html-react-parser-4.2.2.tgz#91f1cc2138bc069d65cbd8b9d97b1e71ed423300" - integrity sha512-lh0wEGISnFZEAmvQqK4xc0duFMUh/m9YYyAhFursWxdtNv+hCZge0kj1y4wep6qPB5Zm33L+2/P6TcGWAJJbjA== +html-react-parser@^5.0.0: + version "5.0.7" + resolved "https://registry.yarnpkg.com/html-react-parser/-/html-react-parser-5.0.7.tgz#3ada0420c0ae05dce2915fff78aad2b9d678041f" + integrity sha512-00ve/0B7ukLUAcAbmD6Vh74EicB+ktLvAM4APeXJjiBsRiPz2ouochTvyUhOJB8apP2t40xAXvpmd+t50aVnJg== dependencies: domhandler "5.0.3" - html-dom-parser "4.0.0" - react-property "2.0.0" - style-to-js "1.1.4" + html-dom-parser "5.0.4" + react-property "2.0.2" + style-to-js "1.1.10" html-tags@^3.3.1: version "3.3.1" @@ -5327,10 +5327,10 @@ ini@^1.3.5: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -inline-style-parser@0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1" - integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q== +inline-style-parser@0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.2.2.tgz#d498b4e6de0373458fc610ff793f6b14ebf45633" + integrity sha512-EcKzdTHVe8wFVOGEYXiW9WmJXPjqi1T+234YpJr98RiFYKHV3cdy1+3mkTE+KHTHxFFLH51SfaGOoUdW+v7ViQ== internal-slot@^1.0.5: version "1.0.5" @@ -7392,10 +7392,10 @@ react-popper@^2.2.5, react-popper@^2.3.0: react-fast-compare "^3.0.1" warning "^4.0.2" -react-property@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/react-property/-/react-property-2.0.0.tgz#2156ba9d85fa4741faf1918b38efc1eae3c6a136" - integrity sha512-kzmNjIgU32mO4mmH5+iUyrqlpFQhF8K2k7eZ4fdLSOPFrD1XgEuSBv9LDEgxRXTMBqMd8ppT0x6TIzqE5pdGdw== +react-property@2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/react-property/-/react-property-2.0.2.tgz#d5ac9e244cef564880a610bc8d868bd6f60fdda6" + integrity sha512-+PbtI3VuDV0l6CleQMsx2gtK0JZbZKbpdu5ynr+lbsuvtmgbNcS3VM0tuY2QjFNOcWxvXeHjDpy42RO+4U2rug== react-redux@^8.0.0: version "8.0.5" @@ -8230,19 +8230,19 @@ style-search@^0.1.0: resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902" integrity sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI= -style-to-js@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/style-to-js/-/style-to-js-1.1.4.tgz#5fa07a181ec3ca354d699edf442549e0ac61ed32" - integrity sha512-zEeU3vy9xL/hdLBFmzqjhm+2vJ1Y35V0ctDeB2sddsvN1856OdMZUCOOfKUn3nOjjEKr6uLhOnY4CrX6gLDRrA== +style-to-js@1.1.10: + version "1.1.10" + resolved "https://registry.yarnpkg.com/style-to-js/-/style-to-js-1.1.10.tgz#ec20e1264ba11dc7f71b94b3a3a05566ed856e54" + integrity sha512-VC7MBJa+y0RZhpnLKDPmVRLRswsASLmixkiZ5R8xZpNT9VyjeRzwnXd2pBzAWdgSGv/pCNNH01gPCCUsB9exYg== dependencies: - style-to-object "0.4.2" + style-to-object "1.0.5" -style-to-object@0.4.2: - version "0.4.2" - resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.4.2.tgz#a8247057111dea8bd3b8a1a66d2d0c9cf9218a54" - integrity sha512-1JGpfPB3lo42ZX8cuPrheZbfQ6kqPPnPHlKMyeRYtfKD+0jG+QsXgXN57O/dvJlzlB2elI6dGmrPnl5VPQFPaA== +style-to-object@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-1.0.5.tgz#5e918349bc3a39eee3a804497d97fcbbf2f0d7c0" + integrity sha512-rDRwHtoDD3UMMrmZ6BzOW0naTjMsVZLIjsGleSKS/0Oz+cgCfAPRspaqJuE8rDzpKha/nEvnM0IF4seEAZUTKQ== dependencies: - inline-style-parser "0.1.1" + inline-style-parser "0.2.2" stylehacks@^6.0.0: version "6.0.0" From 3b63e4380a0723329810508d564186c0a0930ca0 Mon Sep 17 00:00:00 2001 From: Soapbox Bot Date: Tue, 5 Dec 2023 02:01:35 +0000 Subject: [PATCH 075/115] Update dependency jsdom to v23 --- package.json | 2 +- yarn.lock | 180 +++++++++++++++++++++++---------------------------- 2 files changed, 83 insertions(+), 99 deletions(-) diff --git a/package.json b/package.json index c60e9e1c0..41b5e8c81 100644 --- a/package.json +++ b/package.json @@ -202,7 +202,7 @@ "eslint-plugin-tailwindcss": "^3.13.0", "fake-indexeddb": "^5.0.0", "husky": "^8.0.0", - "jsdom": "^22.1.0", + "jsdom": "^23.0.0", "lint-staged": ">=10", "react-intl-translations-manager": "^5.0.3", "react-refresh": "^0.14.0", diff --git a/yarn.lock b/yarn.lock index d73e3e974..e6041c720 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2240,11 +2240,6 @@ resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-14.5.1.tgz#27337d72046d5236b32fd977edee3f74c71d332f" integrity sha512-UCcUKrUYGj7ClomOo2SpNVvx4/fkd/2BbIHDCle8A0ax+P3bU7yJwDBDrS6ZwdTMARWTGODX1hEsCcO+7beJjg== -"@tootallnate/once@2": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" - integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A== - "@trysound/sax@0.2.0": version "0.2.0" resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" @@ -2864,11 +2859,6 @@ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== -abab@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" - integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== - acorn-import-assertions@^1.9.0: version "1.9.0" resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" @@ -2889,12 +2879,12 @@ acorn@^8.10.0, acorn@^8.7.1, acorn@^8.8.2, acorn@^8.9.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== -agent-base@6: - version "6.0.2" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" - integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== +agent-base@^7.0.2, agent-base@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.0.tgz#536802b76bc0b34aa50195eb2442276d613e3434" + integrity sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg== dependencies: - debug "4" + debug "^4.3.4" aggregate-error@^3.0.0: version "3.1.0" @@ -3860,14 +3850,13 @@ damerau-levenshtein@^1.0.8: resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA== -data-urls@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-4.0.0.tgz#333a454eca6f9a5b7b0f1013ff89074c3f522dd4" - integrity sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g== +data-urls@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-5.0.0.tgz#2f76906bce1824429ffecb6920f45a0b30f00dde" + integrity sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg== dependencies: - abab "^2.0.6" - whatwg-mimetype "^3.0.0" - whatwg-url "^12.0.0" + whatwg-mimetype "^4.0.0" + whatwg-url "^14.0.0" date-fns@^2.0.1, date-fns@^2.24.0: version "2.28.0" @@ -4071,13 +4060,6 @@ domelementtype@^2.0.1, domelementtype@^2.2.0, domelementtype@^2.3.0: resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== -domexception@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/domexception/-/domexception-4.0.0.tgz#4ad1be56ccadc86fc76d033353999a8037d03673" - integrity sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw== - dependencies: - webidl-conversions "^7.0.0" - domhandler@5.0.3, domhandler@^5.0.2, domhandler@^5.0.3: version "5.0.3" resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31" @@ -5149,12 +5131,12 @@ html-dom-parser@4.0.0: domhandler "5.0.3" htmlparser2 "9.0.0" -html-encoding-sniffer@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz#2cb1a8cf0db52414776e5b2a7a04d5dd98158de9" - integrity sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA== +html-encoding-sniffer@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz#696df529a7cfd82446369dc5193e590a3735b448" + integrity sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ== dependencies: - whatwg-encoding "^2.0.0" + whatwg-encoding "^3.1.1" html-minifier-terser@^6.1.0: version "6.1.0" @@ -5204,14 +5186,13 @@ http-link-header@^1.0.2: resolved "https://registry.yarnpkg.com/http-link-header/-/http-link-header-1.0.3.tgz#abbc2cdc5e06dd7e196a4983adac08a2d085ec90" integrity sha512-nARK1wSKoBBrtcoESlHBx36c1Ln/gnbNQi1eB6MeTUefJIT3NvUOsV15bClga0k38f0q/kN5xxrGSDS3EFnm9w== -http-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43" - integrity sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w== +http-proxy-agent@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz#e9096c5afd071a3fce56e6252bb321583c124673" + integrity sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ== dependencies: - "@tootallnate/once" "2" - agent-base "6" - debug "4" + agent-base "^7.1.0" + debug "^4.3.4" http2-wrapper@^1.0.0-beta.5.2: version "1.0.3" @@ -5221,12 +5202,12 @@ http2-wrapper@^1.0.0-beta.5.2: quick-lru "^5.1.1" resolve-alpn "^1.0.0" -https-proxy-agent@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" - integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== +https-proxy-agent@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz#e2645b846b90e96c6e6f347fb5b2e41f1590b09b" + integrity sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA== dependencies: - agent-base "6" + agent-base "^7.0.2" debug "4" human-signals@^2.1.0: @@ -5712,34 +5693,32 @@ jsdoc-type-pratt-parser@~4.0.0: resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz#136f0571a99c184d84ec84662c45c29ceff71114" integrity sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ== -jsdom@^22.1.0: - version "22.1.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-22.1.0.tgz#0fca6d1a37fbeb7f4aac93d1090d782c56b611c8" - integrity sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw== +jsdom@^23.0.0: + version "23.0.1" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-23.0.1.tgz#ede7ff76e89ca035b11178d200710d8982ebfee0" + integrity sha512-2i27vgvlUsGEBO9+/kJQRbtqtm+191b5zAZrU/UezVmnC2dlDAFLgDYJvAEi94T4kjsRKkezEtLQTgsNEsW2lQ== dependencies: - abab "^2.0.6" cssstyle "^3.0.0" - data-urls "^4.0.0" + data-urls "^5.0.0" decimal.js "^10.4.3" - domexception "^4.0.0" form-data "^4.0.0" - html-encoding-sniffer "^3.0.0" - http-proxy-agent "^5.0.0" - https-proxy-agent "^5.0.1" + html-encoding-sniffer "^4.0.0" + http-proxy-agent "^7.0.0" + https-proxy-agent "^7.0.2" is-potential-custom-element-name "^1.0.1" - nwsapi "^2.2.4" + nwsapi "^2.2.7" parse5 "^7.1.2" rrweb-cssom "^0.6.0" saxes "^6.0.0" symbol-tree "^3.2.4" - tough-cookie "^4.1.2" - w3c-xmlserializer "^4.0.0" + tough-cookie "^4.1.3" + w3c-xmlserializer "^5.0.0" webidl-conversions "^7.0.0" - whatwg-encoding "^2.0.0" - whatwg-mimetype "^3.0.0" - whatwg-url "^12.0.1" - ws "^8.13.0" - xml-name-validator "^4.0.0" + whatwg-encoding "^3.1.1" + whatwg-mimetype "^4.0.0" + whatwg-url "^14.0.0" + ws "^8.14.2" + xml-name-validator "^5.0.0" jsesc@^2.5.1: version "2.5.2" @@ -6481,7 +6460,7 @@ nth-check@^2.0.1: dependencies: boolbase "^1.0.0" -nwsapi@^2.2.4: +nwsapi@^2.2.7: version "2.2.7" resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.7.tgz#738e0707d3128cb750dddcfe90e4610482df0f30" integrity sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ== @@ -7150,11 +7129,16 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -punycode@^2.1.0, punycode@^2.1.1, punycode@^2.3.0: +punycode@^2.1.0, punycode@^2.1.1: version "2.3.0" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== +punycode@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + qrcode.react@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/qrcode.react/-/qrcode.react-3.1.0.tgz#5c91ddc0340f768316fbdb8fff2765134c2aecd8" @@ -8578,7 +8562,7 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -tough-cookie@^4.1.2: +tough-cookie@^4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== @@ -8595,12 +8579,12 @@ tr46@^1.0.1: dependencies: punycode "^2.1.0" -tr46@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-4.1.1.tgz#281a758dcc82aeb4fe38c7dfe4d11a395aac8469" - integrity sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw== +tr46@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-5.0.0.tgz#3b46d583613ec7283020d79019f1335723801cec" + integrity sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g== dependencies: - punycode "^2.3.0" + punycode "^2.3.1" trim-newlines@^4.0.2: version "4.1.1" @@ -9078,12 +9062,12 @@ vue-template-es2015-compiler@^1.9.0: resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825" integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw== -w3c-xmlserializer@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz#aebdc84920d806222936e3cdce408e32488a3073" - integrity sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw== +w3c-xmlserializer@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz#f925ba26855158594d907313cedd1476c5967f6c" + integrity sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA== dependencies: - xml-name-validator "^4.0.0" + xml-name-validator "^5.0.0" warning@^3.0.0: version "3.0.0" @@ -9152,24 +9136,24 @@ webpack-sources@^3.2.3: watchpack "^2.4.0" webpack-sources "^3.2.3" -whatwg-encoding@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz#e7635f597fd87020858626805a2729fa7698ac53" - integrity sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg== +whatwg-encoding@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz#d0f4ef769905d426e1688f3e34381a99b60b76e5" + integrity sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ== dependencies: iconv-lite "0.6.3" -whatwg-mimetype@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz#5fa1a7623867ff1af6ca3dc72ad6b8a4208beba7" - integrity sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q== +whatwg-mimetype@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz#bc1bf94a985dc50388d54a9258ac405c3ca2fc0a" + integrity sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg== -whatwg-url@^12.0.0, whatwg-url@^12.0.1: - version "12.0.1" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-12.0.1.tgz#fd7bcc71192e7c3a2a97b9a8d6b094853ed8773c" - integrity sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ== +whatwg-url@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-14.0.0.tgz#00baaa7fd198744910c4b1ef68378f2200e4ceb6" + integrity sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw== dependencies: - tr46 "^4.1.1" + tr46 "^5.0.0" webidl-conversions "^7.0.0" whatwg-url@^7.0.0: @@ -9447,20 +9431,20 @@ write-file-atomic@^5.0.1: imurmurhash "^0.1.4" signal-exit "^4.0.1" -ws@^8.13.0: - version "8.14.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.14.1.tgz#4b9586b4f70f9e6534c7bb1d3dc0baa8b8cf01e0" - integrity sha512-4OOseMUq8AzRBI/7SLMUwO+FEDnguetSk7KMb1sHwvF2w2Wv5Hoj0nlifx8vtGsftE/jWHojPy8sMMzYLJ2G/A== +ws@^8.14.2: + version "8.14.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.14.2.tgz#6c249a806eb2db7a20d26d51e7709eab7b2e6c7f" + integrity sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g== xcase@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/xcase/-/xcase-2.0.1.tgz#c7fa72caa0f440db78fd5673432038ac984450b9" integrity sha512-UmFXIPU+9Eg3E9m/728Bii0lAIuoc+6nbrNUKaRPJOFp91ih44qqGlWtxMB6kXFrRD6po+86ksHM5XHCfk6iPw== -xml-name-validator@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835" - integrity sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw== +xml-name-validator@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-5.0.0.tgz#82be9b957f7afdacf961e5980f1bf227c0bf7673" + integrity sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg== xmlchars@^2.2.0: version "2.2.0" From 7c397ae895038c638d2205476a9d56b50858a36c Mon Sep 17 00:00:00 2001 From: Soapbox Bot Date: Tue, 5 Dec 2023 03:04:40 +0000 Subject: [PATCH 076/115] Update dependency react-redux to v9 --- package.json | 2 +- yarn.lock | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index c60e9e1c0..fea83dd14 100644 --- a/package.json +++ b/package.json @@ -145,7 +145,7 @@ "react-motion": "^0.5.2", "react-overlays": "^0.9.0", "react-popper": "^2.3.0", - "react-redux": "^8.0.0", + "react-redux": "^9.0.0", "react-router-dom": "^5.3.0", "react-router-dom-v5-compat": "^6.6.2", "react-router-scroll-4": "^1.0.0-beta.2", diff --git a/yarn.lock b/yarn.lock index d73e3e974..12551290d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7397,16 +7397,12 @@ react-property@2.0.0: resolved "https://registry.yarnpkg.com/react-property/-/react-property-2.0.0.tgz#2156ba9d85fa4741faf1918b38efc1eae3c6a136" integrity sha512-kzmNjIgU32mO4mmH5+iUyrqlpFQhF8K2k7eZ4fdLSOPFrD1XgEuSBv9LDEgxRXTMBqMd8ppT0x6TIzqE5pdGdw== -react-redux@^8.0.0: - version "8.0.5" - resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.0.5.tgz#e5fb8331993a019b8aaf2e167a93d10af469c7bd" - integrity sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw== +react-redux@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-9.0.1.tgz#bbdbdd55d5c3b0e996975269b7d6101b80487139" + integrity sha512-d+S89OqyChnY2J0O8wv8boRgnGo0tjvxkMLV78wx7h2ZyJvyeOQcBg4yrm7IxY36gxc63iOCfjjQAyhohKWJbA== dependencies: - "@babel/runtime" "^7.12.1" - "@types/hoist-non-react-statics" "^3.3.1" "@types/use-sync-external-store" "^0.0.3" - hoist-non-react-statics "^3.3.2" - react-is "^18.0.0" use-sync-external-store "^1.0.0" react-refresh@^0.14.0: From 76445f6db15cfecef4ede62463f18f9f8aaa7771 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 6 Dec 2023 14:51:14 -0600 Subject: [PATCH 077/115] Sentry: decrease tracesSampleRate to .1 --- src/sentry.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sentry.ts b/src/sentry.ts index ac2e6fe90..89f1495f9 100644 --- a/src/sentry.ts +++ b/src/sentry.ts @@ -39,7 +39,7 @@ async function startSentry(dsn: string): Promise { /^moz-extension:\/\//i, ], - tracesSampleRate: 1.0, + tracesSampleRate: .1, }); Sentry.setContext('soapbox', sourceCode); From c2baf98420811b963386eef7f10aee57f10ec41d Mon Sep 17 00:00:00 2001 From: Rizal Sambayu Date: Sun, 10 Dec 2023 14:50:12 +0000 Subject: [PATCH 078/115] Translated using Weblate (Indonesian) Currently translated at 100.0% (1526 of 1526 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/id/ --- src/locales/id.json | 664 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 559 insertions(+), 105 deletions(-) diff --git a/src/locales/id.json b/src/locales/id.json index 5e16c1df9..b766bd50f 100644 --- a/src/locales/id.json +++ b/src/locales/id.json @@ -1,137 +1,162 @@ { - "about.also_available": "Available in:", - "accordion.collapse": "Collapse", - "accordion.expand": "Expand", + "about.also_available": "Tersedia di:", + "accordion.collapse": "Runtuh", + "accordion.expand": "Memperluas", "account.add_or_remove_from_list": "Tambah atau Hapus dari daftar", "account.badges.bot": "Bot", - "account.birthday": "Born {date}", - "account.birthday_today": "Birthday is today!", + "account.birthday": "Lahir {date}", + "account.birthday_today": "Hari ini adalah hari ulang tahun!", "account.block": "Blokir @{name}", "account.block_domain": "Sembunyikan segalanya dari {domain}", "account.blocked": "Terblokir", - "account.chat": "Chat with @{name}", - "account.deactivated": "Deactivated", - "account.direct": "Direct Message @{name}", - "account.domain_blocked": "Domain hidden", - "account.edit_profile": "Ubah profil", + "account.chat": "Ngobrol dengan @{name}", + "account.copy": "Salin tautan ke profil", + "account.deactivated": "Dinonaktifkan", + "account.direct": "Pesan Langsung @{name}", + "account.domain_blocked": "Domain tersembunyi", + "account.edit_profile": "Sunting profil", "account.endorse": "Tampilkan di profil", - "account.endorse.success": "You are now featuring @{acct} on your profile", - "account.familiar_followers": "Followed by {accounts}", - "account.familiar_followers.empty": "No one you know follows {name}.", - "account.familiar_followers.more": "{count} {count, plural, one {other} other {others}} you follow", + "account.endorse.success": "Anda sekarang menampilkan @{acct} di profil Anda", + "account.familiar_followers": "Diikuti oleh {accounts}", + "account.familiar_followers.empty": "Tidak ada orang yang Anda kenal yang mengikuti {name}.", + "account.familiar_followers.more": "{count} {count, plural, satu {other} lainnya {others}} mengikuti anda", "account.follow": "Ikuti", "account.followers": "Pengikut", "account.followers.empty": "Tidak ada satupun yang mengkuti pengguna ini saat ini.", "account.follows": "Mengikuti", "account.follows.empty": "Pengguna ini belum mengikuti siapapun.", "account.follows_you": "Mengikuti anda", - "account.header.alt": "Profile header", + "account.header.alt": "Header profil", "account.hide_reblogs": "Sembunyikan boosts dari @{name}", - "account.last_status": "Last active", + "account.last_status": "Terakhir aktif", "account.link_verified_on": "Kepemilikan tautan ini telah dicek pada {date}", "account.locked_info": "Status privasi akun ini disetel untuk dikunci. Pemilik secara manual meninjau siapa yang dapat mengikuti mereka.", - "account.login": "Log in", + "account.login": "Masuk", "account.media": "Media", - "account.member_since": "Joined {date}", + "account.member_since": "Bergabung {date}", "account.mention": "Balasan", "account.mute": "Bisukan @{name}", - "account.muted": "Muted", - "account.never_active": "Never", - "account.posts": "Posts", - "account.posts_with_replies": "Postingan dengan balasan", - "account.profile": "Profile", - "account.profile_external": "View profile on {domain}", - "account.register": "Sign up", - "account.remote_follow": "Remote follow", - "account.remove_from_followers": "Remove this follower", + "account.muted": "Membisukan", + "account.never_active": "Tidak pernah", + "account.patron": "Patron", + "account.posts": "Postingan", + "account.posts_with_replies": "Postingan & balasan", + "account.profile": "Profil", + "account.profile_external": "Lihat profil di {domain}", + "account.register": "Mendaftar", + "account.remote_follow": "Ikuti jarak jauh", + "account.remove_from_followers": "Hapus pengikut ini", "account.report": "Laporkan @{name}", "account.requested": "Menunggu persetujuan. Klik untuk membatalkan permintaan", - "account.requested_small": "Awaiting approval", - "account.search": "Search from @{name}", - "account.search_self": "Search your posts", + "account.requested_small": "Menunggu persetujuan", + "account.rss_feed": "Subscribe to RSS feed", + "account.search": "Cari dari @{name}", + "account.search_self": "Telusuri postingan Anda", "account.share": "Bagikan profil @{name}", - "account.show_reblogs": "Tampilkan repost dari @{name}", - "account.subscribe": "Subscribe to notifications from @{name}", - "account.subscribe.failure": "An error occurred trying to subscribe to this account.", - "account.subscribe.success": "You have subscribed to this account.", - "account.unblock": "Hapus blokir @{name}", + "account.show_reblogs": "Tampilkan postingan ulang dari @{name}", + "account.subscribe": "Berlangganan notifikasi dari @{name}", + "account.subscribe.failure": "Terjadi kesalahan saat mencoba berlangganan akun ini.", + "account.subscribe.success": "Anda telah berlangganan akun ini.", + "account.unblock": "Buka blokir @{name}", "account.unblock_domain": "Tampilkan {domain}", "account.unendorse": "Jangan tampilkan di profil", - "account.unendorse.success": "You are no longer featuring @{acct}", + "account.unendorse.success": "Anda tidak lagi tampil @{acct}", "account.unfollow": "Berhenti mengikuti", "account.unmute": "Berhenti membisukan @{name}", - "account.unsubscribe": "Unsubscribe to notifications from @{name}", - "account.unsubscribe.failure": "An error occurred trying to unsubscribe to this account.", - "account.unsubscribe.success": "You have unsubscribed from this account.", - "account.verified": "Verified Account", - "account_gallery.none": "No media to show.", - "account_moderation_modal.admin_fe": "Open in AdminFE", - "account_moderation_modal.fields.account_role": "Staff level", - "account_moderation_modal.fields.badges": "Custom badges", - "account_moderation_modal.fields.deactivate": "Deactivate account", - "account_moderation_modal.fields.delete": "Delete account", - "account_moderation_modal.fields.suggested": "Suggested in people to follow", - "account_moderation_modal.fields.verified": "Verified account", + "account.unsubscribe": "Berhenti berlangganan notifikasi dari @{name}", + "account.unsubscribe.failure": "Terjadi kesalahan saat mencoba berhenti berlangganan akun ini.", + "account.unsubscribe.success": "Anda telah berhenti berlangganan akun ini.", + "account.verified": "Akun terverifikasi", + "account_gallery.none": "Tidak ada media untuk ditampilkan.", + "account_moderation_modal.admin_fe": "Buka di AdminFE", + "account_moderation_modal.fields.account_role": "Tingkat staf", + "account_moderation_modal.fields.badges": "Lencana khusus", + "account_moderation_modal.fields.deactivate": "Nonaktifkan akun", + "account_moderation_modal.fields.delete": "Hapus akun", + "account_moderation_modal.fields.suggested": "Disarankan pada orang untuk diikuti", + "account_moderation_modal.fields.verified": "Akun terverifikasi", "account_moderation_modal.info.id": "ID: {id}", "account_moderation_modal.roles.admin": "Admin", "account_moderation_modal.roles.moderator": "Moderator", - "account_moderation_modal.roles.user": "User", + "account_moderation_modal.roles.user": "Pengguna", "account_moderation_modal.title": "Moderate @{acct}", - "account_note.placeholder": "Click to add a note", - "account_search.placeholder": "Search for an account", - "actualStatus.edited": "Edited {date}", - "actualStatuses.quote_tombstone": "Post is unavailable.", - "admin.awaiting_approval.empty_message": "There is nobody waiting for approval. When a new user signs up, you can review them here.", - "admin.dashboard.registration_mode.approval_hint": "Users can sign up, but their account only gets activated when an admin approves it.", - "admin.dashboard.registration_mode.approval_label": "Approval Required", - "admin.dashboard.registration_mode.closed_hint": "Nobody can sign up. You can still invite people.", - "admin.dashboard.registration_mode.closed_label": "Closed", - "admin.dashboard.registration_mode.open_hint": "Anyone can join.", - "admin.dashboard.registration_mode.open_label": "Open", - "admin.dashboard.registration_mode_label": "Registrations", - "admin.dashboard.settings_saved": "Settings saved!", + "account_note.header": "Catatan", + "account_note.placeholder": "Klik untuk menambahkan catatan", + "account_search.placeholder": "Cari akun", + "actualStatus.edited": "Diedit {date}", + "actualStatuses.quote_tombstone": "Postingan tidak tersedia.", + "admin.announcements.action": "Buat pengumuman", + "admin.announcements.all_day": "Sepanjang hari", + "admin.announcements.delete": "Hapus", + "admin.announcements.edit": "Edit", + "admin.announcements.ends_at": "Berakhir pada:", + "admin.announcements.starts_at": "Dimulai pada:", + "admin.awaiting_approval.empty_message": "Tidak ada yang menunggu persetujuan. Saat pengguna baru mendaftar, Anda dapat meninjaunya di sini.", + "admin.dashboard.registration_mode.approval_hint": "Pengguna dapat mendaftar, namun akun mereka hanya diaktifkan ketika admin menyetujuinya.", + "admin.dashboard.registration_mode.approval_label": "Diperlukan Persetujuan", + "admin.dashboard.registration_mode.closed_hint": "Tidak ada yang bisa mendaftar. Anda masih dapat mengundang orang.", + "admin.dashboard.registration_mode.closed_label": "Ditutup", + "admin.dashboard.registration_mode.open_hint": "Siapapun bisa bergabung.", + "admin.dashboard.registration_mode.open_label": "Buka", + "admin.dashboard.registration_mode_label": "Pendaftaran", + "admin.dashboard.settings_saved": "Pengaturan disimpan!", "admin.dashcounters.domain_count_label": "peers", - "admin.dashcounters.mau_label": "monthly active users", - "admin.dashcounters.retention_label": "user retention", - "admin.dashcounters.status_count_label": "posts", - "admin.dashcounters.user_count_label": "total users", - "admin.dashwidgets.email_list_header": "Email list", - "admin.dashwidgets.software_header": "Software", - "admin.latest_accounts_panel.more": "Click to see {count} {count, plural, one {account} other {accounts}}", - "admin.latest_accounts_panel.title": "Latest Accounts", - "admin.moderation_log.empty_message": "You have not performed any moderation actions yet. When you do, a history will be shown here.", - "admin.reports.actions.close": "Close", - "admin.reports.actions.view_status": "View post", - "admin.reports.empty_message": "There are no open reports. If a user gets reported, they will show up here.", - "admin.reports.report_closed_message": "Report on @{name} was closed", - "admin.reports.report_title": "Report on {acct}", - "admin.statuses.actions.delete_status": "Delete post", - "admin.statuses.actions.mark_status_not_sensitive": "Mark post not sensitive", - "admin.statuses.actions.mark_status_sensitive": "Mark post sensitive", - "admin.statuses.status_deleted_message": "Post by @{acct} was deleted", - "admin.statuses.status_marked_message_not_sensitive": "Post by @{acct} was marked not sensitive", - "admin.statuses.status_marked_message_sensitive": "Post by @{acct} was marked sensitive", - "admin.user_index.empty": "No users found.", - "admin.user_index.search_input_placeholder": "Who are you looking for?", - "admin.users.actions.deactivate_user": "Deactivate @{name}", - "admin.users.actions.delete_user": "Delete @{name}", - "admin.users.actions.demote_to_moderator_message": "@{acct} was demoted to a moderator", - "admin.users.actions.demote_to_user_message": "@{acct} was demoted to a regular user", - "admin.users.actions.promote_to_admin_message": "@{acct} was promoted to an admin", - "admin.users.actions.promote_to_moderator_message": "@{acct} was promoted to a moderator", - "admin.users.badges_saved_message": "Custom badges updated.", - "admin.users.remove_donor_message": "@{acct} was removed as a donor", - "admin.users.set_donor_message": "@{acct} was set as a donor", - "admin.users.user_deactivated_message": "@{acct} was deactivated", - "admin.users.user_deleted_message": "@{acct} was deleted", - "admin.users.user_suggested_message": "@{acct} was suggested", - "admin.users.user_unsuggested_message": "@{acct} was unsuggested", - "admin.users.user_unverified_message": "@{acct} was unverified", - "admin.users.user_verified_message": "@{acct} was verified", + "admin.dashcounters.mau_label": "pengguna aktif bulanan", + "admin.dashcounters.retention_label": "retensi pengguna", + "admin.dashcounters.status_count_label": "postsingan", + "admin.dashcounters.user_count_label": "Keseluruhan pengguna", + "admin.dashwidgets.email_list_header": "Daftar email", + "admin.dashwidgets.software_header": "Perangkat lunak", + "admin.edit_announcement.created": "Pengumuman dibuat", + "admin.edit_announcement.deleted": "Pengumuman dihapus", + "admin.edit_announcement.fields.all_day_hint": "Jika dicentang, hanya tanggal dalam rentang waktu yang akan ditampilkan", + "admin.edit_announcement.fields.all_day_label": "Acara sepanjang hari", + "admin.edit_announcement.fields.content_label": "Konten", + "admin.edit_announcement.fields.content_placeholder": "Konten pengumuman", + "admin.edit_announcement.fields.end_time_label": "Tanggal berakhir", + "admin.edit_announcement.fields.end_time_placeholder": "Pengumuman berakhir pada:", + "admin.edit_announcement.fields.start_time_label": "Tanggal mulai", + "admin.edit_announcement.fields.start_time_placeholder": "Pengumuman dimulai pada:", + "admin.edit_announcement.save": "Simpan", + "admin.edit_announcement.updated": "Pengumuman diedit", + "admin.latest_accounts_panel.more": "Klik untuk melihat {count} {count, plural, one {account} lainya {accounts}}", + "admin.latest_accounts_panel.title": "Akun Terbaru", + "admin.moderation_log.empty_message": "Anda belum melakukan tindakan moderasi apa pun. Ketika Anda melakukannya, riwayat akan ditampilkan di sini.", + "admin.reports.actions.close": "Keluar", + "admin.reports.actions.view_status": "Lihat postingan", + "admin.reports.empty_message": "Tidak ada laporan terbuka. Jika pengguna dilaporkan, mereka akan muncul di sini.", + "admin.reports.report_closed_message": "Laporan pada @{name} telah ditutup", + "admin.reports.report_title": "Melaporkan {acct}", + "admin.software.backend": "Backend", + "admin.software.frontend": "Frontend", + "admin.statuses.actions.delete_status": "Hapus postingan", + "admin.statuses.actions.mark_status_not_sensitive": "Tandai postingan tidak sensitif", + "admin.statuses.actions.mark_status_sensitive": "Tandai postingan sensitif", + "admin.statuses.status_deleted_message": "Postingan oleh @{acct} telah dihapus", + "admin.statuses.status_marked_message_not_sensitive": "Postingan oleh @{acct} ditandai tidak sensitif", + "admin.statuses.status_marked_message_sensitive": "Postingan oleh @{acct} ditandai sensitif", + "admin.theme.title": "Tema", + "admin.user_index.empty": "Tidak ada pengguna yang ditemukan.", + "admin.user_index.search_input_placeholder": "Siapa yang kamu cari?", + "admin.users.actions.deactivate_user": "Nonaktifkan @{name}", + "admin.users.actions.delete_user": "Hapus @{name}", + "admin.users.actions.demote_to_moderator_message": "@{acct} diturunkan menjadi moderator", + "admin.users.actions.demote_to_user_message": "@{acct} diturunkan menjadi pengguna biasa", + "admin.users.actions.promote_to_admin_message": "@{acct} dipromosikan menjadi admin", + "admin.users.actions.promote_to_moderator_message": "@{acct} dipromosikan menjadi moderator", + "admin.users.badges_saved_message": "Custom badges diperbarui.", + "admin.users.remove_donor_message": "@{acct} telah dihapus sebagai donor", + "admin.users.set_donor_message": "@{acct} ditetapkan sebagai donor", + "admin.users.user_deactivated_message": "@{acct} telah dinonaktifkan", + "admin.users.user_deleted_message": "@{acct} telah dihapus", + "admin.users.user_suggested_message": "@{acct} disarankan", + "admin.users.user_unsuggested_message": "@{acct} tidak disarankan", + "admin.users.user_unverified_message": "@{acct} tidak terverifikasi", + "admin.users.user_verified_message": "@{acct} telah diverifikasi", "admin_nav.awaiting_approval": "Awaiting Approval", "admin_nav.dashboard": "Dashboard", "admin_nav.reports": "Reports", - "alert.unexpected.body": "We're sorry for the interruption. If the problem persists, please reach out to our support team. You may also try to {clearCookies} (this will log you out).", + "alert.unexpected.body": "Kami mohon maaf atas gangguan ini. Jika masalah terus berlanjut, harap hubungi tim dukungan kami. Anda juga dapat mencoba {clearCookies} (ini akan mengeluarkan Anda).", "alert.unexpected.browser": "Browser", "alert.unexpected.clear_cookies": "clear cookies and browser data", "alert.unexpected.links.help": "Help Center", @@ -139,6 +164,8 @@ "alert.unexpected.links.support": "Support", "alert.unexpected.message": "Terjadi kesalahan yang tidak terduga.", "alert.unexpected.return_home": "Return Home", + "alert.unexpected.submit_feedback": "Berikan umpan balik", + "alert.unexpected.thanks": "Terima kasih atas tanggapan Anda!", "aliases.account.add": "Create alias", "aliases.account_label": "Old account:", "aliases.aliases_list_delete": "Unlink alias", @@ -158,8 +185,10 @@ "app_create.scopes_placeholder": "e.g. 'read write follow'", "app_create.submit": "Create app", "app_create.website_label": "Website", + "auth.awaiting_approval": "Akun Anda sedang menunggu persetujuan", "auth.invalid_credentials": "Wrong username or password", "auth.logged_out": "Logged out.", + "authorize.success": "Disetujui", "backups.actions.create": "Create backup", "backups.empty_message": "No backups found. {action}", "backups.empty_message.action": "Create one now?", @@ -169,14 +198,99 @@ "birthdays_modal.empty": "None of your friends have birthday today.", "boost_modal.combo": "Anda dapat menekan {combo} untuk melewati ini", "boost_modal.title": "Repost?", + "bundle_column_error.body": "Terjadi masalah saat memuat halaman ini.", + "bundle_column_error.retry": "Coba lagi", + "bundle_column_error.title": "Kesalahan jaringan", "card.back.label": "Back", - "chats.actions.delete": "Delete message", + "chat.actions.send": "Kirim", + "chat.failed_to_send": "Pesan gagal terkirim.", + "chat.input.placeholder": "Ketik pesan", + "chat.new_message.title": "Pesan baru", + "chat.page_settings.accepting_messages.label": "Izinkan pengguna memulai obrolan baru dengan Anda", + "chat.page_settings.play_sounds.label": "Putar suara saat Anda menerima pesan", + "chat.page_settings.preferences": "Preferensi", + "chat.page_settings.privacy": "Privasi", + "chat.page_settings.submit": "Simpan", + "chat.page_settings.title": "Pengaturan Pesan", + "chat.retry": "Mencoba Kembali?", + "chat.welcome.accepting_messages.label": "Izinkan pengguna memulai obrolan baru dengan Anda", + "chat.welcome.notice": "Anda dapat mengubah pengaturan ini nanti.", + "chat.welcome.submit": "Simpan & Lanjutkan", + "chat.welcome.subtitle": "Bertukar pesan langsung dengan pengguna lain.", + "chat.welcome.title": "Selamat datang di {br} Obrolan!", + "chat_composer.unblock": "Buka blokir", + "chat_list_item.blocked_you": "Pengguna ini telah memblokir Anda", + "chat_list_item.blocking": "Anda telah memblokir pengguna ini", + "chat_message_list.blocked": "Anda memblokir pengguna ini", + "chat_message_list.blockedBy": "Anda diblokir oleh", + "chat_message_list.network_failure.action": "Coba lagi", + "chat_message_list.network_failure.subtitle": "Kami mengalami kegagalan jaringan.", + "chat_message_list.network_failure.title": "Ups!", + "chat_message_list_intro.actions.accept": "Menerima", + "chat_message_list_intro.actions.leave_chat": "Tinggalkan obrolan", + "chat_message_list_intro.actions.message_lifespan": "Pesan yang lebih lama dari {hari, jamak, satu {# hari} lainnya {# hari}} akan dihapus.", + "chat_message_list_intro.actions.report": "Laporan", + "chat_message_list_intro.intro": "ingin memulai obrolan dengan Anda", + "chat_message_list_intro.leave_chat.confirm": "Tinggalkan Obrolan", + "chat_message_list_intro.leave_chat.heading": "Tinggalkan Obrolan", + "chat_message_list_intro.leave_chat.message": "Apakah Anda yakin ingin keluar dari obrolan ini? Pesan akan dihapus untuk Anda dan obrolan ini akan dihapus dari kotak masuk Anda.", + "chat_pane.blankslate.action": "Kirim pesan kepada seseorang", + "chat_pane.blankslate.body": "Cari seseorang untuk diajak ngobrol.", + "chat_pane.blankslate.title": "Belum ada pesan", + "chat_search.blankslate.body": "Cari seseorang untuk diajak ngobrol.", + "chat_search.blankslate.title": "Mulai obrolan", + "chat_search.empty_results_blankslate.body": "Coba cari nama lain.", + "chat_search.empty_results_blankslate.title": "Tidak ada kecocokan yang ditemukan", + "chat_search.placeholder": "Ketikkan nama", + "chat_search.title": "Pesan", + "chat_settings.auto_delete.14days": "14 hari", + "chat_settings.auto_delete.2minutes": "2 menit", + "chat_settings.auto_delete.30days": "30 hari", + "chat_settings.auto_delete.7days": "7 hari", + "chat_settings.auto_delete.90days": "90 hari", + "chat_settings.auto_delete.days": "{hari, jamak, satu {# hari} other {# hari}}", + "chat_settings.auto_delete.hint": "Pesan terkirim akan terhapus secara otomatis setelah jangka waktu yang dipilih", + "chat_settings.auto_delete.label": "Hapus pesan secara otomatis", + "chat_settings.block.confirm": "Blokir", + "chat_settings.block.heading": "Blokir @{akun}", + "chat_settings.block.message": "Pemblokiran akan mencegah profil ini mengirim pesan langsung kepada Anda dan melihat konten Anda. Anda dapat membatalkan pemblokiran nanti.", + "chat_settings.leave.confirm": "Tinggalkan Obrolan", + "chat_settings.leave.heading": "Tinggalkan Obrolan", + "chat_settings.leave.message": "Apakah Anda yakin ingin keluar dari obrolan ini? Pesan akan dihapus untuk Anda dan obrolan ini akan dihapus dari kotak masuk Anda.", + "chat_settings.options.block_user": "Blokir @{akun}", + "chat_settings.options.leave_chat": "Tinggalkan Obrolan", + "chat_settings.options.report_user": "Laporkan @{acct}", + "chat_settings.options.unblock_user": "Buka Blokir @{acct}", + "chat_settings.title": "Detail Obrolan", + "chat_settings.unblock.confirm": "Buka Blokir", + "chat_settings.unblock.heading": "Buka Blokir @{acct}", + "chat_settings.unblock.message": "Membuka blokir akan memungkinkan profil ini mengirim pesan langsung kepada Anda dan melihat konten Anda.", + "chat_window.auto_delete_label": "Hapus otomatis setelah {hari, jamak, satu {# hari} lainnya {# hari}}", + "chat_window.auto_delete_tooltip": "Pesan obrolan disetel untuk dihapus secara otomatis setelah {hari, jamak, satu {# hari} lainnya {# hari}} setelah dikirim.", + "chats.actions.copy": "Salin", + "chats.actions.delete": "Hapus untuk keduanya", + "chats.actions.deleteForMe": "Hapus untuk saya", "chats.actions.more": "More", - "chats.actions.report": "Report user", + "chats.actions.report": "Laporkan pengguna", "chats.dividers.today": "Today", + "chats.main.blankslate.new_chat": "Kirim pesan kepada seseorang", + "chats.main.blankslate.subtitle": "Cari seseorang untuk diajak ngobrol", + "chats.main.blankslate.title": "Belum ada pesan", + "chats.main.blankslate_with_chats.subtitle": "Pilih dari salah satu obrolan terbuka Anda atau buat pesan baru.", + "chats.main.blankslate_with_chats.title": "Pilih obrolan", "chats.search_placeholder": "Start a chat with…", + "colum.filters.expiration.1800": "30 menit", + "colum.filters.expiration.21600": "6 jam", + "colum.filters.expiration.3600": "1 jam", + "colum.filters.expiration.43200": "12 jam", + "colum.filters.expiration.604800": "1 minggu", + "colum.filters.expiration.86400": "1 hari", + "colum.filters.expiration.never": "Tidak pernah", + "column.admin.announcements": "Pengumuman", "column.admin.awaiting_approval": "Awaiting Approval", + "column.admin.create_announcement": "Buat pengumuman", "column.admin.dashboard": "Dashboard", + "column.admin.edit_announcement": "Sunting pengumuman", "column.admin.moderation_log": "Moderation Log", "column.admin.reports": "Reports", "column.admin.reports.menu.moderation_log": "Moderation Log", @@ -199,14 +313,19 @@ "column.developers.service_worker": "Service Worker", "column.direct": "Pesan langsung", "column.directory": "Browse profiles", + "column.dislikes": "Tidak suka", "column.domain_blocks": "Topik tersembunyi", "column.edit_profile": "Edit profile", + "column.event_map": "Lokasi acara", + "column.event_participants": "Peserta acara", + "column.events": "Acara", "column.export_data": "Export data", "column.familiar_followers": "People you know following {name}", "column.favourited_statuses": "Liked posts", "column.favourites": "Likes", "column.federation_restrictions": "Federation Restrictions", "column.filters": "Muted words", + "column.filters.accounts": "Akun", "column.filters.add_new": "Add New Filter", "column.filters.conversations": "Conversations", "column.filters.create_error": "Error adding filter", @@ -214,19 +333,30 @@ "column.filters.delete_error": "Error deleting filter", "column.filters.drop_header": "Drop instead of hide", "column.filters.drop_hint": "Filtered posts will disappear irreversibly, even if filter is later removed", + "column.filters.edit": "Sunting Filter", "column.filters.expires": "Expire after", + "column.filters.hide_header": "Sembunyikan sepenuhnya", + "column.filters.hide_hint": "Sembunyikan sepenuhnya konten yang difilter, alih-alih menampilkan peringatan", "column.filters.home_timeline": "Home timeline", "column.filters.keyword": "Keyword or phrase", + "column.filters.keywords": "Kata kunci atau frase", "column.filters.notifications": "Notifications", "column.filters.public_timeline": "Public timeline", "column.filters.subheading_add_new": "Add New Filter", + "column.filters.title": "Judul", + "column.filters.whole_word": "Seluruh kata", "column.follow_requests": "Permintaan mengikuti", + "column.followed_tags": "Hashtag yang diikuti", "column.followers": "Followers", "column.following": "Following", + "column.group_blocked_members": "Anggota yang Dibanned", + "column.group_pending_requests": "Permintaan tertunda", + "column.groups": "Grup", "column.home": "Beranda", "column.import_data": "Import data", "column.info": "Server information", "column.lists": "List", + "column.manage_group": "Kelola Grup", "column.mentions": "Mentions", "column.mfa": "Multi-Factor Authentication", "column.mfa_cancel": "Cancel", @@ -239,8 +369,10 @@ "column.pins": "Pinned posts", "column.preferences": "Preferences", "column.public": "Linimasa gabungan", + "column.quotes": "Posting quotes", "column.reactions": "Reactions", "column.reblogs": "Reposts", + "column.registration": "Mendaftar", "column.scheduled_statuses": "Scheduled Posts", "column.search": "Search", "column.settings_store": "Settings store", @@ -253,8 +385,34 @@ "compose.character_counter.title": "Used {chars} out of {maxChars} characters", "compose.edit_success": "Your post was edited", "compose.invalid_schedule": "You must schedule a post at least 5 minutes out.", + "compose.reply_group_indicator.message": "Memposting ke {groupLink}", "compose.submit_success": "Your post was sent", + "compose_event.create": "Membuat", + "compose_event.edit_success": "Acara Anda telah diedit", + "compose_event.fields.approval_required": "Saya ingin menyetujui permintaan partisipasi secara manual", + "compose_event.fields.banner_label": "Spanduk acara", + "compose_event.fields.description_label": "Deskripsi acara", + "compose_event.fields.description_placeholder": "Keterangan", + "compose_event.fields.end_time_label": "Tanggal akhir acara", + "compose_event.fields.end_time_placeholder": "Acara berakhir pada…", + "compose_event.fields.has_end_time": "Acara ini memiliki tanggal berakhir", + "compose_event.fields.location_label": "Lokasi Acara", + "compose_event.fields.name_label": "Nama acara", + "compose_event.fields.name_placeholder": "Nama", + "compose_event.fields.start_time_label": "Tanggal mulai acara", + "compose_event.fields.start_time_placeholder": "Acara dimulai pada…", + "compose_event.participation_requests.authorize": "Mengizinkan", + "compose_event.participation_requests.authorize_success": "Pengguna diterima", + "compose_event.participation_requests.reject": "Menolak", + "compose_event.participation_requests.reject_success": "Pengguna ditolak", + "compose_event.reset_location": "Setel ulang lokasi", + "compose_event.submit_success": "Acara Anda telah dibuat", + "compose_event.tabs.edit": "Sunting detailnya", + "compose_event.tabs.pending": "Kelola permintaan", + "compose_event.update": "Memperbarui", + "compose_event.upload_banner": "Unggah spanduk acara", "compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.", + "compose_form.event_placeholder": "Posting ke acara ini", "compose_form.hashtag_warning": "Toot ini tidak akan ada dalam daftar tagar manapun karena telah di set sebagai tidak terdaftar. Hanya postingan publik yang bisa dicari dengan tagar.", "compose_form.lock_disclaimer": "Akun anda tidak {locked}. Semua orang dapat mengikuti anda untuk melihat postingan khusus untuk pengikut anda.", "compose_form.lock_disclaimer.lock": "terkunci", @@ -271,7 +429,7 @@ "compose_form.poll.remove_option": "Hapus opsi ini", "compose_form.poll.switch_to_multiple": "Change poll to allow multiple choices", "compose_form.poll.switch_to_single": "Change poll to allow for a single choice", - "compose_form.poll_placeholder": "Add a poll topic...", + "compose_form.poll_placeholder": "Tambahkan topik jajak pendapat…", "compose_form.publish": "Publish", "compose_form.publish_loud": "{publish}!", "compose_form.save_changes": "Save changes", @@ -283,10 +441,14 @@ "compose_form.spoiler_placeholder": "Peringatan konten", "compose_form.spoiler_remove": "Remove sensitive", "compose_form.spoiler_title": "Sensitive content", + "compose_group.share_to_followers": "Bagikan dengan pengikut saya", "confirmation_modal.cancel": "Batal", "confirmations.admin.deactivate_user.confirm": "Deactivate @{name}", "confirmations.admin.deactivate_user.heading": "Deactivate @{acct}", "confirmations.admin.deactivate_user.message": "You are about to deactivate @{acct}. Deactivating a user is a reversible action.", + "confirmations.admin.delete_announcement.confirm": "Hapus", + "confirmations.admin.delete_announcement.heading": "Menghapus pengumuman", + "confirmations.admin.delete_announcement.message": "Apakah Anda yakin ingin menghapus pengumuman tersebut?", "confirmations.admin.delete_local_user.checkbox": "I understand that I am about to delete a local user.", "confirmations.admin.delete_status.confirm": "Delete post", "confirmations.admin.delete_status.heading": "Delete post", @@ -307,21 +469,46 @@ "confirmations.block.confirm": "Blokir", "confirmations.block.heading": "Block @{name}", "confirmations.block.message": "Apa anda yakin ingin memblokir {name}?", + "confirmations.block_from_group.confirm": "Blokir", + "confirmations.block_from_group.heading": "Larangan Dari Grup", + "confirmations.block_from_group.message": "Apakah Anda yakin ingin mencekal @{name} dari grup?", + "confirmations.cancel.confirm": "Membuang", + "confirmations.cancel.heading": "Buang postingan", + "confirmations.cancel.message": "Apakah Anda yakin ingin membatalkan pembuatan postingan ini?", "confirmations.cancel_editing.confirm": "Cancel editing", "confirmations.cancel_editing.heading": "Cancel post editing", "confirmations.cancel_editing.message": "Are you sure you want to cancel editing this post? All changes will be lost.", + "confirmations.cancel_event_editing.heading": "Batalkan pengeditan acara", + "confirmations.cancel_event_editing.message": "Apakah Anda yakin ingin membatalkan pengeditan acara ini? Semua perubahan akan hilang.", "confirmations.delete.confirm": "Hapus", "confirmations.delete.heading": "Delete post", "confirmations.delete.message": "Apa anda yakin untuk menghapus status ini?", + "confirmations.delete_event.confirm": "Hapus", + "confirmations.delete_event.heading": "Hapus Acara", + "confirmations.delete_event.message": "Apakah Anda yakin ingin menghapus acara ini?", + "confirmations.delete_from_group.message": "Apakah Anda yakin ingin menghapus postingan @{name}?", + "confirmations.delete_group.confirm": "Hapus", + "confirmations.delete_group.heading": "Hapus Group", + "confirmations.delete_group.message": "Apakah Anda yakin ingin menghapus grup ini? Ini adalah tindakan permanen yang tidak dapat dibatalkan.", "confirmations.delete_list.confirm": "Hapus", "confirmations.delete_list.heading": "Delete list", "confirmations.delete_list.message": "Apakah anda yakin untuk menghapus daftar ini secara permanen?", "confirmations.domain_block.confirm": "Sembunyikan keseluruhan domain", "confirmations.domain_block.heading": "Block {domain}", "confirmations.domain_block.message": "Apakah anda benar benar yakin untuk memblokir keseluruhan {domain}? Dalam kasus tertentu beberapa pemblokiran atau penyembunyian lebih baik.", + "confirmations.kick_from_group.confirm": "Menendang", + "confirmations.kick_from_group.message": "Apakah Anda yakin ingin mengeluarkan @{name} dari grup ini?", + "confirmations.leave_event.confirm": "Tinggalkan acara", + "confirmations.leave_event.message": "Jika Anda ingin bergabung kembali ke acara tersebut, permintaan akan ditinjau kembali secara manual. Apakah Anda yakin ingin melanjutkan?", + "confirmations.leave_group.confirm": "Tinggalkan", + "confirmations.leave_group.heading": "Tinggalkan grup", + "confirmations.leave_group.message": "Anda akan keluar dari grup. Apakah Anda ingin melanjutkan?", "confirmations.mute.confirm": "Bisukan", "confirmations.mute.heading": "Mute @{name}", "confirmations.mute.message": "Apa anda yakin ingin membisukan {name}?", + "confirmations.mute_group.confirm": "Bisu", + "confirmations.mute_group.heading": "Bisukan Grup", + "confirmations.mute_group.message": "Anda akan membisukan grup. Apakah Anda ingin melanjutkan?", "confirmations.redraft.confirm": "Hapus dan konsep ulang", "confirmations.redraft.heading": "Delete & redraft", "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.", @@ -340,6 +527,7 @@ "confirmations.scheduled_status_delete.heading": "Cancel scheduled post", "confirmations.scheduled_status_delete.message": "Are you sure you want to cancel this scheduled post?", "confirmations.unfollow.confirm": "Berhenti mengikuti", + "copy.success": "Disalin ke papan klip!", "crypto_donate.explanation_box.message": "{siteTitle} accepts cryptocurrency donations. You may send a donation to any of the addresses below. Thank you for your support!", "crypto_donate.explanation_box.title": "Sending cryptocurrency donations", "crypto_donate_panel.actions.view": "Click to see {count} {count, plural, one {wallet} other {wallets}}", @@ -366,6 +554,7 @@ "developers.navigation.network_error_label": "Network error", "developers.navigation.service_worker_label": "Service Worker", "developers.navigation.settings_store_label": "Settings store", + "developers.navigation.show_toast": "Pemicu Toast", "developers.navigation.test_timeline_label": "Test timeline", "developers.settings_store.advanced": "Advanced settings", "developers.settings_store.hint": "It is possible to directly edit your user settings here. BE CAREFUL! Editing this section can break your account, and you will only be able to recover through the API.", @@ -417,6 +606,7 @@ "email_confirmation.success": "Your email has been confirmed!", "embed.instructions": "Sematkan status ini di website anda dengan menyalin kode di bawah ini.", "emoji_button.activity": "Aktivitas", + "emoji_button.add_custom": "Tambahkan custom emoji", "emoji_button.custom": "Kustom", "emoji_button.flags": "Bendera", "emoji_button.food": "Makanan & Minuman", @@ -424,28 +614,45 @@ "emoji_button.nature": "Alam", "emoji_button.not_found": "Katakan tidak pada emoji!! (╯°□°)╯︵ ┻━┻", "emoji_button.objects": "Benda-benda", + "emoji_button.oh_no": "Oh tidak!", "emoji_button.people": "Orang", + "emoji_button.pick": "Pilih emoji…", "emoji_button.recent": "Yang sering digunakan", "emoji_button.search": "Cari...", "emoji_button.search_results": "Hasil pencarian", + "emoji_button.skins_1": "Bawaan", + "emoji_button.skins_2": "Cahaya", + "emoji_button.skins_3": "Sedang-Ringan", + "emoji_button.skins_4": "Sedang", + "emoji_button.skins_5": "Sedang-Gelap", + "emoji_button.skins_6": "Gelap", + "emoji_button.skins_choose": "Memilih tampilan warna bawaan", "emoji_button.symbols": "Simbol", "emoji_button.travel": "Tempat Wisata", "empty_column.account_blocked": "You are blocked by @{accountUsername}.", "empty_column.account_favourited_statuses": "This user doesn't have any liked posts yet.", "empty_column.account_timeline": "Tidak ada toot di sini!", "empty_column.account_unavailable": "Profil tidak tersedia", + "empty_column.admin.announcements": "Belum ada pengumuman.", "empty_column.aliases": "You haven't created any account alias yet.", "empty_column.aliases.suggestions": "There are no account suggestions available for the provided term.", "empty_column.blocks": "Anda belum memblokir siapapun.", "empty_column.bookmarks": "You don't have any bookmarks yet. When you add one, it will show up here.", "empty_column.community": "Linimasa lokal masih kosong. Tulis sesuatu secara publik dan buat roda berputar!", "empty_column.direct": "Anda belum memiliki pesan langsung. Ketika Anda mengirim atau menerimanya, maka akan muncul di sini.", + "empty_column.dislikes": "Belum ada yang menyukai postingan ini. Ketika seseorang melakukannya, mereka akan muncul di sini.", "empty_column.domain_blocks": "Tidak ada topik tersembunyi.", + "empty_column.event_participant_requests": "Tidak ada permintaan partisipasi acara yang tertunda.", + "empty_column.event_participants": "Belum ada yang bergabung dalam acara ini. Ketika seseorang melakukannya, mereka akan muncul di sini.", "empty_column.favourited_statuses": "Anda belum memiliki toot favorit. Ketika Anda mengirim atau menerimanya, maka akan muncul di sini.", "empty_column.favourites": "Tidak ada seorangpun yang memfavoritkan toot ini. Ketika seseorang melakukannya, maka akan muncul disini.", "empty_column.filters": "You haven't created any muted words yet.", "empty_column.follow_recommendations": "Looks like no suggestions could be generated for you. You can try using search to look for people you might know or explore trending hashtags.", "empty_column.follow_requests": "Anda belum memiliki permintaan mengikuti. Ketika Anda menerimanya, maka akan muncul disini.", + "empty_column.followed_tags": "Anda belum mengikuti hashtag apa pun.", + "empty_column.group": "Belum ada postingan di grup ini.", + "empty_column.group_blocks": "Grup ini belum melarang pengguna mana pun.", + "empty_column.group_membership_requests": "Tidak ada permintaan keanggotaan yang tertunda untuk grup ini.", "empty_column.hashtag": "Tidak ada apapun dalam hashtag ini.", "empty_column.home": "Linimasa anda kosong! Kunjungi {public} atau gunakan pencarian untuk memulai dan bertemu pengguna lain.", "empty_column.home.local_tab": "the {site_title} tab", @@ -457,12 +664,39 @@ "empty_column.notifications": "Anda tidak memiliki notifikasi apapun. Berinteraksi dengan orang lain untuk memulai percakapan.", "empty_column.notifications_filtered": "You don't have any notifications of this type yet.", "empty_column.public": "Tidak ada apapun disini! Tulis sesuatu, atau ikuti pengguna lain dari server lain untuk mengisi ini", + "empty_column.quotes": "Postingan ini belum dikutip.", "empty_column.remote": "There is nothing here! Manually follow users from {instance} to fill it up.", "empty_column.scheduled_statuses": "You don't have any scheduled statuses yet. When you add one, it will show up here.", "empty_column.search.accounts": "There are no people results for \"{term}\"", "empty_column.search.hashtags": "There are no hashtags results for \"{term}\"", "empty_column.search.statuses": "There are no posts results for \"{term}\"", "empty_column.test": "The test timeline is empty.", + "event.banner": "Spanduk acara", + "event.copy": "Salin tautan ke acara", + "event.date": "Tanggal", + "event.description": "Keterangan", + "event.discussion.empty": "Belum ada yang mengomentari acara ini. Ketika seseorang melakukannya, mereka akan muncul di sini.", + "event.export_ics": "Ekspor ke kalender Anda", + "event.external": "Lihat acara di {domain}", + "event.join_state.accept": "Pergi", + "event.join_state.empty": "Ikut", + "event.join_state.pending": "Tertunda", + "event.join_state.rejected": "Pergi", + "event.location": "Lokasi", + "event.manage": "Mengelola", + "event.organized_by": "Diselenggarakan oleh {name}", + "event.participants": "{count} {rawCount, jamak, satu {orang} lainnya {orang}} hadir", + "event.quote": "Quote acara", + "event.reblog": "Posting ulang acara", + "event.show_on_map": "Tampilkan di peta", + "event.unreblog": "Batalkan pengeposan ulang acara", + "event.website": "Tautan eksternal", + "event_map.navigate": "Navigasi", + "events.create_event": "Membuat acara", + "events.joined_events": "Acara yang bergabung", + "events.joined_events.empty": "Anda belum bergabung dengan acara apa pun.", + "events.recent_events": "Acara terkini", + "events.recent_events.empty": "Belum ada acara publik.", "export_data.actions.export": "Export", "export_data.actions.export_blocks": "Export blocks", "export_data.actions.export_follows": "Export follows", @@ -493,9 +727,14 @@ "filters.added": "Filter added.", "filters.context_header": "Filter contexts", "filters.context_hint": "One or multiple contexts where the filter should apply", + "filters.create_filter": "Buat filter", "filters.filters_list_context_label": "Filter contexts:", "filters.filters_list_drop": "Drop", + "filters.filters_list_expired": "Kedaluwarsa", "filters.filters_list_hide": "Hide", + "filters.filters_list_hide_completely": "Sembunyikan konten", + "filters.filters_list_phrases_label": "Kata kunci atau frase:", + "filters.filters_list_warn": "Tampilkan peringatan", "filters.removed": "Filter deleted.", "followRecommendations.heading": "Suggested Profiles", "follow_request.authorize": "Izinkan", @@ -504,7 +743,109 @@ "gdpr.learn_more": "Learn more", "gdpr.message": "{siteTitle} uses session cookies, which are essential to the website's functioning.", "gdpr.title": "{siteTitle} uses cookies", + "generic.saved": "Disimpan", "getting_started.open_source_notice": "{code_name} adalah perangkat lunak yang bersifat terbuka. Anda dapat berkontribusi atau melaporkan permasalahan/bug di Gitlab {code_link} (v{code_version}).", + "group.banned.message": "Anda dilarang dari {group}", + "group.cancel_request": "Batalkan permintaan", + "group.delete.success": "Grup berhasil dihapus", + "group.deleted.message": "Grup ini telah dihapus.", + "group.demote.user.success": "@{name} sekarang menjadi anggota", + "group.group_mod_authorize.fail": "Gagal menyetujui @{name}", + "group.group_mod_block": "Larangan dari grup", + "group.group_mod_block.success": "@{name} dilarang", + "group.group_mod_demote": "Hapus peran {role}", + "group.group_mod_kick": "Keluarkan @{name} dari grup", + "group.group_mod_kick.success": "Keluarkan @{name} dari grup", + "group.group_mod_promote_mod": "Tetapkan peran {role}", + "group.group_mod_reject.fail": "Gagal menolak @{name}", + "group.group_mod_unblock": "Batalkan pelarangan", + "group.group_mod_unblock.success": "Membatalkan pemblokiran @{name} dari grup", + "group.header.alt": "Header grup", + "group.join.private": "Minta Akses", + "group.join.public": "Bergabung ke grup", + "group.join.request_success": "Permintaan dikirim ke pemilik grup", + "group.join.success": "Grup berhasil bergabung!", + "group.leave": "Meninggalkan grup", + "group.leave.label": "Meninggalkan", + "group.leave.success": "Keluar dari grup", + "group.manage": "Kelola Grup", + "group.member.admin.limit.summary": "Anda dapat menugaskan hingga {count, plural, one {admin} other {admins}} untuk grup saat ini.", + "group.member.admin.limit.title": "Batas admin tercapai", + "group.mute.label": "Bisu", + "group.mute.long_label": "Bisukan Grup", + "group.mute.success": "Membungkam grup", + "group.popover.action": "Lihat Grup", + "group.popover.summary": "Anda harus menjadi anggota grup untuk membalas status ini.", + "group.popover.title": "Keanggotaan diperlukan", + "group.privacy.locked": "Pribadi", + "group.privacy.locked.full": "Grup Tertutup", + "group.privacy.locked.info": "Dapat ditemukan. Pengguna dapat bergabung setelah permintaan mereka disetujui.", + "group.privacy.public": "Publik", + "group.privacy.public.full": "Grup Publik", + "group.privacy.public.info": "Dapat ditemukan. Siapapun bisa bergabung.", + "group.private.message": "Konten hanya dapat dilihat oleh anggota grup", + "group.promote.admin.confirmation.message": "Apakah Anda yakin ingin menetapkan peran admin ke @{name}?", + "group.promote.admin.confirmation.title": "Tetapkan Peran Admin", + "group.promote.admin.success": "@{name} sekarang menjadi admin", + "group.report.label": "Laporkan", + "group.role.admin": "Admin", + "group.role.owner": "Pemilik", + "group.share.label": "Bagikan", + "group.tabs.all": "Semua", + "group.tabs.media": "Media", + "group.tabs.members": "Anggota", + "group.tabs.tags": "Topik", + "group.tags.empty": "Belum ada topik di grup ini.", + "group.tags.hidden.success": "Topik ditandai sebagai tersembunyi", + "group.tags.hide": "Sembunyikan topik", + "group.tags.hint": "Tambahkan maksimal 3 kata kunci yang akan dijadikan topik inti diskusi di grup.", + "group.tags.label": "Tagar", + "group.tags.pin": "Sematkan topik", + "group.tags.pin.success": "Disematkan!", + "group.tags.show": "Tampilkan topik", + "group.tags.total": "Keseluruhan Postingan", + "group.tags.unpin": "Lepas sematan topik", + "group.tags.unpin.success": "Sematan dilepaskan!", + "group.tags.visible.success": "Topik ditandai sebagai terlihat", + "group.unmute.label": "Batal membisukan.", + "group.unmute.long_label": "Suarakan Grup", + "group.unmute.success": "Membunyikan grup", + "group.update.success": "Grup berhasil disimpan", + "group.upload_avatar": "Unggah Avatar", + "group.upload_banner": "Mengunggah foto", + "group.upload_banner.title": "Unggah gambar latar belakang", + "groups.discover.popular.empty": "Tidak dapat mengambil grup populer saat ini. Silakan periksa kembali nanti.", + "groups.discover.popular.show_more": "Tampilkan lebih banyak", + "groups.discover.popular.title": "Grup Populer", + "groups.discover.search.error.subtitle": "Silakan coba lagi nanti.", + "groups.discover.search.error.title": "Terjadi kesalahan", + "groups.discover.search.no_results.subtitle": "Coba cari grup lain.", + "groups.discover.search.no_results.title": "Tidak ada kecocokan yang ditemukan", + "groups.discover.search.placeholder": "Pencarian", + "groups.discover.search.recent_searches.blankslate.subtitle": "Cari nama grup, topik atau kata kunci", + "groups.discover.search.recent_searches.blankslate.title": "Tidak ada pencarian terbaru", + "groups.discover.search.recent_searches.clear_all": "Bersihkan semua", + "groups.discover.search.recent_searches.title": "Pencarian terkini", + "groups.discover.search.results.groups": "Grup", + "groups.discover.search.results.member_count": "{anggota, jamak, satu {anggota} other {anggota}}", + "groups.discover.suggested.empty": "Saat ini tidak dapat mengambil grup yang disarankan. Silakan periksa kembali nanti.", + "groups.discover.suggested.show_more": "Tampilkan lebih banyak", + "groups.discover.suggested.title": "Saran Untuk Anda", + "groups.discover.tags.empty": "Tidak dapat mengambil topik populer saat ini. Silakan periksa kembali nanti.", + "groups.discover.tags.show_more": "Tampilkan Lebih Banyak", + "groups.discover.tags.title": "Telusuri Topik", + "groups.discovery.tags.no_of_groups": "Jumlah grup", + "groups.empty.subtitle": "Mulailah menemukan grup untuk bergabung atau membuat grup Anda sendiri.", + "groups.empty.title": "Belum ada Grup", + "groups.pending.count": "{number, plural, one {# permintaan tertunda} other {# permintaan tertunda}}", + "groups.pending.empty.subtitle": "Anda tidak memiliki permintaan yang tertunda saat ini.", + "groups.pending.empty.title": "Tidak ada permintaan yang tertunda", + "groups.pending.label": "Permintaan Tertunda", + "groups.popular.label": "Grup yang Disarankan", + "groups.search.placeholder": "Cari Grup Saya", + "groups.suggested.label": "Grup yang Disarankan", + "groups.tags.title": "Telusuri Topik", + "hashtag.follow": "Ikuti tagar", "header.login.label": "Log in", "header.register.label": "Register", "home.column_settings.show_reblogs": "Tampilkan repost", @@ -530,6 +871,12 @@ "intervals.full.days": "{number, plural, other {# hari}}", "intervals.full.hours": "{number, plural, other {# jam}}", "intervals.full.minutes": "{number, plural, other {# menit}}", + "join_event.hint": "Anda dapat memberi tahu penyelenggara mengapa Anda ingin berpartisipasi dalam acara ini:", + "join_event.join": "Minta bergabung", + "join_event.placeholder": "Pesan untuk penyelenggara", + "join_event.request_success": "Diminta untuk bergabung dalam acara tersebut", + "join_event.success": "Bergabung dengan acara tersebut", + "join_event.title": "Bergabunglah dengan acara", "keyboard_shortcuts.back": "untuk kembali", "keyboard_shortcuts.blocked": "buka daftar pengguna terblokir", "keyboard_shortcuts.boost": "untuk menyebarkan", @@ -561,6 +908,8 @@ "landing_page_modal.download": "Download", "landing_page_modal.helpCenter": "Help Center", "lightbox.close": "Tutup", + "lightbox.expand": "Memperluas", + "lightbox.minimize": "Memperkecil", "lightbox.next": "Selanjutnya", "lightbox.previous": "Sebelumnya", "lightbox.view_context": "Lihat konteks", @@ -578,6 +927,8 @@ "lists.search": "Cari di antara orang yang Anda ikuti", "lists.subheading": "Daftar Anda", "loading_indicator.label": "Tunggu sebentar...", + "location_search.placeholder": "Temukan alamat", + "login.fields.email_label": "Alamat email", "login.fields.instance_label": "Instance", "login.fields.instance_placeholder": "example.com", "login.fields.otp_code_hint": "Enter the two-factor code generated by your phone app or use one of your recovery codes", @@ -592,6 +943,35 @@ "login_external.errors.instance_fail": "The instance returned an error.", "login_external.errors.network_fail": "Connection failed. Is a browser extension blocking it?", "login_form.header": "Sign In", + "manage_group.blocked_members": "Larang Anggota", + "manage_group.confirmation.copy": "Salin tautan", + "manage_group.confirmation.info_1": "Salin tautan Sebagai pemilik grup ini, Anda dapat menugaskan staf, menghapus postingan, dan banyak lagi.", + "manage_group.confirmation.info_2": "Posting postingan pertama grup dan mulailah percakapan.", + "manage_group.confirmation.info_3": "Bagikan grup baru Anda dengan teman, keluarga, dan pengikut untuk mengembangkan keanggotaannya.", + "manage_group.confirmation.share": "Bagikan grup ini", + "manage_group.confirmation.title": "Anda sudah siap!", + "manage_group.create": "Membuat grup", + "manage_group.delete_group": "Hapus Grup", + "manage_group.done": "Selesai", + "manage_group.edit_group": "Sunting Grup", + "manage_group.fields.cannot_change_hint": "Ini tidak dapat diubah setelah grup dibuat.", + "manage_group.fields.description_label": "Keterangan", + "manage_group.fields.description_placeholder": "Keterangan", + "manage_group.fields.hashtag_placeholder": "Tambahkan topik", + "manage_group.fields.name_help": "Ini tidak dapat diubah setelah grup dibuat.", + "manage_group.fields.name_label": "Nama grup (wajib diisi)", + "manage_group.fields.name_label_optional": "Nama grup", + "manage_group.fields.name_placeholder": "Nama grup", + "manage_group.get_started": "Mari kita mulai!", + "manage_group.next": "Berikutnya", + "manage_group.pending_requests": "permintaan tertunda", + "manage_group.privacy.hint": "Pengaturan ini tidak dapat diubah lagi nanti.", + "manage_group.privacy.label": "Pengaturan Privasi", + "manage_group.privacy.private.hint": "Dapat ditemukan. Pengguna dapat bergabung setelah permintaan mereka disetujui.", + "manage_group.privacy.private.label": "Privasi (perlu persetujuan pemilik)", + "manage_group.privacy.public.hint": "Dapat ditemukan. Siapapun bisa bergabung.", + "manage_group.privacy.public.label": "Publik", + "manage_group.tagline": "Grup menghubungkan Anda dengan orang lain berdasarkan minat yang sama.", "media_panel.empty_message": "No media found.", "media_panel.title": "Media", "mfa.confirm.success_message": "MFA confirmed", @@ -634,12 +1014,15 @@ "mute_modal.auto_expire": "Automatically expire mute?", "mute_modal.duration": "Duration", "mute_modal.hide_notifications": "Sembunyikan notifikasi dari pengguna ini?", + "mutes.empty.groups": "Anda belum membisukan grup mana pun.", "navbar.login.action": "Log in", + "navbar.login.email.placeholder": "Alamat email", "navbar.login.forgot_password": "Forgot password?", "navbar.login.password.label": "Password", "navbar.login.username.placeholder": "Email or username", "navigation.chats": "Chats", "navigation.compose": "Compose", + "navigation.compose_group": "Tulis ke Grup", "navigation.dashboard": "Dashboard", "navigation.developers": "Developers", "navigation.direct_messages": "Messages", @@ -652,12 +1035,21 @@ "navigation_bar.compose": "Tulis toot baru", "navigation_bar.compose_direct": "Direct message", "navigation_bar.compose_edit": "Edit post", + "navigation_bar.compose_event": "Kelola acara", + "navigation_bar.compose_group": "Menulis ke grup", + "navigation_bar.compose_group_reply": "Membalas postingan grup", "navigation_bar.compose_quote": "Quote post", "navigation_bar.compose_reply": "Reply to post", + "navigation_bar.create_event": "Buat acara baru", + "navigation_bar.create_group": "Membuat grup", + "navigation_bar.create_group.private": "Buat Grup Pribadi", + "navigation_bar.create_group.public": "Buat Grup Publik", "navigation_bar.domain_blocks": "Domain tersembunyi", + "navigation_bar.edit_group": "Sunting Grup", "navigation_bar.favourites": "Favorit", "navigation_bar.filters": "Kata yang dibisukan", "navigation_bar.follow_requests": "Permintaan mengikuti", + "navigation_bar.followed_tags": "Tagar yang diikuti", "navigation_bar.import_data": "Import data", "navigation_bar.in_reply_to": "In reply to", "navigation_bar.invites": "Invites", @@ -666,16 +1058,27 @@ "navigation_bar.preferences": "Pengaturan", "navigation_bar.profile_directory": "Profile directory", "navigation_bar.soapbox_config": "Soapbox config", + "new_event_panel.action": "Membuat acara", + "new_event_panel.subtitle": "Tidak dapat menemukan apa yang Anda cari? Jadwalkan acara Anda sendiri.", + "new_event_panel.title": "Buat Acara Baru", + "new_group_panel.action": "Membuat grup", + "new_group_panel.subtitle": "Tidak dapat menemukan apa yang Anda cari? Mulai grup pribadi atau publik Anda sendiri.", + "new_group_panel.title": "Membuat grup", "notification.favourite": "{name} menyukai status anda", "notification.follow": "{name} mengikuti anda", "notification.follow_request": "{name} has requested to follow you", + "notification.group_favourite": "{name} menyukai postingan grup Anda", + "notification.group_reblog": "{nama} memposting ulang postingan grup Anda", "notification.mention": "{name} menyebut Anda", "notification.mentioned": "{name} mentioned you", "notification.move": "{name} moved to {targetName}", "notification.name": "{link}{others}", - "notification.others": " + {count} {count, plural, one {other} other {others}}", + "notification.others": "+ {hitung, jamak, satu {# lainnya} lainnya {# lainnya}}", "notification.pleroma:chat_mention": "{name} sent you a message", "notification.pleroma:emoji_reaction": "{name} reacted to your post", + "notification.pleroma:event_reminder": "Acara yang Anda ikuti akan segera dimulai", + "notification.pleroma:participation_accepted": "Anda diterima untuk mengikuti acara tersebut", + "notification.pleroma:participation_request": "{name} ingin bergabung dengan acara Anda", "notification.poll": "Japat yang Anda ikuti telah berakhir", "notification.reblog": "{name} mem-boost status anda", "notification.status": "{name} just posted", @@ -722,6 +1125,7 @@ "onboarding.suggestions.title": "Suggested accounts", "onboarding.view_feed": "View Feed", "password_reset.confirmation": "Check your email for confirmation.", + "password_reset.fields.email_placeholder": "Alamat email", "password_reset.fields.username_placeholder": "Email or username", "password_reset.header": "Reset Password", "password_reset.reset": "Reset password", @@ -748,6 +1152,8 @@ "preferences.fields.content_type_label": "Default post format", "preferences.fields.delete_modal_label": "Show confirmation dialog before deleting a post", "preferences.fields.demetricator_label": "Use Demetricator", + "preferences.fields.demo_hint": "Gunakan logo dan skema warna bawaan Soapbox. Berguna untuk mengambil tangkapan layar.", + "preferences.fields.demo_label": "Mode demo", "preferences.fields.display_media.default": "Hide media marked as sensitive", "preferences.fields.display_media.hide_all": "Always hide media", "preferences.fields.display_media.show_all": "Always show media", @@ -755,6 +1161,7 @@ "preferences.fields.language_label": "Language", "preferences.fields.media_display_label": "Media display", "preferences.fields.missing_description_modal_label": "Show confirmation dialog before sending a post without media descriptions", + "preferences.fields.preserve_spoilers_label": "Pertahankan peringatan konten saat membalas", "preferences.fields.privacy_label": "Default post privacy", "preferences.fields.reduce_motion_label": "Reduce motion in animations", "preferences.fields.system_font_label": "Use system's default font", @@ -805,6 +1212,7 @@ "registration.sign_up": "Sign up", "registration.tos": "Terms of Service", "registration.username_unavailable": "Username is already taken.", + "reject.success": "Ditolak", "relative_time.days": "{number}d", "relative_time.hours": "{number}h", "relative_time.just_now": "now", @@ -818,7 +1226,11 @@ "remote_instance.pin_host": "Pin {host}", "remote_instance.unpin_host": "Unpin {host}", "remote_interaction.account_placeholder": "Enter your username@domain you want to act from", + "remote_interaction.dislike": "Lanjutkan ke tidak suka", + "remote_interaction.dislike_title": "Tidak menyukai postingan dari jarak jauh", "remote_interaction.divider": "or", + "remote_interaction.event_join": "Lanjutkan untuk bergabung", + "remote_interaction.event_join_title": "Bergabunglah dengan acara dari jarak jauh", "remote_interaction.favourite": "Proceed to like", "remote_interaction.favourite_title": "Like a post remotely", "remote_interaction.follow": "Proceed to follow", @@ -840,11 +1252,16 @@ "reply_mentions.reply_empty": "Replying to post", "report.block": "Block {target}", "report.block_hint": "Do you also want to block this account?", + "report.chatMessage.context": "Saat melaporkan pesan pengguna, lima pesan sebelum dan lima pesan setelah pesan yang dipilih akan diteruskan ke tim moderasi kami untuk mengetahui konteksnya.", + "report.chatMessage.title": "Laporkan pesan", "report.confirmation.content": "If we find that this account is violating the {link} we will take further action on the matter.", + "report.confirmation.entity.account": "akun", + "report.confirmation.entity.group": "grup", "report.confirmation.title": "Thanks for submitting your report.", "report.done": "Done", "report.forward": "Forward to {target}", "report.forward_hint": "The account is from another server. Send a copy of the report there as well?", + "report.group.title": "Laporan Grup", "report.next": "Next", "report.otherActions.addAdditional": "Would you like to add additional statuses to this report?", "report.otherActions.addMore": "Add more", @@ -896,13 +1313,17 @@ "security.update_password.fail": "Update password failed.", "security.update_password.success": "Password successfully updated.", "settings.account_migration": "Move Account", + "settings.blocks": "Blokir", "settings.change_email": "Change Email", "settings.change_password": "Change Password", "settings.configure_mfa": "Configure MFA", "settings.delete_account": "Delete Account", "settings.edit_profile": "Edit Profile", + "settings.messages.label": "Izinkan pengguna memulai obrolan baru dengan Anda", + "settings.mutes": "Bisukan", "settings.other": "Other options", "settings.preferences": "Preferences", + "settings.privacy": "Privasi", "settings.profile": "Profile", "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", @@ -925,6 +1346,7 @@ "soapbox_config.feed_injection_hint": "Inject the feed with additional content, such as suggested profiles.", "soapbox_config.feed_injection_label": "Feed injection", "soapbox_config.fields.crypto_addresses_label": "Cryptocurrency addresses", + "soapbox_config.fields.edit_theme_label": "Edit Tema", "soapbox_config.fields.home_footer_fields_label": "Home footer items", "soapbox_config.fields.logo_label": "Logo", "soapbox_config.fields.promo_panel_fields_label": "Promo panel items", @@ -932,6 +1354,7 @@ "soapbox_config.greentext_label": "Enable greentext support", "soapbox_config.headings.advanced": "Advanced", "soapbox_config.headings.cryptocurrency": "Cryptocurrency", + "soapbox_config.headings.events": "Acara", "soapbox_config.headings.navigation": "Navigation", "soapbox_config.headings.options": "Options", "soapbox_config.headings.theme": "Theme", @@ -942,16 +1365,27 @@ "soapbox_config.hints.promo_panel_icons.link": "Soapbox Icons List", "soapbox_config.home_footer.meta_fields.label_placeholder": "Label", "soapbox_config.home_footer.meta_fields.url_placeholder": "URL", + "soapbox_config.media_preview_hint": "Beberapa backend menyediakan versi media yang dioptimalkan untuk ditampilkan di garis waktu. Namun, gambar pratinjau ini mungkin terlalu kecil tanpa konfigurasi tambahan.", + "soapbox_config.media_preview_label": "Lebih memilih media pratinjau untuk thumbnail", "soapbox_config.promo_panel.meta_fields.icon_placeholder": "Icon", "soapbox_config.promo_panel.meta_fields.label_placeholder": "Label", "soapbox_config.promo_panel.meta_fields.url_placeholder": "URL", - "soapbox_config.raw_json_hint": "Edit the settings data directly. Changes made directly to the JSON file will override the form fields above. Click Save to apply your changes.", + "soapbox_config.raw_json_hint": "Edit data pengaturan secara langsung. Perubahan yang dilakukan langsung pada file JSON akan menggantikan kolom formulir di atas. Klik \"Simpan\" untuk menerapkan perubahan Anda.", + "soapbox_config.raw_json_invalid": "tidak valid", "soapbox_config.raw_json_label": "Advanced: Edit raw JSON data", + "soapbox_config.redirect_root_no_login_hint": "Jalur untuk mengalihkan beranda saat pengguna tidak masuk.", + "soapbox_config.redirect_root_no_login_label": "Arahkan ulang beranda", "soapbox_config.save": "Save", "soapbox_config.saved": "Soapbox config saved!", + "soapbox_config.sentry_dsn_hint": "URL DSN untuk pelaporan kesalahan. Bekerja dengan Sentry dan GlitchTip.", + "soapbox_config.sentry_dsn_label": "Sentry DSN", + "soapbox_config.tile_server_attribution_label": "Atribusi ubin peta", + "soapbox_config.tile_server_label": "Map tile server", "soapbox_config.verified_can_edit_name_label": "Allow verified users to edit their own display name.", "status.admin_account": "Open moderation interface for @{name}", "status.admin_status": "Open this post in the moderation interface", + "status.approval.pending": "Menunggu persetujuan", + "status.approval.rejected": "Ditolak", "status.bookmark": "Bookmark", "status.bookmarked": "Bookmark added.", "status.cancel_reblog_private": "Un-repost", @@ -961,12 +1395,18 @@ "status.delete": "Hapus", "status.detailed_status": "Detailed conversation view", "status.direct": "Direct message @{name}", + "status.disabled_replies.group_membership": "Hanya anggota grup yang dapat membalas", + "status.disfavourite": "Tidak Suka", "status.edit": "Edit", "status.embed": "Embed", "status.external": "View post on {domain}", "status.favourite": "Difavoritkan", "status.filtered": "Filtered", + "status.group": "Diposting di {grup}", + "status.group_mod_delete": "Hapus postingan dari grup", + "status.interactions.dislikes": "{count, plural, one {Tidak suka} other {Tidak suka}}", "status.interactions.favourites": "{count, plural, one {Like} other {Likes}}", + "status.interactions.quotes": "{hitungan, jamak, satu {Kutipan} lainnya {Kutipan}}", "status.interactions.reblogs": "{count, plural, one {Repost} other {Reposts}}", "status.load_more": "Tampilkan semua", "status.mention": "Balasan @{name}", @@ -974,6 +1414,8 @@ "status.mute_conversation": "Mute conversation", "status.open": "Tampilkan status ini", "status.pin": "Pin on profile", + "status.pin_to_group": "Sematkan ke Grup", + "status.pin_to_group.success": "Disematkan ke Grup!", "status.pinned": "Pinned post", "status.quote": "Quote post", "status.reactions.cry": "Sad", @@ -987,6 +1429,7 @@ "status.reblog": "Repost", "status.reblog_private": "Repost to original audience", "status.reblogged_by": "di-repost {name}", + "status.reblogged_by_with_group": "{name} mem-posting ulang dari {group}", "status.reblogs.empty": "No one has reposted this post yet. When someone does, they will show up here.", "status.redraft": "Delete & re-draft", "status.remove_account_from_group": "Remove account from group", @@ -997,6 +1440,7 @@ "status.sensitive_warning": "Konten sensitif", "status.sensitive_warning.subtitle": "This content may not be suitable for all audiences.", "status.share": "Share", + "status.show_filter_reason": "Tetap tunjukkan", "status.show_less_all": "Show less for all", "status.show_more_all": "Show more for all", "status.show_original": "Show original", @@ -1008,6 +1452,7 @@ "status.unbookmarked": "Bookmark removed.", "status.unmute_conversation": "Unmute conversation", "status.unpin": "Unpin from profile", + "status.unpin_to_group": "Lepas sematan dari Grup", "status_list.queue_label": "Click to see {count} new {count, plural, one {post} other {posts}}", "statuses.quote_tombstone": "Post is unavailable.", "statuses.tombstone": "One or more posts are unavailable.", @@ -1025,6 +1470,7 @@ "tabs_bar.all": "All", "tabs_bar.dashboard": "Dashboard", "tabs_bar.fediverse": "Fediverse", + "tabs_bar.groups": "Grup", "tabs_bar.home": "Beranda", "tabs_bar.local": "Local", "tabs_bar.more": "More", @@ -1032,6 +1478,14 @@ "tabs_bar.profile": "Profile", "tabs_bar.search": "Search", "tabs_bar.settings": "Settings", + "textarea.counter.label": "{count} karakter tersisa", + "theme_editor.Reset": "Mengatur ulang", + "theme_editor.export": "Ekspor tema", + "theme_editor.import": "Impor tema", + "theme_editor.import_success": "Tema berhasil diimpor!", + "theme_editor.restore": "Kembalikan tema bawaan", + "theme_editor.save": "Simpan tema", + "theme_editor.saved": "Tema diperbarui!", "theme_toggle.dark": "Dark", "theme_toggle.light": "Light", "theme_toggle.system": "System", From a80fd6327d3a38a5bc23d26df5a3432433bc0a1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sun, 10 Dec 2023 09:38:19 +0000 Subject: [PATCH 079/115] Translated using Weblate (Polish) Currently translated at 99.6% (1520 of 1526 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/pl/ --- src/locales/pl.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/locales/pl.json b/src/locales/pl.json index cd5f42705..9eda9262a 100644 --- a/src/locales/pl.json +++ b/src/locales/pl.json @@ -198,6 +198,9 @@ "birthdays_modal.empty": "Żaden z Twoich znajomych nie ma dziś urodzin.", "boost_modal.combo": "Naciśnij {combo}, aby pominąć to następnym razem", "boost_modal.title": "Repost?", + "bundle_column_error.body": "Coś poszło nie tak podczas ładowania tej strony.", + "bundle_column_error.retry": "Spróbuj ponownie", + "bundle_column_error.title": "Błąd sieci", "card.back.label": "Wstecz", "chat.actions.send": "Wyślij", "chat.failed_to_send": "Nie udało się wysłać wiadomości.", @@ -1369,6 +1372,8 @@ "soapbox_config.redirect_root_no_login_label": "Przekieruj stronę główną", "soapbox_config.save": "Zapisz", "soapbox_config.saved": "Zapisano konfigurację Soapbox!", + "soapbox_config.sentry_dsn_hint": "Adres URL DSN do zgłaszania błędów. Działa z Sentry i GlitchTip.", + "soapbox_config.sentry_dsn_label": "DSN Sentry", "soapbox_config.tile_server_attribution_label": "Atrybucja kafelków map", "soapbox_config.tile_server_label": "Serwer kafelków map", "soapbox_config.verified_can_edit_name_label": "Pozwól zweryfikowanym użytkownikom na zmianę swojej nazwy wyświetlanej.", From 5cdae8672e166478d6cff4acab861e488fe43fa0 Mon Sep 17 00:00:00 2001 From: Poesty Li Date: Sun, 10 Dec 2023 12:32:05 +0000 Subject: [PATCH 080/115] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (1526 of 1526 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/zh_Hans/ --- src/locales/zh-CN.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/locales/zh-CN.json b/src/locales/zh-CN.json index e23e377f5..e2c5d648a 100644 --- a/src/locales/zh-CN.json +++ b/src/locales/zh-CN.json @@ -198,6 +198,9 @@ "birthdays_modal.empty": "今天您的朋友中无人过生日。", "boost_modal.combo": "下次按住 {combo} 即可跳过此提示", "boost_modal.title": "转发?", + "bundle_column_error.body": "载入页面时发生错误。", + "bundle_column_error.retry": "重试", + "bundle_column_error.title": "网络错误", "card.back.label": "返回", "chat.actions.send": "发送", "chat.failed_to_send": "消息发送失败。", From ff209575b4656fc5730bebc336fa04f5aaf6bb5c Mon Sep 17 00:00:00 2001 From: Rizal Sambayu Date: Mon, 11 Dec 2023 18:05:16 +0000 Subject: [PATCH 081/115] Translated using Weblate (Indonesian) Currently translated at 100.0% (1526 of 1526 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/id/ --- src/locales/id.json | 302 ++++++++++++++++++++++---------------------- 1 file changed, 151 insertions(+), 151 deletions(-) diff --git a/src/locales/id.json b/src/locales/id.json index b766bd50f..55b81371e 100644 --- a/src/locales/id.json +++ b/src/locales/id.json @@ -19,7 +19,7 @@ "account.endorse.success": "Anda sekarang menampilkan @{acct} di profil Anda", "account.familiar_followers": "Diikuti oleh {accounts}", "account.familiar_followers.empty": "Tidak ada orang yang Anda kenal yang mengikuti {name}.", - "account.familiar_followers.more": "{count} {count, plural, satu {other} lainnya {others}} mengikuti anda", + "account.familiar_followers.more": "{count, plural, one {# other} lainya {# others}} kamu ikuti", "account.follow": "Ikuti", "account.followers": "Pengikut", "account.followers.empty": "Tidak ada satupun yang mengkuti pengguna ini saat ini.", @@ -27,7 +27,7 @@ "account.follows.empty": "Pengguna ini belum mengikuti siapapun.", "account.follows_you": "Mengikuti anda", "account.header.alt": "Header profil", - "account.hide_reblogs": "Sembunyikan boosts dari @{name}", + "account.hide_reblogs": "Sembunyikan postingan ulang dari @{name}", "account.last_status": "Terakhir aktif", "account.link_verified_on": "Kepemilikan tautan ini telah dicek pada {date}", "account.locked_info": "Status privasi akun ini disetel untuk dikunci. Pemilik secara manual meninjau siapa yang dapat mengikuti mereka.", @@ -49,7 +49,7 @@ "account.report": "Laporkan @{name}", "account.requested": "Menunggu persetujuan. Klik untuk membatalkan permintaan", "account.requested_small": "Menunggu persetujuan", - "account.rss_feed": "Subscribe to RSS feed", + "account.rss_feed": "Berlangganan umpan RSS", "account.search": "Cari dari @{name}", "account.search_self": "Telusuri postingan Anda", "account.share": "Bagikan profil @{name}", @@ -85,12 +85,12 @@ "account_search.placeholder": "Cari akun", "actualStatus.edited": "Diedit {date}", "actualStatuses.quote_tombstone": "Postingan tidak tersedia.", - "admin.announcements.action": "Buat pengumuman", + "admin.announcements.action": "Membuat pengumuman", "admin.announcements.all_day": "Sepanjang hari", "admin.announcements.delete": "Hapus", "admin.announcements.edit": "Edit", - "admin.announcements.ends_at": "Berakhir pada:", - "admin.announcements.starts_at": "Dimulai pada:", + "admin.announcements.ends_at": "Berakhir di:", + "admin.announcements.starts_at": "Dimulai dari:", "admin.awaiting_approval.empty_message": "Tidak ada yang menunggu persetujuan. Saat pengguna baru mendaftar, Anda dapat meninjaunya di sini.", "admin.dashboard.registration_mode.approval_hint": "Pengguna dapat mendaftar, namun akun mereka hanya diaktifkan ketika admin menyetujuinya.", "admin.dashboard.registration_mode.approval_label": "Diperlukan Persetujuan", @@ -109,14 +109,14 @@ "admin.dashwidgets.software_header": "Perangkat lunak", "admin.edit_announcement.created": "Pengumuman dibuat", "admin.edit_announcement.deleted": "Pengumuman dihapus", - "admin.edit_announcement.fields.all_day_hint": "Jika dicentang, hanya tanggal dalam rentang waktu yang akan ditampilkan", + "admin.edit_announcement.fields.all_day_hint": "Apabila dicentang, hanya tanggal dari rentang waktu yang akan ditampilkan", "admin.edit_announcement.fields.all_day_label": "Acara sepanjang hari", "admin.edit_announcement.fields.content_label": "Konten", "admin.edit_announcement.fields.content_placeholder": "Konten pengumuman", - "admin.edit_announcement.fields.end_time_label": "Tanggal berakhir", + "admin.edit_announcement.fields.end_time_label": "Tanggal akhir", "admin.edit_announcement.fields.end_time_placeholder": "Pengumuman berakhir pada:", "admin.edit_announcement.fields.start_time_label": "Tanggal mulai", - "admin.edit_announcement.fields.start_time_placeholder": "Pengumuman dimulai pada:", + "admin.edit_announcement.fields.start_time_placeholder": "Pengumuman dimulai:", "admin.edit_announcement.save": "Simpan", "admin.edit_announcement.updated": "Pengumuman diedit", "admin.latest_accounts_panel.more": "Klik untuk melihat {count} {count, plural, one {account} lainya {accounts}}", @@ -158,25 +158,25 @@ "admin_nav.reports": "Reports", "alert.unexpected.body": "Kami mohon maaf atas gangguan ini. Jika masalah terus berlanjut, harap hubungi tim dukungan kami. Anda juga dapat mencoba {clearCookies} (ini akan mengeluarkan Anda).", "alert.unexpected.browser": "Browser", - "alert.unexpected.clear_cookies": "clear cookies and browser data", - "alert.unexpected.links.help": "Help Center", + "alert.unexpected.clear_cookies": "menghapus cookie dan data browser", + "alert.unexpected.links.help": "Pusat Bantuan", "alert.unexpected.links.status": "Status", "alert.unexpected.links.support": "Support", "alert.unexpected.message": "Terjadi kesalahan yang tidak terduga.", "alert.unexpected.return_home": "Return Home", "alert.unexpected.submit_feedback": "Berikan umpan balik", "alert.unexpected.thanks": "Terima kasih atas tanggapan Anda!", - "aliases.account.add": "Create alias", + "aliases.account.add": "Buat alias", "aliases.account_label": "Old account:", - "aliases.aliases_list_delete": "Unlink alias", - "aliases.search": "Search your old account", - "aliases.success.add": "Account alias created successfully", - "aliases.success.remove": "Account alias removed successfully", - "announcements.title": "Announcements", - "app_create.name_label": "App name", + "aliases.aliases_list_delete": "Batalkan tautan alias", + "aliases.search": "Cari akun lama Anda", + "aliases.success.add": "Alias akun berhasil dibuat", + "aliases.success.remove": "Alias akun berhasil dihapus", + "announcements.title": "Pengumuman", + "app_create.name_label": "Nama aplikasi", "app_create.name_placeholder": "e.g. 'Soapbox'", - "app_create.redirect_uri_label": "Redirect URIs", - "app_create.restart": "Create another", + "app_create.redirect_uri_label": "Mengalihkan URIs", + "app_create.restart": "Buat lainya", "app_create.results.app_label": "App", "app_create.results.explanation_text": "You created a new app and token! Please copy the credentials somewhere; you will not see them again after navigating away from this page.", "app_create.results.explanation_title": "App created successfully", @@ -197,7 +197,7 @@ "birthday_panel.title": "Birthdays", "birthdays_modal.empty": "None of your friends have birthday today.", "boost_modal.combo": "Anda dapat menekan {combo} untuk melewati ini", - "boost_modal.title": "Repost?", + "boost_modal.title": "Posting Ulang?", "bundle_column_error.body": "Terjadi masalah saat memuat halaman ini.", "bundle_column_error.retry": "Coba lagi", "bundle_column_error.title": "Kesalahan jaringan", @@ -205,13 +205,13 @@ "chat.actions.send": "Kirim", "chat.failed_to_send": "Pesan gagal terkirim.", "chat.input.placeholder": "Ketik pesan", - "chat.new_message.title": "Pesan baru", + "chat.new_message.title": "Pesan Baru", "chat.page_settings.accepting_messages.label": "Izinkan pengguna memulai obrolan baru dengan Anda", "chat.page_settings.play_sounds.label": "Putar suara saat Anda menerima pesan", - "chat.page_settings.preferences": "Preferensi", + "chat.page_settings.preferences": "Pengaturan", "chat.page_settings.privacy": "Privasi", "chat.page_settings.submit": "Simpan", - "chat.page_settings.title": "Pengaturan Pesan", + "chat.page_settings.title": "Message Settings", "chat.retry": "Mencoba Kembali?", "chat.welcome.accepting_messages.label": "Izinkan pengguna memulai obrolan baru dengan Anda", "chat.welcome.notice": "Anda dapat mengubah pengaturan ini nanti.", @@ -226,10 +226,10 @@ "chat_message_list.network_failure.action": "Coba lagi", "chat_message_list.network_failure.subtitle": "Kami mengalami kegagalan jaringan.", "chat_message_list.network_failure.title": "Ups!", - "chat_message_list_intro.actions.accept": "Menerima", + "chat_message_list_intro.actions.accept": "Terima", "chat_message_list_intro.actions.leave_chat": "Tinggalkan obrolan", - "chat_message_list_intro.actions.message_lifespan": "Pesan yang lebih lama dari {hari, jamak, satu {# hari} lainnya {# hari}} akan dihapus.", - "chat_message_list_intro.actions.report": "Laporan", + "chat_message_list_intro.actions.message_lifespan": "Pesan yang lebih lama dari {hari, jamak, satu {# day} lainnya {# days}} akan dihapus.", + "chat_message_list_intro.actions.report": "Laporkan", "chat_message_list_intro.intro": "ingin memulai obrolan dengan Anda", "chat_message_list_intro.leave_chat.confirm": "Tinggalkan Obrolan", "chat_message_list_intro.leave_chat.heading": "Tinggalkan Obrolan", @@ -241,23 +241,23 @@ "chat_search.blankslate.title": "Mulai obrolan", "chat_search.empty_results_blankslate.body": "Coba cari nama lain.", "chat_search.empty_results_blankslate.title": "Tidak ada kecocokan yang ditemukan", - "chat_search.placeholder": "Ketikkan nama", + "chat_search.placeholder": "Ketik nama", "chat_search.title": "Pesan", "chat_settings.auto_delete.14days": "14 hari", "chat_settings.auto_delete.2minutes": "2 menit", "chat_settings.auto_delete.30days": "30 hari", "chat_settings.auto_delete.7days": "7 hari", "chat_settings.auto_delete.90days": "90 hari", - "chat_settings.auto_delete.days": "{hari, jamak, satu {# hari} other {# hari}}", + "chat_settings.auto_delete.days": "{day, plural, one {# day} lainya {# days}}", "chat_settings.auto_delete.hint": "Pesan terkirim akan terhapus secara otomatis setelah jangka waktu yang dipilih", "chat_settings.auto_delete.label": "Hapus pesan secara otomatis", "chat_settings.block.confirm": "Blokir", - "chat_settings.block.heading": "Blokir @{akun}", + "chat_settings.block.heading": "Blokir @{acct}", "chat_settings.block.message": "Pemblokiran akan mencegah profil ini mengirim pesan langsung kepada Anda dan melihat konten Anda. Anda dapat membatalkan pemblokiran nanti.", "chat_settings.leave.confirm": "Tinggalkan Obrolan", "chat_settings.leave.heading": "Tinggalkan Obrolan", "chat_settings.leave.message": "Apakah Anda yakin ingin keluar dari obrolan ini? Pesan akan dihapus untuk Anda dan obrolan ini akan dihapus dari kotak masuk Anda.", - "chat_settings.options.block_user": "Blokir @{akun}", + "chat_settings.options.block_user": "Blokir @{acct}", "chat_settings.options.leave_chat": "Tinggalkan Obrolan", "chat_settings.options.report_user": "Laporkan @{acct}", "chat_settings.options.unblock_user": "Buka Blokir @{acct}", @@ -265,13 +265,13 @@ "chat_settings.unblock.confirm": "Buka Blokir", "chat_settings.unblock.heading": "Buka Blokir @{acct}", "chat_settings.unblock.message": "Membuka blokir akan memungkinkan profil ini mengirim pesan langsung kepada Anda dan melihat konten Anda.", - "chat_window.auto_delete_label": "Hapus otomatis setelah {hari, jamak, satu {# hari} lainnya {# hari}}", + "chat_window.auto_delete_label": "Hapus otomatis setelah {day, plural, one {# day} lainya {# days}}", "chat_window.auto_delete_tooltip": "Pesan obrolan disetel untuk dihapus secara otomatis setelah {hari, jamak, satu {# hari} lainnya {# hari}} setelah dikirim.", "chats.actions.copy": "Salin", "chats.actions.delete": "Hapus untuk keduanya", "chats.actions.deleteForMe": "Hapus untuk saya", "chats.actions.more": "More", - "chats.actions.report": "Laporkan pengguna", + "chats.actions.report": "Laporkan", "chats.dividers.today": "Today", "chats.main.blankslate.new_chat": "Kirim pesan kepada seseorang", "chats.main.blankslate.subtitle": "Cari seseorang untuk diajak ngobrol", @@ -288,9 +288,9 @@ "colum.filters.expiration.never": "Tidak pernah", "column.admin.announcements": "Pengumuman", "column.admin.awaiting_approval": "Awaiting Approval", - "column.admin.create_announcement": "Buat pengumuman", + "column.admin.create_announcement": "Membuat pengumuman", "column.admin.dashboard": "Dashboard", - "column.admin.edit_announcement": "Sunting pengumuman", + "column.admin.edit_announcement": "Edit pengumuman", "column.admin.moderation_log": "Moderation Log", "column.admin.reports": "Reports", "column.admin.reports.menu.moderation_log": "Moderation Log", @@ -304,7 +304,7 @@ "column.app_create": "Create app", "column.backups": "Backups", "column.birthdays": "Birthdays", - "column.blocks": "Pengguna diblokir", + "column.blocks": "Blokir", "column.bookmarks": "Bookmarks", "column.chats": "Chats", "column.community": "Linimasa Lokal", @@ -333,30 +333,30 @@ "column.filters.delete_error": "Error deleting filter", "column.filters.drop_header": "Drop instead of hide", "column.filters.drop_hint": "Filtered posts will disappear irreversibly, even if filter is later removed", - "column.filters.edit": "Sunting Filter", + "column.filters.edit": "Edit Filter", "column.filters.expires": "Expire after", "column.filters.hide_header": "Sembunyikan sepenuhnya", - "column.filters.hide_hint": "Sembunyikan sepenuhnya konten yang difilter, alih-alih menampilkan peringatan", + "column.filters.hide_hint": "Menyembunyikan konten yang difilter sepenuhnya, alih-alih menampilkan peringatan", "column.filters.home_timeline": "Home timeline", "column.filters.keyword": "Keyword or phrase", - "column.filters.keywords": "Kata kunci atau frase", + "column.filters.keywords": "Kata kunci atau frasa", "column.filters.notifications": "Notifications", "column.filters.public_timeline": "Public timeline", "column.filters.subheading_add_new": "Add New Filter", "column.filters.title": "Judul", "column.filters.whole_word": "Seluruh kata", "column.follow_requests": "Permintaan mengikuti", - "column.followed_tags": "Hashtag yang diikuti", + "column.followed_tags": "Tagar yang diikuti", "column.followers": "Followers", "column.following": "Following", - "column.group_blocked_members": "Anggota yang Dibanned", - "column.group_pending_requests": "Permintaan tertunda", + "column.group_blocked_members": "Anggota yang diblokir", + "column.group_pending_requests": "Permintaan yang tertunda", "column.groups": "Grup", "column.home": "Beranda", "column.import_data": "Import data", "column.info": "Server information", "column.lists": "List", - "column.manage_group": "Kelola Grup", + "column.manage_group": "Mengelola grup", "column.mentions": "Mentions", "column.mfa": "Multi-Factor Authentication", "column.mfa_cancel": "Cancel", @@ -364,11 +364,11 @@ "column.mfa_disable_button": "Disable", "column.mfa_setup": "Proceed to Setup", "column.migration": "Account migration", - "column.mutes": "Pengguna yang dibisukan", + "column.mutes": "Bisukan", "column.notifications": "Notifikasi", "column.pins": "Pinned posts", "column.preferences": "Preferences", - "column.public": "Linimasa gabungan", + "column.public": "Linimasa Fediverse", "column.quotes": "Posting quotes", "column.reactions": "Reactions", "column.reblogs": "Reposts", @@ -382,7 +382,7 @@ "column_forbidden.title": "Forbidden", "common.cancel": "Cancel", "compare_history_modal.header": "Edit history", - "compose.character_counter.title": "Used {chars} out of {maxChars} characters", + "compose.character_counter.title": "Digunakan {chars} dari {maxChars} {maxChars, plural, one {character} lainya{characters}}", "compose.edit_success": "Your post was edited", "compose.invalid_schedule": "You must schedule a post at least 5 minutes out.", "compose.reply_group_indicator.message": "Memposting ke {groupLink}", @@ -403,11 +403,11 @@ "compose_event.fields.start_time_placeholder": "Acara dimulai pada…", "compose_event.participation_requests.authorize": "Mengizinkan", "compose_event.participation_requests.authorize_success": "Pengguna diterima", - "compose_event.participation_requests.reject": "Menolak", + "compose_event.participation_requests.reject": "Tolak", "compose_event.participation_requests.reject_success": "Pengguna ditolak", "compose_event.reset_location": "Setel ulang lokasi", "compose_event.submit_success": "Acara Anda telah dibuat", - "compose_event.tabs.edit": "Sunting detailnya", + "compose_event.tabs.edit": "Edit detailnya", "compose_event.tabs.pending": "Kelola permintaan", "compose_event.update": "Memperbarui", "compose_event.upload_banner": "Unggah spanduk acara", @@ -472,7 +472,7 @@ "confirmations.block_from_group.confirm": "Blokir", "confirmations.block_from_group.heading": "Larangan Dari Grup", "confirmations.block_from_group.message": "Apakah Anda yakin ingin mencekal @{name} dari grup?", - "confirmations.cancel.confirm": "Membuang", + "confirmations.cancel.confirm": "Buang", "confirmations.cancel.heading": "Buang postingan", "confirmations.cancel.message": "Apakah Anda yakin ingin membatalkan pembuatan postingan ini?", "confirmations.cancel_editing.confirm": "Cancel editing", @@ -486,7 +486,7 @@ "confirmations.delete_event.confirm": "Hapus", "confirmations.delete_event.heading": "Hapus Acara", "confirmations.delete_event.message": "Apakah Anda yakin ingin menghapus acara ini?", - "confirmations.delete_from_group.message": "Apakah Anda yakin ingin menghapus postingan @{name}?", + "confirmations.delete_from_group.message": "Apakah Anda yakin ingin menghapus kiriman @{nama}?", "confirmations.delete_group.confirm": "Hapus", "confirmations.delete_group.heading": "Hapus Group", "confirmations.delete_group.message": "Apakah Anda yakin ingin menghapus grup ini? Ini adalah tindakan permanen yang tidak dapat dibatalkan.", @@ -496,17 +496,17 @@ "confirmations.domain_block.confirm": "Sembunyikan keseluruhan domain", "confirmations.domain_block.heading": "Block {domain}", "confirmations.domain_block.message": "Apakah anda benar benar yakin untuk memblokir keseluruhan {domain}? Dalam kasus tertentu beberapa pemblokiran atau penyembunyian lebih baik.", - "confirmations.kick_from_group.confirm": "Menendang", + "confirmations.kick_from_group.confirm": "Tendangan", "confirmations.kick_from_group.message": "Apakah Anda yakin ingin mengeluarkan @{name} dari grup ini?", "confirmations.leave_event.confirm": "Tinggalkan acara", "confirmations.leave_event.message": "Jika Anda ingin bergabung kembali ke acara tersebut, permintaan akan ditinjau kembali secara manual. Apakah Anda yakin ingin melanjutkan?", "confirmations.leave_group.confirm": "Tinggalkan", "confirmations.leave_group.heading": "Tinggalkan grup", - "confirmations.leave_group.message": "Anda akan keluar dari grup. Apakah Anda ingin melanjutkan?", + "confirmations.leave_group.message": "Anda akan meninggalkan grup. Apakah Anda ingin melanjutkan?", "confirmations.mute.confirm": "Bisukan", "confirmations.mute.heading": "Mute @{name}", "confirmations.mute.message": "Apa anda yakin ingin membisukan {name}?", - "confirmations.mute_group.confirm": "Bisu", + "confirmations.mute_group.confirm": "Bisukan", "confirmations.mute_group.heading": "Bisukan Grup", "confirmations.mute_group.message": "Anda akan membisukan grup. Apakah Anda ingin melanjutkan?", "confirmations.redraft.confirm": "Hapus dan konsep ulang", @@ -523,14 +523,14 @@ "confirmations.revoke_session.confirm": "Revoke", "confirmations.revoke_session.heading": "Revoke current session", "confirmations.revoke_session.message": "You are about to revoke your current session. You will be signed out.", - "confirmations.scheduled_status_delete.confirm": "Cancel", + "confirmations.scheduled_status_delete.confirm": "Discard", "confirmations.scheduled_status_delete.heading": "Cancel scheduled post", "confirmations.scheduled_status_delete.message": "Are you sure you want to cancel this scheduled post?", "confirmations.unfollow.confirm": "Berhenti mengikuti", "copy.success": "Disalin ke papan klip!", "crypto_donate.explanation_box.message": "{siteTitle} accepts cryptocurrency donations. You may send a donation to any of the addresses below. Thank you for your support!", "crypto_donate.explanation_box.title": "Sending cryptocurrency donations", - "crypto_donate_panel.actions.view": "Click to see {count} {count, plural, one {wallet} other {wallets}}", + "crypto_donate_panel.actions.view": "Klik untuk melihat {count} {count, plural, one {wallet} lainya {wallets}}", "crypto_donate_panel.heading": "Donate Cryptocurrency", "crypto_donate_panel.intro.message": "{siteTitle} accepts cryptocurrency donations to fund our service. Thank you for your support!", "datepicker.day": "Day", @@ -554,7 +554,7 @@ "developers.navigation.network_error_label": "Network error", "developers.navigation.service_worker_label": "Service Worker", "developers.navigation.settings_store_label": "Settings store", - "developers.navigation.show_toast": "Pemicu Toast", + "developers.navigation.show_toast": "Pemicu Bersulang", "developers.navigation.test_timeline_label": "Test timeline", "developers.settings_store.advanced": "Advanced settings", "developers.settings_store.hint": "It is possible to directly edit your user settings here. BE CAREFUL! Editing this section can break your account, and you will only be able to recover through the API.", @@ -621,7 +621,7 @@ "emoji_button.search": "Cari...", "emoji_button.search_results": "Hasil pencarian", "emoji_button.skins_1": "Bawaan", - "emoji_button.skins_2": "Cahaya", + "emoji_button.skins_2": "Light", "emoji_button.skins_3": "Sedang-Ringan", "emoji_button.skins_4": "Sedang", "emoji_button.skins_5": "Sedang-Gelap", @@ -649,9 +649,9 @@ "empty_column.filters": "You haven't created any muted words yet.", "empty_column.follow_recommendations": "Looks like no suggestions could be generated for you. You can try using search to look for people you might know or explore trending hashtags.", "empty_column.follow_requests": "Anda belum memiliki permintaan mengikuti. Ketika Anda menerimanya, maka akan muncul disini.", - "empty_column.followed_tags": "Anda belum mengikuti hashtag apa pun.", + "empty_column.followed_tags": "Anda belum mengikuti tagar apa pun.", "empty_column.group": "Belum ada postingan di grup ini.", - "empty_column.group_blocks": "Grup ini belum melarang pengguna mana pun.", + "empty_column.group_blocks": "Grup ini belum mencekal pengguna mana pun.", "empty_column.group_membership_requests": "Tidak ada permintaan keanggotaan yang tertunda untuk grup ini.", "empty_column.hashtag": "Tidak ada apapun dalam hashtag ini.", "empty_column.home": "Linimasa anda kosong! Kunjungi {public} atau gunakan pencarian untuk memulai dan bertemu pengguna lain.", @@ -685,11 +685,11 @@ "event.location": "Lokasi", "event.manage": "Mengelola", "event.organized_by": "Diselenggarakan oleh {name}", - "event.participants": "{count} {rawCount, jamak, satu {orang} lainnya {orang}} hadir", + "event.participants": "{count} {rawCount, plural, one {person} lainya {people}} hadir", "event.quote": "Quote acara", "event.reblog": "Posting ulang acara", "event.show_on_map": "Tampilkan di peta", - "event.unreblog": "Batalkan pengeposan ulang acara", + "event.unreblog": "Batalkan memposting ulang acara", "event.website": "Tautan eksternal", "event_map.navigate": "Navigasi", "events.create_event": "Membuat acara", @@ -727,14 +727,14 @@ "filters.added": "Filter added.", "filters.context_header": "Filter contexts", "filters.context_hint": "One or multiple contexts where the filter should apply", - "filters.create_filter": "Buat filter", + "filters.create_filter": "Membuat filter", "filters.filters_list_context_label": "Filter contexts:", "filters.filters_list_drop": "Drop", - "filters.filters_list_expired": "Kedaluwarsa", + "filters.filters_list_expired": "Kadaluwarsa", "filters.filters_list_hide": "Hide", "filters.filters_list_hide_completely": "Sembunyikan konten", - "filters.filters_list_phrases_label": "Kata kunci atau frase:", - "filters.filters_list_warn": "Tampilkan peringatan", + "filters.filters_list_phrases_label": "Kata kunci atau frasa:", + "filters.filters_list_warn": "Menampilkan peringatan", "filters.removed": "Filter deleted.", "followRecommendations.heading": "Suggested Profiles", "follow_request.authorize": "Izinkan", @@ -745,47 +745,47 @@ "gdpr.title": "{siteTitle} uses cookies", "generic.saved": "Disimpan", "getting_started.open_source_notice": "{code_name} adalah perangkat lunak yang bersifat terbuka. Anda dapat berkontribusi atau melaporkan permasalahan/bug di Gitlab {code_link} (v{code_version}).", - "group.banned.message": "Anda dilarang dari {group}", + "group.banned.message": "Anda dicekal dari {group}", "group.cancel_request": "Batalkan permintaan", "group.delete.success": "Grup berhasil dihapus", "group.deleted.message": "Grup ini telah dihapus.", "group.demote.user.success": "@{name} sekarang menjadi anggota", "group.group_mod_authorize.fail": "Gagal menyetujui @{name}", - "group.group_mod_block": "Larangan dari grup", - "group.group_mod_block.success": "@{name} dilarang", + "group.group_mod_block": "Cekal dari grup", + "group.group_mod_block.success": "@{name} telah dicekal", "group.group_mod_demote": "Hapus peran {role}", - "group.group_mod_kick": "Keluarkan @{name} dari grup", - "group.group_mod_kick.success": "Keluarkan @{name} dari grup", + "group.group_mod_kick": "Tendang @{name} dari grup", + "group.group_mod_kick.success": "Tendang @{name} dari grup", "group.group_mod_promote_mod": "Tetapkan peran {role}", "group.group_mod_reject.fail": "Gagal menolak @{name}", - "group.group_mod_unblock": "Batalkan pelarangan", - "group.group_mod_unblock.success": "Membatalkan pemblokiran @{name} dari grup", - "group.header.alt": "Header grup", + "group.group_mod_unblock": "Batalkan pencekalan", + "group.group_mod_unblock.success": "Batalkan pencekalan @{name} dari grup", + "group.header.alt": "Tajuk grup", "group.join.private": "Minta Akses", - "group.join.public": "Bergabung ke grup", + "group.join.public": "Bergabung dengan Grup", "group.join.request_success": "Permintaan dikirim ke pemilik grup", "group.join.success": "Grup berhasil bergabung!", - "group.leave": "Meninggalkan grup", - "group.leave.label": "Meninggalkan", - "group.leave.success": "Keluar dari grup", - "group.manage": "Kelola Grup", - "group.member.admin.limit.summary": "Anda dapat menugaskan hingga {count, plural, one {admin} other {admins}} untuk grup saat ini.", + "group.leave": "Tinggalkan grup", + "group.leave.label": "Pergi.", + "group.leave.success": "Meninggalkan grup", + "group.manage": "Mengelola grup", + "group.member.admin.limit.summary": "Anda dapat menugaskan hingga {count, plural, one {admin} lainya {admins}} untuk grup saat ini.", "group.member.admin.limit.title": "Batas admin tercapai", - "group.mute.label": "Bisu", + "group.mute.label": "Bisukan", "group.mute.long_label": "Bisukan Grup", - "group.mute.success": "Membungkam grup", + "group.mute.success": "Membisukan grup", "group.popover.action": "Lihat Grup", "group.popover.summary": "Anda harus menjadi anggota grup untuk membalas status ini.", - "group.popover.title": "Keanggotaan diperlukan", + "group.popover.title": "Diperlukan keanggotaan", "group.privacy.locked": "Pribadi", - "group.privacy.locked.full": "Grup Tertutup", + "group.privacy.locked.full": "Grup Pribadi", "group.privacy.locked.info": "Dapat ditemukan. Pengguna dapat bergabung setelah permintaan mereka disetujui.", "group.privacy.public": "Publik", "group.privacy.public.full": "Grup Publik", - "group.privacy.public.info": "Dapat ditemukan. Siapapun bisa bergabung.", + "group.privacy.public.info": "Dapat ditemukan. Siapa pun bisa bergabung.", "group.private.message": "Konten hanya dapat dilihat oleh anggota grup", "group.promote.admin.confirmation.message": "Apakah Anda yakin ingin menetapkan peran admin ke @{name}?", - "group.promote.admin.confirmation.title": "Tetapkan Peran Admin", + "group.promote.admin.confirmation.title": "Menetapkan Peran Admin", "group.promote.admin.success": "@{name} sekarang menjadi admin", "group.report.label": "Laporkan", "group.role.admin": "Admin", @@ -795,56 +795,56 @@ "group.tabs.media": "Media", "group.tabs.members": "Anggota", "group.tabs.tags": "Topik", - "group.tags.empty": "Belum ada topik di grup ini.", + "group.tags.empty": "Belum ada topik dalam grup ini.", "group.tags.hidden.success": "Topik ditandai sebagai tersembunyi", "group.tags.hide": "Sembunyikan topik", - "group.tags.hint": "Tambahkan maksimal 3 kata kunci yang akan dijadikan topik inti diskusi di grup.", + "group.tags.hint": "Tambahkan hingga 3 kata kunci yang akan menjadi topik utama diskusi dalam grup.", "group.tags.label": "Tagar", - "group.tags.pin": "Sematkan topik", + "group.tags.pin": "Pin Topik", "group.tags.pin.success": "Disematkan!", "group.tags.show": "Tampilkan topik", "group.tags.total": "Keseluruhan Postingan", - "group.tags.unpin": "Lepas sematan topik", - "group.tags.unpin.success": "Sematan dilepaskan!", + "group.tags.unpin": "Batalkan pin topik", + "group.tags.unpin.success": "Pin dilepaskan!", "group.tags.visible.success": "Topik ditandai sebagai terlihat", - "group.unmute.label": "Batal membisukan.", - "group.unmute.long_label": "Suarakan Grup", + "group.unmute.label": "Bunyikan", + "group.unmute.long_label": "Batal Membisukan Grup", "group.unmute.success": "Membunyikan grup", "group.update.success": "Grup berhasil disimpan", - "group.upload_avatar": "Unggah Avatar", - "group.upload_banner": "Mengunggah foto", + "group.upload_avatar": "Unggah avatar", + "group.upload_banner": "Unggah foto", "group.upload_banner.title": "Unggah gambar latar belakang", "groups.discover.popular.empty": "Tidak dapat mengambil grup populer saat ini. Silakan periksa kembali nanti.", - "groups.discover.popular.show_more": "Tampilkan lebih banyak", + "groups.discover.popular.show_more": "Tampilkan Lebih Banyak", "groups.discover.popular.title": "Grup Populer", "groups.discover.search.error.subtitle": "Silakan coba lagi nanti.", "groups.discover.search.error.title": "Terjadi kesalahan", "groups.discover.search.no_results.subtitle": "Coba cari grup lain.", - "groups.discover.search.no_results.title": "Tidak ada kecocokan yang ditemukan", + "groups.discover.search.no_results.title": "Tidak ditemukan kecocokan", "groups.discover.search.placeholder": "Pencarian", "groups.discover.search.recent_searches.blankslate.subtitle": "Cari nama grup, topik atau kata kunci", "groups.discover.search.recent_searches.blankslate.title": "Tidak ada pencarian terbaru", - "groups.discover.search.recent_searches.clear_all": "Bersihkan semua", - "groups.discover.search.recent_searches.title": "Pencarian terkini", + "groups.discover.search.recent_searches.clear_all": "Hapus semua", + "groups.discover.search.recent_searches.title": "Pencarian terbaru", "groups.discover.search.results.groups": "Grup", - "groups.discover.search.results.member_count": "{anggota, jamak, satu {anggota} other {anggota}}", - "groups.discover.suggested.empty": "Saat ini tidak dapat mengambil grup yang disarankan. Silakan periksa kembali nanti.", - "groups.discover.suggested.show_more": "Tampilkan lebih banyak", - "groups.discover.suggested.title": "Saran Untuk Anda", + "groups.discover.search.results.member_count": "{members, plural, one {member} lainya {members}}", + "groups.discover.suggested.empty": "Tidak dapat mengambil grup yang disarankan saat ini. Silakan periksa kembali nanti.", + "groups.discover.suggested.show_more": "Tampilkan Lebih Banyak", + "groups.discover.suggested.title": "Disarankan Untuk Anda", "groups.discover.tags.empty": "Tidak dapat mengambil topik populer saat ini. Silakan periksa kembali nanti.", "groups.discover.tags.show_more": "Tampilkan Lebih Banyak", - "groups.discover.tags.title": "Telusuri Topik", + "groups.discover.tags.title": "Jelajahi Topik", "groups.discovery.tags.no_of_groups": "Jumlah grup", - "groups.empty.subtitle": "Mulailah menemukan grup untuk bergabung atau membuat grup Anda sendiri.", + "groups.empty.subtitle": "Mulailah menemukan grup untuk bergabung atau buat grup Anda sendiri.", "groups.empty.title": "Belum ada Grup", - "groups.pending.count": "{number, plural, one {# permintaan tertunda} other {# permintaan tertunda}}", + "groups.pending.count": "{number, plural, one {# pending request} lainya {# pending requests}}", "groups.pending.empty.subtitle": "Anda tidak memiliki permintaan yang tertunda saat ini.", "groups.pending.empty.title": "Tidak ada permintaan yang tertunda", "groups.pending.label": "Permintaan Tertunda", "groups.popular.label": "Grup yang Disarankan", "groups.search.placeholder": "Cari Grup Saya", "groups.suggested.label": "Grup yang Disarankan", - "groups.tags.title": "Telusuri Topik", + "groups.tags.title": "Jelajahi Topik", "hashtag.follow": "Ikuti tagar", "header.login.label": "Log in", "header.register.label": "Register", @@ -880,7 +880,7 @@ "keyboard_shortcuts.back": "untuk kembali", "keyboard_shortcuts.blocked": "buka daftar pengguna terblokir", "keyboard_shortcuts.boost": "untuk menyebarkan", - "keyboard_shortcuts.compose": "untuk fokus ke area penulisan", + "keyboard_shortcuts.compose": "untuk membuka area teks tulis", "keyboard_shortcuts.down": "untuk pindah ke bawah dalam sebuah daftar", "keyboard_shortcuts.enter": "untuk membuka status", "keyboard_shortcuts.favourite": "untuk memfavoritkan", @@ -943,33 +943,33 @@ "login_external.errors.instance_fail": "The instance returned an error.", "login_external.errors.network_fail": "Connection failed. Is a browser extension blocking it?", "login_form.header": "Sign In", - "manage_group.blocked_members": "Larang Anggota", + "manage_group.blocked_members": "Cekal Anggota", "manage_group.confirmation.copy": "Salin tautan", - "manage_group.confirmation.info_1": "Salin tautan Sebagai pemilik grup ini, Anda dapat menugaskan staf, menghapus postingan, dan banyak lagi.", + "manage_group.confirmation.info_1": "Sebagai pemilik grup ini, Anda dapat menugaskan staf, menghapus postingan, dan banyak lagi.", "manage_group.confirmation.info_2": "Posting postingan pertama grup dan mulailah percakapan.", "manage_group.confirmation.info_3": "Bagikan grup baru Anda dengan teman, keluarga, dan pengikut untuk mengembangkan keanggotaannya.", "manage_group.confirmation.share": "Bagikan grup ini", "manage_group.confirmation.title": "Anda sudah siap!", "manage_group.create": "Membuat grup", - "manage_group.delete_group": "Hapus Grup", + "manage_group.delete_group": "Menghapus grup", "manage_group.done": "Selesai", - "manage_group.edit_group": "Sunting Grup", - "manage_group.fields.cannot_change_hint": "Ini tidak dapat diubah setelah grup dibuat.", - "manage_group.fields.description_label": "Keterangan", - "manage_group.fields.description_placeholder": "Keterangan", + "manage_group.edit_group": "Edit grup", + "manage_group.fields.cannot_change_hint": "Hal ini tidak dapat diubah setelah grup dibuat.", + "manage_group.fields.description_label": "Deskripsi", + "manage_group.fields.description_placeholder": "Deskripsi", "manage_group.fields.hashtag_placeholder": "Tambahkan topik", - "manage_group.fields.name_help": "Ini tidak dapat diubah setelah grup dibuat.", + "manage_group.fields.name_help": "Hal ini tidak dapat diubah setelah grup dibuat.", "manage_group.fields.name_label": "Nama grup (wajib diisi)", "manage_group.fields.name_label_optional": "Nama grup", - "manage_group.fields.name_placeholder": "Nama grup", + "manage_group.fields.name_placeholder": "Nama Grup", "manage_group.get_started": "Mari kita mulai!", "manage_group.next": "Berikutnya", - "manage_group.pending_requests": "permintaan tertunda", - "manage_group.privacy.hint": "Pengaturan ini tidak dapat diubah lagi nanti.", - "manage_group.privacy.label": "Pengaturan Privasi", + "manage_group.pending_requests": "Permintaan yang tertunda", + "manage_group.privacy.hint": "Pengaturan ini tidak dapat diubah di kemudian hari.", + "manage_group.privacy.label": "Pengaturan privasi", "manage_group.privacy.private.hint": "Dapat ditemukan. Pengguna dapat bergabung setelah permintaan mereka disetujui.", - "manage_group.privacy.private.label": "Privasi (perlu persetujuan pemilik)", - "manage_group.privacy.public.hint": "Dapat ditemukan. Siapapun bisa bergabung.", + "manage_group.privacy.private.label": "Pribadi (Diperlukan persetujuan pemilik)", + "manage_group.privacy.public.hint": "Dapat ditemukan. Siapa pun bisa bergabung.", "manage_group.privacy.public.label": "Publik", "manage_group.tagline": "Grup menghubungkan Anda dengan orang lain berdasarkan minat yang sama.", "media_panel.empty_message": "No media found.", @@ -1022,7 +1022,7 @@ "navbar.login.username.placeholder": "Email or username", "navigation.chats": "Chats", "navigation.compose": "Compose", - "navigation.compose_group": "Tulis ke Grup", + "navigation.compose_group": "Menulis ke Grup", "navigation.dashboard": "Dashboard", "navigation.developers": "Developers", "navigation.direct_messages": "Messages", @@ -1037,15 +1037,15 @@ "navigation_bar.compose_edit": "Edit post", "navigation_bar.compose_event": "Kelola acara", "navigation_bar.compose_group": "Menulis ke grup", - "navigation_bar.compose_group_reply": "Membalas postingan grup", + "navigation_bar.compose_group_reply": "Membalas kiriman grup", "navigation_bar.compose_quote": "Quote post", "navigation_bar.compose_reply": "Reply to post", "navigation_bar.create_event": "Buat acara baru", - "navigation_bar.create_group": "Membuat grup", - "navigation_bar.create_group.private": "Buat Grup Pribadi", + "navigation_bar.create_group": "Membuat Grup", + "navigation_bar.create_group.private": "Membuat Grup Pribadi", "navigation_bar.create_group.public": "Buat Grup Publik", "navigation_bar.domain_blocks": "Domain tersembunyi", - "navigation_bar.edit_group": "Sunting Grup", + "navigation_bar.edit_group": "Edit Grup", "navigation_bar.favourites": "Favorit", "navigation_bar.filters": "Kata yang dibisukan", "navigation_bar.follow_requests": "Permintaan mengikuti", @@ -1058,16 +1058,16 @@ "navigation_bar.preferences": "Pengaturan", "navigation_bar.profile_directory": "Profile directory", "navigation_bar.soapbox_config": "Soapbox config", - "new_event_panel.action": "Membuat acara", + "new_event_panel.action": "Buat acara", "new_event_panel.subtitle": "Tidak dapat menemukan apa yang Anda cari? Jadwalkan acara Anda sendiri.", "new_event_panel.title": "Buat Acara Baru", - "new_group_panel.action": "Membuat grup", + "new_group_panel.action": "Buat grup", "new_group_panel.subtitle": "Tidak dapat menemukan apa yang Anda cari? Mulai grup pribadi atau publik Anda sendiri.", - "new_group_panel.title": "Membuat grup", + "new_group_panel.title": "Buat grup", "notification.favourite": "{name} menyukai status anda", "notification.follow": "{name} mengikuti anda", "notification.follow_request": "{name} has requested to follow you", - "notification.group_favourite": "{name} menyukai postingan grup Anda", + "notification.group_favourite": "{nama} menyukai kiriman grup Anda", "notification.group_reblog": "{nama} memposting ulang postingan grup Anda", "notification.mention": "{name} menyebut Anda", "notification.mentioned": "{name} mentioned you", @@ -1092,7 +1092,7 @@ "notifications.filter.mentions": "Sebutan", "notifications.filter.polls": "Hasil japat", "notifications.filter.statuses": "Updates from people you follow", - "notifications.group": "{count} notifikasi", + "notifications.group": "{count, plural, one {# notification} lainya {# notifications}}", "notifications.queue_label": "Click to see {count} new {count, plural, one {notification} other {notifications}}", "oauth_consumer.tooltip": "Sign in with {provider}", "oauth_consumers.title": "Other ways to sign in", @@ -1152,7 +1152,7 @@ "preferences.fields.content_type_label": "Default post format", "preferences.fields.delete_modal_label": "Show confirmation dialog before deleting a post", "preferences.fields.demetricator_label": "Use Demetricator", - "preferences.fields.demo_hint": "Gunakan logo dan skema warna bawaan Soapbox. Berguna untuk mengambil tangkapan layar.", + "preferences.fields.demo_hint": "Gunakan logo Soapbox default dan skema warna. Berguna untuk mengambil tangkapan layar.", "preferences.fields.demo_label": "Mode demo", "preferences.fields.display_media.default": "Hide media marked as sensitive", "preferences.fields.display_media.hide_all": "Always hide media", @@ -1161,7 +1161,7 @@ "preferences.fields.language_label": "Language", "preferences.fields.media_display_label": "Media display", "preferences.fields.missing_description_modal_label": "Show confirmation dialog before sending a post without media descriptions", - "preferences.fields.preserve_spoilers_label": "Pertahankan peringatan konten saat membalas", + "preferences.fields.preserve_spoilers_label": "Mempertahankan peringatan konten saat membalas", "preferences.fields.privacy_label": "Default post privacy", "preferences.fields.reduce_motion_label": "Reduce motion in animations", "preferences.fields.system_font_label": "Use system's default font", @@ -1229,7 +1229,7 @@ "remote_interaction.dislike": "Lanjutkan ke tidak suka", "remote_interaction.dislike_title": "Tidak menyukai postingan dari jarak jauh", "remote_interaction.divider": "or", - "remote_interaction.event_join": "Lanjutkan untuk bergabung", + "remote_interaction.event_join": "Proses untuk bergabung", "remote_interaction.event_join_title": "Bergabunglah dengan acara dari jarak jauh", "remote_interaction.favourite": "Proceed to like", "remote_interaction.favourite_title": "Like a post remotely", @@ -1346,7 +1346,7 @@ "soapbox_config.feed_injection_hint": "Inject the feed with additional content, such as suggested profiles.", "soapbox_config.feed_injection_label": "Feed injection", "soapbox_config.fields.crypto_addresses_label": "Cryptocurrency addresses", - "soapbox_config.fields.edit_theme_label": "Edit Tema", + "soapbox_config.fields.edit_theme_label": "Edit tema", "soapbox_config.fields.home_footer_fields_label": "Home footer items", "soapbox_config.fields.logo_label": "Logo", "soapbox_config.fields.promo_panel_fields_label": "Promo panel items", @@ -1365,7 +1365,7 @@ "soapbox_config.hints.promo_panel_icons.link": "Soapbox Icons List", "soapbox_config.home_footer.meta_fields.label_placeholder": "Label", "soapbox_config.home_footer.meta_fields.url_placeholder": "URL", - "soapbox_config.media_preview_hint": "Beberapa backend menyediakan versi media yang dioptimalkan untuk ditampilkan di garis waktu. Namun, gambar pratinjau ini mungkin terlalu kecil tanpa konfigurasi tambahan.", + "soapbox_config.media_preview_hint": "Sebagian backend menyediakan versi media yang dioptimalkan untuk ditampilkan dalam lini masa. Namun demikian, gambar pratinjau ini mungkin terlalu kecil tanpa konfigurasi tambahan.", "soapbox_config.media_preview_label": "Lebih memilih media pratinjau untuk thumbnail", "soapbox_config.promo_panel.meta_fields.icon_placeholder": "Icon", "soapbox_config.promo_panel.meta_fields.label_placeholder": "Label", @@ -1373,13 +1373,13 @@ "soapbox_config.raw_json_hint": "Edit data pengaturan secara langsung. Perubahan yang dilakukan langsung pada file JSON akan menggantikan kolom formulir di atas. Klik \"Simpan\" untuk menerapkan perubahan Anda.", "soapbox_config.raw_json_invalid": "tidak valid", "soapbox_config.raw_json_label": "Advanced: Edit raw JSON data", - "soapbox_config.redirect_root_no_login_hint": "Jalur untuk mengalihkan beranda saat pengguna tidak masuk.", - "soapbox_config.redirect_root_no_login_label": "Arahkan ulang beranda", + "soapbox_config.redirect_root_no_login_hint": "Jalur untuk mengarahkan beranda ketika pengguna tidak masuk.", + "soapbox_config.redirect_root_no_login_label": "Mengalihkan beranda", "soapbox_config.save": "Save", "soapbox_config.saved": "Soapbox config saved!", "soapbox_config.sentry_dsn_hint": "URL DSN untuk pelaporan kesalahan. Bekerja dengan Sentry dan GlitchTip.", "soapbox_config.sentry_dsn_label": "Sentry DSN", - "soapbox_config.tile_server_attribution_label": "Atribusi ubin peta", + "soapbox_config.tile_server_attribution_label": "Map tiles attribution", "soapbox_config.tile_server_label": "Map tile server", "soapbox_config.verified_can_edit_name_label": "Allow verified users to edit their own display name.", "status.admin_account": "Open moderation interface for @{name}", @@ -1391,7 +1391,7 @@ "status.cancel_reblog_private": "Un-repost", "status.cannot_reblog": "This post cannot be reposted", "status.chat": "Chat with @{name}", - "status.copy": "Copy link to post", + "status.copy": "Salin Tautan ke Posting", "status.delete": "Hapus", "status.detailed_status": "Detailed conversation view", "status.direct": "Direct message @{name}", @@ -1403,16 +1403,16 @@ "status.favourite": "Difavoritkan", "status.filtered": "Filtered", "status.group": "Diposting di {grup}", - "status.group_mod_delete": "Hapus postingan dari grup", - "status.interactions.dislikes": "{count, plural, one {Tidak suka} other {Tidak suka}}", + "status.group_mod_delete": "Menghapus postingan dari grup", + "status.interactions.dislikes": "{count, plural, one {Dislike} lainya {Dislikes}}", "status.interactions.favourites": "{count, plural, one {Like} other {Likes}}", - "status.interactions.quotes": "{hitungan, jamak, satu {Kutipan} lainnya {Kutipan}}", + "status.interactions.quotes": "{count, plural, one {Quote} lainya {Quotes}}", "status.interactions.reblogs": "{count, plural, one {Repost} other {Reposts}}", "status.load_more": "Tampilkan semua", "status.mention": "Balasan @{name}", "status.more": "More", "status.mute_conversation": "Mute conversation", - "status.open": "Tampilkan status ini", + "status.open": "Tampilkan Detail Kiriman", "status.pin": "Pin on profile", "status.pin_to_group": "Sematkan ke Grup", "status.pin_to_group.success": "Disematkan ke Grup!", @@ -1440,11 +1440,11 @@ "status.sensitive_warning": "Konten sensitif", "status.sensitive_warning.subtitle": "This content may not be suitable for all audiences.", "status.share": "Share", - "status.show_filter_reason": "Tetap tunjukkan", + "status.show_filter_reason": "Tunjukkan saja.", "status.show_less_all": "Show less for all", "status.show_more_all": "Show more for all", "status.show_original": "Show original", - "status.title": "Post", + "status.title": "Detail Kiriman", "status.title_direct": "Direct message", "status.translate": "Translate", "status.translated_from_with": "Translated from {lang} using {provider}", @@ -1452,7 +1452,7 @@ "status.unbookmarked": "Bookmark removed.", "status.unmute_conversation": "Unmute conversation", "status.unpin": "Unpin from profile", - "status.unpin_to_group": "Lepas sematan dari Grup", + "status.unpin_to_group": "Lepas pin dari Grup", "status_list.queue_label": "Click to see {count} new {count, plural, one {post} other {posts}}", "statuses.quote_tombstone": "Post is unavailable.", "statuses.tombstone": "One or more posts are unavailable.", @@ -1478,12 +1478,12 @@ "tabs_bar.profile": "Profile", "tabs_bar.search": "Search", "tabs_bar.settings": "Settings", - "textarea.counter.label": "{count} karakter tersisa", - "theme_editor.Reset": "Mengatur ulang", + "textarea.counter.label": "{count} karakter yang tersisa", + "theme_editor.Reset": "Atur ulang", "theme_editor.export": "Ekspor tema", "theme_editor.import": "Impor tema", "theme_editor.import_success": "Tema berhasil diimpor!", - "theme_editor.restore": "Kembalikan tema bawaan", + "theme_editor.restore": "Kembalikan tema default", "theme_editor.save": "Simpan tema", "theme_editor.saved": "Tema diperbarui!", "theme_toggle.dark": "Dark", @@ -1508,7 +1508,7 @@ "upload_error.image_size_limit": "Image exceeds the current file size limit ({limit})", "upload_error.limit": "File upload limit exceeded.", "upload_error.poll": "File upload not allowed with polls.", - "upload_error.video_duration_limit": "Video exceeds the current duration limit ({limit} seconds)", + "upload_error.video_duration_limit": "Video melebihi batas durasi saat ini ({limit, plural, one {# second} lainya {# seconds}})", "upload_error.video_size_limit": "Video exceeds the current file size limit ({limit})", "upload_form.description": "Deskripsikan untuk mereka yang tidak bisa melihat dengan jelas", "upload_form.preview": "Preview", From d43f5b50224b29bfc8dfbf76d645a9924f2207c9 Mon Sep 17 00:00:00 2001 From: LibreTranslate Date: Mon, 11 Dec 2023 16:00:54 +0000 Subject: [PATCH 082/115] Translated using Weblate (Indonesian) Currently translated at 100.0% (1526 of 1526 strings) Translation: Soapbox/Soapbox Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/id/ --- src/locales/id.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/locales/id.json b/src/locales/id.json index 55b81371e..7b7b8ae9c 100644 --- a/src/locales/id.json +++ b/src/locales/id.json @@ -164,8 +164,8 @@ "alert.unexpected.links.support": "Support", "alert.unexpected.message": "Terjadi kesalahan yang tidak terduga.", "alert.unexpected.return_home": "Return Home", - "alert.unexpected.submit_feedback": "Berikan umpan balik", - "alert.unexpected.thanks": "Terima kasih atas tanggapan Anda!", + "alert.unexpected.submit_feedback": "Kirim Umpan balik", + "alert.unexpected.thanks": "Terima kasih atas umpan balik Anda!", "aliases.account.add": "Buat alias", "aliases.account_label": "Old account:", "aliases.aliases_list_delete": "Batalkan tautan alias", @@ -429,7 +429,7 @@ "compose_form.poll.remove_option": "Hapus opsi ini", "compose_form.poll.switch_to_multiple": "Change poll to allow multiple choices", "compose_form.poll.switch_to_single": "Change poll to allow for a single choice", - "compose_form.poll_placeholder": "Tambahkan topik jajak pendapat…", + "compose_form.poll_placeholder": "Tambahkan topik poll..", "compose_form.publish": "Publish", "compose_form.publish_loud": "{publish}!", "compose_form.save_changes": "Save changes", @@ -1377,7 +1377,7 @@ "soapbox_config.redirect_root_no_login_label": "Mengalihkan beranda", "soapbox_config.save": "Save", "soapbox_config.saved": "Soapbox config saved!", - "soapbox_config.sentry_dsn_hint": "URL DSN untuk pelaporan kesalahan. Bekerja dengan Sentry dan GlitchTip.", + "soapbox_config.sentry_dsn_hint": "URL DSN untuk pelaporan kesalahan. Sentry dan GlitchTip.", "soapbox_config.sentry_dsn_label": "Sentry DSN", "soapbox_config.tile_server_attribution_label": "Map tiles attribution", "soapbox_config.tile_server_label": "Map tile server", From 0b06f04271f04926abc44e150643df5f89b3a3b2 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 20 Dec 2023 19:36:18 -0600 Subject: [PATCH 083/115] Upgrade tailwindcss to v3.4.0 --- package.json | 6 +++--- yarn.lock | 40 ++++++++++++++++++++-------------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index c60e9e1c0..de40cfe6a 100644 --- a/package.json +++ b/package.json @@ -68,8 +68,8 @@ "@soapbox.pub/wasmboy": "^0.8.0", "@tabler/icons": "^2.0.0", "@tailwindcss/aspect-ratio": "^0.4.2", - "@tailwindcss/forms": "^0.5.3", - "@tailwindcss/typography": "^0.5.9", + "@tailwindcss/forms": "^0.5.7", + "@tailwindcss/typography": "^0.5.10", "@tanstack/react-query": "^5.0.0", "@types/escape-html": "^1.0.1", "@types/http-link-header": "^1.0.3", @@ -209,7 +209,7 @@ "rollup-plugin-visualizer": "^5.9.2", "stylelint": "^15.10.3", "stylelint-config-standard-scss": "^11.0.0", - "tailwindcss": "^3.3.3", + "tailwindcss": "^3.4.0", "vite-plugin-checker": "^0.6.2", "vite-plugin-pwa": "^0.17.0", "vitest": "^0.34.4" diff --git a/yarn.lock b/yarn.lock index d73e3e974..11f033b0b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2161,17 +2161,17 @@ resolved "https://registry.yarnpkg.com/@tailwindcss/aspect-ratio/-/aspect-ratio-0.4.2.tgz#9ffd52fee8e3c8b20623ff0dcb29e5c21fb0a9ba" integrity sha512-8QPrypskfBa7QIMuKHg2TA7BqES6vhBrDLOv8Unb6FcFyd3TjKbc6lcmb9UPQHxfl24sXoJ41ux/H7qQQvfaSQ== -"@tailwindcss/forms@^0.5.3": - version "0.5.3" - resolved "https://registry.yarnpkg.com/@tailwindcss/forms/-/forms-0.5.3.tgz#e4d7989686cbcaf416c53f1523df5225332a86e7" - integrity sha512-y5mb86JUoiUgBjY/o6FJSFZSEttfb3Q5gllE4xoKjAAD+vBrnIhE4dViwUuow3va8mpH4s9jyUbUbrRGoRdc2Q== +"@tailwindcss/forms@^0.5.7": + version "0.5.7" + resolved "https://registry.yarnpkg.com/@tailwindcss/forms/-/forms-0.5.7.tgz#db5421f062a757b5f828bc9286ba626c6685e821" + integrity sha512-QE7X69iQI+ZXwldE+rzasvbJiyV/ju1FGHH0Qn2W3FKbuYtqp8LKcy6iSw79fVUT5/Vvf+0XgLCeYVG+UV6hOw== dependencies: mini-svg-data-uri "^1.2.3" -"@tailwindcss/typography@^0.5.9": - version "0.5.9" - resolved "https://registry.yarnpkg.com/@tailwindcss/typography/-/typography-0.5.9.tgz#027e4b0674929daaf7c921c900beee80dbad93e8" - integrity sha512-t8Sg3DyynFysV9f4JDOVISGsjazNb48AeIYQwcL+Bsq5uf4RYL75C1giZ43KISjeDGBaTN3Kxh7Xj/vRSMJUUg== +"@tailwindcss/typography@^0.5.10": + version "0.5.10" + resolved "https://registry.yarnpkg.com/@tailwindcss/typography/-/typography-0.5.10.tgz#2abde4c6d5c797ab49cf47610830a301de4c1e0a" + integrity sha512-Pe8BuPJQJd3FfRnm6H0ulKIGoMEQS+Vq01R6M5aCrFB/ccR/shT+0kXLjouGC1gFLm9hopTFN+DMP0pfwRWzPw== dependencies: lodash.castarray "^4.4.0" lodash.isplainobject "^4.0.6" @@ -4671,7 +4671,7 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.2.11, fast-glob@^3.2.12, fast-glob@^3.2.5, fast-glob@^3.2.7, fast-glob@^3.2.9, fast-glob@^3.3.1: +fast-glob@^3.2.11, fast-glob@^3.2.5, fast-glob@^3.2.7, fast-glob@^3.2.9, fast-glob@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== @@ -4682,7 +4682,7 @@ fast-glob@^3.2.11, fast-glob@^3.2.12, fast-glob@^3.2.5, fast-glob@^3.2.7, fast-g merge2 "^1.3.0" micromatch "^4.0.4" -fast-glob@^3.3.2: +fast-glob@^3.3.0, fast-glob@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== @@ -5685,10 +5685,10 @@ jest-worker@^27.4.5: merge-stream "^2.0.0" supports-color "^8.0.0" -jiti@^1.18.2: - version "1.20.0" - resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.20.0.tgz#2d823b5852ee8963585c8dd8b7992ffc1ae83b42" - integrity sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA== +jiti@^1.19.1: + version "1.21.0" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d" + integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q== js-base64@^3.6.0: version "3.7.5" @@ -8433,20 +8433,20 @@ table@^6.8.1: string-width "^4.2.3" strip-ansi "^6.0.1" -tailwindcss@^3.3.3: - version "3.3.3" - resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.3.tgz#90da807393a2859189e48e9e7000e6880a736daf" - integrity sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w== +tailwindcss@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.0.tgz#045a9c474e6885ebd0436354e611a76af1c76839" + integrity sha512-VigzymniH77knD1dryXbyxR+ePHihHociZbXnLZHUyzf2MMs2ZVqlUrZ3FvpXP8pno9JzmILt1sZPD19M3IxtA== dependencies: "@alloc/quick-lru" "^5.2.0" arg "^5.0.2" chokidar "^3.5.3" didyoumean "^1.2.2" dlv "^1.1.3" - fast-glob "^3.2.12" + fast-glob "^3.3.0" glob-parent "^6.0.2" is-glob "^4.0.3" - jiti "^1.18.2" + jiti "^1.19.1" lilconfig "^2.1.0" micromatch "^4.0.5" normalize-path "^3.0.0" From 154fa0c0ed62fafeb1f5e5d2c2837dc642163342 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 20 Dec 2023 20:34:09 -0600 Subject: [PATCH 084/115] Convert Tailwind config to TypeScript --- .eslintrc.cjs | 4 +- tailwind.config.cjs => tailwind.config.ts | 18 +++++--- tailwind/colors.cjs | 46 -------------------- tailwind/{colors.test.js => colors.test.ts} | 11 +++-- tailwind/colors.ts | 47 +++++++++++++++++++++ 5 files changed, 66 insertions(+), 60 deletions(-) rename tailwind.config.cjs => tailwind.config.ts (89%) delete mode 100644 tailwind/colors.cjs rename tailwind/{colors.test.js => colors.test.ts} (74%) create mode 100644 tailwind/colors.ts diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 29a8d474a..d3089ab4a 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -61,7 +61,7 @@ module.exports = { 'URLSearchParams', // core-js ], tailwindcss: { - config: 'tailwind.config.cjs', + config: 'tailwind.config.ts', }, }, @@ -268,7 +268,7 @@ module.exports = { 'error', { classRegex: '^(base|container|icon|item|list|outer|wrapper)?[c|C]lass(Name)?$', - config: 'tailwind.config.cjs', + config: 'tailwind.config.ts', }, ], 'tailwindcss/migration-from-tailwind-2': 'error', diff --git a/tailwind.config.cjs b/tailwind.config.ts similarity index 89% rename from tailwind.config.cjs rename to tailwind.config.ts index 2e30e6d29..b108490cf 100644 --- a/tailwind.config.cjs +++ b/tailwind.config.ts @@ -1,7 +1,11 @@ -const { parseColorMatrix } = require('./tailwind/colors.cjs'); +import aspectRatioPlugin from '@tailwindcss/aspect-ratio'; +import formsPlugin from '@tailwindcss/forms'; +import typographyPlugin from '@tailwindcss/typography'; +import { type Config } from 'tailwindcss'; -/** @type {import('tailwindcss').Config} */ -module.exports = { +import { parseColorMatrix } from './tailwind/colors'; + +const config: Config = { content: ['./src/**/*.{html,js,ts,tsx}', './custom/instance/**/*.html', './index.html'], darkMode: 'class', theme: { @@ -98,8 +102,10 @@ module.exports = { }, }, plugins: [ - require('@tailwindcss/forms'), - require('@tailwindcss/typography'), - require('@tailwindcss/aspect-ratio'), + aspectRatioPlugin, + formsPlugin, + typographyPlugin, ], }; + +export default config; \ No newline at end of file diff --git a/tailwind/colors.cjs b/tailwind/colors.cjs deleted file mode 100644 index 412de7d3f..000000000 --- a/tailwind/colors.cjs +++ /dev/null @@ -1,46 +0,0 @@ -// https://tailwindcss.com/docs/customizing-colors#using-css-variables -function withOpacityValue(variable) { - return ({ opacityValue }) => { - if (opacityValue === undefined) { - return `rgb(var(${variable}))`; - } - return `rgb(var(${variable}) / ${opacityValue})`; - }; -} - -// Parse a single color as a CSS variable -const toColorVariable = (colorName, tint = null) => { - const suffix = tint ? `-${tint}` : ''; - const variable = `--color-${colorName}${suffix}`; - - return withOpacityValue(variable); -}; - -// Parse list of tints into Tailwind function with CSS variables -const parseTints = (colorName, tints) => { - return tints.reduce((colorObj, tint) => { - colorObj[tint] = toColorVariable(colorName, tint); - return colorObj; - }, {}); -}; - -// Parse color matrix into Tailwind color palette -const parseColorMatrix = colorMatrix => { - return Object.entries(colorMatrix).reduce((palette, colorData) => { - const [colorName, tints] = colorData; - - // Conditionally parse array or single-tint colors - if (Array.isArray(tints)) { - palette[colorName] = parseTints(colorName, tints); - } else if (tints === true) { - palette[colorName] = toColorVariable(colorName); - } - - return palette; - }, {}); -}; - -module.exports = { - withOpacityValue, - parseColorMatrix, -}; diff --git a/tailwind/colors.test.js b/tailwind/colors.test.ts similarity index 74% rename from tailwind/colors.test.js rename to tailwind/colors.test.ts index 90ac55fd4..426de1db2 100644 --- a/tailwind/colors.test.js +++ b/tailwind/colors.test.ts @@ -1,7 +1,7 @@ import { withOpacityValue, parseColorMatrix, -} from './colors.cjs'; +} from './colors'; describe('withOpacityValue()', () => { it('returns a Tailwind color function with alpha support', () => { @@ -11,8 +11,7 @@ describe('withOpacityValue()', () => { expect(typeof result).toBe('function'); // Test calling the function - expect(result({})).toBe('rgb(var(--color-primary-500))'); - expect(result({ opacityValue: .5 })).toBe('rgb(var(--color-primary-500) / 0.5)'); + expect(result).toBe('rgb(var(--color-primary-500) / )'); }); }); @@ -29,8 +28,8 @@ describe('parseColorMatrix()', () => { const result = parseColorMatrix(colorMatrix); // Colors are mapped to functions which return CSS values - expect(result.primary[500]({})).toEqual('rgb(var(--color-primary-500))'); - expect(result.accent[300]({ opacityValue: .3 })).toEqual('rgb(var(--color-accent-300) / 0.3)'); + // @ts-ignore + expect(result.accent['300']).toEqual('rgb(var(--color-accent-300) / )'); }); it('parses single-tint values', () => { @@ -46,6 +45,6 @@ describe('parseColorMatrix()', () => { const result = parseColorMatrix(colorMatrix); - expect(result['gradient-start']({ opacityValue: .7 })).toEqual('rgb(var(--color-gradient-start) / 0.7)'); + expect(result['gradient-start']).toEqual('rgb(var(--color-gradient-start) / )'); }); }); diff --git a/tailwind/colors.ts b/tailwind/colors.ts new file mode 100644 index 000000000..089d29844 --- /dev/null +++ b/tailwind/colors.ts @@ -0,0 +1,47 @@ +import { type RecursiveKeyValuePair } from 'tailwindcss/types/config'; + +/** https://tailwindcss.com/docs/customizing-colors#using-css-variables */ +function withOpacityValue(variable: string): string { + return `rgb(var(${variable}) / )`; +} + +/** Parse a single color as a CSS variable. */ +const toColorVariable = (colorName: string, tint: number | null = null): string => { + const suffix = tint ? `-${tint}` : ''; + const variable = `--color-${colorName}${suffix}`; + + return withOpacityValue(variable); +}; + +/** Parse list of tints into Tailwind function with CSS variables. */ +const parseTints = (colorName: string, tints: number[]): RecursiveKeyValuePair => { + return tints.reduce>((colorObj, tint) => { + colorObj[tint] = toColorVariable(colorName, tint); + return colorObj; + }, {}); +}; + +interface ColorMatrix { + [colorName: string]: number[] | boolean; +} + +/** Parse color matrix into Tailwind color palette. */ +const parseColorMatrix = (colorMatrix: ColorMatrix): RecursiveKeyValuePair => { + return Object.entries(colorMatrix).reduce((palette, colorData) => { + const [colorName, tints] = colorData; + + // Conditionally parse array or single-tint colors + if (Array.isArray(tints)) { + palette[colorName] = parseTints(colorName, tints); + } else if (tints === true) { + palette[colorName] = toColorVariable(colorName); + } + + return palette; + }, {}); +}; + +export { + withOpacityValue, + parseColorMatrix, +}; From 8108ac2a679a496cddff53bb1e0d3990131bd4af Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 20 Dec 2023 21:17:33 -0600 Subject: [PATCH 085/115] yarn lint:js --fix --- src/components/big-card.tsx | 2 +- src/components/gdpr-banner.tsx | 2 +- src/components/site-error-boundary.tsx | 2 +- src/components/ui/select/select.tsx | 2 +- src/components/ui/tag-input/tag-input.tsx | 2 +- src/components/ui/textarea/textarea.tsx | 2 +- src/features/account/components/header.tsx | 4 ++-- src/features/aliases/components/search.tsx | 2 +- src/features/auth-login/components/consumers-list.tsx | 2 +- src/features/chats/components/chat-page/chat-page.tsx | 4 ++-- .../components/chat-page/components/chat-page-main.tsx | 2 +- .../chats/components/chat-page/components/chat-page-new.tsx | 2 +- .../components/chat-page/components/chat-page-settings.tsx | 2 +- src/features/chats/components/chat-textarea.tsx | 6 +++--- src/features/edit-profile/components/header-picker.tsx | 2 +- src/features/event/components/event-header.tsx | 4 ++-- src/features/feed-suggestions/feed-suggestions.tsx | 2 +- src/features/group/components/group-header.tsx | 6 +++--- src/features/onboarding/steps/fediverse-step.tsx | 2 +- .../placeholder/components/placeholder-notification.tsx | 2 +- .../modals/compose-event-modal/compose-event-modal.tsx | 4 ++-- .../modals/manage-group-modal/steps/confirmation-step.tsx | 2 +- src/features/ui/components/navbar.tsx | 4 ++-- src/features/ui/index.tsx | 2 +- src/pages/home-page.tsx | 2 +- src/pages/landing-page.tsx | 2 +- 26 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/components/big-card.tsx b/src/components/big-card.tsx index 895ac1298..f71c86480 100644 --- a/src/components/big-card.tsx +++ b/src/components/big-card.tsx @@ -12,7 +12,7 @@ const BigCard: React.FC = ({ title, subtitle, children }) => { return ( -
+
{title} {subtitle && {subtitle}} diff --git a/src/components/gdpr-banner.tsx b/src/components/gdpr-banner.tsx index 288a5e421..75bc16bad 100644 --- a/src/components/gdpr-banner.tsx +++ b/src/components/gdpr-banner.tsx @@ -28,7 +28,7 @@ const GdprBanner: React.FC = () => { return ( -
+
diff --git a/src/components/site-error-boundary.tsx b/src/components/site-error-boundary.tsx index 3f39efc25..19a22a0c8 100644 --- a/src/components/site-error-boundary.tsx +++ b/src/components/site-error-boundary.tsx @@ -84,7 +84,7 @@ const SiteErrorBoundary: React.FC = ({ children }) => {
-

+

diff --git a/src/components/ui/select/select.tsx b/src/components/ui/select/select.tsx index 888868a58..4c4c6c2c1 100644 --- a/src/components/ui/select/select.tsx +++ b/src/components/ui/select/select.tsx @@ -13,7 +13,7 @@ const Select = React.forwardRef((props, ref) => { = () => { if (providers.length > 0) { return ( - + diff --git a/src/features/chats/components/chat-page/chat-page.tsx b/src/features/chats/components/chat-page/chat-page.tsx index 16b5e2d0b..344b7a90a 100644 --- a/src/features/chats/components/chat-page/chat-page.tsx +++ b/src/features/chats/components/chat-page/chat-page.tsx @@ -60,7 +60,7 @@ const ChatPage: React.FC = ({ chatId }) => {

{isOnboarded ? (
= ({ chatId }) => { data-testid='chat-page' > diff --git a/src/features/chats/components/chat-page/components/chat-page-main.tsx b/src/features/chats/components/chat-page/components/chat-page-main.tsx index 89371c4da..6a9acd1e2 100644 --- a/src/features/chats/components/chat-page/components/chat-page-main.tsx +++ b/src/features/chats/components/chat-page/components/chat-page-main.tsx @@ -121,7 +121,7 @@ const ChatPageMain = () => { history.push('/chats')} /> diff --git a/src/features/chats/components/chat-page/components/chat-page-new.tsx b/src/features/chats/components/chat-page/components/chat-page-new.tsx index 0a60c56b4..ed9535efd 100644 --- a/src/features/chats/components/chat-page/components/chat-page-new.tsx +++ b/src/features/chats/components/chat-page/components/chat-page-new.tsx @@ -24,7 +24,7 @@ const ChatPageNew: React.FC = () => { history.push('/chats')} /> diff --git a/src/features/chats/components/chat-page/components/chat-page-settings.tsx b/src/features/chats/components/chat-page/components/chat-page-settings.tsx index cb637a36e..d042b75ac 100644 --- a/src/features/chats/components/chat-page/components/chat-page-settings.tsx +++ b/src/features/chats/components/chat-page/components/chat-page-settings.tsx @@ -51,7 +51,7 @@ const ChatPageSettings = () => { history.push('/chats')} /> diff --git a/src/features/chats/components/chat-textarea.tsx b/src/features/chats/components/chat-textarea.tsx index a8269b0c0..f85d897d5 100644 --- a/src/features/chats/components/chat-textarea.tsx +++ b/src/features/chats/components/chat-textarea.tsx @@ -39,9 +39,9 @@ const ChatTextarea: React.FC = React.forwardRef(({ bg-white text-gray-900 shadow-sm placeholder:text-gray-600 focus-within:border-primary-500 - focus-within:ring-1 focus-within:ring-primary-500 dark:border-gray-800 dark:bg-gray-800 - dark:text-gray-100 dark:ring-1 dark:ring-gray-800 dark:placeholder:text-gray-600 dark:focus-within:border-primary-500 - dark:focus-within:ring-primary-500 sm:text-sm + focus-within:ring-1 focus-within:ring-primary-500 sm:text-sm dark:border-gray-800 + dark:bg-gray-800 dark:text-gray-100 dark:ring-1 dark:ring-gray-800 dark:placeholder:text-gray-600 + dark:focus-within:border-primary-500 dark:focus-within:ring-primary-500 `} > {(!!attachments?.length || isUploading) && ( diff --git a/src/features/edit-profile/components/header-picker.tsx b/src/features/edit-profile/components/header-picker.tsx index 13f555844..3176876c6 100644 --- a/src/features/edit-profile/components/header-picker.tsx +++ b/src/features/edit-profile/components/header-picker.tsx @@ -36,7 +36,7 @@ const HeaderPicker = React.forwardRef(({ src, onC