diff --git a/fluxer_app/src/features/app/components/dialogs/shared/ForwardChannelEligibility.test.ts b/fluxer_app/src/features/app/components/dialogs/shared/ForwardChannelEligibility.test.ts deleted file mode 100644 index 6446cb388..000000000 --- a/fluxer_app/src/features/app/components/dialogs/shared/ForwardChannelEligibility.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later - -import {isForwardableChannelType} from '@app/features/app/components/dialogs/shared/ForwardChannelEligibility'; -import {ChannelTypes} from '@fluxer/constants/src/ChannelConstants'; -import {describe, expect, it} from 'vitest'; - -describe('forward channel eligibility', () => { - it('allows every text-based message destination, including text-in-voice channels', () => { - expect(isForwardableChannelType(ChannelTypes.GUILD_TEXT)).toBe(true); - expect(isForwardableChannelType(ChannelTypes.GUILD_VOICE)).toBe(true); - expect(isForwardableChannelType(ChannelTypes.DM)).toBe(true); - expect(isForwardableChannelType(ChannelTypes.GROUP_DM)).toBe(true); - expect(isForwardableChannelType(ChannelTypes.DM_PERSONAL_NOTES)).toBe(true); - }); - it('rejects non-message destinations', () => { - expect(isForwardableChannelType(ChannelTypes.GUILD_CATEGORY)).toBe(false); - expect(isForwardableChannelType(ChannelTypes.GUILD_LINK)).toBe(false); - expect(isForwardableChannelType(-1)).toBe(false); - }); -}); diff --git a/fluxer_app/src/features/app/components/dialogs/shared/ForwardChannelEligibility.ts b/fluxer_app/src/features/app/components/dialogs/shared/ForwardChannelEligibility.ts deleted file mode 100644 index 1265339fa..000000000 --- a/fluxer_app/src/features/app/components/dialogs/shared/ForwardChannelEligibility.ts +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later - -import {TEXT_BASED_CHANNEL_TYPES} from '@fluxer/constants/src/ChannelConstants'; - -export function isForwardableChannelType(channelType: number): boolean { - return TEXT_BASED_CHANNEL_TYPES.has(channelType); -} diff --git a/fluxer_app/src/features/app/components/dialogs/shared/ForwardChannelIndex.test.ts b/fluxer_app/src/features/app/components/dialogs/shared/ForwardChannelIndex.test.ts deleted file mode 100644 index e93bf6240..000000000 --- a/fluxer_app/src/features/app/components/dialogs/shared/ForwardChannelIndex.test.ts +++ /dev/null @@ -1,87 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later - -import { - ForwardChannelIndex, - type ForwardChannelObservation, -} from '@app/features/app/components/dialogs/shared/ForwardChannelIndex'; -import type {Channel} from '@app/features/channel/models/Channel'; -import type {User} from '@app/features/user/models/User'; -import {ChannelTypes} from '@fluxer/constants/src/ChannelConstants'; -import {setupI18n} from '@lingui/core'; -import {describe, expect, it, vi} from 'vitest'; - -vi.mock('@lingui/core/macro', () => ({msg: (descriptor: unknown) => descriptor})); -vi.mock('@app/features/channel/components/SlowmodeIndicator', () => ({formatSlowmodeTime: () => ''})); -vi.mock('@app/features/permissions/utils/PermissionUtils', () => ({formatPermissionLabel: () => ''})); - -const i18n = setupI18n({locale: 'en', messages: {en: {}}}); - -function observation(overrides: Partial): ForwardChannelObservation { - return { - canAttachFiles: true, - canEmbedLinks: true, - canSendMessages: true, - categoryName: null, - channel: null, - displayName: '', - guildMessagesDisabled: false, - guildName: null, - key: '', - memberTimedOut: false, - recipient: null, - searchAliases: [], - slowmodeEnabled: false, - slowmodeRemainingMs: 0, - ...overrides, - }; -} - -const general = observation({ - channel: {id: 'channel-1', name: 'general', type: ChannelTypes.GUILD_TEXT} as unknown as Channel, - displayName: 'general', - key: 'channel-1', -}); -const closedFriendDM = observation({ - displayName: 'Ada Lovelace', - key: 'user:user-1', - recipient: {id: 'user-1'} as unknown as User, - searchAliases: ['ada_dev'], -}); - -function buildIndex(observations: ReadonlyArray): ForwardChannelIndex { - return new ForwardChannelIndex({ - excludedChannelId: 'channel-1', - i18n, - mediaSelection: {hasAttachments: true, hasEmbeds: true}, - observations, - recentChannelIds: [], - }); -} - -describe('forward channel index', () => { - it('lists a friend whose DM is closed ahead of the source channel', () => { - const keys = buildIndex([general, closedFriendDM]) - .filter('') - .map((option) => option.key); - expect(keys).toEqual(['user:user-1', 'channel-1']); - }); - - it('finds a friend whose DM is closed by username', () => { - const matches = buildIndex([general, closedFriendDM]).filter('ada_dev'); - expect(matches.map((option) => option.key)).toEqual(['user:user-1']); - expect(matches[0]?.channel).toBeNull(); - expect(matches[0]?.disableReason).toBeNull(); - }); - - it('selects destinations by key', () => { - const selected = buildIndex([general, closedFriendDM]).select(new Set(['user:user-1', 'channel-1', 'missing'])); - expect(selected.map((option) => option.key)).toEqual(['user:user-1', 'channel-1']); - }); - - it('drops an observation with neither a channel nor a recipient', () => { - const keys = buildIndex([observation({displayName: 'ghost', key: 'user:ghost'})]) - .filter('') - .map((option) => option.key); - expect(keys).toEqual([]); - }); -}); diff --git a/fluxer_app/src/features/app/components/dialogs/shared/ForwardChannelIndex.ts b/fluxer_app/src/features/app/components/dialogs/shared/ForwardChannelIndex.ts deleted file mode 100644 index 7a339452d..000000000 --- a/fluxer_app/src/features/app/components/dialogs/shared/ForwardChannelIndex.ts +++ /dev/null @@ -1,293 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later - -import {isForwardableChannelType} from '@app/features/app/components/dialogs/shared/ForwardChannelEligibility'; -import {matchesForwardChannelSearch} from '@app/features/app/components/dialogs/shared/ForwardChannelSearchMatch'; -import {formatSlowmodeTime} from '@app/features/channel/components/SlowmodeIndicator'; -import type {Channel} from '@app/features/channel/models/Channel'; -import {PERSONAL_NOTES_DESCRIPTOR} from '@app/features/i18n/utils/CommonMessageDescriptors'; -import type {Message} from '@app/features/messaging/models/MessagingMessage'; -import {formatPermissionLabel} from '@app/features/permissions/utils/PermissionUtils'; -import type {User} from '@app/features/user/models/User'; -import {ChannelTypes, Permissions} from '@fluxer/constants/src/ChannelConstants'; -import type {I18n} from '@lingui/core'; -import {msg} from '@lingui/core/macro'; - -const GUILD_MESSAGES_DISABLED_DESCRIPTOR = msg({ - message: 'Sending messages is disabled in this community', - comment: 'Short label in the settings dialog forward channel selection.', -}); -const MEMBER_TIMED_OUT_DESCRIPTOR = msg({ - message: "You're timed out in this community", - comment: 'Short label in the settings dialog forward channel selection. Keep the tone plain and specific.', -}); -const SEND_MESSAGES_PERMISSION_REQUIRED_DESCRIPTOR = msg({ - message: 'You need the "{sendMessagesPermissionLabel}" permission to send messages in this channel', - comment: - 'Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated.', -}); -const EMBED_LINKS_PERMISSION_REQUIRED_DESCRIPTOR = msg({ - message: 'You need the "{embedLinksPermissionLabel}" permission to embed links in this channel', - comment: - 'Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel.', -}); -const ATTACH_FILES_PERMISSION_REQUIRED_DESCRIPTOR = msg({ - message: 'You need the "{attachFilesPermissionLabel}" permission to attach files in this channel', - comment: - 'Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel.', -}); -const SLOWMODE_WAIT_DESCRIPTOR = msg({ - message: 'Slowmode · wait {remaining}', - comment: - 'Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code.', -}); - -const FORWARD_CHANNEL_RESULT_LIMIT = 100; - -export interface ForwardMessageMediaSelection { - readonly hasAttachments: boolean; - readonly hasEmbeds: boolean; -} - -interface ResolveForwardMessageMediaSelectionArgs { - readonly message: Message; - readonly override: ForwardMessageMediaSelection | undefined; -} - -function hasSnapshotAttachments(message: Message): boolean { - if (message.attachments.length > 0) return true; - const snapshots = message.messageSnapshots; - if (snapshots === undefined) return false; - return snapshots.some((snapshot) => { - const attachments = snapshot.attachments; - return attachments != null && attachments.length > 0; - }); -} - -function hasSnapshotEmbeds(message: Message): boolean { - if (message.embeds.length > 0) return true; - const snapshots = message.messageSnapshots; - if (snapshots === undefined) return false; - return snapshots.some((snapshot) => { - const embeds = snapshot.embeds; - return embeds != null && embeds.length > 0; - }); -} - -export function resolveForwardMessageMediaSelection({ - message, - override, -}: ResolveForwardMessageMediaSelectionArgs): ForwardMessageMediaSelection { - if (override !== undefined) return override; - return Object.freeze({ - hasAttachments: hasSnapshotAttachments(message), - hasEmbeds: hasSnapshotEmbeds(message), - }); -} - -export interface ForwardChannelObservation { - readonly canAttachFiles: boolean; - readonly canEmbedLinks: boolean; - readonly canSendMessages: boolean; - readonly categoryName: string | null; - readonly channel: Channel | null; - readonly displayName: string; - readonly guildMessagesDisabled: boolean; - readonly guildName: string | null; - readonly key: string; - readonly memberTimedOut: boolean; - readonly recipient: User | null; - readonly searchAliases: ReadonlyArray; - readonly slowmodeEnabled: boolean; - readonly slowmodeRemainingMs: number; -} - -export interface ForwardChannelOption { - readonly categoryName: string | null; - readonly channel: Channel | null; - readonly disableReason: string | null; - readonly displayName: string; - readonly guildName: string | null; - readonly key: string; - readonly recipient: User | null; - readonly slowmodeEnabled: boolean; - readonly slowmodeRemainingMs: number; -} - -interface IndexedForwardChannelOption extends ForwardChannelOption { - readonly channelNameSearchValue: string; - readonly displayNameSearchValue: string; - readonly guildNameSearchValue: string; - readonly isPersonalNotes: boolean; - readonly isSource: boolean; - readonly recentRank: number | null; - readonly searchAliasValues: ReadonlyArray; -} - -interface BuildForwardChannelIndexRequest { - readonly excludedChannelId: string; - readonly i18n: I18n; - readonly mediaSelection: ForwardMessageMediaSelection; - readonly observations: ReadonlyArray; - readonly recentChannelIds: ReadonlyArray; -} - -interface ForwardChannelSelectionDisabledRequest { - readonly maxSelections: number; - readonly option: ForwardChannelOption; - readonly selectedKeys: ReadonlySet; -} - -function isForwardableObservation(observation: ForwardChannelObservation): boolean { - if (observation.channel == null) return observation.recipient != null; - return isForwardableChannelType(observation.channel.type); -} - -export class ForwardChannelIndex { - private readonly i18n: I18n; - private readonly options: ReadonlyArray; - private readonly optionsByKey: ReadonlyMap; - - constructor({ - excludedChannelId, - i18n, - mediaSelection, - observations, - recentChannelIds, - }: BuildForwardChannelIndexRequest) { - this.i18n = i18n; - const recentRanks = ForwardChannelIndex.buildRecentRanks(recentChannelIds); - const options = observations - .filter(isForwardableObservation) - .map((observation) => this.buildOption({excludedChannelId, mediaSelection, observation, recentRanks})); - options.sort((left, right) => this.compareOptions(left, right)); - this.options = Object.freeze(options); - this.optionsByKey = new Map(options.map((option) => [option.key, option])); - } - - filter(searchQuery: string): ReadonlyArray { - if (searchQuery.trim().length === 0) { - return this.options.slice(0, FORWARD_CHANNEL_RESULT_LIMIT); - } - const normalizedQuery = searchQuery.toLowerCase(); - const personalNotesSearchValue = this.i18n._(PERSONAL_NOTES_DESCRIPTOR).toLowerCase(); - const matches: Array = []; - for (const option of this.options) { - if (!ForwardChannelIndex.matchesSearch({normalizedQuery, personalNotesSearchValue, option})) continue; - matches.push(option); - if (matches.length === FORWARD_CHANNEL_RESULT_LIMIT) break; - } - return matches; - } - - isSelectionDisabled({maxSelections, option, selectedKeys}: ForwardChannelSelectionDisabledRequest): boolean { - if (option.disableReason != null) return true; - if (selectedKeys.has(option.key)) return false; - return selectedKeys.size >= maxSelections; - } - - select(selectedKeys: ReadonlySet): ReadonlyArray { - const selected: Array = []; - for (const key of selectedKeys) { - const option = this.optionsByKey.get(key); - if (option != null) selected.push(option); - } - return selected; - } - - private static buildRecentRanks(recentChannelIds: ReadonlyArray): ReadonlyMap { - return new Map(recentChannelIds.map((channelId, index) => [channelId, index])); - } - - private static matchesSearch({ - normalizedQuery, - personalNotesSearchValue, - option, - }: { - readonly normalizedQuery: string; - readonly personalNotesSearchValue: string; - readonly option: IndexedForwardChannelOption; - }): boolean { - return matchesForwardChannelSearch({normalizedQuery, personalNotesSearchValue, values: option}); - } - - private buildOption({ - excludedChannelId, - mediaSelection, - observation, - recentRanks, - }: { - readonly excludedChannelId: string; - readonly mediaSelection: ForwardMessageMediaSelection; - readonly observation: ForwardChannelObservation; - readonly recentRanks: ReadonlyMap; - }): IndexedForwardChannelOption { - const permissionIssue = this.resolvePermissionIssue(observation, mediaSelection); - const disableReason = this.resolveDisableReason(observation, permissionIssue); - let recentRankValue: number | undefined; - if (observation.channel != null) recentRankValue = recentRanks.get(observation.channel.id); - let recentRank: number | null = null; - if (recentRankValue !== undefined) recentRank = recentRankValue; - const channel = observation.channel; - let channelNameSearchValue = ''; - if (channel?.name) channelNameSearchValue = channel.name.toLowerCase(); - let guildNameSearchValue = ''; - if (observation.guildName != null) guildNameSearchValue = observation.guildName.toLowerCase(); - return Object.freeze({ - categoryName: observation.categoryName, - channel, - channelNameSearchValue, - disableReason, - displayName: observation.displayName, - displayNameSearchValue: observation.displayName.toLowerCase(), - guildName: observation.guildName, - guildNameSearchValue, - isPersonalNotes: channel != null && channel.type === ChannelTypes.DM_PERSONAL_NOTES, - isSource: channel != null && channel.id === excludedChannelId, - key: observation.key, - recentRank, - recipient: observation.recipient, - searchAliasValues: Object.freeze(observation.searchAliases.map((alias) => alias.toLowerCase())), - slowmodeEnabled: observation.slowmodeEnabled, - slowmodeRemainingMs: observation.slowmodeRemainingMs, - }); - } - - private compareOptions(left: IndexedForwardChannelOption, right: IndexedForwardChannelOption): number { - if (left.isSource !== right.isSource) return left.isSource ? 1 : -1; - const leftUnavailable = left.disableReason != null; - const rightUnavailable = right.disableReason != null; - if (leftUnavailable !== rightUnavailable) return leftUnavailable ? 1 : -1; - if (left.recentRank != null && right.recentRank != null) return left.recentRank - right.recentRank; - if (left.recentRank != null) return -1; - if (right.recentRank != null) return 1; - return left.displayNameSearchValue.localeCompare(right.displayNameSearchValue); - } - - private resolveDisableReason(observation: ForwardChannelObservation, permissionIssue: string | null): string | null { - if (permissionIssue != null) return permissionIssue; - if (observation.slowmodeRemainingMs <= 0) return null; - const remaining = formatSlowmodeTime(observation.slowmodeRemainingMs, this.i18n.locale); - return this.i18n._(SLOWMODE_WAIT_DESCRIPTOR, {remaining}); - } - - private resolvePermissionIssue( - observation: ForwardChannelObservation, - mediaSelection: ForwardMessageMediaSelection, - ): string | null { - if (observation.guildMessagesDisabled) return this.i18n._(GUILD_MESSAGES_DISABLED_DESCRIPTOR); - if (observation.memberTimedOut) return this.i18n._(MEMBER_TIMED_OUT_DESCRIPTOR); - if (!observation.canSendMessages) { - const sendMessagesPermissionLabel = formatPermissionLabel(this.i18n, Permissions.SEND_MESSAGES); - return this.i18n._(SEND_MESSAGES_PERMISSION_REQUIRED_DESCRIPTOR, {sendMessagesPermissionLabel}); - } - if (mediaSelection.hasEmbeds && !observation.canEmbedLinks) { - const embedLinksPermissionLabel = formatPermissionLabel(this.i18n, Permissions.EMBED_LINKS); - return this.i18n._(EMBED_LINKS_PERMISSION_REQUIRED_DESCRIPTOR, {embedLinksPermissionLabel}); - } - if (mediaSelection.hasAttachments && !observation.canAttachFiles) { - const attachFilesPermissionLabel = formatPermissionLabel(this.i18n, Permissions.ATTACH_FILES); - return this.i18n._(ATTACH_FILES_PERMISSION_REQUIRED_DESCRIPTOR, {attachFilesPermissionLabel}); - } - return null; - } -} diff --git a/fluxer_app/src/features/app/components/dialogs/shared/ForwardChannelSearch.test.ts b/fluxer_app/src/features/app/components/dialogs/shared/ForwardChannelSearch.test.ts deleted file mode 100644 index 3f0e80f1a..000000000 --- a/fluxer_app/src/features/app/components/dialogs/shared/ForwardChannelSearch.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later - -import { - type ForwardChannelSearchValues, - matchesForwardChannelSearch, -} from '@app/features/app/components/dialogs/shared/ForwardChannelSearchMatch'; -import {describe, expect, it} from 'vitest'; - -const PERSONAL_NOTES = 'personal notes'; - -function recipient(overrides: Partial = {}): ForwardChannelSearchValues { - return { - channelNameSearchValue: '', - displayNameSearchValue: 'ada lovelace', - guildNameSearchValue: '', - isPersonalNotes: false, - searchAliasValues: ['ada_dev', 'ada lovelace', 'countess', 'raid lead'], - ...overrides, - }; -} - -function matches(query: string, values: ForwardChannelSearchValues = recipient()): boolean { - return matchesForwardChannelSearch({ - normalizedQuery: query, - personalNotesSearchValue: PERSONAL_NOTES, - values, - }); -} - -describe('forward channel search matching', () => { - it('matches the rendered global display name', () => { - expect(matches('ada lovelace')).toBe(true); - }); - - it('matches the username', () => { - expect(matches('ada_dev')).toBe(true); - }); - - it('matches a nickname from a guild the reader is not currently viewing', () => { - expect(matches('raid lead')).toBe(true); - }); - - it('matches a relationship nickname', () => { - expect(matches('countess')).toBe(true); - }); - - it('does not match an unrelated query', () => { - expect(matches('grace hopper')).toBe(false); - }); - - it('does not match a recipient with no aliases indexed beyond the display name', () => { - const values = recipient({searchAliasValues: []}); - expect(matches('ada_dev', values)).toBe(false); - expect(matches('ada lovelace', values)).toBe(true); - }); - - it('still matches channel and guild names', () => { - const guildChannel = recipient({ - channelNameSearchValue: 'general', - displayNameSearchValue: 'general', - guildNameSearchValue: 'fluxer hq', - searchAliasValues: [], - }); - expect(matches('general', guildChannel)).toBe(true); - expect(matches('fluxer hq', guildChannel)).toBe(true); - }); - - it('still matches personal notes', () => { - const notes = recipient({displayNameSearchValue: '', isPersonalNotes: true, searchAliasValues: []}); - expect(matches('personal', notes)).toBe(true); - }); -}); diff --git a/fluxer_app/src/features/app/components/dialogs/shared/ForwardChannelSearchMatch.ts b/fluxer_app/src/features/app/components/dialogs/shared/ForwardChannelSearchMatch.ts deleted file mode 100644 index a01211709..000000000 --- a/fluxer_app/src/features/app/components/dialogs/shared/ForwardChannelSearchMatch.ts +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later - -export interface ForwardChannelSearchValues { - readonly channelNameSearchValue: string; - readonly displayNameSearchValue: string; - readonly guildNameSearchValue: string; - readonly isPersonalNotes: boolean; - readonly searchAliasValues: ReadonlyArray; -} - -interface MatchesForwardChannelSearchRequest { - readonly normalizedQuery: string; - readonly personalNotesSearchValue: string; - readonly values: ForwardChannelSearchValues; -} - -export function matchesForwardChannelSearch({ - normalizedQuery, - personalNotesSearchValue, - values, -}: MatchesForwardChannelSearchRequest): boolean { - if (values.isPersonalNotes && personalNotesSearchValue.includes(normalizedQuery)) return true; - if (values.displayNameSearchValue.includes(normalizedQuery)) return true; - if (values.channelNameSearchValue.includes(normalizedQuery)) return true; - if (values.searchAliasValues.some((alias) => alias.includes(normalizedQuery))) return true; - return values.guildNameSearchValue.includes(normalizedQuery); -} diff --git a/fluxer_app/src/features/app/components/dialogs/shared/ForwardChannelSelection.ts b/fluxer_app/src/features/app/components/dialogs/shared/ForwardChannelSelection.ts deleted file mode 100644 index 52e46b6c9..000000000 --- a/fluxer_app/src/features/app/components/dialogs/shared/ForwardChannelSelection.ts +++ /dev/null @@ -1,122 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later - -import { - ForwardChannelIndex, - type ForwardChannelOption, - type ForwardMessageMediaSelection, - resolveForwardMessageMediaSelection, -} from '@app/features/app/components/dialogs/shared/ForwardChannelIndex'; -import {useForwardChannelObservations} from '@app/features/app/components/dialogs/shared/UseForwardChannelObservations'; -import {useShallowStableArray} from '@app/features/app/hooks/useShallowStableArray'; -import type {Channel} from '@app/features/channel/models/Channel'; -import Channels from '@app/features/channel/state/Channels'; -import type {Message} from '@app/features/messaging/models/MessagingMessage'; -import SelectedChannel from '@app/features/navigation/state/SelectedChannel'; -import Users from '@app/features/user/state/Users'; -import {useLingui} from '@lingui/react/macro'; -import {type Dispatch, type SetStateAction, useCallback, useMemo, useState} from 'react'; - -interface UseForwardChannelSelectionOptions { - readonly excludedChannelId: string; - readonly message: Message; - readonly maxSelections?: number; - readonly mediaSelection?: ForwardMessageMediaSelection; -} - -export interface ForwardChannelSelectionState { - readonly filteredChannels: ReadonlyArray; - readonly handleToggleChannel: (key: string) => void; - readonly isChannelSelectionDisabled: (option: ForwardChannelOption) => boolean; - readonly maxSelections: number; - readonly mostRecentlySelectedChannel: Channel | null; - readonly searchQuery: string; - readonly selectedChannelOptions: ReadonlyArray; - readonly selectedKeys: ReadonlySet; - readonly setSearchQuery: Dispatch>; - readonly slowmodeActiveSelectedChannelOptions: ReadonlyArray; - readonly slowmodeEnabledSelectedChannelOptions: ReadonlyArray; -} - -function toggleForwardChannelSelection(key: string, maxSelections: number, previousKeys: Set): Set { - const nextKeys = new Set(previousKeys); - if (nextKeys.has(key)) { - nextKeys.delete(key); - return nextKeys; - } - if (nextKeys.size >= maxSelections) return previousKeys; - nextKeys.add(key); - return nextKeys; -} - -export function useForwardChannelSelection({ - excludedChannelId, - message, - maxSelections = 5, - mediaSelection, -}: UseForwardChannelSelectionOptions): ForwardChannelSelectionState { - const {i18n} = useLingui(); - const locale = i18n.locale; - const allKnownChannels = useShallowStableArray(Channels.allChannels); - const recentChannelIds = useShallowStableArray(SelectedChannel.recentChannels); - const currentUser = Users.currentUser; - const currentUserId = currentUser ? currentUser.id : null; - const resolvedMediaSelection = useMemo( - () => resolveForwardMessageMediaSelection({message, override: mediaSelection}), - [message, mediaSelection], - ); - const observations = useForwardChannelObservations({channels: allKnownChannels, currentUserId, i18n}); - const channelIndex = useMemo( - () => - new ForwardChannelIndex({ - excludedChannelId, - i18n, - mediaSelection: resolvedMediaSelection, - observations, - recentChannelIds, - }), - [excludedChannelId, i18n, locale, observations, recentChannelIds, resolvedMediaSelection], - ); - const [searchQuery, setSearchQuery] = useState(''); - const [selectedKeys, setSelectedKeys] = useState>(new Set()); - const filteredChannels = useMemo(() => channelIndex.filter(searchQuery), [channelIndex, searchQuery]); - const handleToggleChannel = useCallback( - (key: string) => { - setSelectedKeys((previousKeys) => toggleForwardChannelSelection(key, maxSelections, previousKeys)); - }, - [maxSelections], - ); - const isChannelSelectionDisabled = useCallback( - (option: ForwardChannelOption) => channelIndex.isSelectionDisabled({maxSelections, option, selectedKeys}), - [maxSelections, channelIndex, selectedKeys], - ); - const selectedChannelOptions = useMemo(() => channelIndex.select(selectedKeys), [channelIndex, selectedKeys]); - const slowmodeEnabledSelectedChannelOptions = useMemo( - () => selectedChannelOptions.filter((option) => option.slowmodeEnabled), - [selectedChannelOptions], - ); - const slowmodeActiveSelectedChannelOptions = useMemo( - () => selectedChannelOptions.filter((option) => option.slowmodeRemainingMs > 0), - [selectedChannelOptions], - ); - const mostRecentlySelectedChannel = useMemo(() => { - let mostRecent: Channel | null = null; - for (const option of selectedChannelOptions) { - mostRecent = option.channel; - } - return mostRecent; - }, [selectedChannelOptions]); - - return { - filteredChannels, - handleToggleChannel, - isChannelSelectionDisabled, - maxSelections, - mostRecentlySelectedChannel, - searchQuery, - selectedChannelOptions, - selectedKeys, - setSearchQuery, - slowmodeActiveSelectedChannelOptions, - slowmodeEnabledSelectedChannelOptions, - }; -} diff --git a/fluxer_app/src/features/app/components/dialogs/shared/ForwardDefaultDestinations.test.ts b/fluxer_app/src/features/app/components/dialogs/shared/ForwardDefaultDestinations.test.ts new file mode 100644 index 000000000..3441ba9d0 --- /dev/null +++ b/fluxer_app/src/features/app/components/dialogs/shared/ForwardDefaultDestinations.test.ts @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +import { + buildForwardDefaultDestinations, + type ForwardDestination, + type ForwardDestinationRow, + type ForwardRowIdentity, + filterForwardSearchRows, + resolveForwardOrigin, +} from '@app/features/app/components/dialogs/shared/ForwardDefaultDestinations'; +import type {ForwardResultType} from '@app/features/app/components/dialogs/shared/ForwardDestinationQuery'; +import {ChannelTypes} from '@fluxer/constants/src/ChannelConstants'; +import {describe, expect, it} from 'vitest'; + +const DM_RECIPIENTS: ReadonlyMap = new Map([['dm-1', 'user-1']]); +const KNOWN_USERS: ReadonlySet = new Set(['user-1', 'user-9']); +const INVALID_IDS: ReadonlySet = new Set(['text-blocked']); + +function channelType(channelId: string): ForwardResultType | null { + if (channelId.startsWith('text-')) return 'text_channel'; + if (channelId.startsWith('voice-')) return 'voice_channel'; + if (channelId.startsWith('gdm-')) return 'group_dm'; + return null; +} + +function resolveChannel(channelId: string): ForwardRowIdentity | null { + const recipientId = DM_RECIPIENTS.get(channelId); + if (recipientId !== undefined) return {id: recipientId, type: 'user'}; + const type = channelType(channelId); + return type == null ? null : {id: channelId, type}; +} + +function resolveDestination(destination: ForwardDestination): ForwardRowIdentity | null { + if (destination.type === 'channel') return resolveChannel(destination.id); + return KNOWN_USERS.has(destination.id) ? {id: destination.id, type: 'user'} : null; +} + +function isValid(row: ForwardRowIdentity): boolean { + return !INVALID_IDS.has(row.id); +} + +interface DefaultsOverrides { + readonly frequentIds?: ReadonlyArray; + readonly history?: ReadonlyArray; + readonly mode?: ForwardResultType | null; + readonly origin?: ForwardDestination | null; + readonly pinned?: ReadonlyArray; + readonly selected?: ReadonlyArray; +} + +function defaults(overrides: DefaultsOverrides): ReadonlyArray { + const rows = buildForwardDefaultDestinations({ + frequentIds: [], + history: [], + isValid, + mode: null, + origin: null, + pinned: [], + resolveChannel, + resolveDestination, + selected: [], + ...overrides, + }); + return rows.map((row) => `${row.type}:${row.id}`); +} + +function channelIds(prefix: string, count: number): ReadonlyArray { + return Array.from({length: count}, (_, index) => `${prefix}-${index}`); +} + +describe('buildForwardDefaultDestinations', () => { + it('lists pinned destinations, then history, then frecency, keeping the first copy of each', () => { + expect( + defaults({ + frequentIds: ['voice-1', 'guild-1', 'text-1', 'gdm-1'], + history: ['text-1', 'text-2', 'dm-1'], + pinned: [ + {id: 'text-2', type: 'channel'}, + {id: 'user-9', type: 'user'}, + ], + }), + ).toEqual([ + 'text_channel:text-2', + 'user:user-9', + 'text_channel:text-1', + 'user:user-1', + 'voice_channel:voice-1', + 'group_dm:gdm-1', + ]); + }); + + it('drops unknown users, unresolvable ids and invalid rows', () => { + expect( + defaults({ + frequentIds: ['guild-1', 'text-blocked', 'text-1'], + pinned: [{id: 'user-unknown', type: 'user'}], + }), + ).toEqual(['text_channel:text-1']); + }); + + it('hides the origin channel unless it is selected', () => { + const origin: ForwardDestination = {id: 'text-1', type: 'channel'}; + expect(defaults({history: ['text-1', 'text-2'], origin})).toEqual(['text_channel:text-2']); + expect(defaults({history: ['text-1', 'text-2'], origin, selected: [origin]})).toEqual([ + 'text_channel:text-1', + 'text_channel:text-2', + ]); + }); + + it('hides the recipient of a DM origin', () => { + const origin = resolveForwardOrigin('dm-1', {recipientIds: ['user-1'], type: ChannelTypes.DM}); + expect(origin).toEqual({id: 'user-1', type: 'user'}); + expect(defaults({history: ['dm-1', 'text-1'], origin})).toEqual(['text_channel:text-1']); + }); + + it('caps the list at 15 rows', () => { + expect(defaults({frequentIds: channelIds('text', 20)})).toEqual( + channelIds('text', 15).map((id) => `text_channel:${id}`), + ); + }); + + it('filters to the mode without a cap', () => { + const frequentIds = [...channelIds('text', 20), 'dm-1', 'voice-1']; + expect(defaults({frequentIds, mode: 'text_channel'})).toEqual( + channelIds('text', 20).map((id) => `text_channel:${id}`), + ); + expect(defaults({frequentIds, mode: 'user'})).toEqual(['user:user-1']); + }); + + it('reads at most 8 history entries and 100 frecency entries', () => { + const history = channelIds('text-h', 10); + const frequentIds = channelIds('text-f', 120); + const rows = defaults({frequentIds, history, mode: 'text_channel'}); + expect(rows).toHaveLength(108); + expect(rows).not.toContain('text_channel:text-h-8'); + expect(rows).not.toContain('text_channel:text-f-100'); + }); + + it('maps each row to the destination the selection stores', () => { + const rows = buildForwardDefaultDestinations({ + frequentIds: ['dm-1', 'gdm-1', 'voice-1'], + history: [], + isValid, + mode: null, + origin: null, + pinned: [], + resolveChannel, + resolveDestination, + selected: [], + }); + expect(rows.map((row) => row.destination)).toEqual([ + {id: 'user-1', type: 'user'}, + {id: 'gdm-1', type: 'channel'}, + {id: 'voice-1', type: 'channel'}, + ]); + }); +}); + +describe('resolveForwardOrigin', () => { + it('uses the channel for anything but a DM', () => { + expect(resolveForwardOrigin('text-1', {recipientIds: [], type: ChannelTypes.GUILD_TEXT})).toEqual({ + id: 'text-1', + type: 'channel', + }); + expect(resolveForwardOrigin('gdm-1', {recipientIds: ['user-1', 'user-9'], type: ChannelTypes.GROUP_DM})).toEqual({ + id: 'gdm-1', + type: 'channel', + }); + expect(resolveForwardOrigin('text-1', null)).toEqual({id: 'text-1', type: 'channel'}); + }); +}); + +describe('filterForwardSearchRows', () => { + it('drops invalid rows and duplicate ids without a cap or origin exclusion', () => { + const results: ReadonlyArray = [ + {id: 'user-1', type: 'user'}, + {id: 'text-blocked', type: 'text_channel'}, + {id: 'text-1', type: 'text_channel'}, + {id: 'text-1', type: 'voice_channel'}, + ...channelIds('text-x', 30).map((id): ForwardRowIdentity => ({id, type: 'text_channel'})), + ]; + const rows: ReadonlyArray = filterForwardSearchRows(results, isValid); + expect(rows).toHaveLength(32); + expect(rows.slice(0, 2)).toEqual([ + {destination: {id: 'user-1', type: 'user'}, id: 'user-1', type: 'user'}, + {destination: {id: 'text-1', type: 'channel'}, id: 'text-1', type: 'text_channel'}, + ]); + }); +}); diff --git a/fluxer_app/src/features/app/components/dialogs/shared/ForwardDefaultDestinations.ts b/fluxer_app/src/features/app/components/dialogs/shared/ForwardDefaultDestinations.ts new file mode 100644 index 000000000..6483c38b5 --- /dev/null +++ b/fluxer_app/src/features/app/components/dialogs/shared/ForwardDefaultDestinations.ts @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +import type {ForwardResultType} from '@app/features/app/components/dialogs/shared/ForwardDestinationQuery'; +import {ChannelTypes} from '@fluxer/constants/src/ChannelConstants'; + +const DEFAULT_DESTINATION_LIMIT = 15; +const HISTORY_LIMIT = 8; +const FREQUENT_LIMIT = 100; + +export interface ForwardDestination { + readonly id: string; + readonly type: 'user' | 'channel'; +} + +export interface ForwardRowIdentity { + readonly id: string; + readonly type: ForwardResultType; +} + +export interface ForwardDestinationRow extends ForwardRowIdentity { + readonly destination: ForwardDestination; +} + +interface ForwardOriginChannel { + readonly recipientIds: ReadonlyArray; + readonly type: number; +} + +interface BuildForwardDefaultDestinationsRequest { + readonly frequentIds: ReadonlyArray; + readonly history: ReadonlyArray; + readonly isValid: (row: ForwardRowIdentity) => boolean; + readonly mode: ForwardResultType | null; + readonly origin: ForwardDestination | null; + readonly pinned: ReadonlyArray; + readonly resolveChannel: (channelId: string) => ForwardRowIdentity | null; + readonly resolveDestination: (destination: ForwardDestination) => ForwardRowIdentity | null; + readonly selected: ReadonlyArray; +} + +export function resolveForwardOrigin( + channelId: string, + channel: ForwardOriginChannel | null | undefined, +): ForwardDestination { + if (channel != null && channel.type === ChannelTypes.DM && channel.recipientIds.length > 0) { + return Object.freeze({id: channel.recipientIds[0], type: 'user'}); + } + return Object.freeze({id: channelId, type: 'channel'}); +} + +export function buildForwardDefaultDestinations({ + frequentIds, + history, + isValid, + mode, + origin, + pinned, + resolveChannel, + resolveDestination, + selected, +}: BuildForwardDefaultDestinationsRequest): ReadonlyArray { + const candidates = [ + ...pinned.map((destination) => resolveDestination(destination)), + ...history.slice(0, HISTORY_LIMIT).map((channelId) => resolveChannel(channelId)), + ...frequentIds.slice(0, FREQUENT_LIMIT).map((channelId) => resolveChannel(channelId)), + ]; + const rows = candidates.filter((row): row is ForwardRowIdentity => row != null && isValid(row)); + const originSelected = + origin != null && selected.some((destination) => destination.type === origin.type && destination.id === origin.id); + const hiddenIds = origin == null || originSelected ? [] : [origin.id]; + if (mode != null) { + return dedupeRows( + rows.filter((row) => row.type === mode), + hiddenIds, + ); + } + return dedupeRows(rows, hiddenIds).slice(0, DEFAULT_DESTINATION_LIMIT); +} + +export function filterForwardSearchRows( + results: ReadonlyArray, + isValid: (row: ForwardRowIdentity) => boolean, +): ReadonlyArray { + return dedupeRows( + results.filter((result) => isValid(result)), + [], + ); +} + +function dedupeRows( + rows: ReadonlyArray, + hiddenIds: ReadonlyArray, +): Array { + const seenIds = new Set(hiddenIds); + const deduped: Array = []; + for (const {id, type} of rows) { + if (seenIds.has(id)) continue; + seenIds.add(id); + const destination: ForwardDestination = Object.freeze({id, type: type === 'user' ? 'user' : 'channel'}); + deduped.push(Object.freeze({destination, id, type})); + } + return deduped; +} diff --git a/fluxer_app/src/features/app/components/dialogs/shared/ForwardDestinationQuery.test.ts b/fluxer_app/src/features/app/components/dialogs/shared/ForwardDestinationQuery.test.ts new file mode 100644 index 000000000..3d8a39a4b --- /dev/null +++ b/fluxer_app/src/features/app/components/dialogs/shared/ForwardDestinationQuery.test.ts @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +import {parseForwardDestinationQuery} from '@app/features/app/components/dialogs/shared/ForwardDestinationQuery'; +import {describe, expect, it} from 'vitest'; + +const ALL_TYPES = ['user', 'text_channel', 'voice_channel', 'group_dm']; + +describe('parseForwardDestinationQuery', () => { + it('searches every destination type without a sigil', () => { + expect(parseForwardDestinationQuery('general')).toEqual({mode: null, query: 'general', resultTypes: ALL_TYPES}); + expect(parseForwardDestinationQuery('')).toEqual({mode: null, query: '', resultTypes: ALL_TYPES}); + }); + + it('narrows to one type for the @, # and ! sigils', () => { + expect(parseForwardDestinationQuery('@bob')).toEqual({mode: 'user', query: 'bob', resultTypes: ['user']}); + expect(parseForwardDestinationQuery('#gen')).toEqual({ + mode: 'text_channel', + query: 'gen', + resultTypes: ['text_channel'], + }); + expect(parseForwardDestinationQuery('!lounge')).toEqual({ + mode: 'voice_channel', + query: 'lounge', + resultTypes: ['voice_channel'], + }); + }); + + it('keeps a bare sigil as a mode with an empty query', () => { + expect(parseForwardDestinationQuery('#')).toEqual({mode: 'text_channel', query: '', resultTypes: ['text_channel']}); + }); + + it('strips the guild, game and global user sigils without narrowing', () => { + expect(parseForwardDestinationQuery('*guild')).toEqual({mode: null, query: 'guild', resultTypes: ALL_TYPES}); + expect(parseForwardDestinationQuery('$game')).toEqual({mode: null, query: 'game', resultTypes: ALL_TYPES}); + expect(parseForwardDestinationQuery('@@bob')).toEqual({mode: null, query: 'bob', resultTypes: ALL_TYPES}); + }); + + it('strips only a leading @ but the first other sigil anywhere', () => { + expect(parseForwardDestinationQuery('a@b')).toEqual({mode: null, query: 'a@b', resultTypes: ALL_TYPES}); + expect(parseForwardDestinationQuery('foo#bar#baz')).toEqual({ + mode: null, + query: 'foobar#baz', + resultTypes: ALL_TYPES, + }); + expect(parseForwardDestinationQuery('@#x')).toEqual({mode: 'user', query: '#x', resultTypes: ['user']}); + }); +}); diff --git a/fluxer_app/src/features/app/components/dialogs/shared/ForwardDestinationQuery.ts b/fluxer_app/src/features/app/components/dialogs/shared/ForwardDestinationQuery.ts new file mode 100644 index 000000000..d1f759488 --- /dev/null +++ b/fluxer_app/src/features/app/components/dialogs/shared/ForwardDestinationQuery.ts @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +export type ForwardResultType = 'user' | 'text_channel' | 'voice_channel' | 'group_dm'; + +export interface ForwardDestinationQuery { + readonly mode: ForwardResultType | null; + readonly query: string; + readonly resultTypes: ReadonlyArray; +} + +const FORWARD_RESULT_TYPES: ReadonlyArray = Object.freeze([ + 'user', + 'text_channel', + 'voice_channel', + 'group_dm', +]); +const SIGIL_RESULT_TYPES: ReadonlyMap = new Map([ + ['@', 'user'], + ['#', 'text_channel'], + ['!', 'voice_channel'], +]); +const GLOBAL_USER_SIGIL = '@@'; +const SIGIL_PATTERN = /^@|#|!|\*|\$/; + +export function parseForwardDestinationQuery(text: string): ForwardDestinationQuery { + if (text.startsWith(GLOBAL_USER_SIGIL)) { + return Object.freeze({mode: null, query: text.slice(GLOBAL_USER_SIGIL.length), resultTypes: FORWARD_RESULT_TYPES}); + } + const query = text.replace(SIGIL_PATTERN, ''); + const mode = SIGIL_RESULT_TYPES.get(text.charAt(0)); + if (mode === undefined) return Object.freeze({mode: null, query, resultTypes: FORWARD_RESULT_TYPES}); + return Object.freeze({mode, query, resultTypes: Object.freeze([mode])}); +} diff --git a/fluxer_app/src/features/app/components/dialogs/shared/ForwardDestinationSearch.test.ts b/fluxer_app/src/features/app/components/dialogs/shared/ForwardDestinationSearch.test.ts new file mode 100644 index 000000000..6bee31bef --- /dev/null +++ b/fluxer_app/src/features/app/components/dialogs/shared/ForwardDestinationSearch.test.ts @@ -0,0 +1,326 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +import type {ForwardResultType} from '@app/features/app/components/dialogs/shared/ForwardDestinationQuery'; +import { + buildForwardSearchBoosters, + type ForwardChannelCandidate, + type ForwardGroupDMCandidate, + type ForwardSearchBoosters, + type ForwardSearchResult, + type ForwardUserCandidate, + searchForwardDestinations, +} from '@app/features/app/components/dialogs/shared/ForwardDestinationSearch'; +import {loadUnicodeConfusables} from '@app/features/search/utils/SearchTextMatching'; +import {beforeAll, describe, expect, it} from 'vitest'; + +const ALL_TYPES: ReadonlyArray = ['user', 'text_channel', 'voice_channel', 'group_dm']; +const NO_BOOSTERS = buildForwardSearchBoosters({dmUserIds: [], frequent: [], friendIds: []}); +let confusables: ReadonlyMap = new Map(); + +beforeAll(async () => { + confusables = await loadUnicodeConfusables(); +}); + +interface SearchOverrides { + readonly blacklist?: ReadonlySet; + readonly boosters?: ForwardSearchBoosters; + readonly channels?: ReadonlyArray; + readonly confusables?: ReadonlyMap; + readonly groupDMs?: ReadonlyArray; + readonly limit?: number; + readonly resultTypes?: ReadonlyArray; + readonly users?: ReadonlyArray; +} + +function search(query: string, overrides: SearchOverrides = {}): ReadonlyArray { + return searchForwardDestinations({ + blacklist: new Set(), + boosters: NO_BOOSTERS, + channels: [], + confusables, + groupDMs: [], + limit: 20, + resultTypes: ALL_TYPES, + users: [], + ...overrides, + query, + }); +} + +function channel(id: string, name: string, overrides: Partial = {}): ForwardChannelCandidate { + return {canAccess: true, guildName: null, hasFrecency: false, id, kind: 'text', name, parentName: null, ...overrides}; +} + +function user(id: string, username: string, overrides: Partial = {}): ForwardUserCandidate { + return {friendNickname: null, globalName: null, id, nicknames: [], username, ...overrides}; +} + +function groupDM(id: string, name: string, memberFields: ReadonlyArray = []): ForwardGroupDMCandidate { + return {id, memberFields, name}; +} + +function tier(results: ReadonlyArray): number | null { + return results.length === 0 ? null : results[0].score / 1000; +} + +function channelTier( + query: string, + candidate: ForwardChannelCandidate, + resultTypes: ReadonlyArray = ['text_channel'], +): number | null { + return tier(search(query, {channels: [candidate], resultTypes})); +} + +function userTier(query: string, candidate: ForwardUserCandidate, overrides: SearchOverrides = {}): number | null { + return tier(search(query, {resultTypes: ['user'], users: [candidate], ...overrides})); +} + +function summarize(results: ReadonlyArray): ReadonlyArray { + return results.map((result) => `${result.type}:${result.id}:${result.score}`); +} + +describe('forward destination channel search', () => { + const general = channel('general', 'general'); + + it('scores exact, prefix, contains and fuzzy name matches', () => { + expect(channelTier('general', general)).toBe(10); + expect(channelTier('gen', general)).toBe(7); + expect(channelTier('eral', general)).toBe(5); + expect(channelTier('gnrl', general)).toBe(1); + }); + + it('adds the frecency bonus up to the tier cap', () => { + expect(channelTier('gen', channel('general', 'general', {hasFrecency: true}))).toBe(10); + expect(channelTier('eral', channel('general', 'general', {hasFrecency: true}))).toBe(7); + }); + + it('matches a full phrase across a dash', () => { + expect(channelTier('general chat', channel('general-chat', 'general-chat'))).toBe(7); + }); + + it('rejects words in the wrong order', () => { + expect(channelTier('chat general', channel('general-chat', 'general-chat'))).toBeNull(); + }); + + it('lets leftover words match the guild name at half weight, capped at 6', () => { + expect(channelTier('general foo', channel('general', 'general', {guildName: 'Foo Server'}))).toBe(6); + }); + + it('rejects a query that leaves more than one word unmatched', () => { + expect(channelTier('gen my server', channel('general', 'general', {guildName: 'My Server'}))).toBeNull(); + }); + + it('needs the channel name itself to match', () => { + expect(channelTier('foo', channel('general', 'general', {guildName: 'foo'}))).toBeNull(); + }); + + it('caps a query with a stray space at 6', () => { + const inGuild = channel('general', 'general', {guildName: 'Foo Server'}); + expect(channelTier('general ', inGuild)).toBe(6); + expect(channelTier(' general', inGuild)).toBe(6); + }); + + it('penalises voice channels found by the text search only', () => { + const lounge = channel('lounge', 'lounge', {kind: 'voice'}); + expect(search('lounge', {channels: [lounge], resultTypes: ['text_channel']})).toEqual([ + {comparator: 'lounge', id: 'lounge', score: 9000, type: 'voice_channel'}, + ]); + expect(channelTier('lounge', lounge, ['voice_channel'])).toBe(10); + }); + + it('keeps the penalised text-search copy of a voice channel when both searches find it', () => { + const lounge = channel('lounge', 'lounge', {kind: 'voice'}); + const boosters = buildForwardSearchBoosters({ + dmUserIds: [], + frequent: [{id: 'lounge', kind: 'voice', score: 10}], + friendIds: [], + }); + expect(summarize(search('lounge', {boosters, channels: [lounge], resultTypes: ['voice_channel']}))).toEqual([ + 'voice_channel:lounge:20000', + ]); + expect(summarize(search('lounge', {boosters, channels: [lounge]}))).toEqual(['voice_channel:lounge:9000']); + }); + + it('does not fold diacritics in channel names', () => { + expect(channelTier('cafe', channel('cafe', 'café'))).toBeNull(); + }); + + it('skips channels the reader cannot access', () => { + expect(channelTier('general', channel('general', 'general', {canAccess: false}))).toBeNull(); + }); + + it('keeps candidate order between channels with equal scores', () => { + const channels = [channel('z', 'general-z'), channel('a', 'general-a'), channel('m', 'general')]; + expect(search('general', {channels, resultTypes: ['text_channel']}).map((result) => result.id)).toEqual([ + 'm', + 'z', + 'a', + ]); + }); + + it('truncates each category to the limit before merging', () => { + const channels = Array.from({length: 25}, (_, index) => channel(`c${index}`, `general-${index}`)); + const results = search('general', {channels, limit: 20}); + expect(results.map((result) => result.id)).toEqual(channels.slice(0, 20).map((candidate) => candidate.id)); + }); +}); + +describe('forward destination user search', () => { + it('ranks a case-insensitive prefix at 10 and a substring at 5', () => { + const bobby = user('1', 'bobby'); + expect(userTier('Bob', bobby)).toBe(10); + expect(userTier('ob', bobby)).toBe(5); + }); + + it('folds diacritics in the field but not in the query', () => { + expect(userTier('jose', user('1', 'José'))).toBe(1); + expect(userTier('josé', user('1', 'jose99'))).toBeNull(); + }); + + it('matches look-alike characters once the confusables table is loaded', () => { + expect(userTier('b0b', user('1', 'bob'))).toBe(1); + expect(userTier('b0b', user('1', 'bob'), {confusables: new Map()})).toBeNull(); + }); + + it('does not trim the query', () => { + expect(userTier('john ', user('1', 'john'))).toBeNull(); + }); + + it('matches the exact user id', () => { + expect(userTier('123456789012345678', user('123456789012345678', 'ada'))).toBe(10); + }); + + it('matches community nicknames, friend nicknames and global names', () => { + expect(userTier('mods', user('1', 'ada', {nicknames: ['Mods Team']}))).toBe(10); + expect(userTier('count', user('1', 'ada', {friendNickname: 'Countess'}))).toBe(10); + expect(userTier('love', user('1', 'ada', {globalName: 'Ada Lovelace'}))).toBe(5); + }); + + it('reports the first field that produced the best score', () => { + const [strongest] = search('love', { + users: [user('1', 'ada', {globalName: 'Lovelace', nicknames: ['Ada Lovelace']})], + }); + expect(strongest.comparator).toBe('Lovelace'); + const [first] = search('ada', {users: [user('1', 'ada_x', {globalName: 'Ada'})]}); + expect(first.comparator).toBe('ada_x'); + }); + + it('skips blacklisted users', () => { + expect(userTier('ada', user('me', 'ada'), {blacklist: new Set(['me'])})).toBeNull(); + }); + + it('multiplies by the user booster', () => { + const boosters = buildForwardSearchBoosters({dmUserIds: [], frequent: [], friendIds: ['1']}); + expect(userTier('bob', user('1', 'bob'), {boosters})).toBeCloseTo(12); + }); + + it('breaks ties alphabetically by the matched name', () => { + const users = [user('1', 'Bob_b'), user('2', 'bob_a'), user('3', 'bob_c')]; + expect(search('bob', {users}).map((result) => result.id)).toEqual(['2', '1', '3']); + }); +}); + +describe('forward destination group DM search', () => { + it('folds diacritics and look-alikes in the name', () => { + expect(tier(search('cafe', {groupDMs: [groupDM('g', 'Café Crew')]}))).toBe(7); + expect(tier(search('rnovie', {groupDMs: [groupDM('g', 'movie night')]}))).toBe(7); + }); + + it('caps member matches at 5', () => { + expect(tier(search('alice', {groupDMs: [groupDM('g', 'Weekend', ['alice', 'Alice A.'])]}))).toBe(5); + }); + + it('prefers a stronger name match over a member match', () => { + expect(tier(search('weekend', {groupDMs: [groupDM('g', 'Weekend', ['weekend_fan'])]}))).toBe(10); + }); +}); + +describe('forward destination search merge', () => { + it('returns nothing for a blank query', () => { + expect(search(' ', {channels: [channel('general', 'general')]})).toEqual([]); + }); + + it('only searches the requested result types', () => { + const results = search('general', { + channels: [channel('general', 'general')], + groupDMs: [groupDM('g', 'general')], + resultTypes: ['user'], + users: [user('1', 'general')], + }); + expect(summarize(results)).toEqual(['user:1:10000']); + }); + + it('orders equal scores as users, group DMs, text channels, then voice channels', () => { + const results = search('general', { + channels: [channel('v', 'general', {kind: 'voice'}), channel('t', 'general')], + groupDMs: [groupDM('g', 'general')], + users: [user('1', 'general')], + }); + expect(summarize(results)).toEqual([ + 'user:1:10000', + 'group_dm:g:10000', + 'text_channel:t:10000', + 'voice_channel:v:9000', + ]); + }); + + it('sorts higher scores first across types', () => { + const results = search('gen', { + channels: [channel('t', 'general', {hasFrecency: true})], + users: [user('1', 'xgen')], + }); + expect(summarize(results)).toEqual(['text_channel:t:10000', 'user:1:5000']); + }); +}); + +describe('buildForwardSearchBoosters', () => { + it('scales frecency against the highest score and adds friend and open DM boosts', () => { + const boosters = buildForwardSearchBoosters({ + dmUserIds: ['user-1', 'user-3'], + frequent: [ + {id: 'guild-1', kind: 'other', score: 200}, + {id: 'dm-1', kind: 'dm', recipientId: 'user-1', score: 100}, + {id: 'text-1', kind: 'text', score: 50}, + {id: 'voice-1', kind: 'voice', score: 150}, + {id: 'gdm-1', kind: 'group_dm', score: 20}, + ], + friendIds: ['user-1', 'user-2'], + }); + expect(boosters.users.get('user-1')).toBeCloseTo(1.8); + expect(boosters.users.get('user-2')).toBeCloseTo(1.2); + expect(boosters.users.get('user-3')).toBeCloseTo(1.1); + expect(boosters.users.has('dm-1')).toBe(false); + expect(boosters.textChannels.get('text-1')).toBe(1.25); + expect(boosters.voiceChannels.get('voice-1')).toBe(1.75); + expect(boosters.groupDMs.get('gdm-1')).toBeCloseTo(1.1); + expect(boosters.textChannels.has('guild-1')).toBe(false); + }); + + it('falls back to a boost of 1 when every frecency score is zero', () => { + const boosters = buildForwardSearchBoosters({ + dmUserIds: [], + frequent: [{id: 'text-1', kind: 'text', score: 0}], + friendIds: [], + }); + expect(boosters.textChannels.get('text-1')).toBe(1); + }); + + it('boosts text channels only in the text search and voice channels only in the voice search', () => { + const boosters = buildForwardSearchBoosters({ + dmUserIds: [], + frequent: [ + {id: 't', kind: 'text', score: 10}, + {id: 'v', kind: 'voice', score: 10}, + ], + friendIds: [], + }); + const channels = [channel('t', 'general'), channel('v', 'general', {kind: 'voice'})]; + expect(summarize(search('general', {boosters, channels, resultTypes: ['text_channel']}))).toEqual([ + 'text_channel:t:20000', + 'voice_channel:v:9000', + ]); + expect(summarize(search('general', {boosters, channels, resultTypes: ['voice_channel']}))).toEqual([ + 'voice_channel:v:20000', + ]); + }); +}); diff --git a/fluxer_app/src/features/app/components/dialogs/shared/ForwardDestinationSearch.ts b/fluxer_app/src/features/app/components/dialogs/shared/ForwardDestinationSearch.ts new file mode 100644 index 000000000..dbca08970 --- /dev/null +++ b/fluxer_app/src/features/app/components/dialogs/shared/ForwardDestinationSearch.ts @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +import type {ForwardResultType} from '@app/features/app/components/dialogs/shared/ForwardDestinationQuery'; +import { + buildChannelSearchTerms, + consumeBestSearchTerm, + createSearchTerm, + escapeSearchPattern, + fuzzySearch, + scoreSearchTerm, + stripCombiningMarks, + toConfusableSkeleton, +} from '@app/features/search/utils/SearchTextMatching'; + +const SCORE_SCALE = 1000; +const FRIEND_BOOST = 0.2; +const OPEN_DM_BOOST = 0.1; +const GROUP_DM_MEMBER_SCORE_CAP = 5; +const CHANNEL_CONTEXT_WEIGHT = 0.5; +const CHANNEL_CONTEXT_SCORE_CAP = 6; +const VOICE_IN_TEXT_SEARCH_PENALTY = 1; +const VOICE_IN_TEXT_SEARCH_FLOOR = 0.5; +const CHANNEL_FRECENCY_BONUS = 3; + +type ForwardChannelKind = 'text' | 'voice'; + +export interface ForwardUserCandidate { + readonly friendNickname: string | null; + readonly globalName: string | null; + readonly id: string; + readonly nicknames: ReadonlyArray; + readonly username: string; +} + +export interface ForwardGroupDMCandidate { + readonly id: string; + readonly memberFields: ReadonlyArray; + readonly name: string; +} + +export interface ForwardChannelCandidate { + readonly canAccess: boolean; + readonly guildName: string | null; + readonly hasFrecency: boolean; + readonly id: string; + readonly kind: ForwardChannelKind; + readonly name: string; + readonly parentName: string | null; +} + +export interface ForwardFrequentItem { + readonly id: string; + readonly kind: 'dm' | 'group_dm' | 'text' | 'voice' | 'other'; + readonly recipientId?: string | null; + readonly score: number; +} + +export interface ForwardSearchBoosters { + readonly groupDMs: ReadonlyMap; + readonly textChannels: ReadonlyMap; + readonly users: ReadonlyMap; + readonly voiceChannels: ReadonlyMap; +} + +export interface ForwardSearchResult { + readonly comparator: string; + readonly id: string; + readonly score: number; + readonly type: ForwardResultType; +} + +interface BuildForwardSearchBoostersRequest { + readonly dmUserIds: Iterable; + readonly frequent: ReadonlyArray; + readonly friendIds: Iterable; +} + +interface SearchForwardDestinationsRequest { + readonly blacklist: ReadonlySet; + readonly boosters: ForwardSearchBoosters; + readonly channels: ReadonlyArray; + readonly confusables: ReadonlyMap; + readonly groupDMs: ReadonlyArray; + readonly limit: number; + readonly query: string; + readonly resultTypes: ReadonlyArray; + readonly users: ReadonlyArray; +} + +export function buildForwardSearchBoosters({ + dmUserIds, + frequent, + friendIds, +}: BuildForwardSearchBoostersRequest): ForwardSearchBoosters { + const maxScore = frequent.reduce((max, item) => Math.max(max, item.score), 0); + const users = new Map(); + const groupDMs = new Map(); + const textChannels = new Map(); + const voiceChannels = new Map(); + for (const item of frequent) { + const boost = maxScore > 0 ? 1 + item.score / maxScore : 1; + switch (item.kind) { + case 'dm': + if (item.recipientId != null) users.set(item.recipientId, boost); + break; + case 'group_dm': + groupDMs.set(item.id, boost); + break; + case 'text': + textChannels.set(item.id, boost); + break; + case 'voice': + voiceChannels.set(item.id, boost); + break; + case 'other': + break; + } + } + for (const friendId of friendIds) users.set(friendId, (users.get(friendId) ?? 1) + FRIEND_BOOST); + for (const userId of dmUserIds) users.set(userId, (users.get(userId) ?? 1) + OPEN_DM_BOOST); + return Object.freeze({groupDMs, textChannels, users, voiceChannels}); +} + +export function searchForwardDestinations( + request: SearchForwardDestinationsRequest, +): ReadonlyArray { + const {boosters, channels, confusables, limit, query, resultTypes} = request; + if (query.trim() === '') return []; + const results = [ + ...(resultTypes.includes('user') + ? searchUsers(query, request.users, boosters.users, request.blacklist, confusables, limit) + : []), + ...(resultTypes.includes('group_dm') + ? searchGroupDMs(query, request.groupDMs, boosters.groupDMs, confusables, limit) + : []), + ...(resultTypes.includes('text_channel') + ? searchChannels(query, channels, 'text', boosters.textChannels, limit) + : []), + ...(resultTypes.includes('voice_channel') + ? searchChannels(query, channels, 'voice', boosters.voiceChannels, limit) + : []), + ]; + const seenKeys = new Set(); + const merged = results.filter((result) => { + const key = `${result.type}-${result.id}`; + if (seenKeys.has(key)) return false; + seenKeys.add(key); + return true; + }); + return merged.sort(compareSearchResults); +} + +function compareSearchResults(left: ForwardSearchResult, right: ForwardSearchResult): number { + if (left.score === right.score && left.type === 'user') { + const leftName = left.comparator.toLocaleLowerCase(); + const rightName = right.comparator.toLocaleLowerCase(); + if (leftName < rightName) return -1; + if (leftName > rightName) return 1; + } + return right.score - left.score; +} + +function sortAndLimit(results: Array, limit: number): Array { + return results.sort(compareSearchResults).slice(0, limit); +} + +function searchUsers( + query: string, + users: ReadonlyArray, + boosters: ReadonlyMap, + blacklist: ReadonlySet, + confusables: ReadonlyMap, + limit: number, +): Array { + const escapedQuery = escapeSearchPattern(query); + const prefixQuery = new RegExp(`^${escapedQuery}`, 'i'); + const containQuery = new RegExp(escapedQuery, 'i'); + const queryLower = query.toLocaleLowerCase(); + const querySkeleton = toConfusableSkeleton(queryLower, confusables); + const scoreField = (field: string): number => { + if (prefixQuery.test(field)) return 10; + if (containQuery.test(field)) return 5; + const stripped = stripCombiningMarks(field.toLocaleLowerCase()); + if (fuzzySearch(queryLower, stripped)) return 1; + if (fuzzySearch(querySkeleton, toConfusableSkeleton(stripped, confusables))) return 1; + return 0; + }; + const matches: Array = []; + for (const user of users) { + if (blacklist.has(user.id)) continue; + const booster = boosters.get(user.id) ?? 1; + if (user.id === query) { + matches.push({comparator: user.id, id: user.id, score: 10 * booster, type: 'user'}); + continue; + } + let best: ForwardSearchResult | null = null; + for (const field of [user.username, user.friendNickname, user.globalName, ...user.nicknames]) { + if (field == null) continue; + const score = scoreField(field) * booster; + if (score === 0 || (best != null && best.score >= score)) continue; + best = {comparator: field, id: user.id, score, type: 'user'}; + } + if (best != null) matches.push(best); + } + return sortAndLimit(matches, limit).map((match) => Object.freeze({...match, score: SCORE_SCALE * match.score})); +} + +function searchGroupDMs( + query: string, + groupDMs: ReadonlyArray, + boosters: ReadonlyMap, + confusables: ReadonlyMap, + limit: number, +): Array { + const normalize = (text: string): string => + stripCombiningMarks(toConfusableSkeleton(text.toLocaleLowerCase(), confusables)); + const term = createSearchTerm(normalize(query)); + const results: Array = []; + for (const groupDM of groupDMs) { + let score = scoreSearchTerm(normalize(groupDM.name), term); + for (const field of groupDM.memberFields) { + score = Math.max(score, Math.min(GROUP_DM_MEMBER_SCORE_CAP, scoreSearchTerm(normalize(field), term))); + } + if (score === 0) continue; + results.push( + Object.freeze({ + comparator: groupDM.name, + id: groupDM.id, + score: SCORE_SCALE * score * (boosters.get(groupDM.id) ?? 1), + type: 'group_dm', + }), + ); + } + return sortAndLimit(results, limit); +} + +function searchChannels( + query: string, + channels: ReadonlyArray, + searchKind: ForwardChannelKind, + boosters: ReadonlyMap, + limit: number, +): Array { + const terms = buildChannelSearchTerms(query); + const results: Array = []; + for (const channel of channels) { + if (searchKind === 'voice' && channel.kind !== 'voice') continue; + if (!channel.canAccess) continue; + const remainingTerms = [...terms]; + let score = consumeBestSearchTerm(channel.name.toLocaleLowerCase(), remainingTerms, true); + if (score === 0) continue; + if (remainingTerms.length > 0) { + for (const context of [channel.guildName, channel.parentName]) { + if (context == null || context === '') continue; + score += CHANNEL_CONTEXT_WEIGHT * consumeBestSearchTerm(context.toLocaleLowerCase(), remainingTerms, false); + } + score = Math.min(CHANNEL_CONTEXT_SCORE_CAP, score); + } + if (remainingTerms.length > 1) continue; + if (remainingTerms.length === 1 && !remainingTerms[0].isFullMatch) continue; + if (searchKind === 'text' && channel.kind === 'voice') { + score = Math.max(score - VOICE_IN_TEXT_SEARCH_PENALTY, VOICE_IN_TEXT_SEARCH_FLOOR); + } + score = Math.min(score + (channel.hasFrecency ? CHANNEL_FRECENCY_BONUS : 0), score >= 7 ? 10 : 7); + results.push( + Object.freeze({ + comparator: channel.name, + id: channel.id, + score: SCORE_SCALE * score * (boosters.get(channel.id) ?? 1), + type: channel.kind === 'voice' ? 'voice_channel' : 'text_channel', + }), + ); + } + return sortAndLimit(results, limit); +} diff --git a/fluxer_app/src/features/app/components/dialogs/shared/ForwardDestinationSelection.test.ts b/fluxer_app/src/features/app/components/dialogs/shared/ForwardDestinationSelection.test.ts new file mode 100644 index 000000000..3766de772 --- /dev/null +++ b/fluxer_app/src/features/app/components/dialogs/shared/ForwardDestinationSelection.test.ts @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +import { + buildForwardDefaultDestinations, + type ForwardDestination, + type ForwardRowIdentity, +} from '@app/features/app/components/dialogs/shared/ForwardDefaultDestinations'; +import { + type ForwardPinnedDestinations, + forwardDestinationKey, + MAX_FORWARD_DESTINATIONS, + pinForwardDestinations, + toggleForwardDestination, +} from '@app/features/app/components/dialogs/shared/ForwardDestinationSelection'; +import {describe, expect, it} from 'vitest'; + +const UNPINNED: ForwardPinnedDestinations = {engineQuery: null, pinned: []}; +const HISTORY: ReadonlyArray = ['text-1', 'text-2', 'text-3']; + +function channel(id: string): ForwardDestination { + return {id, type: 'channel'}; +} + +function user(id: string): ForwardDestination { + return {id, type: 'user'}; +} + +function resolveChannel(channelId: string): ForwardRowIdentity { + return {id: channelId, type: 'text_channel'}; +} + +function resolveDestination(destination: ForwardDestination): ForwardRowIdentity { + if (destination.type === 'user') return {id: destination.id, type: 'user'}; + return resolveChannel(destination.id); +} + +interface PickerState { + readonly engineQuery: string; + readonly pinned: ForwardPinnedDestinations; + readonly selected: ReadonlyArray; +} + +interface PickerRender { + readonly rows: ReadonlyArray; + readonly state: PickerState; +} + +function renderPicker(state: PickerState): PickerRender { + const pinned = pinForwardDestinations(state.pinned, state.engineQuery, state.selected); + const rows = buildForwardDefaultDestinations({ + frequentIds: [], + history: HISTORY, + isValid: () => true, + mode: null, + origin: null, + pinned: pinned.pinned, + resolveChannel, + resolveDestination, + selected: state.selected, + }); + return {rows: rows.map((row) => row.id), state: {...state, pinned}}; +} + +function togglePicker(state: PickerState, destination: ForwardDestination): PickerState { + const selected = toggleForwardDestination(state.selected, destination); + const engineQuery = selected.length > state.selected.length ? '' : state.engineQuery; + return {...state, engineQuery, selected}; +} + +describe('toggleForwardDestination', () => { + it('puts the newest pick first and removes a pick in place', () => { + const picked = toggleForwardDestination(toggleForwardDestination([], channel('text-1')), user('user-1')); + expect(picked).toEqual([user('user-1'), channel('text-1')]); + expect(toggleForwardDestination(picked, channel('text-1'))).toEqual([user('user-1')]); + }); + + it('tells a user apart from a channel with the same id', () => { + expect(forwardDestinationKey(user('1'))).toBe('user:1'); + expect(forwardDestinationKey(channel('1'))).toBe('channel:1'); + expect(toggleForwardDestination([channel('1')], user('1'))).toEqual([user('1'), channel('1')]); + }); + + it('refuses a new pick at the cap but still removes one', () => { + const full = Array.from({length: MAX_FORWARD_DESTINATIONS}, (_, index) => channel(`text-${index}`)); + expect(toggleForwardDestination(full, channel('text-extra'))).toBe(full); + expect(toggleForwardDestination(full, channel('text-0'))).toHaveLength(MAX_FORWARD_DESTINATIONS - 1); + }); +}); + +describe('pinForwardDestinations', () => { + it('pins the live selection on the first render', () => { + const selected = [channel('text-1')]; + expect(pinForwardDestinations(UNPINNED, '', selected)).toEqual({engineQuery: '', pinned: selected}); + }); + + it('keeps the snapshot while the engine query stays the same', () => { + const snapshot = pinForwardDestinations(UNPINNED, '', []); + expect(pinForwardDestinations(snapshot, '', [channel('text-1')])).toBe(snapshot); + }); + + it('pins the live selection again when the engine query changes', () => { + const snapshot = pinForwardDestinations(UNPINNED, '', []); + const selected = [user('user-1'), channel('text-1')]; + expect(pinForwardDestinations(snapshot, 'abc', selected)).toEqual({engineQuery: 'abc', pinned: selected}); + }); +}); + +describe('forward default list while selecting', () => { + it('keeps rows in place until a search clears, then pins the selection newest first', () => { + const opened = renderPicker({engineQuery: '', pinned: UNPINNED, selected: []}); + expect(opened.rows).toEqual(['text-1', 'text-2', 'text-3']); + + const pickedWithoutQuery = renderPicker(togglePicker(opened.state, channel('text-3'))); + expect(pickedWithoutQuery.state.selected).toEqual([channel('text-3')]); + expect(pickedWithoutQuery.rows).toEqual(['text-1', 'text-2', 'text-3']); + + const searching = renderPicker({...pickedWithoutQuery.state, engineQuery: 'ada'}); + const pickedFromSearch = renderPicker(togglePicker(searching.state, user('user-9'))); + expect(pickedFromSearch.state.engineQuery).toBe(''); + expect(pickedFromSearch.rows).toEqual(['user-9', 'text-3', 'text-1', 'text-2']); + + const removed = renderPicker(togglePicker(pickedFromSearch.state, channel('text-3'))); + expect(removed.state.selected).toEqual([user('user-9')]); + expect(removed.rows).toEqual(['user-9', 'text-3', 'text-1', 'text-2']); + }); + + it('re-pins the live selection when a typed query is cleared by hand', () => { + const opened = renderPicker({engineQuery: '', pinned: UNPINNED, selected: []}); + const picked = renderPicker(togglePicker(opened.state, channel('text-2'))); + const searching = renderPicker({...picked.state, engineQuery: 'x'}); + const cleared = renderPicker({...searching.state, engineQuery: ''}); + expect(cleared.rows).toEqual(['text-2', 'text-1', 'text-3']); + }); +}); diff --git a/fluxer_app/src/features/app/components/dialogs/shared/ForwardDestinationSelection.ts b/fluxer_app/src/features/app/components/dialogs/shared/ForwardDestinationSelection.ts new file mode 100644 index 000000000..5bb022422 --- /dev/null +++ b/fluxer_app/src/features/app/components/dialogs/shared/ForwardDestinationSelection.ts @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +import type {ForwardDestination} from '@app/features/app/components/dialogs/shared/ForwardDefaultDestinations'; + +export const MAX_FORWARD_DESTINATIONS = 5; + +export interface ForwardPinnedDestinations { + readonly engineQuery: string | null; + readonly pinned: ReadonlyArray; +} + +export function forwardDestinationKey(destination: ForwardDestination): string { + return `${destination.type}:${destination.id}`; +} + +export function toggleForwardDestination( + selected: ReadonlyArray, + destination: ForwardDestination, +): ReadonlyArray { + const key = forwardDestinationKey(destination); + const remaining = selected.filter((entry) => forwardDestinationKey(entry) !== key); + if (remaining.length < selected.length) return Object.freeze(remaining); + if (selected.length >= MAX_FORWARD_DESTINATIONS) return selected; + return Object.freeze([destination, ...selected]); +} + +export function pinForwardDestinations( + previous: ForwardPinnedDestinations, + engineQuery: string, + selected: ReadonlyArray, +): ForwardPinnedDestinations { + if (engineQuery === previous.engineQuery) return previous; + return Object.freeze({engineQuery, pinned: selected}); +} diff --git a/fluxer_app/src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts b/fluxer_app/src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts deleted file mode 100644 index 1bfa7654b..000000000 --- a/fluxer_app/src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts +++ /dev/null @@ -1,388 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later - -import type {ForwardChannelObservation} from '@app/features/app/components/dialogs/shared/ForwardChannelIndex'; -import {useShallowStableArray} from '@app/features/app/hooks/useShallowStableArray'; -import RuntimeConfig from '@app/features/app/state/RuntimeConfig'; -import type {Channel} from '@app/features/channel/models/Channel'; -import Channels from '@app/features/channel/state/Channels'; -import * as ChannelUtils from '@app/features/channel/utils/ChannelUtils'; -import DeveloperOptions from '@app/features/devtools/state/DeveloperOptions'; -import Guilds from '@app/features/guild/state/Guilds'; -import GuildMembers from '@app/features/member/state/GuildMembers'; -import Permission from '@app/features/permissions/state/Permission'; -import Relationships from '@app/features/relationship/state/Relationships'; -import Slowmode from '@app/features/slowmode/state/Slowmode'; -import {useNow} from '@app/features/ui/state/Tick'; -import type {User} from '@app/features/user/models/User'; -import Users from '@app/features/user/state/Users'; -import * as NicknameUtils from '@app/features/user/utils/NicknameUtils'; -import {ChannelTypes, Permissions} from '@fluxer/constants/src/ChannelConstants'; -import {GuildOperations} from '@fluxer/constants/src/GuildConstants'; -import {CHANNEL_RATE_LIMIT_PER_USER_MAX} from '@fluxer/constants/src/LimitConstants'; -import {RelationshipTypes} from '@fluxer/constants/src/UserConstants'; -import type {I18n} from '@lingui/core'; -import {msg} from '@lingui/core/macro'; -import {computed, type IComputedValue} from 'mobx'; -import {useMemo, useRef} from 'react'; - -const EMPTY_SEARCH_ALIASES: ReadonlyArray = Object.freeze([]); - -const CHANNEL_DESCRIPTOR = msg({ - message: 'Channel {id}', - comment: 'Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code.', -}); - -interface UseForwardChannelObservationsOptions { - readonly channels: ReadonlyArray; - readonly currentUserId: string | null; - readonly i18n: I18n; -} - -interface ForwardChannelObservationBase { - readonly canAttachFiles: boolean; - readonly canEmbedLinks: boolean; - readonly canSendMessages: boolean; - readonly categoryName: string | null; - readonly channel: Channel | null; - readonly displayName: string; - readonly guildMessagesDisabled: boolean; - readonly guildName: string | null; - readonly key: string; - readonly memberTimedOut: boolean; - readonly recipient: User | null; - readonly searchAliases: ReadonlyArray; - readonly slowmodeEnabled: boolean; -} - -interface ForwardSlowmodeChannel { - readonly channelId: string; - readonly index: number; - readonly rateLimitPerUser: number; -} - -interface ForwardChannelObservationSelection { - readonly bases: ReadonlyArray; - readonly slowmodeChannels: ReadonlyArray; -} - -function resolveChannelDisplayName(channel: Channel, i18n: I18n): string { - if (channel.type === ChannelTypes.DM) { - const recipient = channel.recipientIds.length > 0 ? Users.getUser(channel.recipientIds[0]) : null; - if (recipient) { - return NicknameUtils.getNickname(recipient, null); - } - } - if ( - channel.type === ChannelTypes.DM_PERSONAL_NOTES || - channel.type === ChannelTypes.DM || - channel.type === ChannelTypes.GROUP_DM - ) { - return ChannelUtils.getDMDisplayName(channel); - } - if (channel.name) return channel.name; - return i18n._(CHANNEL_DESCRIPTOR, {id: channel.id}); -} - -function resolveForwardChannelKey(channel: Channel): string { - if (channel.type === ChannelTypes.DM && channel.recipientIds.length > 0) { - return resolveForwardRecipientKey(channel.recipientIds[0]); - } - return channel.id; -} - -function resolveForwardRecipientKey(userId: string): string { - return `user:${userId}`; -} - -function collectChannelSearchAliases(channel: Channel): ReadonlyArray { - if (channel.type !== ChannelTypes.DM && channel.type !== ChannelTypes.GROUP_DM) { - return EMPTY_SEARCH_ALIASES; - } - return collectRecipientSearchAliases(channel.recipientIds); -} - -function collectRecipientSearchAliases(recipientIds: ReadonlyArray): ReadonlyArray { - const aliases = new Set(); - const guilds = Guilds.getGuilds(); - for (const recipientId of recipientIds) { - const recipient = Users.getUser(recipientId); - if (!recipient) continue; - aliases.add(recipient.username); - aliases.add(recipient.displayName); - if (recipient.globalName) aliases.add(recipient.globalName); - const relationshipNickname = Relationships.getRelationship(recipientId)?.nickname; - if (relationshipNickname) aliases.add(relationshipNickname); - for (const guild of guilds) { - const nick = GuildMembers.getMember(guild.id, recipientId)?.nick; - if (nick) aliases.add(nick); - } - } - return Object.freeze([...aliases].filter((alias) => alias.length > 0)); -} - -function resolveChannelCategoryName(channel: Channel): string | null { - if (!channel.parentId) return null; - const category = Channels.getChannel(channel.parentId); - if (!category || !category.name) return null; - return category.name; -} - -function isCurrentMemberTimedOut(channel: Channel, currentUserId: string | null): boolean { - if (!channel.guildId || currentUserId === null) return false; - const member = GuildMembers.getMember(channel.guildId, currentUserId); - if (!member) return false; - return member.isTimedOut(); -} - -function resolveSlowmodeRemainingMs( - entry: ForwardSlowmodeChannel, - mockSlowmodeActive: boolean, - mockSlowmodeRemaining: number, -): number { - if (mockSlowmodeActive) return mockSlowmodeRemaining; - return Slowmode.getSlowmodeRemaining(entry.channelId, entry.rateLimitPerUser); -} - -function areForwardChannelObservationBasesEqual( - left: ForwardChannelObservationBase, - right: ForwardChannelObservationBase, -): boolean { - if (left.channel !== right.channel || left.displayName !== right.displayName) return false; - if (left.key !== right.key || left.recipient !== right.recipient) return false; - if (left.guildName !== right.guildName || left.categoryName !== right.categoryName) return false; - if (left.guildMessagesDisabled !== right.guildMessagesDisabled || left.memberTimedOut !== right.memberTimedOut) { - return false; - } - if (left.canSendMessages !== right.canSendMessages || left.canEmbedLinks !== right.canEmbedLinks) return false; - if (left.searchAliases.length !== right.searchAliases.length) return false; - if (left.searchAliases.some((alias, index) => alias !== right.searchAliases[index])) return false; - return left.canAttachFiles === right.canAttachFiles && left.slowmodeEnabled === right.slowmodeEnabled; -} - -function areForwardSlowmodeChannelsEqual(left: ForwardSlowmodeChannel, right: ForwardSlowmodeChannel): boolean { - return ( - left.channelId === right.channelId && left.index === right.index && left.rateLimitPerUser === right.rateLimitPerUser - ); -} - -function areForwardChannelObservationSelectionsEqual( - left: ForwardChannelObservationSelection, - right: ForwardChannelObservationSelection, -): boolean { - if (left.bases.length !== right.bases.length || left.slowmodeChannels.length !== right.slowmodeChannels.length) { - return false; - } - for (let index = 0; index < left.bases.length; index += 1) { - const leftBase = left.bases[index]; - const rightBase = right.bases[index]; - if (leftBase === undefined || rightBase === undefined) { - throw new Error(`Forward channel observation ${index.toString()} is missing`); - } - if (!areForwardChannelObservationBasesEqual(leftBase, rightBase)) return false; - } - for (let index = 0; index < left.slowmodeChannels.length; index += 1) { - const leftEntry = left.slowmodeChannels[index]; - const rightEntry = right.slowmodeChannels[index]; - if (leftEntry === undefined || rightEntry === undefined) { - throw new Error(`Forward slowmode channel ${index.toString()} is missing`); - } - if (!areForwardSlowmodeChannelsEqual(leftEntry, rightEntry)) return false; - } - return true; -} - -class ForwardChannelObservationsOwner { - private readonly selection: IComputedValue; - private readonly locale: string; - - constructor(private readonly request: UseForwardChannelObservationsOptions) { - this.locale = request.i18n.locale; - this.selection = computed(() => this.buildSelection(), {equals: areForwardChannelObservationSelectionsEqual}); - } - - matches(request: UseForwardChannelObservationsOptions): boolean { - return ( - this.request.channels === request.channels && - this.request.currentUserId === request.currentUserId && - this.request.i18n === request.i18n && - this.locale === request.i18n.locale - ); - } - - read(): ForwardChannelObservationSelection { - return this.selection.get(); - } - - private buildSelection(): ForwardChannelObservationSelection { - const bases: Array = []; - const slowmodeChannels: Array = []; - const keys = new Set(); - for (const channel of this.request.channels) { - const index = bases.length; - const base = this.buildBase(channel); - if (keys.has(base.key)) continue; - keys.add(base.key); - bases.push(base); - if (base.slowmodeEnabled) { - slowmodeChannels.push( - Object.freeze({channelId: channel.id, index, rateLimitPerUser: channel.rateLimitPerUser}), - ); - } - } - for (const base of this.buildClosedFriendDMBases()) { - if (keys.has(base.key)) continue; - keys.add(base.key); - bases.push(base); - } - return Object.freeze({bases: Object.freeze(bases), slowmodeChannels: Object.freeze(slowmodeChannels)}); - } - - private buildClosedFriendDMBases(): ReadonlyArray { - if (RuntimeConfig.directMessagesDisabled) return []; - const bases: Array = []; - for (const relationship of Relationships.getRelationships()) { - if (relationship.type !== RelationshipTypes.FRIEND) continue; - const recipient = Users.getUser(relationship.userId); - if (!recipient) continue; - bases.push( - Object.freeze({ - canAttachFiles: true, - canEmbedLinks: true, - canSendMessages: true, - categoryName: null, - channel: null, - displayName: NicknameUtils.getNickname(recipient, null), - guildMessagesDisabled: false, - guildName: null, - key: resolveForwardRecipientKey(recipient.id), - memberTimedOut: false, - recipient, - searchAliases: collectRecipientSearchAliases([recipient.id]), - slowmodeEnabled: false, - }), - ); - } - return bases; - } - - private buildBase(channel: Channel): ForwardChannelObservationBase { - const guildId = channel.guildId; - if (!guildId) { - return Object.freeze({ - canAttachFiles: true, - canEmbedLinks: true, - canSendMessages: true, - categoryName: resolveChannelCategoryName(channel), - channel, - displayName: resolveChannelDisplayName(channel, this.request.i18n), - guildMessagesDisabled: false, - guildName: null, - key: resolveForwardChannelKey(channel), - memberTimedOut: false, - recipient: null, - searchAliases: collectChannelSearchAliases(channel), - slowmodeEnabled: false, - }); - } - const guild = Guilds.getGuild(guildId); - let guildName: string | null = null; - let guildMessagesDisabled = false; - if (guild) { - guildName = guild.name; - guildMessagesDisabled = (guild.disabledOperations & GuildOperations.SEND_MESSAGE) !== 0; - } - let slowmodeEnabled = false; - if ( - Number.isSafeInteger(channel.rateLimitPerUser) && - channel.rateLimitPerUser > 0 && - channel.rateLimitPerUser <= CHANNEL_RATE_LIMIT_PER_USER_MAX - ) { - slowmodeEnabled = !Permission.can(Permissions.BYPASS_SLOWMODE, channel); - } - return Object.freeze({ - canAttachFiles: Permission.can(Permissions.ATTACH_FILES, channel), - canEmbedLinks: Permission.can(Permissions.EMBED_LINKS, channel), - canSendMessages: Permission.can(Permissions.SEND_MESSAGES, channel), - categoryName: resolveChannelCategoryName(channel), - channel, - displayName: resolveChannelDisplayName(channel, this.request.i18n), - guildMessagesDisabled, - guildName, - key: resolveForwardChannelKey(channel), - memberTimedOut: isCurrentMemberTimedOut(channel, this.request.currentUserId), - recipient: null, - searchAliases: collectChannelSearchAliases(channel), - slowmodeEnabled, - }); - } -} - -function buildForwardChannelObservations( - selection: ForwardChannelObservationSelection, - slowmodeRemainingValues: ReadonlyArray, -): ReadonlyArray { - const remainingByIndex = new Map(); - for (let entryIndex = 0; entryIndex < selection.slowmodeChannels.length; entryIndex += 1) { - const entry = selection.slowmodeChannels[entryIndex]; - const remainingMs = slowmodeRemainingValues[entryIndex]; - if (entry === undefined || remainingMs === undefined) { - throw new Error(`Forward slowmode remaining value ${entryIndex.toString()} is missing`); - } - remainingByIndex.set(entry.index, remainingMs); - } - return Object.freeze( - selection.bases.map((base, index) => { - const remainingMs = remainingByIndex.get(index); - return Object.freeze({ - canAttachFiles: base.canAttachFiles, - canEmbedLinks: base.canEmbedLinks, - canSendMessages: base.canSendMessages, - categoryName: base.categoryName, - channel: base.channel, - displayName: base.displayName, - guildMessagesDisabled: base.guildMessagesDisabled, - guildName: base.guildName, - key: base.key, - searchAliases: base.searchAliases, - memberTimedOut: base.memberTimedOut, - recipient: base.recipient, - slowmodeEnabled: base.slowmodeEnabled, - slowmodeRemainingMs: remainingMs === undefined ? 0 : remainingMs, - }); - }), - ); -} - -export function useForwardChannelObservations({ - channels, - currentUserId, - i18n, -}: UseForwardChannelObservationsOptions): ReadonlyArray { - const request: UseForwardChannelObservationsOptions = {channels, currentUserId, i18n}; - const ownerRef = useRef(null); - let owner = ownerRef.current; - if (owner === null || !owner.matches(request)) { - owner = new ForwardChannelObservationsOwner(request); - ownerRef.current = owner; - } - const selection = owner.read(); - const mockSlowmodeActive = DeveloperOptions.mockSlowmodeActive; - const mockSlowmodeRemaining = DeveloperOptions.mockSlowmodeRemaining; - const slowmodeRemainingValues = useShallowStableArray( - selection.slowmodeChannels.map((entry) => - resolveSlowmodeRemainingMs(entry, mockSlowmodeActive, mockSlowmodeRemaining), - ), - ); - let hasActiveSlowmodeChannel = false; - for (const remainingMs of slowmodeRemainingValues) { - if (remainingMs > 0) { - hasActiveSlowmodeChannel = true; - break; - } - } - useNow(hasActiveSlowmodeChannel); - return useMemo( - () => buildForwardChannelObservations(selection, slowmodeRemainingValues), - [selection, slowmodeRemainingValues], - ); -} diff --git a/fluxer_app/src/features/app/components/dialogs/shared/UseForwardDestinations.ts b/fluxer_app/src/features/app/components/dialogs/shared/UseForwardDestinations.ts new file mode 100644 index 000000000..f582a05fa --- /dev/null +++ b/fluxer_app/src/features/app/components/dialogs/shared/UseForwardDestinations.ts @@ -0,0 +1,597 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +import { + buildForwardDefaultDestinations, + type ForwardDestination, + type ForwardRowIdentity, + filterForwardSearchRows, + resolveForwardOrigin, +} from '@app/features/app/components/dialogs/shared/ForwardDefaultDestinations'; +import {parseForwardDestinationQuery} from '@app/features/app/components/dialogs/shared/ForwardDestinationQuery'; +import { + buildForwardSearchBoosters, + type ForwardChannelCandidate, + type ForwardFrequentItem, + type ForwardGroupDMCandidate, + type ForwardSearchBoosters, + type ForwardSearchResult, + type ForwardUserCandidate, + searchForwardDestinations, +} from '@app/features/app/components/dialogs/shared/ForwardDestinationSearch'; +import { + type ForwardPinnedDestinations, + forwardDestinationKey, + pinForwardDestinations, + toggleForwardDestination, +} from '@app/features/app/components/dialogs/shared/ForwardDestinationSelection'; +import RuntimeConfig from '@app/features/app/state/RuntimeConfig'; +import {formatSlowmodeTime} from '@app/features/channel/components/SlowmodeIndicator'; +import type {Channel} from '@app/features/channel/models/Channel'; +import ChannelFrecency from '@app/features/channel/state/ChannelFrecency'; +import Channels from '@app/features/channel/state/Channels'; +import * as ChannelUtils from '@app/features/channel/utils/ChannelUtils'; +import DeveloperOptions from '@app/features/devtools/state/DeveloperOptions'; +import type {Guild} from '@app/features/guild/models/Guild'; +import Guilds from '@app/features/guild/state/Guilds'; +import {PERSONAL_NOTES_DESCRIPTOR} from '@app/features/i18n/utils/CommonMessageDescriptors'; +import GuildMembers from '@app/features/member/state/GuildMembers'; +import type {ForwardMediaSelection} from '@app/features/messaging/commands/MessageCommands'; +import type {Message} from '@app/features/messaging/models/MessagingMessage'; +import SelectedChannel from '@app/features/navigation/state/SelectedChannel'; +import Permission from '@app/features/permissions/state/Permission'; +import {formatPermissionLabel} from '@app/features/permissions/utils/PermissionUtils'; +import {Logger} from '@app/features/platform/utils/AppLogger'; +import Relationships from '@app/features/relationship/state/Relationships'; +import {getLoadedUnicodeConfusables, loadUnicodeConfusables} from '@app/features/search/utils/SearchTextMatching'; +import Slowmode from '@app/features/slowmode/state/Slowmode'; +import {useNow} from '@app/features/ui/state/Tick'; +import type {User} from '@app/features/user/models/User'; +import Users from '@app/features/user/state/Users'; +import * as NicknameUtils from '@app/features/user/utils/NicknameUtils'; +import {ChannelTypes, Permissions} from '@fluxer/constants/src/ChannelConstants'; +import {GuildNSFWLevel, GuildOperations} from '@fluxer/constants/src/GuildConstants'; +import {CHANNEL_RATE_LIMIT_PER_USER_MAX} from '@fluxer/constants/src/LimitConstants'; +import {RelationshipTypes} from '@fluxer/constants/src/UserConstants'; +import type {MessageEmbed} from '@fluxer/schema/src/domains/message/EmbedSchemas'; +import type {MessageAttachment} from '@fluxer/schema/src/domains/message/MessageResponseSchemas'; +import type {I18n} from '@lingui/core'; +import {msg} from '@lingui/core/macro'; +import {useLingui} from '@lingui/react/macro'; +import {comparer, computed, type IComputedValue} from 'mobx'; +import {useEffect, useMemo, useState} from 'react'; + +const GUILD_MESSAGES_DISABLED_DESCRIPTOR = msg({ + message: 'Sending messages is disabled in this community', + comment: 'Short label under a destination row in the forward modal, shown when the community has messaging disabled.', +}); +const EMBED_LINKS_PERMISSION_REQUIRED_DESCRIPTOR = msg({ + message: 'You need the "{embedLinksPermissionLabel}" permission to embed links in this channel', + comment: + 'Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel.', +}); +const ATTACH_FILES_PERMISSION_REQUIRED_DESCRIPTOR = msg({ + message: 'You need the "{attachFilesPermissionLabel}" permission to attach files in this channel', + comment: + 'Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel.', +}); +const AGE_RESTRICTED_DESTINATION_DESCRIPTOR = msg({ + message: 'This message can only be forwarded to age-restricted channels', + comment: + 'Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted.', +}); +const SLOWMODE_WAIT_DESCRIPTOR = msg({ + message: 'Slowmode · wait {remaining}', + comment: + 'Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code.', +}); +const CHANNEL_DESCRIPTOR = msg({ + message: 'Channel {id}', + comment: + 'Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code.', +}); + +const SEARCH_LIMIT = 20; +const SINGLE_TYPE_SEARCH_LIMIT = 50; +const NO_DESTINATIONS: ReadonlyArray = Object.freeze([]); +const NO_STRINGS: ReadonlyArray = Object.freeze([]); +const NO_ATTACHMENTS: ReadonlyArray = Object.freeze([]); +const NO_EMBEDS: ReadonlyArray = Object.freeze([]); +const NO_SEARCH_RESULTS: ReadonlyArray = Object.freeze([]); +const NO_CONFUSABLES: ReadonlyMap = new Map(); +const INITIAL_PINNED_DESTINATIONS: ForwardPinnedDestinations = Object.freeze({ + engineQuery: null, + pinned: NO_DESTINATIONS, +}); +const logger = new Logger('ForwardDestinations'); + +interface ForwardMediaNeeds { + readonly hasAgeRestrictedMedia: boolean; + readonly hasAttachments: boolean; + readonly hasEmbeds: boolean; +} + +interface ForwardSearchCandidates { + readonly boosters: ForwardSearchBoosters; + readonly channels: ReadonlyArray; + readonly groupDMs: ReadonlyArray; + readonly users: ReadonlyArray; +} + +export interface ForwardDestinationOption { + readonly channel: Channel | null; + readonly destination: ForwardDestination; + readonly detail: string | null; + readonly disableReason: string | null; + readonly displayName: string; + readonly key: string; + readonly slowmodeEnabled: boolean; + readonly slowmodeRemainingMs: number; + readonly user: User | null; +} + +interface UseForwardDestinationsOptions { + readonly mediaSelection: ForwardMediaSelection | undefined; + readonly message: Message; +} + +interface ForwardDestinationsState { + readonly composerChannel: Channel | null; + readonly options: ReadonlyArray; + readonly searchQuery: string; + readonly selected: ReadonlyArray; + readonly selectedKeys: ReadonlySet; + readonly setSearchQuery: (query: string) => void; + readonly slowmodeActiveSelectedOptions: ReadonlyArray; + readonly slowmodeEnabledSelectedOptions: ReadonlyArray; + readonly toggleDestination: (destination: ForwardDestination) => void; +} + +function findDirectMessageChannel(userId: string): Channel | null { + for (const channel of Channels.getPrivateChannels()) { + if (channel.type === ChannelTypes.DM && channel.recipientIds.includes(userId)) return channel; + } + return null; +} + +function resolveForwardChannelRow(channelId: string): ForwardRowIdentity | null { + const channel = Channels.getChannel(channelId); + if (channel == null) return null; + switch (channel.type) { + case ChannelTypes.DM: { + if (channel.recipientIds.length === 0) return null; + const recipientId = channel.recipientIds[0]; + if (Users.getUser(recipientId) == null) return null; + return {id: recipientId, type: 'user'}; + } + case ChannelTypes.GROUP_DM: + case ChannelTypes.DM_PERSONAL_NOTES: + return {id: channel.id, type: 'group_dm'}; + case ChannelTypes.GUILD_VOICE: + return {id: channel.id, type: 'voice_channel'}; + case ChannelTypes.GUILD_TEXT: + return {id: channel.id, type: 'text_channel'}; + default: + return null; + } +} + +function resolveForwardDestinationRow(destination: ForwardDestination): ForwardRowIdentity | null { + if (destination.type === 'channel') return resolveForwardChannelRow(destination.id); + if (Users.getUser(destination.id) == null) return null; + return {id: destination.id, type: 'user'}; +} + +function isForwardRowValid(row: ForwardRowIdentity): boolean { + switch (row.type) { + case 'user': + return !RuntimeConfig.directMessagesDisabled || findDirectMessageChannel(row.id) != null; + case 'group_dm': + return true; + case 'text_channel': + case 'voice_channel': { + const channel = Channels.getChannel(row.id); + if (channel == null) return false; + if (!Permission.can(Permissions.VIEW_CHANNEL | Permissions.SEND_MESSAGES, channel)) return false; + return !GuildMembers.isUserTimedOut(channel.guildId ?? null, Users.currentUserId); + } + } +} + +function collectGuildNicknames(): ReadonlyMap> { + const nicknames = new Map>(); + for (const guild of Guilds.getGuilds()) { + for (const member of GuildMembers.getMembers(guild.id)) { + if (member.nick == null) continue; + const userNicknames = nicknames.get(member.user.id); + if (userNicknames === undefined) { + nicknames.set(member.user.id, [member.nick]); + } else { + userNicknames.push(member.nick); + } + } + } + return nicknames; +} + +function buildForwardUserCandidates(): ReadonlyArray { + const nicknames = collectGuildNicknames(); + const candidates: Array = []; + for (const user of Users.getUsers()) { + const relationship = Relationships.getRelationship(user.id); + if (relationship?.type === RelationshipTypes.BLOCKED) continue; + let friendNickname: string | null = null; + if (relationship?.type === RelationshipTypes.FRIEND) friendNickname = relationship.nickname; + candidates.push( + Object.freeze({ + friendNickname, + globalName: user.globalName, + id: user.id, + nicknames: nicknames.get(user.id) ?? NO_STRINGS, + username: user.discriminator === '0' ? user.username : `${user.username}#${user.discriminator}`, + }), + ); + } + return Object.freeze(candidates); +} + +function collectRecipientSearchFields(recipientIds: ReadonlyArray): ReadonlyArray { + const fields: Array = []; + for (const recipientId of recipientIds) { + const recipient = Users.getUser(recipientId); + if (recipient == null) continue; + fields.push(recipient.username); + if (recipient.globalName != null) fields.push(recipient.globalName); + const relationshipNickname = Relationships.getRelationship(recipientId)?.nickname; + if (relationshipNickname != null) fields.push(relationshipNickname); + } + return Object.freeze(fields); +} + +function buildForwardGroupDMCandidates(i18n: I18n): ReadonlyArray { + const candidates: Array = []; + for (const channel of Channels.getPrivateChannels()) { + if (channel.type !== ChannelTypes.GROUP_DM) continue; + candidates.push( + Object.freeze({ + id: channel.id, + memberFields: collectRecipientSearchFields(channel.recipientIds), + name: ChannelUtils.getDMDisplayName(channel), + }), + ); + } + const currentUserId = Users.currentUserId; + const personalNotes = currentUserId == null ? undefined : Channels.getChannel(currentUserId); + if (personalNotes?.type === ChannelTypes.DM_PERSONAL_NOTES) { + candidates.push( + Object.freeze({id: personalNotes.id, memberFields: NO_STRINGS, name: i18n._(PERSONAL_NOTES_DESCRIPTOR)}), + ); + } + return Object.freeze(candidates); +} + +function buildForwardChannelCandidates(): ReadonlyArray { + const candidates: Array = []; + for (const channel of Channels.allChannels) { + if (channel.type !== ChannelTypes.GUILD_TEXT && channel.type !== ChannelTypes.GUILD_VOICE) continue; + const isVoice = channel.type === ChannelTypes.GUILD_VOICE; + const accessPermissions = isVoice ? Permissions.VIEW_CHANNEL | Permissions.CONNECT : Permissions.VIEW_CHANNEL; + candidates.push( + Object.freeze({ + canAccess: Permission.can(accessPermissions, channel), + guildName: channel.guildId == null ? null : (Guilds.getGuild(channel.guildId)?.name ?? null), + hasFrecency: ChannelFrecency.getScore(channel.id) > 0, + id: channel.id, + kind: isVoice ? 'voice' : 'text', + name: channel.name ?? '', + parentName: channel.parentId == null ? null : (Channels.getChannel(channel.parentId)?.name ?? null), + }), + ); + } + return Object.freeze(candidates); +} + +function resolveForwardFrequentItem(id: string): ForwardFrequentItem { + const score = ChannelFrecency.getScore(id); + const channel = Guilds.getGuild(id) == null ? Channels.getChannel(id) : undefined; + switch (channel?.type) { + case ChannelTypes.DM: + return {id, kind: 'dm', recipientId: channel.recipientIds.length > 0 ? channel.recipientIds[0] : null, score}; + case ChannelTypes.GROUP_DM: + case ChannelTypes.DM_PERSONAL_NOTES: + return {id, kind: 'group_dm', score}; + case ChannelTypes.GUILD_TEXT: + return {id, kind: 'text', score}; + case ChannelTypes.GUILD_VOICE: + return {id, kind: 'voice', score}; + default: + return {id, kind: 'other', score}; + } +} + +function buildForwardSearchBoostersFromStores(): ForwardSearchBoosters { + const friendIds: Array = []; + for (const relationship of Relationships.getRelationships()) { + if (relationship.type === RelationshipTypes.FRIEND) friendIds.push(relationship.userId); + } + const dmUserIds: Array = []; + for (const channel of Channels.getPrivateChannels()) { + if (channel.type === ChannelTypes.DM && channel.recipientIds.length > 0) dmUserIds.push(channel.recipientIds[0]); + } + return buildForwardSearchBoosters({ + dmUserIds, + frequent: ChannelFrecency.frequentIds.map(resolveForwardFrequentItem), + friendIds, + }); +} + +function createForwardSearchCandidates(i18n: I18n): IComputedValue { + const options = {equals: comparer.structural}; + const users = computed(buildForwardUserCandidates, options); + const groupDMs = computed(() => buildForwardGroupDMCandidates(i18n), options); + const channels = computed(buildForwardChannelCandidates, options); + const boosters = computed(buildForwardSearchBoostersFromStores, options); + return computed(() => + Object.freeze({boosters: boosters.get(), channels: channels.get(), groupDMs: groupDMs.get(), users: users.get()}), + ); +} + +function selectForwardedAttachments( + message: Message, + mediaSelection: ForwardMediaSelection | undefined, +): ReadonlyArray { + const snapshot = message.messageSnapshots?.[0]; + const attachments = snapshot == null ? message.attachments : (snapshot.attachments ?? NO_ATTACHMENTS); + const attachmentIds = mediaSelection?.attachmentIds; + if (attachmentIds !== undefined) return attachments.filter((attachment) => attachmentIds.includes(attachment.id)); + if (mediaSelection?.embedIndices !== undefined) return NO_ATTACHMENTS; + return attachments; +} + +function selectForwardedEmbeds( + message: Message, + mediaSelection: ForwardMediaSelection | undefined, +): ReadonlyArray { + const snapshot = message.messageSnapshots?.[0]; + const embeds = snapshot == null ? message.embeds : (snapshot.embeds ?? NO_EMBEDS); + const embedIndices = mediaSelection?.embedIndices; + if (embedIndices !== undefined) return embeds.filter((_embed, index) => embedIndices.includes(index)); + if (mediaSelection?.attachmentIds !== undefined) return NO_EMBEDS; + return embeds; +} + +function isAgeRestrictedEmbed(embed: MessageEmbed): boolean { + if (embed.nsfw === true) return true; + return (embed.children ?? []).some((child) => child.nsfw === true); +} + +function resolveForwardMediaNeeds( + message: Message, + mediaSelection: ForwardMediaSelection | undefined, +): ForwardMediaNeeds { + const attachments = selectForwardedAttachments(message, mediaSelection); + const embeds = selectForwardedEmbeds(message, mediaSelection); + return Object.freeze({ + hasAgeRestrictedMedia: + attachments.some((attachment) => attachment.nsfw === true) || embeds.some(isAgeRestrictedEmbed), + hasAttachments: attachments.length > 0, + hasEmbeds: embeds.length > 0, + }); +} + +function canReceiveAgeRestrictedMedia(channel: Channel): boolean { + if (channel.type === ChannelTypes.DM_PERSONAL_NOTES) return true; + if (channel.nsfw) return true; + if (channel.guildId == null) return false; + return Guilds.getGuild(channel.guildId)?.nsfwLevel === GuildNSFWLevel.AGE_RESTRICTED; +} + +function resolveAgeRestrictedDisableReason( + channel: Channel | null, + mediaNeeds: ForwardMediaNeeds, + i18n: I18n, +): string | null { + if (!mediaNeeds.hasAgeRestrictedMedia) return null; + if (channel != null && canReceiveAgeRestrictedMedia(channel)) return null; + return i18n._(AGE_RESTRICTED_DESTINATION_DESCRIPTOR); +} + +function isSlowmodeEnforced(channel: Channel): boolean { + const rateLimitPerUser = channel.rateLimitPerUser; + if (!Number.isSafeInteger(rateLimitPerUser) || rateLimitPerUser <= 0) return false; + if (rateLimitPerUser > CHANNEL_RATE_LIMIT_PER_USER_MAX) return false; + return !Permission.can(Permissions.BYPASS_SLOWMODE, channel); +} + +function resolveSlowmodeRemainingMs(channel: Channel): number { + if (DeveloperOptions.mockSlowmodeActive) return DeveloperOptions.mockSlowmodeRemaining; + return Slowmode.getSlowmodeRemaining(channel.id, channel.rateLimitPerUser); +} + +function isSlowmodeActive(option: ForwardDestinationOption): boolean { + return option.slowmodeRemainingMs > 0; +} + +function formatGuildChannelDetail(guild: Guild | undefined, channel: Channel): string | null { + let categoryName: string | undefined; + if (channel.parentId != null) categoryName = Channels.getChannel(channel.parentId)?.name; + const detail = [guild?.name, categoryName].filter(Boolean).join(' • '); + return detail === '' ? null : detail; +} + +function resolveGuildChannelDisableReason( + channel: Channel, + guild: Guild | undefined, + slowmodeRemainingMs: number, + mediaNeeds: ForwardMediaNeeds, + i18n: I18n, +): string | null { + const ageRestrictedReason = resolveAgeRestrictedDisableReason(channel, mediaNeeds, i18n); + if (ageRestrictedReason != null) return ageRestrictedReason; + if (guild != null && (guild.disabledOperations & GuildOperations.SEND_MESSAGE) !== 0) { + return i18n._(GUILD_MESSAGES_DISABLED_DESCRIPTOR); + } + if (mediaNeeds.hasAttachments && !Permission.can(Permissions.ATTACH_FILES, channel)) { + const attachFilesPermissionLabel = formatPermissionLabel(i18n, Permissions.ATTACH_FILES); + return i18n._(ATTACH_FILES_PERMISSION_REQUIRED_DESCRIPTOR, {attachFilesPermissionLabel}); + } + if (mediaNeeds.hasEmbeds && !Permission.can(Permissions.EMBED_LINKS, channel)) { + const embedLinksPermissionLabel = formatPermissionLabel(i18n, Permissions.EMBED_LINKS); + return i18n._(EMBED_LINKS_PERMISSION_REQUIRED_DESCRIPTOR, {embedLinksPermissionLabel}); + } + if (slowmodeRemainingMs <= 0) return null; + return i18n._(SLOWMODE_WAIT_DESCRIPTOR, {remaining: formatSlowmodeTime(slowmodeRemainingMs, i18n.locale)}); +} + +function resolveForwardDestinationOption( + destination: ForwardDestination, + mediaNeeds: ForwardMediaNeeds, + i18n: I18n, +): ForwardDestinationOption | null { + const key = forwardDestinationKey(destination); + if (destination.type === 'user') { + const user = Users.getUser(destination.id); + if (user == null) return null; + return Object.freeze({ + channel: null, + destination, + detail: NicknameUtils.formatUserTagForStreamerMode(user), + disableReason: resolveAgeRestrictedDisableReason(findDirectMessageChannel(destination.id), mediaNeeds, i18n), + displayName: NicknameUtils.getNickname(user, null), + key, + slowmodeEnabled: false, + slowmodeRemainingMs: 0, + user, + }); + } + const channel = Channels.getChannel(destination.id); + if (channel == null) return null; + if (channel.guildId == null) { + return Object.freeze({ + channel, + destination, + detail: null, + disableReason: resolveAgeRestrictedDisableReason(channel, mediaNeeds, i18n), + displayName: ChannelUtils.getDMDisplayName(channel), + key, + slowmodeEnabled: false, + slowmodeRemainingMs: 0, + user: null, + }); + } + const guild = Guilds.getGuild(channel.guildId); + const slowmodeEnabled = isSlowmodeEnforced(channel); + const slowmodeRemainingMs = slowmodeEnabled ? resolveSlowmodeRemainingMs(channel) : 0; + return Object.freeze({ + channel, + destination, + detail: formatGuildChannelDetail(guild, channel), + disableReason: resolveGuildChannelDisableReason(channel, guild, slowmodeRemainingMs, mediaNeeds, i18n), + displayName: channel.name || i18n._(CHANNEL_DESCRIPTOR, {id: channel.id}), + key, + slowmodeEnabled, + slowmodeRemainingMs, + user: null, + }); +} + +function resolveForwardDestinationOptions( + destinations: ReadonlyArray, + mediaNeeds: ForwardMediaNeeds, + i18n: I18n, +): ReadonlyArray { + const options: Array = []; + for (const destination of destinations) { + const option = resolveForwardDestinationOption(destination, mediaNeeds, i18n); + if (option != null) options.push(option); + } + return options; +} + +function resolveForwardComposerChannel(selected: ReadonlyArray): Channel | null { + for (const destination of selected) { + const channel = + destination.type === 'user' ? findDirectMessageChannel(destination.id) : Channels.getChannel(destination.id); + if (channel != null) return channel; + } + return null; +} + +export function useForwardDestinations({ + mediaSelection, + message, +}: UseForwardDestinationsOptions): ForwardDestinationsState { + const {i18n} = useLingui(); + const [searchQuery, setSearchQuery] = useState(''); + const [selected, setSelected] = useState(NO_DESTINATIONS); + const [pinnedDestinations, setPinnedDestinations] = useState(INITIAL_PINNED_DESTINATIONS); + const [confusables, setConfusables] = useState(() => getLoadedUnicodeConfusables() ?? NO_CONFUSABLES); + const searchCandidates = useMemo(() => createForwardSearchCandidates(i18n), [i18n, i18n.locale]); + const mediaNeeds = useMemo(() => resolveForwardMediaNeeds(message, mediaSelection), [message, mediaSelection]); + const parsedQuery = useMemo(() => parseForwardDestinationQuery(searchQuery), [searchQuery]); + const engineQuery = parsedQuery.query.trim() === '' ? '' : parsedQuery.query; + const currentPinned = pinForwardDestinations(pinnedDestinations, engineQuery, selected); + if (currentPinned !== pinnedDestinations) setPinnedDestinations(currentPinned); + useEffect(() => { + let isMounted = true; + loadUnicodeConfusables().then( + (loaded) => { + if (isMounted) setConfusables(loaded); + }, + (error: unknown) => logger.warn('Failed to load Unicode confusables', error), + ); + return () => { + isMounted = false; + }; + }, []); + const candidates = engineQuery === '' ? null : searchCandidates.get(); + const currentUserId = Users.currentUserId; + const searchResults = useMemo(() => { + if (candidates == null) return NO_SEARCH_RESULTS; + return searchForwardDestinations({ + ...candidates, + blacklist: new Set(currentUserId == null ? NO_STRINGS : [currentUserId]), + confusables, + limit: parsedQuery.resultTypes.length === 1 ? SINGLE_TYPE_SEARCH_LIMIT : SEARCH_LIMIT, + query: engineQuery, + resultTypes: parsedQuery.resultTypes, + }); + }, [candidates, confusables, currentUserId, engineQuery, parsedQuery]); + const rows = + candidates == null + ? buildForwardDefaultDestinations({ + frequentIds: ChannelFrecency.frequentIds, + history: [...new Set(SelectedChannel.sortedRecentVisits.map((visit) => visit.channelId))], + isValid: isForwardRowValid, + mode: parsedQuery.mode, + origin: resolveForwardOrigin(message.channelId, Channels.getChannel(message.channelId)), + pinned: currentPinned.pinned, + resolveChannel: resolveForwardChannelRow, + resolveDestination: resolveForwardDestinationRow, + selected, + }) + : filterForwardSearchRows(searchResults, isForwardRowValid); + const options = resolveForwardDestinationOptions( + rows.map((row) => row.destination), + mediaNeeds, + i18n, + ); + const selectedOptions = resolveForwardDestinationOptions(selected, mediaNeeds, i18n); + useNow(options.some(isSlowmodeActive) || selectedOptions.some(isSlowmodeActive)); + const toggleDestination = (destination: ForwardDestination) => { + const next = toggleForwardDestination(selected, destination); + if (next === selected) return; + if (next.length > selected.length) setSearchQuery(''); + setSelected(next); + }; + return { + composerChannel: resolveForwardComposerChannel(selected), + options, + searchQuery, + selected, + selectedKeys: new Set(selected.map(forwardDestinationKey)), + setSearchQuery, + slowmodeActiveSelectedOptions: selectedOptions.filter(isSlowmodeActive), + slowmodeEnabledSelectedOptions: selectedOptions.filter((option) => option.slowmodeEnabled), + toggleDestination, + }; +} diff --git a/fluxer_app/src/features/app/hooks/useShallowStableArray.ts b/fluxer_app/src/features/app/hooks/useShallowStableArray.ts deleted file mode 100644 index b2fa9c792..000000000 --- a/fluxer_app/src/features/app/hooks/useShallowStableArray.ts +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later - -import {useRef} from 'react'; - -export function useShallowStableArray>(values: Values): Values { - const stableValuesRef = useRef(values); - const stableValues = stableValuesRef.current; - if (stableValues.length !== values.length || values.some((value, index) => !Object.is(value, stableValues[index]))) { - stableValuesRef.current = values; - } - return stableValuesRef.current; -} diff --git a/fluxer_app/src/features/channel/state/ChannelFrecency.test.ts b/fluxer_app/src/features/channel/state/ChannelFrecency.test.ts new file mode 100644 index 000000000..4a73f8e9a --- /dev/null +++ b/fluxer_app/src/features/channel/state/ChannelFrecency.test.ts @@ -0,0 +1,272 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +import {ChannelTypes} from '@fluxer/constants/src/ChannelConstants'; +import {autorun, runInAction} from 'mobx'; +import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest'; + +interface FakeChannel { + readonly id: string; + readonly type: number; + readonly recipientIds: ReadonlyArray; +} + +type ChannelFrecencyStore = typeof import('@app/features/channel/state/ChannelFrecency')['default']; + +interface SyncedFieldFake { + seed: Record}> | null; + toMessage: (() => {usage: Record}>}) | null; +} + +const fakes = await vi.hoisted(async () => { + const {observable} = await import('mobx'); + return { + navigation: observable({guildId: null as string | null, channelId: null as string | null}), + voice: observable({ + guildId: null as string | null, + channelId: null as string | null, + localDisconnectReason: null as string | null, + }), + guildIds: new Set(), + channels: new Map(), + synced: {seed: null, toMessage: null} as SyncedFieldFake, + }; +}); + +vi.mock('@app/features/user/state/SyncedField', () => ({ + makeSyncedField: async ( + store: object, + config: { + toMessage: (store: never) => {usage: Record}>}; + applyMessage: (store: never, message: {usage: Record}) => void; + }, + ) => { + fakes.synced.toMessage = () => config.toMessage(store as never); + if (fakes.synced.seed !== null) { + config.applyMessage(store as never, {usage: fakes.synced.seed}); + } + }, +})); + +vi.mock('@app/features/navigation/state/Navigation', () => ({default: fakes.navigation})); +vi.mock('@app/features/voice/engine/MediaEngineFacade', () => ({default: fakes.voice})); +vi.mock('@app/features/guild/state/Guilds', () => ({ + default: {getGuild: (guildId: string) => (fakes.guildIds.has(guildId) ? {id: guildId} : undefined)}, +})); +vi.mock('@app/features/channel/state/Channels', () => ({ + default: { + getChannel: (channelId: string) => fakes.channels.get(channelId), + getPrivateChannels: () => Array.from(fakes.channels.values()), + }, +})); + +const HOUR_MS = 3_600_000; +const DAY_MS = 24 * HOUR_MS; +const T0 = Date.UTC(2026, 6, 15, 12); +const GUILD_ID = '1400000000000000100'; +const OTHER_GUILD_ID = '1400000000000000200'; +const TEXT_CHANNEL_ID = '1400000000000000101'; +const OTHER_TEXT_CHANNEL_ID = '1400000000000000102'; +const VOICE_CHANNEL_ID = '1400000000000000103'; +const OTHER_VOICE_CHANNEL_ID = '1400000000000000104'; +const OTHER_GUILD_VOICE_CHANNEL_ID = '1400000000000000201'; +const DM_CHANNEL_ID = '1400000000000000301'; +const FRIEND_ID = '1400000000000000401'; + +async function startChannelFrecency( + synced?: ReadonlyArray}]>, +): Promise { + vi.resetModules(); + fakes.synced.seed = + synced === undefined + ? null + : Object.fromEntries( + synced.map(([key, entry]) => [ + key, + {totalUses: entry.totalUses, recentUsesMs: entry.recentUses.map((use) => BigInt(use))}, + ]), + ); + const {default: ChannelFrecency} = await import('@app/features/channel/state/ChannelFrecency'); + await vi.advanceTimersByTimeAsync(0); + return ChannelFrecency; +} + +function navigate(guildId: string | null, channelId: string | null): void { + runInAction(() => { + fakes.navigation.guildId = guildId; + fakes.navigation.channelId = channelId; + }); +} + +function setVoiceChannel(guildId: string | null, channelId: string | null): void { + runInAction(() => { + fakes.voice.localDisconnectReason = channelId == null ? 'user' : null; + fakes.voice.guildId = guildId; + fakes.voice.channelId = channelId; + }); +} + +function moveVoiceChannel(guildId: string | null, channelId: string): void { + runInAction(() => { + fakes.voice.localDisconnectReason = 'channelMove'; + fakes.voice.guildId = null; + fakes.voice.channelId = null; + }); + setVoiceChannel(guildId, channelId); +} + +function totalUses(store: ChannelFrecencyStore, key: string): number { + return store.usageHistory.get(key)?.totalUses ?? 0; +} + +function keyFor(index: number): string { + return `1400000000000000${String(index).padStart(3, '0')}`; +} + +beforeEach(() => { + vi.useFakeTimers(); + vi.setSystemTime(T0); + navigate(null, null); + setVoiceChannel(null, null); + runInAction(() => { + fakes.voice.localDisconnectReason = null; + }); + fakes.guildIds.clear(); + fakes.channels.clear(); +}); + +afterEach(() => { + vi.useRealTimers(); +}); + +describe('ChannelFrecency tracking', () => { + it('counts the landing channel and its guild once when tracking starts', async () => { + navigate(GUILD_ID, TEXT_CHANNEL_ID); + const store = await startChannelFrecency(); + expect(totalUses(store, TEXT_CHANNEL_ID)).toBe(1); + expect(totalUses(store, GUILD_ID)).toBe(1); + expect(store.getScore(TEXT_CHANNEL_ID)).toBe(100); + }); + + it('counts a channel again after a page without a channel but not a guild the user stays in', async () => { + const store = await startChannelFrecency(); + navigate(GUILD_ID, TEXT_CHANNEL_ID); + navigate(GUILD_ID, OTHER_TEXT_CHANNEL_ID); + navigate(GUILD_ID, TEXT_CHANNEL_ID); + expect(totalUses(store, TEXT_CHANNEL_ID)).toBe(2); + expect(totalUses(store, GUILD_ID)).toBe(1); + navigate(null, null); + navigate(GUILD_ID, TEXT_CHANNEL_ID); + expect(totalUses(store, TEXT_CHANNEL_ID)).toBe(3); + expect(totalUses(store, GUILD_ID)).toBe(2); + }); + + it('treats direct messages as guildless and never stores ids that are not snowflakes', async () => { + const store = await startChannelFrecency(); + navigate(GUILD_ID, TEXT_CHANNEL_ID); + navigate('@me', DM_CHANNEL_ID); + navigate(GUILD_ID, 'settings'); + navigate(GUILD_ID, TEXT_CHANNEL_ID); + expect([...store.usageHistory.keys()]).toEqual([TEXT_CHANNEL_ID, GUILD_ID, DM_CHANNEL_ID]); + expect(totalUses(store, TEXT_CHANNEL_ID)).toBe(2); + expect(totalUses(store, GUILD_ID)).toBe(2); + expect(totalUses(store, DM_CHANNEL_ID)).toBe(1); + }); + + it('counts voice joins through the same last selection as navigation', async () => { + const store = await startChannelFrecency(); + navigate(GUILD_ID, VOICE_CHANNEL_ID); + setVoiceChannel(GUILD_ID, VOICE_CHANNEL_ID); + expect(totalUses(store, VOICE_CHANNEL_ID)).toBe(1); + navigate(GUILD_ID, TEXT_CHANNEL_ID); + setVoiceChannel(GUILD_ID, OTHER_VOICE_CHANNEL_ID); + navigate(GUILD_ID, OTHER_VOICE_CHANNEL_ID); + expect(totalUses(store, OTHER_VOICE_CHANNEL_ID)).toBe(1); + setVoiceChannel(null, null); + setVoiceChannel(GUILD_ID, OTHER_VOICE_CHANNEL_ID); + expect(totalUses(store, OTHER_VOICE_CHANNEL_ID)).toBe(2); + setVoiceChannel(OTHER_GUILD_ID, OTHER_GUILD_VOICE_CHANNEL_ID); + expect(totalUses(store, OTHER_GUILD_VOICE_CHANNEL_ID)).toBe(1); + expect(totalUses(store, OTHER_GUILD_ID)).toBe(1); + expect(totalUses(store, GUILD_ID)).toBe(2); + }); + + it('counts a move between voice channels in one guild as a single guild use', async () => { + const store = await startChannelFrecency(); + setVoiceChannel(GUILD_ID, VOICE_CHANNEL_ID); + moveVoiceChannel(GUILD_ID, OTHER_VOICE_CHANNEL_ID); + expect(totalUses(store, VOICE_CHANNEL_ID)).toBe(1); + expect(totalUses(store, OTHER_VOICE_CHANNEL_ID)).toBe(1); + expect(totalUses(store, GUILD_ID)).toBe(1); + }); + + it('keeps at most 100 keys and drops the one used longest ago', async () => { + const store = await startChannelFrecency(); + for (let index = 0; index <= 100; index++) { + store.track(keyFor(index), T0 + index); + } + expect(store.usageHistory.size).toBe(100); + expect(store.usageHistory.has(keyFor(0))).toBe(false); + expect(store.usageHistory.has(keyFor(100))).toBe(true); + }); +}); + +describe('ChannelFrecency account sync', () => { + it('re-derives persisted frecency against the current time on start', async () => { + const store = await startChannelFrecency([ + [TEXT_CHANNEL_ID, {totalUses: 5, recentUses: [T0 - 8 * DAY_MS - HOUR_MS, T0 - 8 * DAY_MS]}], + [GUILD_ID, {totalUses: 1, recentUses: []}], + ]); + expect(store.getScore(TEXT_CHANNEL_ID)).toBe(50); + expect(store.usageHistory.has(GUILD_ID)).toBe(false); + }); + + it('re-derives frecency again as a long session ages', async () => { + const store = await startChannelFrecency([[TEXT_CHANNEL_ID, {totalUses: 3, recentUses: [T0 - DAY_MS]}]]); + expect(store.getScore(TEXT_CHANNEL_ID)).toBe(210); + await vi.advanceTimersByTimeAsync(6 * DAY_MS); + expect(store.getScore(TEXT_CHANNEL_ID)).toBe(30); + }); + + it('hands the account sync only the uses, not the derived scores', async () => { + await startChannelFrecency(); + navigate(GUILD_ID, TEXT_CHANNEL_ID); + await vi.advanceTimersByTimeAsync(1_000); + expect(fakes.synced.toMessage?.()).toEqual({ + usage: { + [TEXT_CHANNEL_ID]: {totalUses: 1, recentUsesMs: [BigInt(T0)]}, + [GUILD_ID]: {totalUses: 1, recentUsesMs: [BigInt(T0)]}, + }, + }); + }); +}); + +describe('ChannelFrecency ranking', () => { + it('ranks resolvable guild, channel and direct message keys by frecency', async () => { + fakes.guildIds.add(GUILD_ID); + fakes.channels.set(TEXT_CHANNEL_ID, {id: TEXT_CHANNEL_ID, type: ChannelTypes.GUILD_TEXT, recipientIds: []}); + fakes.channels.set(DM_CHANNEL_ID, {id: DM_CHANNEL_ID, type: ChannelTypes.DM, recipientIds: [FRIEND_ID]}); + const store = await startChannelFrecency(); + store.track(GUILD_ID); + store.track(FRIEND_ID); + store.track(OTHER_TEXT_CHANNEL_ID); + store.track(TEXT_CHANNEL_ID); + store.track(TEXT_CHANNEL_ID); + expect(store.frequentIds).toEqual([TEXT_CHANNEL_ID, GUILD_ID, DM_CHANNEL_ID]); + expect(store.getScore(TEXT_CHANNEL_ID)).toBe(200); + expect(store.getScore(DM_CHANNEL_ID)).toBe(0); + }); + + it('lets observers follow the ranking as the user moves around', async () => { + fakes.guildIds.add(GUILD_ID); + fakes.channels.set(TEXT_CHANNEL_ID, {id: TEXT_CHANNEL_ID, type: ChannelTypes.GUILD_TEXT, recipientIds: []}); + const store = await startChannelFrecency(); + const seen: Array> = []; + const dispose = autorun(() => { + seen.push(store.frequentIds); + }); + navigate(GUILD_ID, TEXT_CHANNEL_ID); + dispose(); + expect(seen[0]).toEqual([]); + expect(seen.at(-1)).toEqual([TEXT_CHANNEL_ID, GUILD_ID]); + }); +}); diff --git a/fluxer_app/src/features/channel/state/ChannelFrecency.ts b/fluxer_app/src/features/channel/state/ChannelFrecency.ts new file mode 100644 index 000000000..15e2d5dbc --- /dev/null +++ b/fluxer_app/src/features/channel/state/ChannelFrecency.ts @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +import Channels from '@app/features/channel/state/Channels'; +import { + type ChannelFrecencyEntry, + capChannelFrecencyHistory, + channelFrecencyHistoryFromWire, + channelFrecencyHistoryToWire, + computeChannelFrecency, + mergeChannelFrecencyWireUsage, + rankFrequentChannelIds, + restoreChannelFrecencyHistory, + trackChannelUse, +} from '@app/features/channel/utils/ChannelFrecencyCalculator'; +import Guilds from '@app/features/guild/state/Guilds'; +import Navigation from '@app/features/navigation/state/Navigation'; +import {makeSyncedField} from '@app/features/user/state/SyncedField'; +import MediaEngine from '@app/features/voice/engine/MediaEngineFacade'; +import {ME} from '@fluxer/constants/src/AppConstants'; +import {ChannelTypes} from '@fluxer/constants/src/ChannelConstants'; +import {ChannelFrecencyStateSchema} from '@fluxer/schema/src/gen/fluxer/user/preferences/v1/preferences_pb'; +import {comparer, isObservableMap, makeAutoObservable, observable, reaction} from 'mobx'; + +const TRACKABLE_ID_PATTERN = /^\d{17,19}$/; +const FRECENCY_REFRESH_INTERVAL_MS = 3_600_000; +const FRECENCY_SYNC_DEBOUNCE_MS = 1_500; + +let lastChannelId: string | null = null; +let lastGuildId: string | null = null; + +function isTrackableId(id: string | null): id is string { + return id !== null && TRACKABLE_ID_PATTERN.test(id); +} + +function findDMChannelIdForRecipient(userId: string): string | null { + for (const channel of Channels.getPrivateChannels()) { + if (channel.type === ChannelTypes.DM && channel.recipientIds.includes(userId)) { + return channel.id; + } + } + return null; +} + +function resolveFrecencyRecordId(key: string): string | null { + return Guilds.getGuild(key)?.id ?? Channels.getChannel(key)?.id ?? findDMChannelIdForRecipient(key); +} + +class ChannelFrecency { + usageHistory = new Map(); + + constructor() { + makeAutoObservable(this, {usageHistory: observable.shallow}, {autoBind: true}); + void this.initPersistence(); + } + + private async initPersistence(): Promise { + await makeSyncedField(this, { + field: 'channelFrecency', + schema: ChannelFrecencyStateSchema, + persist: ['usageHistory'], + debounceMs: FRECENCY_SYNC_DEBOUNCE_MS, + toMessage: (store) => ({usage: channelFrecencyHistoryToWire(store.usageHistory)}), + applyMessage: (store, message) => { + store.usageHistory = channelFrecencyHistoryFromWire(message.usage, Date.now()); + }, + mergeRemote: (local, incoming) => ({ + usage: mergeChannelFrecencyWireUsage(local.usage, incoming.usage, Date.now()), + }), + }); + this.refreshHistory(); + setInterval(this.refreshHistory, FRECENCY_REFRESH_INTERVAL_MS); + reaction( + () => [Navigation.guildId, Navigation.channelId] as const, + ([guildId, channelId]) => this.recordSelection(guildId, channelId), + {equals: comparer.shallow, fireImmediately: true}, + ); + reaction( + () => [MediaEngine.guildId, MediaEngine.channelId] as const, + ([guildId, channelId]) => { + if (channelId === null && MediaEngine.localDisconnectReason === 'channelMove') return; + this.recordSelection(guildId, channelId); + }, + {equals: comparer.shallow}, + ); + } + + get frequentIds(): ReadonlyArray { + return rankFrequentChannelIds(this.usageHistory, resolveFrecencyRecordId); + } + + getScore(id: string): number { + return this.usageHistory.get(id)?.frecency ?? 0; + } + + track(key: string, timestamp?: number): void { + trackChannelUse(this.usageHistory, key, timestamp); + capChannelFrecencyHistory(this.usageHistory); + computeChannelFrecency(this.usageHistory, Date.now()); + } + + recordSelection(guildId: string | null, channelId: string | null): void { + const selectedGuildId = guildId === ME ? null : guildId; + if (channelId !== lastChannelId) { + lastChannelId = channelId; + if (isTrackableId(channelId)) { + this.track(channelId); + } + } + if (selectedGuildId !== lastGuildId) { + lastGuildId = selectedGuildId; + if (isTrackableId(selectedGuildId)) { + this.track(selectedGuildId); + } + } + } + + private refreshHistory(): void { + const current: unknown = this.usageHistory; + if (!isObservableMap(current)) return; + this.usageHistory = restoreChannelFrecencyHistory(current.entries(), Date.now()); + } +} + +export default new ChannelFrecency(); diff --git a/fluxer_app/src/features/channel/utils/ChannelFrecencyCalculator.test.ts b/fluxer_app/src/features/channel/utils/ChannelFrecencyCalculator.test.ts new file mode 100644 index 000000000..9ab222270 --- /dev/null +++ b/fluxer_app/src/features/channel/utils/ChannelFrecencyCalculator.test.ts @@ -0,0 +1,305 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +import { + type ChannelFrecencyEntry, + type ChannelFrecencyHistory, + capChannelFrecencyHistory, + channelFrecencyDayDiff, + channelFrecencyHistoryFromWire, + channelFrecencyHistoryToWire, + channelFrecencyWeight, + computeChannelFrecency, + mergeChannelFrecencyWireUsage, + rankFrequentChannelIds, + restoreChannelFrecencyHistory, + trackChannelUse, +} from '@app/features/channel/utils/ChannelFrecencyCalculator'; +import {afterEach, describe, expect, it, vi} from 'vitest'; + +const HOUR_MS = 3_600_000; +const DAY_MS = 24 * HOUR_MS; +const NOW = Date.UTC(2026, 6, 15, 12); +const CHANNEL_ID = '1400000000000000001'; +const STOCKHOLM_SUMMER_TIME_START = Date.UTC(2026, 2, 29, 1); +const STOCKHOLM_SUMMER_TIME_END = Date.UTC(2026, 9, 25, 1); + +function useStockholmClock(): void { + vi.spyOn(Date.prototype, 'getTimezoneOffset').mockImplementation(function (this: Date) { + const time = this.getTime(); + return time >= STOCKHOLM_SUMMER_TIME_START && time < STOCKHOLM_SUMMER_TIME_END ? -120 : -60; + }); +} + +function computedEntry(frecency: number): ChannelFrecencyEntry { + return {totalUses: 1, recentUses: [NOW], frecency, score: frecency}; +} + +function keyFor(index: number): string { + return `1400000000000000${String(index).padStart(3, '0')}`; +} + +afterEach(() => { + vi.restoreAllMocks(); + vi.useRealTimers(); +}); + +describe('channelFrecencyWeight', () => { + it.each([ + [0, 100], + [1, 70], + [2, 50], + [3, 50], + [4, 30], + [6, 30], + [7, 10], + [365, 10], + [-1, 1], + [-3, 1], + ])('weights an age of %i days as %i', (dayDiff, weight) => { + expect(channelFrecencyWeight(dayDiff)).toBe(weight); + }); +}); + +describe('channelFrecencyDayDiff', () => { + it('counts whole elapsed days and truncates toward zero', () => { + expect(channelFrecencyDayDiff(NOW, NOW - 23 * HOUR_MS)).toBe(0); + expect(channelFrecencyDayDiff(NOW, NOW - 25 * HOUR_MS)).toBe(1); + expect(channelFrecencyDayDiff(NOW, NOW - 6 * DAY_MS - 23 * HOUR_MS)).toBe(6); + expect(channelFrecencyDayDiff(NOW, NOW + 12 * HOUR_MS)).toBe(0); + expect(channelFrecencyDayDiff(NOW, NOW + 36 * HOUR_MS)).toBe(-1); + }); + + it('counts noon to noon across the spring clock change as one day although only 23 hours pass', () => { + useStockholmClock(); + const saturdayNoon = Date.UTC(2026, 2, 28, 11); + const sundayNoon = Date.UTC(2026, 2, 29, 10); + expect(sundayNoon - saturdayNoon).toBe(23 * HOUR_MS); + expect(channelFrecencyDayDiff(sundayNoon, saturdayNoon)).toBe(1); + expect(channelFrecencyWeight(channelFrecencyDayDiff(sundayNoon, saturdayNoon))).toBe(70); + }); + + it('keeps 24.5 hours across the autumn clock change inside the same day', () => { + useStockholmClock(); + const saturdayNoon = Date.UTC(2026, 9, 24, 10); + const sundayHalfPastEleven = Date.UTC(2026, 9, 25, 10, 30); + expect(sundayHalfPastEleven - saturdayNoon).toBe(24.5 * HOUR_MS); + expect(channelFrecencyDayDiff(sundayHalfPastEleven, saturdayNoon)).toBe(0); + }); +}); + +describe('trackChannelUse', () => { + it('starts a new key with one uncomputed use', () => { + const history: ChannelFrecencyHistory = new Map(); + trackChannelUse(history, CHANNEL_ID, NOW); + expect(history.get(CHANNEL_ID)).toEqual({totalUses: 1, recentUses: [NOW], frecency: -1, score: 0}); + }); + + it('keeps arrival order for untimed uses and sorts when a timestamp is given', () => { + vi.useFakeTimers(); + const history: ChannelFrecencyHistory = new Map(); + vi.setSystemTime(NOW); + trackChannelUse(history, CHANNEL_ID); + vi.setSystemTime(NOW - HOUR_MS); + trackChannelUse(history, CHANNEL_ID); + expect(history.get(CHANNEL_ID)?.recentUses).toEqual([NOW, NOW - HOUR_MS]); + trackChannelUse(history, CHANNEL_ID, NOW - 2 * HOUR_MS); + expect(history.get(CHANNEL_ID)?.recentUses).toEqual([NOW - 2 * HOUR_MS, NOW - HOUR_MS, NOW]); + expect(history.get(CHANNEL_ID)?.totalUses).toBe(3); + }); +}); + +describe('computeChannelFrecency', () => { + it('scores 12 uses whose last 10 are 4 today, 3 yesterday and 3 five days ago as 840', () => { + const history: ChannelFrecencyHistory = new Map(); + const uses = [ + NOW - 20 * DAY_MS, + NOW - 20 * DAY_MS, + NOW - 5 * DAY_MS - HOUR_MS, + NOW - 5 * DAY_MS - 2 * HOUR_MS, + NOW - 5 * DAY_MS - 3 * HOUR_MS, + NOW - DAY_MS - HOUR_MS, + NOW - DAY_MS - 2 * HOUR_MS, + NOW - DAY_MS - 3 * HOUR_MS, + NOW - HOUR_MS, + NOW - 2 * HOUR_MS, + NOW - 3 * HOUR_MS, + NOW - 4 * HOUR_MS, + ]; + for (const use of uses) { + trackChannelUse(history, CHANNEL_ID, use); + } + computeChannelFrecency(history, NOW); + expect(history.get(CHANNEL_ID)).toEqual({ + totalUses: 12, + recentUses: [ + NOW - 5 * DAY_MS - 3 * HOUR_MS, + NOW - 5 * DAY_MS - 2 * HOUR_MS, + NOW - 5 * DAY_MS - HOUR_MS, + NOW - DAY_MS - 3 * HOUR_MS, + NOW - DAY_MS - 2 * HOUR_MS, + NOW - DAY_MS - HOUR_MS, + NOW - 4 * HOUR_MS, + NOW - 3 * HOUR_MS, + NOW - 2 * HOUR_MS, + NOW - HOUR_MS, + ], + frecency: 840, + score: 700, + }); + }); + + it('leaves computed entries alone until the key is used again', () => { + const history: ChannelFrecencyHistory = new Map(); + trackChannelUse(history, CHANNEL_ID, NOW - 8 * DAY_MS); + computeChannelFrecency(history, NOW - 8 * DAY_MS); + const computed = history.get(CHANNEL_ID); + expect(computed?.frecency).toBe(100); + computeChannelFrecency(history, NOW); + expect(history.get(CHANNEL_ID)).toBe(computed); + trackChannelUse(history, CHANNEL_ID, NOW); + computeChannelFrecency(history, NOW); + expect(history.get(CHANNEL_ID)).toEqual({ + totalUses: 2, + recentUses: [NOW - 8 * DAY_MS, NOW], + frecency: 110, + score: 110, + }); + }); +}); + +describe('capChannelFrecencyHistory', () => { + it('drops the key whose last use is oldest once there are more than 100 keys', () => { + const history: ChannelFrecencyHistory = new Map(); + trackChannelUse(history, keyFor(0), NOW - 10 * DAY_MS); + trackChannelUse(history, keyFor(0), NOW + 500); + for (let index = 1; index <= 100; index++) { + trackChannelUse(history, keyFor(index), NOW + index); + } + capChannelFrecencyHistory(history); + expect(history.size).toBe(100); + expect(history.has(keyFor(0))).toBe(true); + expect(history.has(keyFor(1))).toBe(false); + }); + + it('drops the earlier key when two share the oldest last use', () => { + const history: ChannelFrecencyHistory = new Map(); + trackChannelUse(history, keyFor(0), NOW); + trackChannelUse(history, keyFor(1), NOW); + for (let index = 2; index <= 100; index++) { + trackChannelUse(history, keyFor(index), NOW + index); + } + capChannelFrecencyHistory(history); + expect(history.has(keyFor(0))).toBe(false); + expect(history.has(keyFor(1))).toBe(true); + }); +}); + +describe('rankFrequentChannelIds', () => { + it('sorts resolved ids by frecency, keeps key order on ties and drops unresolved keys', () => { + const history: ChannelFrecencyHistory = new Map([ + ['a', computedEntry(100)], + ['b', computedEntry(300)], + ['c', computedEntry(100)], + ['user', computedEntry(200)], + ['gone', computedEntry(999)], + ]); + const resolved = new Map([ + ['a', 'a'], + ['b', 'b'], + ['c', 'c'], + ['user', 'dm-channel'], + ]); + expect(rankFrequentChannelIds(history, (key) => resolved.get(key) ?? null)).toEqual(['b', 'dm-channel', 'a', 'c']); + }); + + it('returns at most 100 ids', () => { + const history: ChannelFrecencyHistory = new Map(); + for (let index = 0; index < 150; index++) { + history.set(keyFor(index), computedEntry(100)); + } + const ranked = rankFrequentChannelIds(history, (key) => key); + expect(ranked).toHaveLength(100); + expect(ranked[99]).toBe(keyFor(99)); + }); +}); + +describe('restoreChannelFrecencyHistory', () => { + it('re-derives every persisted entry against now and drops unusable ones', () => { + const persisted: ReadonlyArray = [ + ['a', {totalUses: 5, recentUses: [NOW - 8 * DAY_MS - HOUR_MS, NOW - 8 * DAY_MS], frecency: 999, score: 999}], + ['b', {totalUses: 2, recentUses: [], frecency: 50, score: 50}], + ['c', {totalUses: 'many', recentUses: [NOW]}], + ['d', {totalUses: 1, recentUses: [NOW - HOUR_MS, 'soon', -5, null], frecency: 1, score: 1}], + [42, {totalUses: 1, recentUses: [NOW]}], + ['e', null], + ]; + const restored = restoreChannelFrecencyHistory(persisted, NOW); + expect([...restored.keys()]).toEqual(['a', 'd']); + expect(restored.get('a')).toEqual({ + totalUses: 5, + recentUses: [NOW - 8 * DAY_MS - HOUR_MS, NOW - 8 * DAY_MS], + frecency: 50, + score: 20, + }); + expect(restored.get('d')).toEqual({totalUses: 1, recentUses: [NOW - HOUR_MS], frecency: 100, score: 100}); + }); +}); + +describe('channel frecency account sync', () => { + it('carries only the uses over the wire and re-derives on the way back', () => { + const history: ChannelFrecencyHistory = new Map(); + trackChannelUse(history, 'a', NOW - HOUR_MS); + trackChannelUse(history, 'a', NOW); + computeChannelFrecency(history, NOW); + const usage = channelFrecencyHistoryToWire(history); + expect(usage).toEqual({a: {totalUses: 2, recentUsesMs: [BigInt(NOW - HOUR_MS), BigInt(NOW)]}}); + const restored = channelFrecencyHistoryFromWire(usage, NOW); + expect(restored.get('a')).toEqual({ + totalUses: 2, + recentUses: [NOW - HOUR_MS, NOW], + frecency: 200, + score: 200, + }); + }); + + it('drops wire entries whose uses have all aged out of scoring', () => { + const restored = channelFrecencyHistoryFromWire({a: {totalUses: 3, recentUsesMs: []}}, NOW); + expect(restored.size).toBe(0); + }); + + it('merges two devices by keeping the higher count and the newest ten uses', () => { + const merged = mergeChannelFrecencyWireUsage( + { + a: {totalUses: 9, recentUsesMs: [BigInt(NOW - 2 * DAY_MS), BigInt(NOW - HOUR_MS)]}, + b: {totalUses: 1, recentUsesMs: [BigInt(NOW - HOUR_MS)]}, + }, + { + a: {totalUses: 4, recentUsesMs: [BigInt(NOW - HOUR_MS), BigInt(NOW)]}, + c: {totalUses: 2, recentUsesMs: [BigInt(NOW)]}, + }, + NOW, + ); + expect(merged.a).toEqual({ + totalUses: 9, + recentUsesMs: [BigInt(NOW - 2 * DAY_MS), BigInt(NOW - HOUR_MS), BigInt(NOW)], + }); + expect(Object.keys(merged).sort()).toEqual(['a', 'b', 'c']); + }); + + it('keeps at most ten uses and a hundred keys when merging', () => { + const uses = Array.from({length: 8}, (_value, index) => BigInt(NOW - index * HOUR_MS)); + const local: Record}> = {}; + const incoming: Record}> = {}; + for (let index = 0; index < 60; index++) { + local[keyFor(index)] = {totalUses: 1, recentUsesMs: [BigInt(NOW - index * HOUR_MS)]}; + } + for (let index = 60; index < 130; index++) { + incoming[keyFor(index)] = {totalUses: 1, recentUsesMs: [BigInt(NOW - index * HOUR_MS)]}; + } + local.a = {totalUses: 20, recentUsesMs: uses}; + incoming.a = {totalUses: 20, recentUsesMs: [BigInt(NOW + HOUR_MS), BigInt(NOW + 2 * HOUR_MS), BigInt(NOW)]}; + const merged = mergeChannelFrecencyWireUsage(local, incoming, NOW); + expect(merged.a.recentUsesMs).toHaveLength(10); + expect(Object.keys(merged)).toHaveLength(100); + }); +}); diff --git a/fluxer_app/src/features/channel/utils/ChannelFrecencyCalculator.ts b/fluxer_app/src/features/channel/utils/ChannelFrecencyCalculator.ts new file mode 100644 index 000000000..241901d36 --- /dev/null +++ b/fluxer_app/src/features/channel/utils/ChannelFrecencyCalculator.ts @@ -0,0 +1,221 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +export interface ChannelFrecencyEntry { + readonly totalUses: number; + readonly recentUses: ReadonlyArray; + readonly frecency: number; + readonly score: number; +} + +export type ChannelFrecencyHistory = Map; + +interface RankedChannelFrecency { + readonly id: string; + readonly frecency: number; +} + +const CHANNEL_FRECENCY_MAX_ITEMS = 100; +const CHANNEL_FRECENCY_MAX_SAMPLES = 10; +const CHANNEL_FRECENCY_UNCOMPUTED = -1; + +const DAY_MS = 86_400_000; +const MINUTE_MS = 60_000; + +function createEntry( + totalUses: number, + recentUses: ReadonlyArray, + frecency: number, + score: number, +): ChannelFrecencyEntry { + return Object.freeze({totalUses, recentUses: Object.freeze(recentUses), frecency, score}); +} + +function utcOffsetMinutes(timestamp: number): number { + return -new Date(timestamp).getTimezoneOffset(); +} + +function compareAscending(a: number, b: number): number { + return a - b; +} + +export function channelFrecencyDayDiff(now: number, then: number): number { + const zoneDeltaMs = (utcOffsetMinutes(then) - utcOffsetMinutes(now)) * MINUTE_MS; + return Math.trunc((now - then - zoneDeltaMs) / DAY_MS) || 0; +} + +export function channelFrecencyWeight(dayDiff: number): number { + if (dayDiff === 0) return 100; + if (dayDiff >= 1 && dayDiff < 2) return 70; + if (dayDiff >= 2 && dayDiff < 4) return 50; + if (dayDiff >= 4 && dayDiff < 7) return 30; + if (dayDiff >= 7) return 10; + return 1; +} + +function scoreRecentUses(recentUses: ReadonlyArray, now: number): number { + const sampleCount = Math.min(recentUses.length, CHANNEL_FRECENCY_MAX_SAMPLES); + let score = 0; + for (let index = 0; index < sampleCount; index++) { + score += channelFrecencyWeight(channelFrecencyDayDiff(now, recentUses[index])); + } + return score; +} + +export function trackChannelUse(history: ChannelFrecencyHistory, key: string, timestamp?: number): void { + const use = timestamp ?? Date.now(); + const entry = history.get(key); + if (entry === undefined) { + history.set(key, createEntry(1, [use], CHANNEL_FRECENCY_UNCOMPUTED, 0)); + return; + } + const recentUses = [...entry.recentUses, use]; + if (timestamp !== undefined) { + recentUses.sort(compareAscending); + } + history.set( + key, + createEntry( + entry.totalUses + 1, + recentUses.slice(-CHANNEL_FRECENCY_MAX_SAMPLES), + CHANNEL_FRECENCY_UNCOMPUTED, + entry.score, + ), + ); +} + +export function computeChannelFrecency(history: ChannelFrecencyHistory, now: number): void { + for (const [key, entry] of history) { + if (entry.frecency !== CHANNEL_FRECENCY_UNCOMPUTED) continue; + const score = scoreRecentUses(entry.recentUses, now); + if (score > 0) { + const frecency = Math.ceil(entry.totalUses * (score / entry.recentUses.length)); + history.set(key, createEntry(entry.totalUses, entry.recentUses, frecency, score)); + } else { + history.delete(key); + } + } +} + +function findOldestLastUseKey(history: ReadonlyMap): string | null { + let oldestKey: string | null = null; + let oldestLastUse = Number.POSITIVE_INFINITY; + for (const [key, entry] of history) { + const lastUse = entry.recentUses.at(-1); + if (lastUse !== undefined && lastUse < oldestLastUse) { + oldestKey = key; + oldestLastUse = lastUse; + } + } + return oldestKey; +} + +export function capChannelFrecencyHistory(history: ChannelFrecencyHistory): void { + while (history.size > CHANNEL_FRECENCY_MAX_ITEMS) { + const oldestKey = findOldestLastUseKey(history); + if (oldestKey === null) return; + history.delete(oldestKey); + } +} + +export function rankFrequentChannelIds( + history: ReadonlyMap, + resolveRecordId: (key: string) => string | null, +): ReadonlyArray { + const ranked: Array = []; + for (const [key, entry] of history) { + const id = resolveRecordId(key); + if (id !== null) { + ranked.push({id, frecency: entry.frecency}); + } + } + ranked.sort((a, b) => b.frecency - a.frecency); + return Object.freeze(ranked.slice(0, CHANNEL_FRECENCY_MAX_ITEMS).map((item) => item.id)); +} + +interface ChannelFrecencyWireEntry { + readonly totalUses: number; + readonly recentUsesMs: ReadonlyArray; +} + +export type ChannelFrecencyWireUsage = Record}>; + +export type ChannelFrecencyWireUsageInput = Readonly>; + +function entryToWire(entry: ChannelFrecencyEntry): {totalUses: number; recentUsesMs: Array} { + return {totalUses: entry.totalUses, recentUsesMs: entry.recentUses.map((use) => BigInt(use))}; +} + +export function channelFrecencyHistoryToWire( + history: ReadonlyMap, +): ChannelFrecencyWireUsage { + const usage: ChannelFrecencyWireUsage = {}; + for (const [key, entry] of history) { + usage[key] = entryToWire(entry); + } + return usage; +} + +function readWireUses(entry: ChannelFrecencyWireEntry | undefined): Array { + if (entry === undefined) return []; + return entry.recentUsesMs.map((use) => Number(use)).filter(isUseTimestamp); +} + +export function channelFrecencyHistoryFromWire( + usage: ChannelFrecencyWireUsageInput, + now: number, +): ChannelFrecencyHistory { + const persisted: Array = []; + for (const [key, entry] of Object.entries(usage)) { + persisted.push([key, {totalUses: entry?.totalUses, recentUses: readWireUses(entry)}]); + } + return restoreChannelFrecencyHistory(persisted, now); +} + +export function mergeChannelFrecencyWireUsage( + local: ChannelFrecencyWireUsageInput, + incoming: ChannelFrecencyWireUsageInput, + now: number, +): ChannelFrecencyWireUsage { + const merged: ChannelFrecencyHistory = new Map(); + const keys = new Set([...Object.keys(local), ...Object.keys(incoming)]); + for (const key of keys) { + const localEntry = local[key]; + const incomingEntry = incoming[key]; + const uses = [...new Set([...readWireUses(localEntry), ...readWireUses(incomingEntry)])]; + if (uses.length === 0) continue; + uses.sort(compareAscending); + const totalUses = Math.max(localEntry?.totalUses ?? 0, incomingEntry?.totalUses ?? 0); + if (!Number.isFinite(totalUses) || totalUses <= 0) continue; + merged.set(key, createEntry(totalUses, uses.slice(-CHANNEL_FRECENCY_MAX_SAMPLES), CHANNEL_FRECENCY_UNCOMPUTED, 0)); + } + computeChannelFrecency(merged, now); + capChannelFrecencyHistory(merged); + return channelFrecencyHistoryToWire(merged); +} + +function isUseTimestamp(value: unknown): value is number { + return typeof value === 'number' && Number.isFinite(value) && value > 0; +} + +function readPersistedEntry(value: unknown): ChannelFrecencyEntry | null { + if (typeof value !== 'object' || value === null) return null; + const {totalUses, recentUses} = value as {readonly totalUses?: unknown; readonly recentUses?: unknown}; + if (typeof totalUses !== 'number' || !Number.isFinite(totalUses) || !Array.isArray(recentUses)) return null; + return createEntry(totalUses, recentUses.filter(isUseTimestamp), CHANNEL_FRECENCY_UNCOMPUTED, 0); +} + +export function restoreChannelFrecencyHistory( + persisted: Iterable, + now: number, +): ChannelFrecencyHistory { + const history: ChannelFrecencyHistory = new Map(); + for (const [key, value] of persisted) { + if (typeof key !== 'string') continue; + const entry = readPersistedEntry(value); + if (entry !== null) { + history.set(key, entry); + } + } + computeChannelFrecency(history, now); + return history; +} diff --git a/fluxer_app/src/features/i18n/locales/ar/messages.po b/fluxer_app/src/features/i18n/locales/ar/messages.po index b005fbed6..8312b4017 100644 --- a/fluxer_app/src/features/i18n/locales/ar/messages.po +++ b/fluxer_app/src/features/i18n/locales/ar/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "... تشغيل الوضع المكثف. رائع!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(معدّلة)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, zero {# مجتمع غير متاح مؤقتًا بسبب msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, zero {# اتصال} one {اتصال واحد} two {اتصالان} few {# اتصالات} many {# اتصالًا} other {# اتصال}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, zero {# ملف} one {# ملف} two {# ملفين} few {# ملفات} many {# ملفًا} other {# ملف}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, zero {# هدية} one {هدية واحدة} two {هديتان} few {# هدايا} many {# هدية} other {# هدية}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, zero {# صورة} one {# صورة} two {# صورتين} few {# صور} many {# صورة} other {# صورة}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, zero {# عنصر} one {عنصر واحد} two {عنصران} few {# عناصر} many {# عنصرًا} other {# عنصر}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, zero {# ثانية} one {ثانية واحدة} two {ث msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, zero {# اقتراح متاح} one {اقتراح واحد متاح} two {اقتراحان متاحان} few {# اقتراحات متاحة} many {# اقتراحًا متاحًا} other {# اقتراح متاح}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, zero {# مقطع فيديو} one {# مقطع فيديو} two {# مقطعي فيديو} few {# مقاطع فيديو} many {# مقطع فيديو} other {# مقطع فيديو}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, zero {تنتهي صلاحية هذه الدعوة خلا msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, zero {تنتهي صلاحية رابط الدعوة خلال # ساعة.} one {تنتهي صلاحية رابط الدعوة خلال ساعة واحدة.} two {تنتهي صلاحية رابط الدعوة خلال ساعتين.} few {تنتهي صلاحية رابط الدعوة خلال # ساعات.} many {تنتهي صلاحية رابط الدعوة خلال # ساعة.} other {تنتهي صلاحية رابط الدعوة خلال # ساعة.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, zero {# صورة} one {# صورة} two {# صورتين} few {# صور} many {# صورة} other {# صورة}}، {videoCount, plural, zero {# مقطع فيديو} one {# مقطع فيديو} two {# مقطعي فيديو} few {# مقاطع فيديو} many {# مقطع فيديو} other {# مقطع فيديو}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "إشارة" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "أضاف <0/> <1/> إلى المجموعة." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "إضافة بوت إلى مجتمع بالأذونات المطلوبة" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "إضافة تعليق (اختياري)" @@ -6687,7 +6714,7 @@ msgstr "لا يمكن تحميل الملفات هنا" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "إعدادات الفئة" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "تنبيه" @@ -7372,8 +7399,8 @@ msgstr "القناة" msgid "Channel" msgstr "القناة" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "القناة {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "الأوامر" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "التعليقات معطّلة لأن الوضع البطيء مفعّل في قناة واحدة أو أكثر من القنوات المحددة. سيحظر الوضع البطيء التعليق مباشرةً بعد إعادة التوجيه." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "التعليقات معطّلة لأن الوضع البطيء مفعّل في {forwardChannelDisplayName}. سيحظر الوضع البطيء التعليق مباشرةً بعد إعادة التوجيه." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "التعليقات غير متاحة عندما يكون الوضع البطيء مفعّلًا." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "حدث خطأ أثناء عرض المحتوى" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "خطأ في عرض LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "إعادة توجيه الوسائط" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "إعادة توجيه الرسالة" @@ -18216,7 +18243,7 @@ msgstr "الاستيراد غير متاح" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "مهم" @@ -21355,7 +21382,7 @@ msgstr "إعدادات عرض الرسائل متاحة على سطح المكت msgid "Message editing" msgstr "تعديل الرسالة" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "تمت إعادة توجيه الرسالة" @@ -21404,7 +21431,7 @@ msgstr "أزرار إدخال الرسائل" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "الرسالة طويلة جدًا" @@ -23059,7 +23086,7 @@ msgstr "لا توجد تغييرات لحفظها" msgid "No channels available" msgstr "لا توجد قنوات متاحة" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "لم يتم العثور على قنوات" @@ -23670,7 +23697,7 @@ msgstr "ليس صوابًا أو خطأ" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "فتح الرمز التعبيري في المتصفح" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "فتح منتقي الرموز التعبيرية" @@ -29360,6 +29387,7 @@ msgstr "معاينة التمرير في الفيديو" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "معاينة التمرير في الفيديو" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "البحث باسم المستخدم أو المعرف" msgid "Search channels" msgstr "البحث في القنوات" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "البحث في القنوات أو الرسائل المباشرة" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "إرسال" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "إرسال ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "إرسال رسالة نصية قصيرة إلى رقم الهاتف ه msgid "Sending malware or dangerous links" msgstr "إرسال برامج ضارة أو روابط خطيرة" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "تم تعطيل إرسال الرسائل في هذا المجتمع" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "تتوقف اختصارات لوحة المفاتيح مؤقتًا أثناء التسجيل." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "قصّر الرسالة وحاول مرة أخرى." @@ -31780,8 +31804,8 @@ msgstr "تحميل الملف الشخصي ببطء" msgid "Slowmode" msgstr "الوضع البطيء" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "الوضع البطيء · انتظر {remaining}" @@ -34920,6 +34944,11 @@ msgstr "لم يعد هذا العضو موجودًا في المجتمع. حدّ msgid "This member isn't connected to voice anymore." msgstr "لم يعد هذا العضو متصلًا بالقناة الصوتية." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "لا يمكن إعادة توجيه هذه الرسالة إلا إلى القنوات المخصصة للبالغين" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "الطوابع الزمنية" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "نصيحة" @@ -36521,7 +36550,7 @@ msgstr "كيان غير معروف" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "خطأ غير معروف" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "جارٍ انتظار مفتاح المرور…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "في انتظار انتهاء الوضع البطيء في {forwardChannelDisplayName}." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "في انتظار انتهاء الوضع البطيء في قناة واحدة أو أكثر من القنوات المحددة." @@ -39077,7 +39106,7 @@ msgstr "تنشيط" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "تحذير" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "تحتاج إلى الوصول إلى بريدك الإلكتروني الحالي لتغييره من هنا. استخدم التحقق عبر الهاتف إذا كان متاحًا أو اتصل بالدعم." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "أنت بحاجة إلى إذن \"{attachFilesPermissionLabel}\" لإرفاق الملفات في هذه القناة" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "أنت بحاجة إلى إذن \"{embedLinksPermissionLabel}\" لتضمين الروابط في هذه القناة" @@ -40432,11 +40461,6 @@ msgstr "أنت بحاجة إلى إذن \"{permissionLabel}\" لاستخدام msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "أنت بحاجة إلى إذن \"{permissionLabel}\" لاستخدام الملصقات من المجتمعات الأخرى هنا." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "أنت بحاجة إلى إذن \"{sendMessagesPermissionLabel}\" لإرسال الرسائل في هذه القناة" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "أنت ترسل الرسائل بسرعة كبيرة" msgid "You're streaming!" msgstr "أنت تبث الآن!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "أنت في المهلة داخل هذا المجتمع" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "أنت في المهلة. المراسلة والتفاعلات والصوت متوقفة مؤقتًا حتى تنتهي المهلة." diff --git a/fluxer_app/src/features/i18n/locales/auto-i18n-reviewed-unchanged.json b/fluxer_app/src/features/i18n/locales/auto-i18n-reviewed-unchanged.json index 2d53962dd..c6ea3049a 100644 --- a/fluxer_app/src/features/i18n/locales/auto-i18n-reviewed-unchanged.json +++ b/fluxer_app/src/features/i18n/locales/auto-i18n-reviewed-unchanged.json @@ -2,6 +2,9 @@ "version": 1, "locales": { "ar": [ + { + "msgid": "+{count}" + }, { "msgid": "AV1" }, @@ -58,6 +61,9 @@ } ], "bg": [ + { + "msgid": "+{count}" + }, { "msgid": "AV1" }, @@ -147,6 +153,9 @@ } ], "cs": [ + { + "msgid": "+{count}" + }, { "msgid": "15 FPS" }, @@ -367,6 +376,9 @@ } ], "da": [ + { + "msgid": "+{count}" + }, { "msgid": "15 FPS" }, @@ -846,6 +858,9 @@ } ], "de": [ + { + "msgid": "+{count}" + }, { "msgid": "15 FPS" }, @@ -1202,6 +1217,9 @@ } ], "el": [ + { + "msgid": "+{count}" + }, { "msgid": "15 FPS" }, @@ -1347,6 +1365,9 @@ } ], "en-GB": [ + { + "msgid": "+{count}" + }, { "msgid": "128 kbps voice quality" }, @@ -2889,6 +2910,9 @@ { "msgid": "This is off until you turn it on. While it is on, members of other communities can use the in-app one-click \"Clone\" shortcut on your custom stickers. Turning it off does not prevent anyone from saving the image and uploading it themselves." }, + { + "msgid": "This message can only be forwarded to age-restricted channels" + }, { "msgid": "This number is verified by texting us instead. Go back and start phone verification again to get the code and the number to text." }, @@ -3540,12 +3564,21 @@ { "msgid": "{count, plural, =0 {∞ No limit} one {# participant} other {# participants}}" }, + { + "msgid": "{count, plural, one {# file} other {# files}}" + }, + { + "msgid": "{count, plural, one {# image} other {# images}}" + }, { "msgid": "{count, plural, one {# minute} other {# minutes}}" }, { "msgid": "{count, plural, one {# more permission} other {# more permissions}}" }, + { + "msgid": "{count, plural, one {# video} other {# videos}}" + }, { "msgid": "{count, plural, one {The invite was limited to # use.} other {The invite was limited to # uses.}}" }, @@ -3558,6 +3591,9 @@ { "msgid": "{expressionName} is a custom sticker from this community. Members can use it here." }, + { + "msgid": "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" + }, { "msgid": "{name} copy" }, @@ -3651,6 +3687,9 @@ } ], "es-419": [ + { + "msgid": "+{count}" + }, { "msgid": "15 FPS" }, @@ -3888,6 +3927,9 @@ { "msgid": "{count, plural, one {# emoji} other {# emojis}}" }, + { + "msgid": "{count, plural, one {# video} other {# videos}}" + }, { "msgid": "{fps} FPS" }, @@ -3934,6 +3976,9 @@ } ], "es-ES": [ + { + "msgid": "+{count}" + }, { "msgid": "15 FPS" }, @@ -4128,6 +4173,9 @@ } ], "fi": [ + { + "msgid": "+{count}" + }, { "msgid": "15 FPS" }, @@ -4285,6 +4333,9 @@ } ], "fr": [ + { + "msgid": "+{count}" + }, { "msgid": "1 mention" }, @@ -4690,6 +4741,9 @@ { "msgid": "{channelHeading}, {mentionCount} mentions" }, + { + "msgid": "{count, plural, one {# image} other {# images}}" + }, { "msgid": "{count, plural, one {# minute} other {# minutes}}" }, @@ -4780,6 +4834,9 @@ } ], "he": [ + { + "msgid": "+{count}" + }, { "msgid": "AV1" }, @@ -4866,6 +4923,9 @@ } ], "hi": [ + { + "msgid": "+{count}" + }, { "msgid": "15 FPS" }, @@ -4943,6 +5003,9 @@ } ], "hr": [ + { + "msgid": "+{count}" + }, { "msgid": "15 FPS" }, @@ -5113,6 +5176,9 @@ } ], "hu": [ + { + "msgid": "+{count}" + }, { "msgid": "15 FPS" }, @@ -5292,6 +5358,9 @@ } ], "id": [ + { + "msgid": "+{count}" + }, { "msgid": "15 FPS" }, @@ -5622,6 +5691,9 @@ } ], "it": [ + { + "msgid": "+{count}" + }, { "msgid": "15 FPS" }, @@ -5969,6 +6041,9 @@ } ], "ja": [ + { + "msgid": "+{count}" + }, { "msgid": "15 FPS" }, @@ -6097,6 +6172,9 @@ } ], "ko": [ + { + "msgid": "+{count}" + }, { "msgid": "15 FPS" }, @@ -6177,6 +6255,9 @@ } ], "lt": [ + { + "msgid": "+{count}" + }, { "msgid": "60 FPS" }, @@ -6248,6 +6329,9 @@ } ], "nl": [ + { + "msgid": "+{count}" + }, { "msgid": "1 week" }, @@ -6770,6 +6854,9 @@ } ], "no": [ + { + "msgid": "+{count}" + }, { "msgid": "15 FPS" }, @@ -7067,6 +7154,9 @@ } ], "pl": [ + { + "msgid": "+{count}" + }, { "msgid": "AV1" }, @@ -7259,6 +7349,9 @@ } ], "pt-BR": [ + { + "msgid": "+{count}" + }, { "msgid": "15 FPS" }, @@ -7556,6 +7649,9 @@ } ], "ro": [ + { + "msgid": "+{count}" + }, { "msgid": "15 FPS" }, @@ -7914,6 +8010,9 @@ } ], "ru": [ + { + "msgid": "+{count}" + }, { "msgid": "AV1" }, @@ -8003,6 +8102,9 @@ } ], "sv-SE": [ + { + "msgid": "+{count}" + }, { "msgid": "15 FPS" }, @@ -8300,6 +8402,9 @@ } ], "th": [ + { + "msgid": "+{count}" + }, { "msgid": "15 FPS" }, @@ -8404,6 +8509,9 @@ } ], "tr": [ + { + "msgid": "+{count}" + }, { "msgid": "15 FPS" }, @@ -8570,6 +8678,9 @@ } ], "uk": [ + { + "msgid": "+{count}" + }, { "msgid": "AV1" }, @@ -8665,6 +8776,9 @@ } ], "vi": [ + { + "msgid": "+{count}" + }, { "msgid": "15 FPS" }, @@ -8854,6 +8968,9 @@ } ], "zh-CN": [ + { + "msgid": "+{count}" + }, { "msgid": "AV1" }, @@ -8946,6 +9063,9 @@ } ], "zh-TW": [ + { + "msgid": "+{count}" + }, { "msgid": "15 FPS" }, diff --git a/fluxer_app/src/features/i18n/locales/bg/messages.po b/fluxer_app/src/features/i18n/locales/bg/messages.po index 04f9ac5cc..a965095e8 100644 --- a/fluxer_app/src/features/i18n/locales/bg/messages.po +++ b/fluxer_app/src/features/i18n/locales/bg/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "... включиш сбития режим. Супер!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(редактирано)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# общност е временно недостъ msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# връзка} other {# връзки}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# файл} other {# файла}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# подарък} other {# подаръка}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# изображение} other {# изображения}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# елемент} other {# елемента}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# секунда} other {# секунди}}" msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, one {# налично предложение} other {# налични предложения}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# видео} other {# видеа}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {Тази покана изтича след # ча msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {Линкът ти за покана изтича след # час.} other {Линкът ти за покана изтича след # часа.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# изображение} other {# изображения}}, {videoCount, plural, one {# видео} other {# видеа}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@споменаване" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/> добави <1/> в групата." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "Добавяне на бот към общност с поисканите разрешения" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "Добавяне на коментар (по избор)" @@ -6687,7 +6714,7 @@ msgstr "Тук не можеш да качваш файлове" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "Настройки на категорията" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "Внимание" @@ -7372,8 +7399,8 @@ msgstr "канал" msgid "Channel" msgstr "Канал" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "Канал {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "Команди" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "Коментарите са изключени, защото в един или повече от избраните канали е включен бавен режим. Коментарът ще бъде блокиран от бавния режим веднага след препращането." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "Коментарите са изключени, защото в {forwardChannelDisplayName} е включен бавен режим. Коментарът ще бъде блокиран от бавния режим веднага след препращането." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "Коментарите не са достъпни, докато е включен бавен режим." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "Грешка при изобразяване на съдържанието" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "Грешка при изобразяване на LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "Препращане на медия" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "Препращане на съобщение" @@ -18216,7 +18243,7 @@ msgstr "Импортирането е недостъпно" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "Важно" @@ -21355,7 +21382,7 @@ msgstr "Настройките за показване на съобщения msgid "Message editing" msgstr "Редактиране на съобщения" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "Съобщението е препратено" @@ -21404,7 +21431,7 @@ msgstr "Бутони за въвеждане на съобщения" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "Съобщението е твърде дълго" @@ -23059,7 +23086,7 @@ msgstr "Няма промени за запазване" msgid "No channels available" msgstr "Няма налични канали" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "Няма намерени канали" @@ -23670,7 +23697,7 @@ msgstr "Не е вярно или невярно" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "Отваряне на емоджи в браузър" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "Отваряне на палитрата с емоджита" @@ -29360,6 +29387,7 @@ msgstr "Преглед при превъртане" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "Преглед при превъртане" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "Търсене по потребителско име или ID" msgid "Search channels" msgstr "Търсене на канали" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "Търсене на канали или DM" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "Изпращане" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "Изпращане ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "Изпращането на SMS до този телефонен ном msgid "Sending malware or dangerous links" msgstr "Изпращане на злонамерен софтуер или опасни линкове" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "Изпращането на съобщения е деактивирано в тази общност" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "Клавишните комбинации са на пауза по време на записване." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "Съкрати съобщението и опитай отново." @@ -31780,8 +31804,8 @@ msgstr "Бавно зареждане на профил" msgid "Slowmode" msgstr "Бавен режим" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "Бавен режим · изчакай {remaining}" @@ -34920,6 +34944,11 @@ msgstr "Този член вече не е в общността. Обнови msgid "This member isn't connected to voice anymore." msgstr "Този член вече не е свързан с гласов канал." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "Това съобщение може да бъде препратено само към канали с ограничена възраст" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "Клейма за време" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "Съвет" @@ -36521,7 +36550,7 @@ msgstr "неизвестен обект" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "Неизвестна грешка" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "Изчакване на ключ за достъп…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "Изчаква се бавният режим в {forwardChannelDisplayName} да изтече." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "Изчаква се да изтече бавният режим в един или повече избрани канала." @@ -39077,7 +39106,7 @@ msgstr "Събуждане" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "Предупреждение" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "За да смениш имейла си оттук, трябва да имаш достъп до текущия. Използвай потвърждение по телефона, ако е налично, или се свържи с поддръжката." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "Нужно е разрешението „{attachFilesPermissionLabel}“, за да прикачваш файлове в този канал" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "Нужно е разрешението „{embedLinksPermissionLabel}“, за да вграждаш линкове в този канал" @@ -40432,11 +40461,6 @@ msgstr "Нужно е разрешението „{permissionLabel}“, за д msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "Нужно е разрешението „{permissionLabel}“, за да използваш стикери от други общности тук." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "Нужно ти е разрешението „{sendMessagesPermissionLabel}“, за да изпращаш съобщения в този канал" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "Изпращаш съобщения твърде бързо" msgid "You're streaming!" msgstr "Излъчваш на живо!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "Наложено ти е време за изчакване в тази общност" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "Наложено ти е време за изчакване. Съобщенията, реакциите и гласовият чат са на пауза, докато то изтече." diff --git a/fluxer_app/src/features/i18n/locales/cs/messages.po b/fluxer_app/src/features/i18n/locales/cs/messages.po index 277588c0d..7cc3f22bc 100644 --- a/fluxer_app/src/features/i18n/locales/cs/messages.po +++ b/fluxer_app/src/features/i18n/locales/cs/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "... zapnout zhuštěný režim. Super!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(upraveno)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# komunita je dočasně nedostupná kvůli poruše msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# připojení} other {# připojení}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# soubor} few {# soubory} many {# souboru} other {# souborů}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# dárek} few {# dárky} many {# dárku} other {# dárků}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# obrázek} few {# obrázky} many {# obrázku} other {# obrázků}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# položka} few {# položky} many {# položky} other {# položek}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# sekunda} few {# sekundy} many {# sekundy} other { msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, one {K dispozici je # návrh} few {K dispozici jsou # návrhy} many {K dispozici je # návrhu} other {K dispozici je # návrhů}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# video} few {# videa} many {# videa} other {# videí}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {Tato pozvánka vyprší za # hodinu.} few {Tato poz msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {Váš odkaz na pozvánku vyprší za # hodinu.} few {Váš odkaz na pozvánku vyprší za # hodiny.} many {Váš odkaz na pozvánku vyprší za # hodiny.} other {Váš odkaz na pozvánku vyprší za # hodin.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# obrázek} few {# obrázky} many {# obrázku} other {# obrázků}}, {videoCount, plural, one {# video} few {# videa} many {# videa} other {# videí}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@zmínka" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/> přidal(a) <1/> do skupiny." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "Přidat bota do komunity s požadovanými oprávněními" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "Přidat komentář (volitelné)" @@ -6687,7 +6714,7 @@ msgstr "Sem nelze nahrávat soubory" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "Nastavení kategorie" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "Upozornění" @@ -7372,8 +7399,8 @@ msgstr "kanál" msgid "Channel" msgstr "Kanál" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "Kanál {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "Příkazy" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "Komentáře jsou zakázány, protože jeden nebo více vybraných kanálů má zapnutý pomalý režim. Komentář by byl pomalým režimem zablokován hned po přeposlání." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "Komentáře jsou zakázány, protože v kanálu {forwardChannelDisplayName} je zapnutý pomalý režim. Komentář by byl pomalým režimem zablokován hned po přeposlání." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "Komentáře nejsou dostupné, když je zapnutý pomalý režim." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "Chyba při vykreslování obsahu" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "Chyba při vykreslování LaTeXu: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "Přeposlat médium" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "Přeposlat zprávu" @@ -18216,7 +18243,7 @@ msgstr "Import není k dispozici" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "Důležité" @@ -21355,7 +21382,7 @@ msgstr "Nastavení zobrazení zpráv je k dispozici pouze na počítači." msgid "Message editing" msgstr "Úprava zpráv" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "Zpráva přeposlána" @@ -21404,7 +21431,7 @@ msgstr "Tlačítka pro zadávání zpráv" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "Zpráva je příliš dlouhá" @@ -23059,7 +23086,7 @@ msgstr "Žádné změny k uložení" msgid "No channels available" msgstr "Žádné kanály nejsou k dispozici" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "Nebyly nalezeny žádné kanály" @@ -23670,7 +23697,7 @@ msgstr "Není to pravda ani nepravda" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "Otevřít emoji v prohlížeči" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "Otevřít výběr emoji" @@ -29360,6 +29387,7 @@ msgstr "Náhled při posouvání v záznamu" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "Náhled při posouvání v záznamu" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "Hledat podle uživatelského jména nebo ID" msgid "Search channels" msgstr "Hledat kanály" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "Hledat kanály nebo soukromé konverzace" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "Odeslat" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "Odeslat ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "Odesílání SMS na toto telefonní číslo je pro {PRODUCT_NAME} příl msgid "Sending malware or dangerous links" msgstr "Odesílání malwaru nebo nebezpečných odkazů" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "V této komunitě je odesílání zpráv zakázáno" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "Během zaznamenávání jsou klávesové zkratky pozastavené." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "Zkraťte zprávu a zkuste to znovu." @@ -31780,8 +31804,8 @@ msgstr "Pomalé načítání profilu" msgid "Slowmode" msgstr "Pomalý režim" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "Pomalý režim · čekejte {remaining}" @@ -34920,6 +34944,11 @@ msgstr "Tento člen již není v komunitě. Obnovte stránku a zkuste to znovu." msgid "This member isn't connected to voice anymore." msgstr "Tento člen už není připojen k hlasovému chatu." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "Tuto zprávu lze přeposlat pouze do kanálů s omezeným věkem" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "Časové značky" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "Tip" @@ -36521,7 +36550,7 @@ msgstr "neznámá entita" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "Neznámá chyba" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "Čekání na přístupový klíč…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "Čekání na vypršení pomalého režimu v kanálu {forwardChannelDisplayName}." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "Čekání na vypršení pomalého režimu v jednom nebo více vybraných kanálech." @@ -39077,7 +39106,7 @@ msgstr "Probudit" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "Upozornění" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "Pro změnu e-mailu potřebujete přístup k tomu stávajícímu. Použijte ověření telefonem, pokud je k dispozici, nebo kontaktujte podporu." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "K připojení souborů v tomto kanálu potřebujete oprávnění \"{attachFilesPermissionLabel}\"" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "K zobrazování vložených náhledů odkazů v tomto kanálu potřebujete oprávnění „{embedLinksPermissionLabel}“" @@ -40432,11 +40461,6 @@ msgstr "K používání emoji z jiných komunit zde potřebujete oprávnění \" msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "K používání samolepek z jiných komunit zde potřebujete oprávnění „{permissionLabel}“." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "K odesílání zpráv v tomto kanálu potřebujete oprávnění \"{sendMessagesPermissionLabel}\"" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "Posíláte zprávy příliš rychle" msgid "You're streaming!" msgstr "Streamujete!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "V této komunitě máte dočasné omezení" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "Máte dočasné omezení. Dokud nevyprší, nemůžete posílat zprávy, přidávat reakce ani používat hlasové kanály." diff --git a/fluxer_app/src/features/i18n/locales/da/messages.po b/fluxer_app/src/features/i18n/locales/da/messages.po index add24526b..c2bdc64ab 100644 --- a/fluxer_app/src/features/i18n/locales/da/messages.po +++ b/fluxer_app/src/features/i18n/locales/da/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "... slå kompakt visning til. Fedt!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(redigeret)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# fællesskab er midlertidigt utilgængeligt på gr msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# forbindelse} other {# forbindelser}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# fil} other {# filer}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# gave} other {# gaver}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# billede} other {# billeder}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# element} other {# elementer}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# sekund} other {# sekunder}}" msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, one {# forslag tilgængeligt} other {# forslag tilgængelige}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# video} other {# videoer}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {Denne invitation udløber om # time.} other {Denne msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {Dit invitationslink udløber om # time.} other {Dit invitationslink udløber om # timer.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# billede} other {# billeder}}, {videoCount, plural, one {# video} other {# videoer}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@omtale" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/> føjede <1/> til gruppen." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "Tilføj en bot til et fællesskab med de ønskede tilladelser" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "Tilføj en kommentar (valgfrit)" @@ -6687,7 +6714,7 @@ msgstr "Kan ikke uploade filer her" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "Kategoriindstillinger" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "Pas på" @@ -7372,8 +7399,8 @@ msgstr "kanal" msgid "Channel" msgstr "Kanal" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "Kanal {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "Kommandoer" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "Kommentarer er deaktiveret, fordi langsom tilstand er slået til i en eller flere valgte kanaler. Kommentaren ville blive blokeret af langsom tilstand lige efter videresendelsen." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "Kommentarer er deaktiveret, fordi langsom tilstand er slået til i {forwardChannelDisplayName}. Kommentaren ville blive blokeret af langsom tilstand lige efter videresendelsen." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "Kommentarer er ikke tilgængelige, når langsom tilstand er slået til." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "Fejl ved visning af indhold" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "Fejl under gengivelse af LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "Videresend medie" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "Videresend besked" @@ -18216,7 +18243,7 @@ msgstr "Import ikke tilgængelig" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "Vigtigt" @@ -21355,7 +21382,7 @@ msgstr "Indstillinger for visning af beskeder er kun tilgængelige på computere msgid "Message editing" msgstr "Redigering af beskeder" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "Besked videresendt" @@ -21404,7 +21431,7 @@ msgstr "Knapper i skrivefeltet" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "Beskeden er for lang" @@ -23059,7 +23086,7 @@ msgstr "Ingen ændringer at gemme" msgid "No channels available" msgstr "Ingen kanaler tilgængelige" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "Ingen kanaler fundet" @@ -23670,7 +23697,7 @@ msgstr "Ikke sand eller falsk" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "Åbn emoji i browser" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "Åbn emoji-vælger" @@ -29360,6 +29387,7 @@ msgstr "Forhåndsvisning ved spoling" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "Forhåndsvisning ved spoling" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "Søg efter brugernavn eller id" msgid "Search channels" msgstr "Søg kanaler" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "Søg kanaler eller direkte beskeder" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "Send" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "Send ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "Det er for dyrt for {PRODUCT_NAME} at sende en SMS til dette telefonnumm msgid "Sending malware or dangerous links" msgstr "Sender malware eller farlige links" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "Afsendelse af beskeder er deaktiveret i dette fællesskab" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "Genveje sættes på pause under optagelse." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "Forkort beskeden, og prøv igen." @@ -31780,8 +31804,8 @@ msgstr "Langsom indlæsning af profil" msgid "Slowmode" msgstr "Langsom tilstand" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "Langsom tilstand · vent {remaining}" @@ -34920,6 +34944,11 @@ msgstr "Dette medlem er ikke længere i fællesskabet. Opdater og prøv igen." msgid "This member isn't connected to voice anymore." msgstr "Dette medlem er ikke længere i taleopkaldet." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "Denne besked kan kun videresendes til kanaler med aldersbegrænsning" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "Tidsstempler" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "Tip" @@ -36521,7 +36550,7 @@ msgstr "ukendt objekt" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "Ukendt fejl" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "Venter på adgangsnøgle …" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "Venter på, at ventetiden i langsom tilstand udløber i {forwardChannelDisplayName}." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "Venter på, at ventetiden i langsom tilstand udløber i en eller flere valgte kanaler." @@ -39077,7 +39106,7 @@ msgstr "Væk" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "Advarsel" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "Du skal have adgang til din nuværende e-mail for at ændre den herfra. Brug telefonbekræftelse, hvis det er muligt, eller kontakt support." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "Du skal have tilladelsen \"{attachFilesPermissionLabel}\" for at vedhæfte filer i denne kanal" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "Du skal have tilladelsen \"{embedLinksPermissionLabel}\" for at kunne indlejre links i denne kanal" @@ -40432,11 +40461,6 @@ msgstr "Du skal have tilladelsen \"{permissionLabel}\" for at bruge emojis fra a msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "Du skal have tilladelsen \"{permissionLabel}\" for at bruge klistermærker fra andre fællesskaber her." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "Du skal have tilladelsen \"{sendMessagesPermissionLabel}\" for at sende beskeder i denne kanal" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "Du sender beskeder for hurtigt" msgid "You're streaming!" msgstr "Du streamer!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "Du har timeout i dette fællesskab" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "Du har timeout. Du kan ikke sende beskeder, reagere eller deltage i taleopkald, før timeouten udløber." diff --git a/fluxer_app/src/features/i18n/locales/de/messages.po b/fluxer_app/src/features/i18n/locales/de/messages.po index fbc2adac4..b1c32afc3 100644 --- a/fluxer_app/src/features/i18n/locales/de/messages.po +++ b/fluxer_app/src/features/i18n/locales/de/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "... den Kompaktmodus aktivieren. Super!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(bearbeitet)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# Community ist aufgrund einer Fehlfunktion des Flu msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# Verbindung} other {# Verbindungen}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# Datei} other {# Dateien}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# Geschenk} other {# Geschenke}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# Bild} other {# Bilder}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# Element} other {# Elemente}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# Sekunde} other {# Sekunden}}" msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, one {# Vorschlag verfügbar} other {# Vorschläge verfügbar}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# Video} other {# Videos}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {Diese Einladung läuft in # Stunde ab.} other {Dies msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {Dein Einladungslink läuft in # Stunde ab.} other {Dein Einladungslink läuft in # Stunden ab.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# Bild} other {# Bilder}}, {videoCount, plural, one {# Video} other {# Videos}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@-Erwähnung" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/> hat <1/> zur Gruppe hinzugefügt." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "Einen Bot mit den angeforderten Berechtigungen zu einer Community hinzufügen" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "Kommentar hinzufügen (optional)" @@ -6687,7 +6714,7 @@ msgstr "Dateien können hier nicht hochgeladen werden" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "Kategorieeinstellungen" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "Vorsicht" @@ -7372,8 +7399,8 @@ msgstr "Kanal" msgid "Channel" msgstr "Kanal" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "Kanal {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "Befehle" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "Kommentare sind deaktiviert, da in einem oder mehreren ausgewählten Kanälen der Slow-Modus aktiviert ist. Der Kommentar würde direkt nach dem Weiterleiten durch den Slow-Modus blockiert werden." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "Kommentare sind deaktiviert, da der Slow-Modus in {forwardChannelDisplayName} aktiviert ist. Der Kommentar würde direkt nach dem Weiterleiten durch den Slow-Modus blockiert werden." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "Kommentare sind nicht verfügbar, solange der Slow-Modus aktiviert ist." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "Fehler beim Rendern des Inhalts" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "Fehler beim Rendern von LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "Medien weiterleiten" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "Nachricht weiterleiten" @@ -18216,7 +18243,7 @@ msgstr "Import nicht verfügbar" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "Wichtig" @@ -21355,7 +21382,7 @@ msgstr "Nachrichtenanzeige-Einstellungen sind nur auf dem Desktop verfügbar." msgid "Message editing" msgstr "Nachrichten bearbeiten" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "Nachricht weitergeleitet" @@ -21404,7 +21431,7 @@ msgstr "Schaltflächen für die Nachrichteneingabe" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "Nachricht ist zu lang" @@ -23059,7 +23086,7 @@ msgstr "Keine Änderungen zum Speichern" msgid "No channels available" msgstr "Keine Kanäle verfügbar" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "Keine Kanäle gefunden" @@ -23670,7 +23697,7 @@ msgstr "Weder wahr noch falsch" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "Emoji im Browser öffnen" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "Emoji-Auswahl öffnen" @@ -29360,6 +29387,7 @@ msgstr "Vorschau beim Spulen" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "Vorschau beim Spulen" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "Nach Nutzername oder ID suchen" msgid "Search channels" msgstr "Kanäle suchen" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "Kanäle oder DMs suchen" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "Senden" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "Senden ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "Das Senden einer SMS an diese Telefonnummer ist für {PRODUCT_NAME} zu t msgid "Sending malware or dangerous links" msgstr "Malware oder gefährliche Links senden" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "Das Senden von Nachrichten ist in dieser Community deaktiviert" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "Während der Aufnahme sind Tastenkombinationen pausiert." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "Nachricht kürzen und erneut versuchen." @@ -31780,8 +31804,8 @@ msgstr "Langsames Laden des Profils" msgid "Slowmode" msgstr "Slow-Modus" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "Slow-Modus · warte {remaining}" @@ -34920,6 +34944,11 @@ msgstr "Dieses Mitglied ist nicht mehr in der Community. Aktualisiere die Seite msgid "This member isn't connected to voice anymore." msgstr "Dieses Mitglied ist nicht mehr mit dem Sprachkanal verbunden." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "Diese Nachricht kann nur an Kanäle mit Altersbeschränkung weitergeleitet werden" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "Zeitstempel" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "Tipp" @@ -36521,7 +36550,7 @@ msgstr "unbekannte Entität" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "Unbekannter Fehler" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "Warte auf Passkey …" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "Warten, bis die Wartezeit des Slow-Modus in {forwardChannelDisplayName} abgelaufen ist." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "Warten, bis die Wartezeit des Slow-Modus in einem oder mehreren ausgewählten Kanälen abgelaufen ist." @@ -39077,7 +39106,7 @@ msgstr "Aufwecken" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "Warnung" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "Du benötigst Zugriff auf deine aktuelle E-Mail-Adresse, um sie hier zu ändern. Nutze, falls verfügbar, die Telefonverifizierung oder kontaktiere den Support." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "Du benötigst die Berechtigung \"{attachFilesPermissionLabel}\", um Dateien in diesem Kanal anzuhängen" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "Du benötigst die Berechtigung \"{embedLinksPermissionLabel}\", um Links in diesem Kanal einzubetten" @@ -40432,11 +40461,6 @@ msgstr "Du benötigst die Berechtigung \"{permissionLabel}\", um hier Emojis aus msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "Du benötigst die Berechtigung \"{permissionLabel}\", um hier Sticker aus anderen Communitys zu verwenden." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "Du benötigst die Berechtigung \"{sendMessagesPermissionLabel}\", um Nachrichten in diesem Kanal zu senden" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "Du sendest zu schnell Nachrichten" msgid "You're streaming!" msgstr "Du streamst!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "Für dich gilt in dieser Community ein Timeout" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "Für dich gilt ein Timeout. Du kannst keine Nachrichten senden, reagieren oder am Sprachchat teilnehmen, bis er abgelaufen ist." diff --git a/fluxer_app/src/features/i18n/locales/el/messages.po b/fluxer_app/src/features/i18n/locales/el/messages.po index 3d8ef68cd..1d7999f2a 100644 --- a/fluxer_app/src/features/i18n/locales/el/messages.po +++ b/fluxer_app/src/features/i18n/locales/el/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "...ενεργοποιήσεις την πυκνή λειτουργία. Ωραία!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(επεξεργασμένο)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# κοινότητα είναι προσωρινά msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# σύνδεση} other {# συνδέσεις}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# αρχείο} other {# αρχεία}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# δώρο} other {# δώρα}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# εικόνα} other {# εικόνες}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# αντικείμενο} other {# αντικείμενα}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# δευτερόλεπτο} other {# δευτερό msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, one {# διαθέσιμη πρόταση} other {# διαθέσιμες προτάσεις}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# βίντεο} other {# βίντεο}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {Αυτή η πρόσκληση λήγει σε # ώ msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {Ο σύνδεσμος πρόσκλησής σας λήγει σε # ώρα.} other {Ο σύνδεσμος πρόσκλησής σας λήγει σε # ώρες.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# εικόνα} other {# εικόνες}}, {videoCount, plural, one {# βίντεο} other {# βίντεο}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@mention" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "Ο/Η <0/> πρόσθεσε τον/την <1/> στην ομάδα." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "Προσθήκη bot σε μια κοινότητα με τα ζητούμενα δικαιώματα" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "Προσθήκη σχολίου (προαιρετικό)" @@ -6687,7 +6714,7 @@ msgstr "Δεν μπορείτε να ανεβάσετε αρχεία εδώ" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "Ρυθμίσεις κατηγορίας" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "Προσοχή" @@ -7372,8 +7399,8 @@ msgstr "κανάλι" msgid "Channel" msgstr "Κανάλι" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "Κανάλι {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "Εντολές" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "Τα σχόλια είναι απενεργοποιημένα επειδή ένα ή περισσότερα επιλεγμένα κανάλια έχουν ενεργοποιημένη την αργή λειτουργία. Το σχόλιο θα αποκλειόταν από την αργή λειτουργία αμέσως μετά την προώθηση." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "Τα σχόλια είναι απενεργοποιημένα επειδή η αργή λειτουργία είναι ενεργοποιημένη στο {forwardChannelDisplayName}. Το σχόλιο θα αποκλειόταν από την αργή λειτουργία αμέσως μετά την προώθηση." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "Τα σχόλια δεν είναι διαθέσιμα όσο είναι ενεργή η αργή λειτουργία." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "Σφάλμα κατά την απόδοση περιεχομένου" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "Σφάλμα κατά την απόδοση LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "Προώθηση πολυμέσων" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "Προώθηση μηνύματος" @@ -18216,7 +18243,7 @@ msgstr "Η εισαγωγή δεν είναι διαθέσιμη" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "Σημαντικό" @@ -21355,7 +21382,7 @@ msgstr "Οι ρυθμίσεις εμφάνισης μηνυμάτων είναι msgid "Message editing" msgstr "Επεξεργασία μηνύματος" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "Το μήνυμα προωθήθηκε" @@ -21404,7 +21431,7 @@ msgstr "Κουμπιά εισαγωγής μηνυμάτων" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "Το μήνυμα είναι πολύ μεγάλο" @@ -23059,7 +23086,7 @@ msgstr "Δεν υπάρχουν αλλαγές για αποθήκευση" msgid "No channels available" msgstr "Δεν υπάρχουν διαθέσιμα κανάλια" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "Δεν βρέθηκαν κανάλια" @@ -23670,7 +23697,7 @@ msgstr "Δεν είναι αληθές ή ψευδές" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "Άνοιγμα emoji στο πρόγραμμα περιήγησης" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "Άνοιγμα επιλογέα emoji" @@ -29360,6 +29387,7 @@ msgstr "Προεπισκόπηση μετακίνησης" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "Προεπισκόπηση μετακίνησης" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "Αναζήτηση με όνομα χρήστη ή ID" msgid "Search channels" msgstr "Αναζήτηση καναλιών" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "Αναζήτηση καναλιών ή DM" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "Αποστολή" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "Αποστολή ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "Η αποστολή SMS σε αυτόν τον αριθμό τηλεφώ msgid "Sending malware or dangerous links" msgstr "Αποστολή κακόβουλου λογισμικού ή επικίνδυνων συνδέσμων" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "Η αποστολή μηνυμάτων έχει απενεργοποιηθεί σε αυτήν την κοινότητα" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "Οι συντομεύσεις απενεργοποιούνται προσωρινά κατά την καταγραφή." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "Συντομεύστε το μήνυμα και δοκιμάστε ξανά." @@ -31780,8 +31804,8 @@ msgstr "Αργή φόρτωση προφίλ" msgid "Slowmode" msgstr "Αργή λειτουργία" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "Αργή λειτουργία · αναμονή {remaining}" @@ -34920,6 +34944,11 @@ msgstr "Αυτό το μέλος δεν είναι πλέον στην κοιν msgid "This member isn't connected to voice anymore." msgstr "Αυτό το μέλος δεν είναι πλέον συνδεδεμένο στη φωνητική συνομιλία." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "Αυτό το μήνυμα μπορεί να προωθηθεί μόνο σε κανάλια με περιορισμό ηλικίας" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "Χρονοσημάνσεις" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "Συμβουλή" @@ -36521,7 +36550,7 @@ msgstr "άγνωστη οντότητα" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "Άγνωστο σφάλμα" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "Αναμονή για κλειδί πρόσβασης…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "Αναμονή λήξης της αργής λειτουργίας στο κανάλι {forwardChannelDisplayName}." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "Αναμονή λήξης της αργής λειτουργίας σε ένα ή περισσότερα επιλεγμένα κανάλια." @@ -39077,7 +39106,7 @@ msgstr "Αφύπνιση" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "Προειδοποίηση" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "Για να αλλάξετε το email σας από εδώ, πρέπει να έχετε πρόσβαση στο τρέχον email σας. Χρησιμοποιήστε την επαλήθευση μέσω τηλεφώνου, αν είναι διαθέσιμη, ή επικοινωνήστε με την υποστήριξη." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "Χρειάζεστε το δικαίωμα «{attachFilesPermissionLabel}» για να επισυνάψετε αρχεία σε αυτό το κανάλι" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "Χρειάζεστε το δικαίωμα «{embedLinksPermissionLabel}» για να ενσωματώσετε συνδέσμους σε αυτό το κανάλι" @@ -40432,11 +40461,6 @@ msgstr "Χρειάζεστε το δικαίωμα «{permissionLabel}» για msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "Χρειάζεστε το δικαίωμα «{permissionLabel}» για να χρησιμοποιήσετε αυτοκόλλητα από άλλες κοινότητες εδώ." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "Χρειάζεστε το δικαίωμα \"{sendMessagesPermissionLabel}\" για να στέλνετε μηνύματα σε αυτό το κανάλι" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "Στέλνετε μηνύματα πολύ γρήγορα" msgid "You're streaming!" msgstr "Κάνετε μετάδοση!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "Έχετε προσωρινό περιορισμό σε αυτήν την κοινότητα" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "Είστε σε προσωρινό περιορισμό. Η ανταλλαγή μηνυμάτων, οι αντιδράσεις και η φωνή έχουν τεθεί σε παύση μέχρι να λήξει ο περιορισμός." diff --git a/fluxer_app/src/features/i18n/locales/en-GB/messages.po b/fluxer_app/src/features/i18n/locales/en-GB/messages.po index 574c5a56f..da4039305 100644 --- a/fluxer_app/src/features/i18n/locales/en-GB/messages.po +++ b/fluxer_app/src/features/i18n/locales/en-GB/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "... turn dense mode on. Nice!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(edited)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# community is temporarily unavailable due to a flu msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# connection} other {# connections}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# file} other {# files}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# gift} other {# gifts}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# image} other {# images}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# item} other {# items}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# second} other {# seconds}}" msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, one {# suggestion available} other {# suggestions available}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# video} other {# videos}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {This invite expires in # hour.} other {This invite msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@mention" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/> added <1/> to the group." @@ -2640,7 +2667,6 @@ msgstr "A browser check is required before phone verification. Try again from th msgid "a channel" msgstr "a channel" -# auto-i18n: reviewed unchanged #. Shown under the "This emoji is from" or "This sticker is from" label in the expression info card when the source community is private to the viewer or cannot be reached. #: src/features/expressions/components/ExpressionInfoCard.tsx:84 msgid "A community that is either invite-only or unavailable." @@ -3135,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "Add a bot to a community with requested permissions" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "Add a comment (optional)" @@ -6688,7 +6714,7 @@ msgstr "Can't upload files here" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6927,7 +6953,7 @@ msgstr "Category settings" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "Caution" @@ -7373,8 +7399,8 @@ msgstr "channel" msgid "Channel" msgstr "Channel" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "Channel {id}" @@ -8805,17 +8831,17 @@ msgid "Commands" msgstr "Commands" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "Comments are unavailable while slowmode is on." @@ -14679,7 +14705,7 @@ msgid "Error rendering content" msgstr "Error rendering content" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16098,7 +16124,7 @@ msgstr "Forward media" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "Forward message" @@ -18217,7 +18243,7 @@ msgstr "Import unavailable" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "Important" @@ -21356,7 +21382,7 @@ msgstr "Message display settings are only available on desktop." msgid "Message editing" msgstr "Message editing" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "Message forwarded" @@ -21405,7 +21431,7 @@ msgstr "Message input buttons" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "Message is too long" @@ -23060,7 +23086,7 @@ msgstr "No changes to save" msgid "No channels available" msgstr "No channels available" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "No channels found" @@ -23671,7 +23697,7 @@ msgstr "Not true or false" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24312,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "Open emoji in browser" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "Open emoji picker" @@ -29361,6 +29387,7 @@ msgstr "Scrub preview" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29369,6 +29396,7 @@ msgstr "Scrub preview" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29408,11 +29436,6 @@ msgstr "Search by username or ID" msgid "Search channels" msgstr "Search channels" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "Search channels or DMs" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30005,7 +30028,7 @@ msgid "Send" msgstr "Send" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "Send ({selectedCount}/{selectionLimit})" @@ -30218,8 +30241,8 @@ msgstr "Sending an SMS to this phone number is too expensive for {PRODUCT_NAME}, msgid "Sending malware or dangerous links" msgstr "Sending malware or dangerous links" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "Sending messages is disabled in this community" @@ -30924,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "Shortcuts are paused while recording." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "Shorten the message and try again." @@ -31781,8 +31804,8 @@ msgstr "Slow profile load" msgid "Slowmode" msgstr "Slowmode" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "Slowmode · wait {remaining}" @@ -34921,6 +34944,11 @@ msgstr "This member is no longer in the community. Refresh and try again." msgid "This member isn't connected to voice anymore." msgstr "This member isn't connected to voice anymore." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "This message can only be forwarded to age-restricted channels" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35352,7 +35380,7 @@ msgstr "Timestamps" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "Tip" @@ -36522,7 +36550,7 @@ msgstr "unknown entity" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "Unknown error" @@ -39057,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "Waiting for passkey…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "Waiting for slowmode in {forwardChannelDisplayName} to expire." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "Waiting for slowmode in one or more selected channels to expire." @@ -39078,7 +39106,7 @@ msgstr "Wake up" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "Warning" @@ -40391,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "You need access to your current email to change it from here. Use phone verification if available or contact support." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" @@ -40433,11 +40461,6 @@ msgstr "You need the \"{permissionLabel}\" permission to use emoji from other co msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "You need the \"{permissionLabel}\" permission to use stickers from other communities here." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40680,11 +40703,6 @@ msgstr "You're sending messages too quickly" msgid "You're streaming!" msgstr "You're streaming!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "You're timed out in this community" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." diff --git a/fluxer_app/src/features/i18n/locales/en-US/messages.po b/fluxer_app/src/features/i18n/locales/en-US/messages.po index b53100963..0e2ec2cad 100644 --- a/fluxer_app/src/features/i18n/locales/en-US/messages.po +++ b/fluxer_app/src/features/i18n/locales/en-US/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "... turn dense mode on. Nice!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(edited)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# community is temporarily unavailable due to a flu msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# connection} other {# connections}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# file} other {# files}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# gift} other {# gifts}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# image} other {# images}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# item} other {# items}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# second} other {# seconds}}" msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, one {# suggestion available} other {# suggestions available}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# video} other {# videos}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {This invite expires in # hour.} other {This invite msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@mention" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/> added <1/> to the group." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "Add a bot to a community with requested permissions" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "Add a comment (optional)" @@ -6687,7 +6714,7 @@ msgstr "Can't upload files here" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "Category settings" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "Caution" @@ -7372,8 +7399,8 @@ msgstr "channel" msgid "Channel" msgstr "Channel" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "Channel {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "Commands" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "Comments are unavailable while slowmode is on." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "Error rendering content" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "Forward media" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "Forward message" @@ -18216,7 +18243,7 @@ msgstr "Import unavailable" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "Important" @@ -21355,7 +21382,7 @@ msgstr "Message display settings are only available on desktop." msgid "Message editing" msgstr "Message editing" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "Message forwarded" @@ -21404,7 +21431,7 @@ msgstr "Message input buttons" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "Message is too long" @@ -23059,7 +23086,7 @@ msgstr "No changes to save" msgid "No channels available" msgstr "No channels available" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "No channels found" @@ -23670,7 +23697,7 @@ msgstr "Not true or false" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "Open emoji in browser" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "Open emoji picker" @@ -29360,6 +29387,7 @@ msgstr "Scrub preview" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "Scrub preview" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "Search by username or ID" msgid "Search channels" msgstr "Search channels" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "Search channels or DMs" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "Send" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "Send ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "Sending an SMS to this phone number is too expensive for {PRODUCT_NAME}, msgid "Sending malware or dangerous links" msgstr "Sending malware or dangerous links" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "Sending messages is disabled in this community" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "Shortcuts are paused while recording." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "Shorten the message and try again." @@ -31780,8 +31804,8 @@ msgstr "Slow profile load" msgid "Slowmode" msgstr "Slowmode" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "Slowmode · wait {remaining}" @@ -34920,6 +34944,11 @@ msgstr "This member is no longer in the community. Refresh and try again." msgid "This member isn't connected to voice anymore." msgstr "This member isn't connected to voice anymore." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "This message can only be forwarded to age-restricted channels" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "Timestamps" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "Tip" @@ -36521,7 +36550,7 @@ msgstr "unknown entity" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "Unknown error" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "Waiting for passkey…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "Waiting for slowmode in {forwardChannelDisplayName} to expire." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "Waiting for slowmode in one or more selected channels to expire." @@ -39077,7 +39106,7 @@ msgstr "Wake up" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "Warning" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "You need access to your current email to change it from here. Use phone verification if available or contact support." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" @@ -40432,11 +40461,6 @@ msgstr "You need the \"{permissionLabel}\" permission to use emoji from other co msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "You need the \"{permissionLabel}\" permission to use stickers from other communities here." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "You're sending messages too quickly" msgid "You're streaming!" msgstr "You're streaming!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "You're timed out in this community" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." diff --git a/fluxer_app/src/features/i18n/locales/es-419/messages.po b/fluxer_app/src/features/i18n/locales/es-419/messages.po index eaaffcb2b..cae3f4dec 100644 --- a/fluxer_app/src/features/i18n/locales/es-419/messages.po +++ b/fluxer_app/src/features/i18n/locales/es-419/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "... actives el modo denso. ¡Genial!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(editado)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# comunidad no está disponible temporalmente debid msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# conexión} other {# conexiones}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# archivo} other {# archivos}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# regalo} other {# regalos}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# imagen} other {# imágenes}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# elemento} other {# elementos}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# segundo} other {# segundos}}" msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, one {# sugerencia disponible} many {# sugerencias disponibles} other {# sugerencias disponibles}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# video} other {# videos}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {Esta invitación vence en # hora.} other {Esta invi msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {Tu enlace de invitación vence en # hora.} many {Tu enlace de invitación vence en # horas.} other {Tu enlace de invitación vence en # horas.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# imagen} other {# imágenes}}, {videoCount, plural, one {# video} other {# videos}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@mención" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/> agregó a <1/> al grupo." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "Agregar un bot a una comunidad con los permisos solicitados" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "Agregar un comentario (opcional)" @@ -6687,7 +6714,7 @@ msgstr "No se pueden subir archivos aquí" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "Configuración de categoría" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "Precaución" @@ -7372,8 +7399,8 @@ msgstr "canal" msgid "Channel" msgstr "Canal" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "Canal {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "Comandos" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "Los comentarios están desactivados porque uno o más canales seleccionados tienen el modo lento activado. El comentario sería bloqueado por el modo lento justo después del reenvío." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "Los comentarios están deshabilitados porque el modo lento está activado en {forwardChannelDisplayName}. El comentario se bloquearía por el modo lento justo después del reenvío." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "Los comentarios no están disponibles mientras el modo lento esté activado." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "Error al mostrar el contenido" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "Error al renderizar LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "Reenviar archivo multimedia" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "Reenviar mensaje" @@ -18216,7 +18243,7 @@ msgstr "Importación no disponible" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "Importante" @@ -21355,7 +21382,7 @@ msgstr "La configuración de visualización de mensajes solo está disponible en msgid "Message editing" msgstr "Edición de mensajes" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "Mensaje reenviado" @@ -21404,7 +21431,7 @@ msgstr "Botones de entrada de mensajes" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "El mensaje es demasiado largo" @@ -23059,7 +23086,7 @@ msgstr "No hay cambios para guardar" msgid "No channels available" msgstr "No hay canales disponibles" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "No se encontraron canales" @@ -23670,7 +23697,7 @@ msgstr "No es verdadero ni falso" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "Abrir emoji en el navegador" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "Abrir selector de emojis" @@ -29360,6 +29387,7 @@ msgstr "Vista previa al recorrer el video" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "Vista previa al recorrer el video" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "Buscar por nombre de usuario o ID" msgid "Search channels" msgstr "Buscar canales" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "Buscar canales o mensajes directos" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "Enviar" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "Enviar ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "Enviar un SMS a este número de teléfono es demasiado costoso para {PRO msgid "Sending malware or dangerous links" msgstr "Enviar malware o enlaces peligrosos" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "No se pueden enviar mensajes en esta comunidad" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "Los atajos se pausan durante la grabación." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "Acorta el mensaje e inténtalo de nuevo." @@ -31780,8 +31804,8 @@ msgstr "Carga lenta de perfil" msgid "Slowmode" msgstr "Modo lento" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "Modo lento · espera {remaining}" @@ -34920,6 +34944,11 @@ msgstr "Este miembro ya no está en la comunidad. Actualiza y vuelve a intentarl msgid "This member isn't connected to voice anymore." msgstr "Este miembro ya no está conectado al chat de voz." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "Este mensaje solo se puede reenviar a canales con restricción de edad" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "Marcas de tiempo" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "Consejo" @@ -36521,7 +36550,7 @@ msgstr "entidad desconocida" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "Error desconocido" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "Esperando la llave de acceso…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "Esperando que el modo lento en {forwardChannelDisplayName} expire." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "Esperando que el modo lento en uno o más canales seleccionados expire." @@ -39077,7 +39106,7 @@ msgstr "Reactivar" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "Advertencia" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "Necesitas acceso a tu correo electrónico actual para cambiarlo desde aquí. Usa la verificación por teléfono si está disponible o contacta a soporte." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "Necesitas el permiso \"{attachFilesPermissionLabel}\" para adjuntar archivos en este canal" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "Necesitas el permiso \"{embedLinksPermissionLabel}\" para incrustar enlaces en este canal" @@ -40432,11 +40461,6 @@ msgstr "Necesitas el permiso \"{permissionLabel}\" para usar emojis de otras com msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "Necesitas el permiso \"{permissionLabel}\" para usar stickers de otras comunidades aquí." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "Necesitas el permiso \"{sendMessagesPermissionLabel}\" para enviar mensajes en este canal" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "Estás enviando mensajes muy rápido" msgid "You're streaming!" msgstr "¡Estás transmitiendo!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "Estás en aislamiento temporal en esta comunidad" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "Estás en aislamiento temporal. No puedes enviar mensajes, reaccionar ni conectarte a canales de voz hasta que termine." diff --git a/fluxer_app/src/features/i18n/locales/es-ES/messages.po b/fluxer_app/src/features/i18n/locales/es-ES/messages.po index 91b092258..f8e4b3142 100644 --- a/fluxer_app/src/features/i18n/locales/es-ES/messages.po +++ b/fluxer_app/src/features/i18n/locales/es-ES/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "... actives el modo denso. ¡Genial!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(editado)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# comunidad no está disponible temporalmente debid msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# conexión} other {# conexiones}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# archivo} other {# archivos}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# regalo} other {# regalos}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# imagen} other {# imágenes}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# elemento} other {# elementos}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# segundo} other {# segundos}}" msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, one {# sugerencia disponible} many {# sugerencias disponibles} other {# sugerencias disponibles}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# vídeo} other {# vídeos}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {Esta invitación caduca en # hora.} other {Esta inv msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {Tu enlace de invitación caduca en # hora.} many {Tu enlace de invitación caduca en # horas.} other {Tu enlace de invitación caduca en # horas.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# imagen} other {# imágenes}}, {videoCount, plural, one {# vídeo} other {# vídeos}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@mención" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/> añadió a <1/> al grupo." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "Añadir un bot a una comunidad con los permisos solicitados" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "Añadir un comentario (opcional)" @@ -6687,7 +6714,7 @@ msgstr "No se pueden subir archivos aquí" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "Ajustes de categoría" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "Precaución" @@ -7372,8 +7399,8 @@ msgstr "canal" msgid "Channel" msgstr "Canal" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "Canal {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "Comandos" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "Los comentarios están desactivados porque uno o varios de los canales seleccionados tienen el modo lento activado. El comentario se bloquearía por el modo lento justo después del reenvío." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "Los comentarios están deshabilitados porque el modo lento está activado en {forwardChannelDisplayName}. El comentario se bloquearía por el modo lento justo después del reenvío." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "Los comentarios no están disponibles mientras el modo lento esté activado." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "Error al mostrar el contenido" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "Error al renderizar LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "Reenviar contenido multimedia" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "Reenviar mensaje" @@ -18216,7 +18243,7 @@ msgstr "Importación no disponible" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "Importante" @@ -21355,7 +21382,7 @@ msgstr "Los ajustes de visualización de mensajes solo están disponibles en la msgid "Message editing" msgstr "Edición de mensajes" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "Mensaje reenviado" @@ -21404,7 +21431,7 @@ msgstr "Botones de entrada de mensajes" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "El mensaje es demasiado largo" @@ -23059,7 +23086,7 @@ msgstr "No hay cambios que guardar" msgid "No channels available" msgstr "No hay canales disponibles" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "No se encontraron canales" @@ -23670,7 +23697,7 @@ msgstr "No es verdadero ni falso" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "Abrir emoji en el navegador" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "Abrir selector de emojis" @@ -29360,6 +29387,7 @@ msgstr "Vista previa al recorrer el vídeo" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "Vista previa al recorrer el vídeo" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "Buscar por nombre de usuario o ID" msgid "Search channels" msgstr "Buscar canales" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "Buscar canales o MD" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "Enviar" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "Enviar ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "Enviar un SMS a este número de teléfono es demasiado caro para {PRODUC msgid "Sending malware or dangerous links" msgstr "Enviar malware o enlaces peligrosos" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "El envío de mensajes está deshabilitado en esta comunidad" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "Los atajos se pausan durante la grabación." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "Acorta el mensaje y vuelve a intentarlo." @@ -31780,8 +31804,8 @@ msgstr "Carga lenta del perfil" msgid "Slowmode" msgstr "Modo lento" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "Modo lento · espera {remaining}" @@ -34920,6 +34944,11 @@ msgstr "Este miembro ya no está en la comunidad. Actualiza y vuelve a intentarl msgid "This member isn't connected to voice anymore." msgstr "Este miembro ya no está conectado al chat de voz." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "Este mensaje solo se puede reenviar a canales con restricción de edad" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "Marcas de tiempo" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "Consejo" @@ -36521,7 +36550,7 @@ msgstr "entidad desconocida" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "Error desconocido" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "Esperando la clave de acceso…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "Esperando a que el modo lento en {forwardChannelDisplayName} expire." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "Esperando a que el modo lento caduque en uno o más canales seleccionados." @@ -39077,7 +39106,7 @@ msgstr "Reactivar" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "Advertencia" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "Necesitas acceder a tu correo electrónico actual para cambiarlo desde aquí. Usa la verificación por teléfono si está disponible o contacta con soporte." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "Necesitas el permiso \"{attachFilesPermissionLabel}\" para adjuntar archivos en este canal" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "Necesitas el permiso \"{embedLinksPermissionLabel}\" para incrustar enlaces en este canal" @@ -40432,11 +40461,6 @@ msgstr "Necesitas el permiso \"{permissionLabel}\" para usar aquí los emojis de msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "Necesitas el permiso \"{permissionLabel}\" para usar pegatinas de otras comunidades aquí." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "Necesitas el permiso \"{sendMessagesPermissionLabel}\" para enviar mensajes en este canal" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "Estás enviando mensajes demasiado rápido" msgid "You're streaming!" msgstr "¡Estás transmitiendo!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "Estás en aislamiento temporal en esta comunidad" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "Estás en aislamiento temporal. No puedes enviar mensajes, reaccionar ni conectarte a canales de voz hasta que termine." diff --git a/fluxer_app/src/features/i18n/locales/fi/messages.po b/fluxer_app/src/features/i18n/locales/fi/messages.po index b38cb2caa..93540a613 100644 --- a/fluxer_app/src/features/i18n/locales/fi/messages.po +++ b/fluxer_app/src/features/i18n/locales/fi/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "...otat tiiviin tilan käyttöön. Hienoa!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(muokattu)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# yhteisö on tilapäisesti pois käytöstä toimin msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# yhteys} other {# yhteyttä}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# tiedosto} other {# tiedostoa}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# lahja} other {# lahjaa}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# kuva} other {# kuvaa}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# kohde} other {# kohdetta}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# sekunti} other {# sekuntia}}" msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, one {# ehdotus saatavilla} other {# ehdotusta saatavilla}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# video} other {# videota}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {Tämä kutsu vanhenee # tunnin kuluttua.} other {T msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {Kutsulinkkisi vanhenee # tunnin kuluttua.} other {Kutsulinkkisi vanhenee # tunnin kuluttua.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# kuva} other {# kuvaa}}, {videoCount, plural, one {# video} other {# videota}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@maininta" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/> lisäsi käyttäjän <1/> ryhmään." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "Lisätä botin yhteisöön pyydetyillä käyttöoikeuksilla" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "Lisää kommentti (valinnainen)" @@ -6687,7 +6714,7 @@ msgstr "Tiedostoja ei voi lähettää tähän" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "Kategorian asetukset" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "Huomio" @@ -7372,8 +7399,8 @@ msgstr "kanava" msgid "Channel" msgstr "Kanava" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "Kanava {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "Komennot" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "Kommentointi on poistettu käytöstä, koska yhdellä tai useammalla valitulla kanavalla on hidas tila päällä. Hidas tila estäisi kommentin heti edelleenlähetyksen jälkeen." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "Kommentointi on poistettu käytöstä, koska kanavalla {forwardChannelDisplayName} on hidas tila päällä. Hidas tila estäisi kommentin heti edelleenlähetyksen jälkeen." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "Kommentit eivät ole käytettävissä, kun hidas tila on päällä." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "Virhe sisällön näyttämisessä" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "Virhe LaTeXin renderöinnissä: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "Välitä media" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "Välitä viesti" @@ -18216,7 +18243,7 @@ msgstr "Tuonti ei ole käytettävissä" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "Tärkeää" @@ -21355,7 +21382,7 @@ msgstr "Viestien näyttöasetukset ovat käytettävissä vain työpöytäsovellu msgid "Message editing" msgstr "Viestin muokkaus" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "Viesti välitetty" @@ -21404,7 +21431,7 @@ msgstr "Viestinsyötön painikkeet" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "Viesti on liian pitkä" @@ -23059,7 +23086,7 @@ msgstr "Ei tallennettavia muutoksia" msgid "No channels available" msgstr "Ei kanavia saatavilla" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "Kanavia ei löytynyt" @@ -23670,7 +23697,7 @@ msgstr "Ei ole tosi eikä epätosi" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "Avaa emoji selaimessa" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "Avaa emojivalitsin" @@ -29360,6 +29387,7 @@ msgstr "Kelauksen esikatselu" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "Kelauksen esikatselu" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "Hae käyttäjänimellä tai tunnuksella" msgid "Search channels" msgstr "Hae kanavia" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "Hae kanavia tai yksityisviestejä" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "Lähetä" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "Lähetä ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "Tekstiviestin lähettäminen tähän puhelinnumeroon on liian kallista { msgid "Sending malware or dangerous links" msgstr "Haittaohjelmien tai vaarallisten linkkien lähettäminen" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "Viestien lähettäminen on poistettu käytöstä tässä yhteisössä" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "Pikanäppäimet eivät ole käytössä näppäinyhdistelmän tallennuksen aikana." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "Lyhennä viestiä ja yritä uudelleen." @@ -31780,8 +31804,8 @@ msgstr "Hidas profiilin lataus" msgid "Slowmode" msgstr "Hidas tila" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "Hidas tila · odota {remaining}" @@ -34920,6 +34944,11 @@ msgstr "Tämä jäsen ei ole enää yhteisössä. Päivitä ja yritä uudelleen. msgid "This member isn't connected to voice anymore." msgstr "Tämä jäsen ei ole enää äänikanavalla." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "Tämä viesti voidaan välittää vain ikärajoitettuihin kanaviin" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "Aikaleimat" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "Vinkki" @@ -36521,7 +36550,7 @@ msgstr "tuntematon taho" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "Tuntematon virhe" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "Odotetaan pääsyavainta…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "Odotetaan hitaan tilan päättymistä kanavalla {forwardChannelDisplayName}." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "Odotetaan hitaan tilan päättymistä yhdessä tai useammassa valitussa kanavassa." @@ -39077,7 +39106,7 @@ msgstr "Herätä" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "Varoitus" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "Jotta voit vaihtaa sähköpostiosoitteesi täältä, tarvitset pääsyn nykyiseen sähköpostiisi. Käytä puhelinvarmennusta, jos se on saatavilla, tai ota yhteyttä tukeen." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "Tarvitset \"{attachFilesPermissionLabel}\" -käyttöoikeuden liittääksesi tiedostoja tällä kanavalla" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "Tarvitset \"{embedLinksPermissionLabel}\" -käyttöoikeuden upottaaksesi linkkejä tällä kanavalla" @@ -40432,11 +40461,6 @@ msgstr "Tarvitset \"{permissionLabel}\" -käyttöoikeuden käyttääksesi muiden msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "Tarvitset \"{permissionLabel}\" -käyttöoikeuden käyttääksesi muiden yhteisöjen tarroja täällä." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "Tarvitset \"{sendMessagesPermissionLabel}\" -käyttöoikeuden lähettääksesi viestejä tällä kanavalla" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "Lähetät viestejä liian nopeasti" msgid "You're streaming!" msgstr "Striimaat!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "Sinulla on jäähy tässä yhteisössä" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "Sinulla on jäähy. Viestit, reaktiot ja puhe ovat keskeytettyinä, kunnes jäähy päättyy." diff --git a/fluxer_app/src/features/i18n/locales/fr/messages.po b/fluxer_app/src/features/i18n/locales/fr/messages.po index 4cda0238f..3a74379ac 100644 --- a/fluxer_app/src/features/i18n/locales/fr/messages.po +++ b/fluxer_app/src/features/i18n/locales/fr/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "... activer le mode dense. Chouette !" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(modifié)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# communauté est temporairement indisponible en ra msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# connexion} other {# connexions}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# fichier} other {# fichiers}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# cadeau} other {# cadeaux}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# image} other {# images}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# élément} other {# éléments}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# seconde} other {# secondes}}" msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, one {# suggestion disponible} many {# suggestions disponibles} other {# suggestions disponibles}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# vidéo} other {# vidéos}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {Cette invitation expire dans # heure.} other {Cette msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {Votre lien d’invitation expire dans # heure.} other {Votre lien d’invitation expire dans # heures.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# vidéo} other {# vidéos}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@mention" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/> a ajouté <1/> au groupe." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "Ajouter un bot à une communauté avec les permissions demandées" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "Ajouter un commentaire (facultatif)" @@ -6687,7 +6714,7 @@ msgstr "Impossible d’envoyer des fichiers ici" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "Paramètres de catégorie" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "Attention" @@ -7372,8 +7399,8 @@ msgstr "salon" msgid "Channel" msgstr "Salon" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "Salon {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "Commandes" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "Les commentaires sont désactivés car un ou plusieurs des salons sélectionnés ont le mode lent activé. Le commentaire serait bloqué par le mode lent juste après le transfert." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "Les commentaires sont désactivés, car le mode lent est activé dans {forwardChannelDisplayName}. Le commentaire serait bloqué par le mode lent juste après le transfert." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "Les commentaires ne sont pas disponibles lorsque le mode lent est activé." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "Erreur lors de l'affichage du contenu" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "Erreur lors du rendu LaTeX : {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "Transférer le média" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "Transférer le message" @@ -18216,7 +18243,7 @@ msgstr "Importation non disponible" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "Important" @@ -21355,7 +21382,7 @@ msgstr "Les paramètres d'affichage des messages ne sont disponibles que sur ord msgid "Message editing" msgstr "Modification des messages" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "Message transféré" @@ -21404,7 +21431,7 @@ msgstr "Boutons de saisie de message" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "Message trop long" @@ -23059,7 +23086,7 @@ msgstr "Aucune modification à enregistrer" msgid "No channels available" msgstr "Aucun salon disponible" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "Aucun salon trouvé" @@ -23670,7 +23697,7 @@ msgstr "Ce n’est ni vrai ni faux" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "Ouvrir l'emoji dans le navigateur" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "Ouvrir le sélecteur d'emojis" @@ -29360,6 +29387,7 @@ msgstr "Aperçu lors du déplacement dans la vidéo" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "Aperçu lors du déplacement dans la vidéo" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "Rechercher par nom d'utilisateur ou ID" msgid "Search channels" msgstr "Rechercher des salons" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "Rechercher des salons ou des MP" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "Envoyer" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "Envoyer ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "L'envoi d'un SMS à ce numéro de téléphone est trop coûteux pour {PR msgid "Sending malware or dangerous links" msgstr "Envoi de logiciels malveillants ou de liens dangereux" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "L'envoi de messages est désactivé dans cette communauté" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "Les raccourcis sont suspendus pendant l’enregistrement." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "Raccourcissez le message et réessayez." @@ -31780,8 +31804,8 @@ msgstr "Chargement lent du profil" msgid "Slowmode" msgstr "Mode lent" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "Mode lent · attendez {remaining}" @@ -34920,6 +34944,11 @@ msgstr "Ce membre ne fait plus partie de la communauté. Actualisez et réessaye msgid "This member isn't connected to voice anymore." msgstr "Ce membre n’est plus connecté à la discussion vocale." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "Ce message ne peut être transféré qu'aux chaînes soumises à restriction d'âge." + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "Horodatages" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "Astuce" @@ -36521,7 +36550,7 @@ msgstr "entité inconnue" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "Erreur inconnue" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "En attente de la clé d’accès…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "En attente de l'expiration du mode lent dans {forwardChannelDisplayName}." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "En attente de l'expiration du mode lent dans un ou plusieurs salons sélectionnés." @@ -39077,7 +39106,7 @@ msgstr "Sortie de veille" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "Attention" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "Vous devez avoir accès à votre adresse e-mail actuelle pour la modifier d'ici. Utilisez la vérification par téléphone si disponible ou contactez l'assistance." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "Vous devez disposer de la permission « {attachFilesPermissionLabel} » pour joindre des fichiers dans ce salon" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "Vous devez disposer de la permission « {embedLinksPermissionLabel} » pour intégrer des liens dans ce salon" @@ -40432,11 +40461,6 @@ msgstr "Vous devez disposer de la permission « {permissionLabel} » pour utilis msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "Vous devez disposer de la permission « {permissionLabel} » pour utiliser ici les stickers d’autres communautés." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "Vous devez disposer de la permission « {sendMessagesPermissionLabel} » pour envoyer des messages dans ce salon" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "Vous envoyez des messages trop rapidement" msgid "You're streaming!" msgstr "Vous diffusez en direct !" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "Vous faites l’objet d’une restriction temporaire dans cette communauté" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "Vous faites l’objet d’une restriction temporaire. L’envoi de messages, les réactions et les connexions vocales sont suspendus jusqu’à sa fin." diff --git a/fluxer_app/src/features/i18n/locales/he/messages.po b/fluxer_app/src/features/i18n/locales/he/messages.po index 5a7f723c0..5b8b3943f 100644 --- a/fluxer_app/src/features/i18n/locales/he/messages.po +++ b/fluxer_app/src/features/i18n/locales/he/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "... להפעיל מצב צפוף. יפה!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(נערך)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# קהילה אינה זמינה באופן זמנ msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# חיבור} other {# חיבורים}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# קובץ} other {# קבצים}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# מתנה} other {# מתנות}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# תמונה} other {# תמונות}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# פריט} other {# פריטים}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# שנייה} other {# שניות}}" msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, one {# הצעה זמינה} two {# הצעות זמינות} other {# הצעות זמינות}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# סרטון} other {# סרטונים}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {ההזמנה הזו תפוג בעוד שעה.} othe msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {תוקף קישור ההזמנה שלך יפוג בעוד שעה אחת.} two {תוקף קישור ההזמנה שלך יפוג בעוד שעתיים.} other {תוקף קישור ההזמנה שלך יפוג בעוד # שעות.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# תמונה} other {# תמונות}}, {videoCount, plural, one {# סרטון} other {# סרטונים}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@mention" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/> הוסיף/ה את <1/> לקבוצה." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "הוספת בוט לקהילה עם ההרשאות המבוקשות" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "הוסף הערה (אופציונלי)" @@ -6687,7 +6714,7 @@ msgstr "לא ניתן להעלות קבצים כאן" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "הגדרות קטגוריה" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "זהירות" @@ -7372,8 +7399,8 @@ msgstr "ערוץ" msgid "Channel" msgstr "ערוץ" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "ערוץ {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "פקודות" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "התגובות מושבתות כי מצב איטי מופעל באחד או יותר מהערוצים שבחרת. התגובה תיחסם על ידי מצב איטי מיד לאחר ההעברה." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "התגובות מושבתות כי מצב איטי מופעל ב-{forwardChannelDisplayName}. התגובה תיחסם על ידי מצב איטי מיד לאחר ההעברה." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "התגובות אינן זמינות כשמצב איטי מופעל." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "שגיאה בעיבוד התוכן" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "שגיאה בעיבוד LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "העבר מדיה" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "העברת הודעה" @@ -18216,7 +18243,7 @@ msgstr "ייבוא לא זמין" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "חשוב" @@ -21355,7 +21382,7 @@ msgstr "הגדרות תצוגת ההודעות זמינות רק במחשב." msgid "Message editing" msgstr "עריכת הודעה" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "ההודעה הועברה" @@ -21404,7 +21431,7 @@ msgstr "כפתורי שדה ההודעה" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "ההודעה ארוכה מדי" @@ -23059,7 +23086,7 @@ msgstr "אין שינויים לשמירה" msgid "No channels available" msgstr "אין ערוצים זמינים" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "לא נמצאו ערוצים" @@ -23670,7 +23697,7 @@ msgstr "לא אמת או שקר" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "פתח אימוג'י בדפדפן" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "פתח בורר אימוג'י" @@ -29360,6 +29387,7 @@ msgstr "תצוגה מקדימה בגלילה" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "תצוגה מקדימה בגלילה" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "חיפוש לפי שם משתמש או מזהה" msgid "Search channels" msgstr "חיפוש ערוצים" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "חיפוש ערוצים או צ'אטים פרטיים" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "שליחה" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "שליחה ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "שליחת SMS למספר הטלפון הזה יקרה מדי עבור { msgid "Sending malware or dangerous links" msgstr "שליחת תוכנות זדוניות או קישורים מסוכנים" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "שליחת הודעות מושבתת בקהילה זו" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "קיצורי הדרך מושהים בזמן הקלטת צירוף מקשים." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "יש לקצר את ההודעה ולנסות שוב." @@ -31780,8 +31804,8 @@ msgstr "טעינת פרופיל איטית" msgid "Slowmode" msgstr "מצב איטי" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "מצב איטי · המתן {remaining}" @@ -34920,6 +34944,11 @@ msgstr "החבר הזה כבר לא נמצא בקהילה. רענן ונסה ש msgid "This member isn't connected to voice anymore." msgstr "החבר הזה כבר לא מחובר לערוץ הקולי." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "לא ניתן להעביר הודעה זו אלא לערוצים המיועדים לגיל מסוים" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "חותמות זמן" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "טיפ" @@ -36521,7 +36550,7 @@ msgstr "ישות לא ידועה" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "שגיאה לא ידועה" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "ממתין למפתח גישה…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "ממתין שתוקף מצב איטי ב-{forwardChannelDisplayName} יפוג." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "ממתין שתוקף מצב איטי באחד או יותר מהערוצים שנבחרו יפוג." @@ -39077,7 +39106,7 @@ msgstr "התעוררות" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "אזהרה" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "כדי לשנות את כתובת האימייל שלך מכאן, עליך לגשת לאימייל הנוכחי שלך. השתמש באימות טלפוני אם זמין, או פנה לתמיכה." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "דרושה לך ההרשאה \"{attachFilesPermissionLabel}\" כדי לצרף קבצים בערוץ זה" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "דרושה לך ההרשאה \"{embedLinksPermissionLabel}\" כדי להטמיע קישורים בערוץ זה" @@ -40432,11 +40461,6 @@ msgstr "דרושה לך ההרשאה \"{permissionLabel}\" כדי להשתמש msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "דרושה לך ההרשאה \"{permissionLabel}\" כדי להשתמש במדבקות מקהילות אחרות כאן." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "דרושה לך ההרשאה \"{sendMessagesPermissionLabel}\" כדי לשלוח הודעות בערוץ זה" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "אתה שולח הודעות מהר מדי" msgid "You're streaming!" msgstr "אתה משדר!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "אתה בפסק זמן בקהילה זו" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "קיבלת פסק זמן. שליחת הודעות, ריאקציות וקול מושהים עד שפסק הזמן יסתיים." diff --git a/fluxer_app/src/features/i18n/locales/hi/messages.po b/fluxer_app/src/features/i18n/locales/hi/messages.po index ad0d518e2..6fbf1b146 100644 --- a/fluxer_app/src/features/i18n/locales/hi/messages.po +++ b/fluxer_app/src/features/i18n/locales/hi/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "... सघन मोड चालू करें। बढ़िया!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(संपादित)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# कम्युनिटी फ्लक्स msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# कनेक्शन} other {# कनेक्शन}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# फ़ाइल} other {# फ़ाइलें}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# उपहार} other {# उपहार}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# इमेज} other {# इमेज}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# आइटम} other {# आइटम}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# सेकंड} other {# सेकंड}}" msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, =0 {# सुझाव उपलब्ध हैं} one {# सुझाव उपलब्ध है} other {# सुझाव उपलब्ध हैं}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# वीडियो} other {# वीडियो}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {यह इनवाइट # घंटे में msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {आपका इनवाइट लिंक # घंटे में समाप्त हो जाएगा।} other {आपका इनवाइट लिंक # घंटों में समाप्त हो जाएगा।}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# इमेज} other {# इमेज}}, {videoCount, plural, one {# वीडियो} other {# वीडियो}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@mention" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/> ने <1/> को ग्रुप में जोड़ा।" @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "मांगी गई अनुमतियों के साथ किसी कम्युनिटी में बॉट जोड़ना" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "कोई टिप्पणी जोड़ें (वैकल्पिक)" @@ -6687,7 +6714,7 @@ msgstr "यहां फ़ाइलें अपलोड नहीं की #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "श्रेणी सेटिंग्स" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "सावधान" @@ -7372,8 +7399,8 @@ msgstr "चैनल" msgid "Channel" msgstr "चैनल" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "चैनल {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "कमांड" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "टिप्पणियाँ बंद हैं क्योंकि एक या अधिक चुने गए चैनलों में स्लोमोड चालू है। फ़ॉरवर्ड के तुरंत बाद स्लोमोड टिप्पणी को ब्लॉक कर देगा।" #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "{forwardChannelDisplayName} में स्लोमोड चालू होने के कारण टिप्पणियाँ बंद हैं। फ़ॉरवर्ड के तुरंत बाद स्लोमोड टिप्पणी को ब्लॉक कर देगा।" #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "स्लोमोड चालू होने पर टिप्पणियाँ उपलब्ध नहीं हैं।" @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "कंटेंट रेंडर करने में गड़बड़ी हुई" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "LaTeX रेंडर करने में गड़बड़ी: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "मीडिया फ़ॉरवर्ड करें" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "मैसेज फ़ॉरवर्ड करें" @@ -18216,7 +18243,7 @@ msgstr "इंपोर्ट उपलब्ध नहीं है" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "ज़रूरी" @@ -21355,7 +21382,7 @@ msgstr "मैसेज डिस्प्ले सेटिंग्स सि msgid "Message editing" msgstr "मैसेज एडिट करना" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "मैसेज फ़ॉरवर्ड किया गया" @@ -21404,7 +21431,7 @@ msgstr "मैसेज इनपुट बटन" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "मैसेज बहुत लंबा है" @@ -23059,7 +23086,7 @@ msgstr "सेव करने के लिए कोई बदलाव नह msgid "No channels available" msgstr "कोई चैनल उपलब्ध नहीं है" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "कोई चैनल नहीं मिला" @@ -23670,7 +23697,7 @@ msgstr "सही या ग़लत नहीं है" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "ब्राउज़र में इमोजी खोलें" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "इमोजी पिकर खोलें" @@ -29360,6 +29387,7 @@ msgstr "स्क्रब प्रीव्यू" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "स्क्रब प्रीव्यू" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "यूज़रनेम या आईडी से खोजें" msgid "Search channels" msgstr "चैनल खोजें" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "चैनल या DM खोजें" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "भेजें" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "भेजें ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "{PRODUCT_NAME} के लिए इस फ़ोन नंबर पर msgid "Sending malware or dangerous links" msgstr "मैलवेयर या खतरनाक लिंक भेजना" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "इस कम्युनिटी में मैसेज भेजना बंद है" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "रिकॉर्डिंग के दौरान कीबोर्ड शॉर्टकट रोक दिए जाते हैं।" #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "मैसेज छोटा करें और फिर से कोशिश करें।" @@ -31780,8 +31804,8 @@ msgstr "प्रोफ़ाइल लोड धीमा करें" msgid "Slowmode" msgstr "स्लोमोड" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "स्लोमोड · {remaining} इंतज़ार करें" @@ -34920,6 +34944,11 @@ msgstr "यह सदस्य अब कम्युनिटी में न msgid "This member isn't connected to voice anymore." msgstr "यह सदस्य अब वॉइस से कनेक्टेड नहीं है।" +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "यह संदेश केवल आयु-प्रतिबंधित चैनलों पर ही अग्रेषित किया जा सकता है" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "टाइमस्टैम्प" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "टिप" @@ -36521,7 +36550,7 @@ msgstr "अज्ञात इकाई" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "अज्ञात गड़बड़ी" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "पासकी का इंतज़ार हो रहा है…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "{forwardChannelDisplayName} में स्लोमोड के खत्म होने का इंतज़ार किया जा रहा है।" #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "एक या ज़्यादा चुने गए चैनलों में स्लोमोड के खत्म होने का इंतज़ार किया जा रहा है।" @@ -39077,7 +39106,7 @@ msgstr "जगाएँ" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "चेतावनी" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "इसे यहां से बदलने के लिए आपको अपने मौजूदा ईमेल का एक्सेस चाहिए। अगर उपलब्ध हो, तो फ़ोन वेरिफ़िकेशन का इस्तेमाल करें या सहायता से संपर्क करें।" #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "इस चैनल में फ़ाइलें अटैच करने के लिए आपको \"{attachFilesPermissionLabel}\" अनुमति चाहिए" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "इस चैनल में लिंक एम्बेड करने के लिए आपको \"{embedLinksPermissionLabel}\" अनुमति चाहिए" @@ -40432,11 +40461,6 @@ msgstr "यहां अन्य कम्युनिटी से इमो msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "यहां अन्य कम्युनिटी से स्टिकर इस्तेमाल करने के लिए आपको \"{permissionLabel}\" अनुमति चाहिए।" -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "इस चैनल में मैसेज भेजने के लिए आपको \"{sendMessagesPermissionLabel}\" अनुमति चाहिए" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "आप बहुत तेज़ी से मैसेज भेज र msgid "You're streaming!" msgstr "आप स्ट्रीम कर रहे हैं!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "इस कम्युनिटी में आपका टाइमआउट चल रहा है" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "आपका टाइमआउट चल रहा है। टाइमआउट खत्म होने तक मैसेजिंग, रिएक्शन और वॉइस रोक दिए गए हैं।" diff --git a/fluxer_app/src/features/i18n/locales/hr/messages.po b/fluxer_app/src/features/i18n/locales/hr/messages.po index f49cf2b6d..1fc9a2460 100644 --- a/fluxer_app/src/features/i18n/locales/hr/messages.po +++ b/fluxer_app/src/features/i18n/locales/hr/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "... uključite zbijeni način rada. Super!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(uređeno)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# zajednica privremeno nije dostupna zbog kvara na msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# veza} few {# veze} other {# veza}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# datoteka} few {# datoteke} other {# datoteka}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# poklon} few {# poklona} other {# poklona}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# slika} few {# slike} other {# slika}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# stavka} few {# stavke} other {# stavki}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# sekunda} few {# sekunde} other {# sekundi}}" msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, one {Dostupan je # prijedlog} few {Dostupna su # prijedloga} other {Dostupno je # prijedloga}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# videozapis} few {# videozapisa} other {# videozapisa}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {Ova pozivnica istječe za # sat.} few {Ova pozivnic msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {Vaša poveznica za pozivnicu istječe za # sat.} few {Vaša poveznica za pozivnicu istječe za # sata.} other {Vaša poveznica za pozivnicu istječe za # sati.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# slika} few {# slike} other {# slika}}, {videoCount, plural, one {# videozapis} few {# videozapisa} other {# videozapisa}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@spominjanje" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/> je dodao/la <1/> u grupu." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "Dodajte bota zajednici s traženim dopuštenjima" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "Dodaj komentar (neobavezno)" @@ -6687,7 +6714,7 @@ msgstr "Ovdje nije moguće učitati datoteke" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "Postavke kategorije" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "Oprez" @@ -7372,8 +7399,8 @@ msgstr "kanal" msgid "Channel" msgstr "Kanal" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "Kanal {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "Naredbe" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "Komentari su onemogućeni jer je na jednom ili više odabranih kanala uključen usporeni način rada. Komentar bi odmah nakon prosljeđivanja bio blokiran usporenim načinom rada." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "Komentari su onemogućeni jer je u kanalu {forwardChannelDisplayName} uključen usporeni način rada. Komentar bi odmah nakon prosljeđivanja bio blokiran usporenim načinom rada." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "Komentari su nedostupni dok je uključen usporeni način rada." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "Pogreška pri prikazu sadržaja" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "Pogreška pri renderiranju LaTeX-a: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "Proslijedi medij" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "Proslijedi poruku" @@ -18216,7 +18243,7 @@ msgstr "Uvoz nedostupan" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "Važno" @@ -21355,7 +21382,7 @@ msgstr "Postavke prikaza poruka dostupne su samo na računalu." msgid "Message editing" msgstr "Uređivanje poruka" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "Poruka proslijeđena" @@ -21404,7 +21431,7 @@ msgstr "Gumbi za unos poruke" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "Poruka je predugačka" @@ -23059,7 +23086,7 @@ msgstr "Nema promjena za spremanje" msgid "No channels available" msgstr "Nema dostupnih kanala" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "Nema pronađenih kanala" @@ -23670,7 +23697,7 @@ msgstr "Nije točno ili netočno" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "Otvori emoji u pregledniku" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "Otvori birač emojija" @@ -29360,6 +29387,7 @@ msgstr "Pregled pri pomicanju" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "Pregled pri pomicanju" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "Pretražite po korisničkom imenu ili ID-u" msgid "Search channels" msgstr "Pretražite kanale" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "Pretražite kanale ili izravne poruke" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "Pošalji" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "Pošalji ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "Slanje SMS-a na ovaj broj telefona preskupo je za {PRODUCT_NAME}, stoga msgid "Sending malware or dangerous links" msgstr "Slanje zlonamjernog softvera ili opasnih poveznica" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "Slanje poruka onemogućeno je u ovoj zajednici" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "Tipkovnički prečaci pauziraju se tijekom snimanja." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "Skratite poruku i pokušajte ponovno." @@ -31780,8 +31804,8 @@ msgstr "Sporo učitavanje profila" msgid "Slowmode" msgstr "Usporeni način rada" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "Usporeni način rada · čekajte {remaining}" @@ -34920,6 +34944,11 @@ msgstr "Ovaj član više nije u zajednici. Osvježite i pokušajte ponovno." msgid "This member isn't connected to voice anymore." msgstr "Ovaj član više nije povezan s glasovnim kanalom." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "Ovu poruku možete proslijediti samo u kanale s ograničenim pristupom prema dobi" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "Vremenske oznake" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "Savjet" @@ -36521,7 +36550,7 @@ msgstr "nepoznat entitet" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "Nepoznata pogreška" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "Čekanje pristupnog ključa…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "Čeka se istek usporenog načina rada u kanalu {forwardChannelDisplayName}." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "Čeka se istek usporenog načina rada u jednom ili više odabranih kanala." @@ -39077,7 +39106,7 @@ msgstr "Buđenje" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "Upozorenje" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "Za promjenu e-pošte ovdje morate imati pristup svojoj trenutačnoj adresi e-pošte. Upotrijebite provjeru telefonom ako je dostupna ili se obratite podršci." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "Potrebno vam je dopuštenje \"{attachFilesPermissionLabel}\" za prilaganje datoteka u ovom kanalu" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "Potrebno vam je dopuštenje \"{embedLinksPermissionLabel}\" za ugrađivanje poveznica u ovom kanalu" @@ -40432,11 +40461,6 @@ msgstr "Potrebno vam je dopuštenje \"{permissionLabel}\" da biste ovdje koristi msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "Potrebno vam je dopuštenje \"{permissionLabel}\" da biste ovdje koristili naljepnice iz drugih zajednica." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "Potrebno vam je dopuštenje \"{sendMessagesPermissionLabel}\" za slanje poruka u ovom kanalu" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "Prebrzo šaljete poruke" msgid "You're streaming!" msgstr "Prenosite uživo!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "Imate vremensko ograničenje u ovoj zajednici" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "Imate vremensko ograničenje. Slanje poruka, reagiranje i pridruživanje glasovnim kanalima pauzirani su dok vremensko ograničenje ne istekne." diff --git a/fluxer_app/src/features/i18n/locales/hu/messages.po b/fluxer_app/src/features/i18n/locales/hu/messages.po index 788d0ae6a..82adc8948 100644 --- a/fluxer_app/src/features/i18n/locales/hu/messages.po +++ b/fluxer_app/src/features/i18n/locales/hu/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "... bekapcsold a sűrű módot. Szuper!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(szerkesztve)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# közösség átmenetileg nem elérhető egy „fl msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# kapcsolat} other {# kapcsolat}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# fájl} other {# fájl}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# ajándék} other {# ajándék}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# kép} other {# kép}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# elem} other {# elem}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# másodperc} other {# másodperc}}" msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, one {# javaslat érhető el} other {# javaslat érhető el}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# videó} other {# videó}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {Ez a meghívó # óra múlva jár le.} other {Ez a msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {A meghívólinked # óra múlva jár le.} other {A meghívólinked # óra múlva jár le.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# kép} other {# kép}}, {videoCount, plural, one {# videó} other {# videó}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@említés" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/> hozzáadta <1/> felhasználót a csoporthoz." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "Bot hozzáadása egy közösséghez a kért jogosultságokkal" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "Megjegyzés hozzáadása (opcionális)" @@ -6687,7 +6714,7 @@ msgstr "Ide nem tölthetsz fel fájlokat" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "Kategóriabeállítások" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "Figyelem" @@ -7372,8 +7399,8 @@ msgstr "csatorna" msgid "Channel" msgstr "Csatorna" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "Csatorna {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "Parancsok" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "Nem adhatsz hozzá megjegyzést, mert legalább egy kiválasztott csatornában be van kapcsolva a lassú mód. A lassú mód közvetlenül a továbbítás után megakadályozná a megjegyzés elküldését." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "Nem adhatsz hozzá megjegyzést, mert a(z) {forwardChannelDisplayName} csatornában be van kapcsolva a lassú mód. A lassú mód közvetlenül a továbbítás után megakadályozná a megjegyzés elküldését." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "Bekapcsolt lassú mód mellett nem adhatsz hozzá megjegyzést." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "Hiba a tartalom megjelenítésekor" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "Hiba a LaTeX megjelenítésekor: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "Média továbbítása" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "Üzenet továbbítása" @@ -18216,7 +18243,7 @@ msgstr "Az importálás nem érhető el" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "Fontos" @@ -21355,7 +21382,7 @@ msgstr "Az üzenetmegjelenítési beállítások csak asztali gépen érhetők e msgid "Message editing" msgstr "Üzenet szerkesztése" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "Üzenet továbbítva" @@ -21404,7 +21431,7 @@ msgstr "Üzenetbeviteli gombok" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "Az üzenet túl hosszú" @@ -23059,7 +23086,7 @@ msgstr "Nincs menthető változás" msgid "No channels available" msgstr "Nincsenek elérhető csatornák" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "Nem található csatorna" @@ -23670,7 +23697,7 @@ msgstr "Nem igaz vagy hamis" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "Emoji megnyitása böngészőben" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "Emojiválasztó megnyitása" @@ -29360,6 +29387,7 @@ msgstr "Előnézet tekerés közben" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "Előnézet tekerés közben" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "Keresés felhasználónév vagy azonosító alapján" msgid "Search channels" msgstr "Csatornák keresése" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "Csatornák vagy közvetlen üzenetek keresése" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "Küldés" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "Küldés ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "Túl drága lenne a(z) {PRODUCT_NAME} számára, ha SMS-t küldenénk er msgid "Sending malware or dangerous links" msgstr "Kártevő vagy veszélyes linkek küldése" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "Az üzenetküldés le van tiltva ebben a közösségben" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "A billentyűparancsok a rögzítés idejére szünetelnek." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "Rövidítsd le az üzenetet, és próbáld újra." @@ -31780,8 +31804,8 @@ msgstr "Lassú profilbetöltés" msgid "Slowmode" msgstr "Lassú mód" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "Lassú mód · hátralévő várakozás: {remaining}" @@ -34920,6 +34944,11 @@ msgstr "Ez a tag már nincs a közösségben. Frissítsd, és próbáld újra." msgid "This member isn't connected to voice anymore." msgstr "Ez a tag már nincs hanghívásban." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "Ez az üzenet csak korlátozottan megtekinthető csatornákra továbbítható" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "Időbélyegek" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "Tipp" @@ -36521,7 +36550,7 @@ msgstr "ismeretlen entitás" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "Ismeretlen hiba" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "Várakozás a jelszókulcsra…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "Várakozás, amíg a lassú mód lejár a következő csatornán: {forwardChannelDisplayName}." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "Várakozás, amíg a lassú mód lejár egy vagy több kiválasztott csatornán." @@ -39077,7 +39106,7 @@ msgstr "Felébresztés" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "Figyelem" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "Az e-mail-címed megváltoztatásához hozzá kell férned a jelenlegi címedhez. Használj telefonos ellenőrzést, ha elérhető, vagy vedd fel a kapcsolatot az ügyfélszolgálattal." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "Fájlok csatolásához a(z) „{attachFilesPermissionLabel}” jogosultságra van szükséged ebben a csatornában" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "Linkek beágyazásához a(z) „{embedLinksPermissionLabel}” jogosultságra van szükséged ebben a csatornában" @@ -40432,11 +40461,6 @@ msgstr "Más közösségek emojijainak itteni használatához a(z) „{permissio msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "Más közösségek matricáinak itteni használatához a(z) „{permissionLabel}” jogosultságra van szükséged." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "Üzenetek küldéséhez a(z) „{sendMessagesPermissionLabel}” jogosultságra van szükséged ebben a csatornában" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "Túl gyorsan küldesz üzeneteket" msgid "You're streaming!" msgstr "Élőben közvetítesz!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "Ideiglenes korlátozás alatt állsz ebben a közösségben" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "Ideiglenes korlátozás alatt állsz. A lejártáig nem küldhetsz üzeneteket, nem reagálhatsz és nem csatlakozhatsz hangbeszélgetéshez." diff --git a/fluxer_app/src/features/i18n/locales/id/messages.po b/fluxer_app/src/features/i18n/locales/id/messages.po index 1b4f154fe..898262ca3 100644 --- a/fluxer_app/src/features/i18n/locales/id/messages.po +++ b/fluxer_app/src/features/i18n/locales/id/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "... nyalakan mode rapat. Mantap!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(diedit)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# komunitas sementara tidak tersedia karena kerusak msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# koneksi} other {# koneksi}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# file} other {# file}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# hadiah} other {# hadiah}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# gambar} other {# gambar}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# item} other {# item}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# detik} other {# detik}}" msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, other {# saran tersedia}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# video} other {# video}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {Undangan ini akan kedaluwarsa dalam # jam.} other { msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, other {Tautan undanganmu akan kedaluwarsa dalam # jam.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# gambar} other {# gambar}}, {videoCount, plural, one {# video} other {# video}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@mention" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/> menambahkan <1/> ke grup." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "Tambahkan bot ke komunitas dengan izin yang diminta" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "Tambah komentar (opsional)" @@ -6687,7 +6714,7 @@ msgstr "Tidak bisa mengunggah file di sini" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "Pengaturan kategori" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "Perhatian" @@ -7372,8 +7399,8 @@ msgstr "saluran" msgid "Channel" msgstr "Saluran" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "Saluran {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "Perintah" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "Komentar dinonaktifkan karena satu atau beberapa saluran yang dipilih mengaktifkan mode lambat. Komentar akan langsung diblokir mode lambat setelah pesan diteruskan." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "Komentar dinonaktifkan karena mode lambat aktif di {forwardChannelDisplayName}. Komentar akan langsung diblokir mode lambat setelah pesan diteruskan." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "Komentar tidak tersedia saat mode lambat aktif." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "Gagal merender konten" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "Gagal merender LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "Teruskan media" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "Teruskan pesan" @@ -18216,7 +18243,7 @@ msgstr "Impor tidak tersedia" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "Penting" @@ -21355,7 +21382,7 @@ msgstr "Pengaturan tampilan pesan hanya tersedia di desktop." msgid "Message editing" msgstr "Edit pesan" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "Pesan diteruskan" @@ -21404,7 +21431,7 @@ msgstr "Tombol input pesan" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "Pesan terlalu panjang" @@ -23059,7 +23086,7 @@ msgstr "Tidak ada perubahan untuk disimpan" msgid "No channels available" msgstr "Tidak ada saluran yang tersedia" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "Tidak ada saluran yang ditemukan" @@ -23670,7 +23697,7 @@ msgstr "Bukan benar atau salah" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "Buka emoji di browser" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "Buka pemilih emoji" @@ -29360,6 +29387,7 @@ msgstr "Pratinjau geser video" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "Pratinjau geser video" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "Cari berdasarkan nama pengguna atau ID" msgid "Search channels" msgstr "Cari saluran" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "Cari saluran atau DM" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "Kirim" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "Kirim ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "Mengirim SMS ke nomor telepon ini terlalu mahal untuk {PRODUCT_NAME}, ja msgid "Sending malware or dangerous links" msgstr "Mengirim malware atau tautan berbahaya" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "Pengiriman pesan dinonaktifkan di komunitas ini" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "Pintasan dijeda selama perekaman." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "Persingkat pesan dan coba lagi." @@ -31780,8 +31804,8 @@ msgstr "Muat profil lambat" msgid "Slowmode" msgstr "Mode lambat" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "Mode lambat · tunggu {remaining}" @@ -34920,6 +34944,11 @@ msgstr "Anggota ini tidak lagi berada di komunitas. Segarkan dan coba lagi." msgid "This member isn't connected to voice anymore." msgstr "Anggota ini sudah tidak terhubung ke suara." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "Pesan ini hanya dapat diteruskan ke channel yang dibatasi usia" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "Stempel waktu" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "Tips" @@ -36521,7 +36550,7 @@ msgstr "entitas tidak dikenal" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "Kesalahan tidak dikenal" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "Menunggu passkey…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "Menunggu mode lambat di {forwardChannelDisplayName} berakhir." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "Menunggu mode lambat di satu atau beberapa saluran yang dipilih berakhir." @@ -39077,7 +39106,7 @@ msgstr "Bangunkan" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "Peringatan" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "Kamu perlu akses ke email saat ini untuk mengubahnya dari sini. Gunakan verifikasi telepon jika tersedia atau hubungi dukungan." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "Kamu memerlukan izin \"{attachFilesPermissionLabel}\" untuk melampirkan file di saluran ini" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "Kamu memerlukan izin \"{embedLinksPermissionLabel}\" untuk menyematkan tautan di saluran ini" @@ -40432,11 +40461,6 @@ msgstr "Kamu memerlukan izin \"{permissionLabel}\" untuk menggunakan emoji dari msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "Kamu memerlukan izin \"{permissionLabel}\" untuk menggunakan stiker dari komunitas lain di sini." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "Kamu memerlukan izin \"{sendMessagesPermissionLabel}\" untuk mengirim pesan di saluran ini" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "Kamu mengirim pesan terlalu cepat" msgid "You're streaming!" msgstr "Kamu sedang streaming!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "Kamu sedang diberi batas waktu di komunitas ini" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "Kamu sedang diberi batas waktu. Pesan, reaksi, dan suara dijeda sampai batas waktunya berakhir." diff --git a/fluxer_app/src/features/i18n/locales/it/messages.po b/fluxer_app/src/features/i18n/locales/it/messages.po index 152b2d2d7..8e4f46410 100644 --- a/fluxer_app/src/features/i18n/locales/it/messages.po +++ b/fluxer_app/src/features/i18n/locales/it/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "... attiva la modalità compatta. Ottimo!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(modificato)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# community è temporaneamente non disponibile a ca msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# connessione} other {# connessioni}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# file} other {# file}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# regalo} other {# regali}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# immagine} other {# immagini}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# elemento} other {# elementi}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# secondo} other {# secondi}}" msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, one {# suggerimento disponibile} many {# suggerimenti disponibili} other {# suggerimenti disponibili}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# video} other {# video}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {Questo invito scade tra # ora.} other {Questo invit msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {Il tuo link d'invito scade tra # ora.} many {Il tuo link d'invito scade tra # ore.} other {Il tuo link d'invito scade tra # ore.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# immagine} other {# immagini}}, {videoCount, plural, one {# video} other {# video}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@menzione" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/> ha aggiunto <1/> al gruppo." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "Aggiungi un bot a una community con le autorizzazioni richieste" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "Aggiungi un commento (facoltativo)" @@ -6687,7 +6714,7 @@ msgstr "Impossibile caricare file qui" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "Impostazioni categoria" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "Attenzione" @@ -7372,8 +7399,8 @@ msgstr "canale" msgid "Channel" msgstr "Canale" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "Canale {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "Comandi" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "I commenti sono disabilitati perché uno o più canali selezionati hanno la modalità lenta attiva. Il commento verrebbe bloccato dalla modalità lenta subito dopo l'inoltro." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "I commenti sono disabilitati perché la modalità lenta è attiva in {forwardChannelDisplayName}. Il commento verrebbe bloccato dalla modalità lenta subito dopo l'inoltro." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "I commenti non sono disponibili con la modalità lenta attiva." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "Errore durante il rendering dei contenuti" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "Errore durante il rendering di LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "Inoltra contenuto multimediale" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "Inoltra messaggio" @@ -18216,7 +18243,7 @@ msgstr "Importazione non disponibile" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "Importante" @@ -21355,7 +21382,7 @@ msgstr "Le impostazioni di visualizzazione dei messaggi sono disponibili solo su msgid "Message editing" msgstr "Modifica messaggi" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "Messaggio inoltrato" @@ -21404,7 +21431,7 @@ msgstr "Pulsanti di input del messaggio" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "Il messaggio è troppo lungo" @@ -23059,7 +23086,7 @@ msgstr "Nessuna modifica da salvare" msgid "No channels available" msgstr "Nessun canale disponibile" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "Nessun canale trovato" @@ -23670,7 +23697,7 @@ msgstr "Non è né vero né falso" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "Apri emoji nel browser" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "Apri selettore emoji" @@ -29360,6 +29387,7 @@ msgstr "Anteprima durante lo scorrimento del video" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "Anteprima durante lo scorrimento del video" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "Cerca per nome utente o ID" msgid "Search channels" msgstr "Cerca canali" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "Cerca canali o DM" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "Invia" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "Invia ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "Inviare un SMS a questo numero di telefono è troppo costoso per {PRODUC msgid "Sending malware or dangerous links" msgstr "Invio di malware o link pericolosi" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "L'invio di messaggi è disabilitato in questa community" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "Le scorciatoie sono sospese durante la registrazione." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "Accorcia il messaggio e riprova." @@ -31780,8 +31804,8 @@ msgstr "Caricamento lento del profilo" msgid "Slowmode" msgstr "Modalità lenta" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "Modalità lenta · attendi {remaining}" @@ -34920,6 +34944,11 @@ msgstr "Questo membro non fa più parte della community. Aggiorna e riprova." msgid "This member isn't connected to voice anymore." msgstr "Questo membro non è più connesso alla chat vocale." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "Questo messaggio può essere inoltrato solo a canali con restrizioni d'età" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "Timestamp" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "Suggerimento" @@ -36521,7 +36550,7 @@ msgstr "entità sconosciuta" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "Errore sconosciuto" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "In attesa della passkey…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "In attesa che la modalità lenta in {forwardChannelDisplayName} scada." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "In attesa che la modalità lenta scada in uno o più canali selezionati." @@ -39077,7 +39106,7 @@ msgstr "Riattivazione" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "Avviso" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "Per modificare l'email da qui, devi avere accesso a quella attuale. Usa la verifica telefonica se disponibile o contatta il supporto." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "Per allegare file in questo canale, devi avere il permesso \"{attachFilesPermissionLabel}\"" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "Per incorporare link in questo canale, ti serve l'autorizzazione \"{embedLinksPermissionLabel}\"" @@ -40432,11 +40461,6 @@ msgstr "Per usare le emoji di altre community qui, ti serve l'autorizzazione \"{ msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "Per usare gli sticker di altre community qui, ti serve il permesso \"{permissionLabel}\"." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "Per inviare messaggi in questo canale, devi avere l'autorizzazione \"{sendMessagesPermissionLabel}\"" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "Stai inviando messaggi troppo velocemente" msgid "You're streaming!" msgstr "Stai trasmettendo in streaming!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "Sei in timeout in questa community" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "Sei in timeout. Messaggi, reazioni e chiamate vocali sono in pausa fino alla scadenza del timeout." diff --git a/fluxer_app/src/features/i18n/locales/ja/messages.po b/fluxer_app/src/features/i18n/locales/ja/messages.po index cac07a781..d463020fa 100644 --- a/fluxer_app/src/features/i18n/locales/ja/messages.po +++ b/fluxer_app/src/features/i18n/locales/ja/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "…コンパクト表示をオンに。いいね!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(編集済み)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {#件のコミュニティがフラックスキャ msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {#件の接続} other {#件の接続}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# ファイル} other {# ファイル}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {#件のギフト} other {#件のギフト}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# 画像} other {# 件の画像}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {#件} other {#件}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {#秒} other {#秒}}" msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, other {#件の候補があります}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# 個の動画} other {# 個の動画}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {この招待は#時間後に期限切れになり msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {招待リンクは#時間後に期限切れになります。} other {招待リンクは#時間後に期限切れになります。}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# 画像} other {# 画像}}、{videoCount, plural, one {# 動画} other {# 動画}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "メンション" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/>が<1/>をグループに追加しました。" @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "リクエストされた権限でボットをコミュニティに追加" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "コメントを追加(任意)" @@ -6687,7 +6714,7 @@ msgstr "ここにファイルをアップロードできません" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "カテゴリ設定" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "注意" @@ -7372,8 +7399,8 @@ msgstr "チャンネル" msgid "Channel" msgstr "チャンネル" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "チャンネル {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "コマンド" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "選択したチャンネルのいずれかでスローモードがオンになっているため、コメントは無効です。転送後すぐにスローモードによってコメントがブロックされます。" #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "{forwardChannelDisplayName}ではスローモードがオンになっているため、コメントは無効です。転送直後にスローモードによってコメントがブロックされます。" #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "スローモード中はコメントできません。" @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "コンテンツの表示中にエラーが発生しました" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "LaTeXのレンダリングエラー: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "メディアを転送" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "メッセージを転送" @@ -18216,7 +18243,7 @@ msgstr "インポートできません" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "重要" @@ -21355,7 +21382,7 @@ msgstr "メッセージ表示設定はデスクトップ版でのみ利用でき msgid "Message editing" msgstr "メッセージの編集" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "メッセージを転送しました" @@ -21404,7 +21431,7 @@ msgstr "メッセージ入力ボタン" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "メッセージが長すぎます" @@ -23059,7 +23086,7 @@ msgstr "保存する変更はありません" msgid "No channels available" msgstr "利用できるチャンネルがありません" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "チャンネルが見つかりませんでした" @@ -23670,7 +23697,7 @@ msgstr "真偽値ではありません" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "ブラウザで絵文字を開く" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "絵文字ピッカーを開く" @@ -29360,6 +29387,7 @@ msgstr "スクラブプレビュー" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "スクラブプレビュー" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "ユーザー名またはIDで検索" msgid "Search channels" msgstr "チャンネルを検索" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "チャンネルまたはDMを検索" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "送信" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "送信 ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "{PRODUCT_NAME}からこの電話番号にSMSを送信すると費用が msgid "Sending malware or dangerous links" msgstr "マルウェアや危険なリンクの送信" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "このコミュニティではメッセージを送信できません" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "記録中はショートカットが一時停止されます。" #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "メッセージを短くして、もう一度お試しください。" @@ -31780,8 +31804,8 @@ msgstr "プロフィールの読み込みを遅くする" msgid "Slowmode" msgstr "スローモード" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "スローモード · 残り{remaining}" @@ -34920,6 +34944,11 @@ msgstr "このメンバーはコミュニティにいません。画面を更新 msgid "This member isn't connected to voice anymore." msgstr "このメンバーはすでにボイスチャンネルに接続していません。" +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "このメッセージは年齢制限のあるチャンネルにのみ転送できます" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "タイムスタンプ" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "ヒント" @@ -36521,7 +36550,7 @@ msgstr "不明なエンティティ" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "不明なエラー" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "パスキーを待機中…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "{forwardChannelDisplayName}のスローモードが解除されるまで待っています。" #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "選択したチャンネルのいずれかでスローモードが解除されるまで待っています。" @@ -39077,7 +39106,7 @@ msgstr "スリープ解除" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "警告" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "メールアドレスを変更するには、現在のメールアドレスにアクセスできる必要があります。電話番号認証を利用するか、サポートにお問い合わせください。" #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "このチャンネルでファイルを添付するには、「{attachFilesPermissionLabel}」の権限が必要です" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "このチャンネルにリンクを埋め込むには、「{embedLinksPermissionLabel}」の権限が必要です" @@ -40432,11 +40461,6 @@ msgstr "他のコミュニティの絵文字をここで使用するには、「 msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "他のコミュニティのスタンプをここで使用するには、「{permissionLabel}」の権限が必要です。" -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "このチャンネルでメッセージを送信するには、「{sendMessagesPermissionLabel}」の権限が必要です" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "メッセージの送信ペースが速すぎます" msgid "You're streaming!" msgstr "配信中!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "このコミュニティではタイムアウト中です" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "タイムアウト中です。タイムアウト期間が終了するまで、メッセージ送信、リアクション、音声が一時停止されます。" diff --git a/fluxer_app/src/features/i18n/locales/ko/messages.po b/fluxer_app/src/features/i18n/locales/ko/messages.po index 047752027..a0c4dcd68 100644 --- a/fluxer_app/src/features/i18n/locales/ko/messages.po +++ b/fluxer_app/src/features/i18n/locales/ko/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "... 좁게 모드를 켜 보세요. 좋아요!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(수정됨)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {#개 커뮤니티가 플럭스 캐패시터 오작 msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {연결 #개} other {연결 #개}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {#개의 파일} other {#개의 파일}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {#개 선물} other {#개 선물}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {#개의 이미지} other {#개의 이미지}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {#개 항목} other {#개 항목}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {#초} other {#초}}" msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, other {추천 검색어 #개 사용 가능}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {#개의 동영상} other {#개의 동영상}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {이 초대 링크는 #시간 후에 만료됩니다 msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {초대 링크는 #시간 후에 만료됩니다.} other {초대 링크는 #시간 후에 만료됩니다.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {#개의 이미지} other {#개의 이미지}}, {videoCount, plural, one {#개의 동영상} other {#개의 동영상}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@mention" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/>님이 <1/>님을 그룹에 추가했습니다." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "요청된 권한으로 봇을 커뮤니티에 추가" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "코멘트 추가 (선택 사항)" @@ -6687,7 +6714,7 @@ msgstr "여기에 파일을 올릴 수 없습니다" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "카테고리 설정" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "주의" @@ -7372,8 +7399,8 @@ msgstr "채널" msgid "Channel" msgstr "채널" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "채널 {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "명령어" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "선택한 채널 중 하나 이상에 슬로우 모드가 켜져 있어 댓글을 사용할 수 없습니다. 전달 직후 슬로우 모드에 걸려 댓글이 전송되지 않습니다." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "{forwardChannelDisplayName} 채널에 슬로우 모드가 켜져 있어 댓글을 사용할 수 없습니다. 전달 직후 슬로우 모드에 걸려 댓글이 전송되지 않습니다." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "슬로우 모드 중에는 댓글을 사용할 수 없습니다." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "콘텐츠 렌더링 오류" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "LaTeX 렌더링 오류: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "미디어 전달" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "메시지 전달" @@ -18216,7 +18243,7 @@ msgstr "가져올 수 없음" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "중요" @@ -21355,7 +21382,7 @@ msgstr "메시지 표시 설정은 데스크톱에서만 사용할 수 있습니 msgid "Message editing" msgstr "메시지 수정" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "메시지 전달됨" @@ -21404,7 +21431,7 @@ msgstr "메시지 입력 버튼" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "메시지가 너무 깁니다" @@ -23059,7 +23086,7 @@ msgstr "저장할 변경사항 없음" msgid "No channels available" msgstr "채널을 찾을 수 없습니다" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "채널을 찾을 수 없습니다" @@ -23670,7 +23697,7 @@ msgstr "참 또는 거짓이 아닙니다" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "브라우저에서 이모티콘 열기" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "이모티콘 선택기 열기" @@ -29360,6 +29387,7 @@ msgstr "스크러빙 미리보기" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "스크러빙 미리보기" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "사용자 이름 또는 ID로 검색" msgid "Search channels" msgstr "채널 검색" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "채널 또는 DM 검색" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "보내기" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "보내기 ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "{PRODUCT_NAME}에서 이 전화번호로 SMS를 보내는 비용이 너 msgid "Sending malware or dangerous links" msgstr "악성 코드 또는 위험한 링크 전송" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "이 커뮤니티에서는 메시지 전송이 비활성화되어 있습니다" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "기록하는 동안에는 단축키가 일시 중지됩니다." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "메시지를 줄여서 다시 시도해 주세요." @@ -31780,8 +31804,8 @@ msgstr "프로필 로드 속도 저하" msgid "Slowmode" msgstr "슬로우 모드" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "슬로우 모드 · {remaining} 대기" @@ -34920,6 +34944,11 @@ msgstr "이 멤버는 더 이상 커뮤니티에 없습니다. 새로고침 후 msgid "This member isn't connected to voice anymore." msgstr "이 멤버는 더 이상 음성 채팅에 연결되어 있지 않습니다." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "이 메시지는 연령 제한 채널로만 전달할 수 있습니다." + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "타임스탬프" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "팁" @@ -36521,7 +36550,7 @@ msgstr "알 수 없는 항목" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "알 수 없는 오류" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "패스키를 기다리는 중…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "{forwardChannelDisplayName} 채널의 슬로우 모드가 만료되기를 기다리는 중입니다." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "선택한 채널 중 일부 채널의 슬로우 모드 만료를 기다리는 중입니다." @@ -39077,7 +39106,7 @@ msgstr "절전 해제" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "경고" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "이메일을 변경하려면 현재 이메일에 액세스해야 합니다. 가능한 경우 전화 인증을 사용하거나 고객지원팀에 문의하세요." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "이 채널에 파일을 첨부하려면 \"{attachFilesPermissionLabel}\" 권한이 필요합니다" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "이 채널에 링크를 임베드하려면 \"{embedLinksPermissionLabel}\" 권한이 필요합니다" @@ -40432,11 +40461,6 @@ msgstr "여기에서 다른 커뮤니티의 이모티콘을 사용하려면 \"{p msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "여기에서 다른 커뮤니티의 스티커를 사용하려면 \"{permissionLabel}\" 권한이 필요합니다." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "이 채널에서 메시지를 보내려면 \"{sendMessagesPermissionLabel}\" 권한이 필요합니다" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "메시지를 너무 빨리 보내고 있습니다" msgid "You're streaming!" msgstr "스트리밍 중입니다!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "이 커뮤니티에서 타임아웃 상태입니다" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "타임아웃 상태입니다. 타임아웃이 끝날 때까지 메시지, 반응, 음성 기능이 일시 중지됩니다." diff --git a/fluxer_app/src/features/i18n/locales/lt/messages.po b/fluxer_app/src/features/i18n/locales/lt/messages.po index fa05f60a8..9d5acda7e 100644 --- a/fluxer_app/src/features/i18n/locales/lt/messages.po +++ b/fluxer_app/src/features/i18n/locales/lt/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "... įjungsite tankųjį režimą. Puiku!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(redaguota)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# bendruomenė laikinai nepasiekiama dėl srauto ko msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# ryšys} few {# ryšiai} other {# ryšių}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# failas} few {# failai} many {# failo} other {# failų}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# dovana} few {# dovanos} other {# dovanų}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# vaizdas} few {# vaizdai} many {# vaizdo} other {# vaizdų}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# elementas} few {# elementai} other {# elementų}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# sekundė} few {# sekundės} other {# sekundžių} msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, one {Galimas # pasiūlymas} few {Galimi # pasiūlymai} many {Galima # pasiūlymo} other {Galima # pasiūlymų}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# vaizdo įrašas} few {# vaizdo įrašai} many {# vaizdo įrašo} other {# vaizdo įrašų}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {Šis kvietimas baigs galioti po # valandos.} other msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {Jūsų kvietimo nuoroda baigs galioti po # valandos.} few {Jūsų kvietimo nuoroda baigs galioti po # valandų.} other {Jūsų kvietimo nuoroda baigs galioti po # valandų.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# vaizdas} few {# vaizdai} many {# vaizdo} other {# vaizdų}}, {videoCount, plural, one {# vaizdo įrašas} few {# vaizdo įrašai} many {# vaizdo įrašo} other {# vaizdo įrašų}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "paminėjimas" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/> pridėjo <1/> į grupę." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "Pridėti botą į bendruomenę su prašomais leidimais" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "Pridėti komentarą (pasirinktinai)" @@ -6687,7 +6714,7 @@ msgstr "Čia negalima įkelti failų" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "Kategorijos nustatymai" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "Atsargiai" @@ -7372,8 +7399,8 @@ msgstr "kanalas" msgid "Channel" msgstr "Kanalas" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "Kanalas „{id}“" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "Komandos" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "Komentarai išjungti, nes viename ar daugiau pasirinktų kanalų įjungtas lėtasis režimas. Komentaras būtų užblokuotas lėtojo režimo iškart po persiuntimo." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "Komentarai išjungti, nes kanale „{forwardChannelDisplayName}“ įjungtas lėtasis režimas. Komentaras būtų užblokuotas lėtojo režimo iškart po persiuntimo." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "Komentarai nepasiekiami, kai įjungtas lėtasis režimas." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "Klaida atvaizduojant turinį" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "Klaida atvaizduojant LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "Persiųsti mediją" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "Persiųsti žinutę" @@ -18216,7 +18243,7 @@ msgstr "Importavimas nepasiekiamas" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "Svarbu" @@ -21355,7 +21382,7 @@ msgstr "Žinučių rodymo nustatymai pasiekiami tik darbalaukio programoje." msgid "Message editing" msgstr "Redaguoti žinutę" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "Žinutė persiųsta" @@ -21404,7 +21431,7 @@ msgstr "Žinutės įvesties mygtukai" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "Žinutė per ilga" @@ -23059,7 +23086,7 @@ msgstr "Nėra išsaugotinų pakeitimų" msgid "No channels available" msgstr "Nėra pasiekiamų kanalų" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "Kanalų nerasta" @@ -23670,7 +23697,7 @@ msgstr "Reikšmė nėra tiesa arba netiesa" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "Atidaryti jaustuką naršyklėje" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "Atidaryti jaustukų parinkiklį" @@ -29360,6 +29387,7 @@ msgstr "Prasukimo peržiūra" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "Prasukimo peržiūra" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "Ieškoti pagal naudotojo vardą arba ID" msgid "Search channels" msgstr "Ieškoti kanalų" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "Ieškoti kanalų ar tiesioginių žinučių" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "Siųsti" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "Siųsti ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "SMS siuntimas šiuo telefono numeriu „{PRODUCT_NAME}“ yra per brangu msgid "Sending malware or dangerous links" msgstr "Kenksmingų programų ar pavojingų nuorodų siuntimas" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "Šioje bendruomenėje žinučių siuntimas išjungtas" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "Įrašant spartieji klavišai laikinai neveikia." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "Sutrumpinkite žinutę ir bandykite dar kartą." @@ -31780,8 +31804,8 @@ msgstr "Lėtas profilio įkėlimas" msgid "Slowmode" msgstr "Lėtasis režimas" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "Lėtasis režimas · palaukite {remaining}" @@ -34920,6 +34944,11 @@ msgstr "Šis narys nebėra bendruomenėje. Atnaujinkite ir bandykite dar kartą. msgid "This member isn't connected to voice anymore." msgstr "Šis narys nebėra prisijungęs prie balso pokalbio." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "Šią žinutę galima persiųsti tik į amžiaus apribojimų turinčius kanalus" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "Laiko žymos" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "Patarimas" @@ -36521,7 +36550,7 @@ msgstr "nežinomas subjektas" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "Nežinoma klaida" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "Laukiama prieigos rakto…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "Laukiama, kol pasibaigs lėtasis režimas kanale „{forwardChannelDisplayName}“." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "Laukiama, kol pasibaigs lėtasis režimas viename ar keliuose pasirinktuose kanaluose." @@ -39077,7 +39106,7 @@ msgstr "Pažadinti" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "Įspėjimas" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "Kad galėtumėte pakeisti el. pašto adresą, turite turėti prieigą prie dabartinio. Jei įmanoma, naudokite telefono patvirtinimą arba susisiekite su palaikymo komanda." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "Norėdami pridėti failus šiame kanale, turite turėti leidimą „{attachFilesPermissionLabel}“" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "Norėdami įterpti nuorodas šiame kanale, turite turėti leidimą „{embedLinksPermissionLabel}“" @@ -40432,11 +40461,6 @@ msgstr "Norėdami čia naudoti jaustukus iš kitų bendruomenių, turite turėti msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "Norėdami čia naudoti lipdukus iš kitų bendruomenių, turite turėti leidimą „{permissionLabel}“." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "Norėdami siųsti žinutes šiame kanale, turite turėti „{sendMessagesPermissionLabel}“ leidimą" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "Žinutes siunčiate per greitai" msgid "You're streaming!" msgstr "Jūs transliuojate!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "Šioje bendruomenėje jums taikomas laikinas apribojimas" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "Jums taikomas laikinas apribojimas. Žinučių siuntimas, reakcijos ir balso funkcijos pristabdytos, kol apribojimas baigsis." diff --git a/fluxer_app/src/features/i18n/locales/nl/messages.po b/fluxer_app/src/features/i18n/locales/nl/messages.po index 01074a41f..4e25de11d 100644 --- a/fluxer_app/src/features/i18n/locales/nl/messages.po +++ b/fluxer_app/src/features/i18n/locales/nl/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "... compacte modus inschakelen. Mooi!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(bewerkt)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# community is tijdelijk niet beschikbaar door een msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# verbinding} other {# verbindingen}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# bestand} other {# bestanden}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# cadeau} other {# cadeaus}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# afbeelding} other {# afbeeldingen}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# item} other {# items}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# seconde} other {# seconden}}" msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, one {# suggestie beschikbaar} other {# suggesties beschikbaar}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# video} other {# video's}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {Deze uitnodiging verloopt over # uur.} other {Deze msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {Je uitnodigingslink verloopt over # uur.} other {Je uitnodigingslink verloopt over # uur.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# afbeelding} other {# afbeeldingen}}, {videoCount, plural, one {# video} other {# video's}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@vermelding" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/> heeft <1/> toegevoegd aan de groep." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "Voeg een bot toe aan een community met de gevraagde machtigingen" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "Opmerking toevoegen (optioneel)" @@ -6687,7 +6714,7 @@ msgstr "Kan hier geen bestanden uploaden" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "Categorie-instellingen" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "Let op" @@ -7372,8 +7399,8 @@ msgstr "kanaal" msgid "Channel" msgstr "Kanaal" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "Kanaal {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "Opdrachten" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "Reacties zijn uitgeschakeld omdat slowmodus actief is in een of meer geselecteerde kanalen. De reactie zou direct na het doorsturen door slowmodus worden geblokkeerd." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "Reacties zijn uitgeschakeld omdat slowmodus actief is in {forwardChannelDisplayName}. De reactie zou direct na het doorsturen door slowmodus worden geblokkeerd." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "Reacties zijn niet beschikbaar als de slowmodus is ingeschakeld." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "Fout bij het weergeven van inhoud" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "Fout bij het weergeven van LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "Media doorsturen" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "Bericht doorsturen" @@ -18216,7 +18243,7 @@ msgstr "Importeren niet beschikbaar" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "Belangrijk" @@ -21355,7 +21382,7 @@ msgstr "Instellingen voor de weergave van berichten zijn alleen beschikbaar op d msgid "Message editing" msgstr "Bericht bewerken" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "Bericht doorgestuurd" @@ -21404,7 +21431,7 @@ msgstr "Knoppen voor berichtinvoer" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "Bericht is te lang" @@ -23059,7 +23086,7 @@ msgstr "Geen wijzigingen om op te slaan" msgid "No channels available" msgstr "Geen kanalen beschikbaar" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "Geen kanalen gevonden" @@ -23670,7 +23697,7 @@ msgstr "Niet waar of onwaar" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "Emoji in browser openen" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "Emoji-kiezer openen" @@ -29360,6 +29387,7 @@ msgstr "Voorbeeld bij spoelen" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "Voorbeeld bij spoelen" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "Zoeken op gebruikersnaam of ID" msgid "Search channels" msgstr "Kanalen zoeken" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "Kanalen of DM's zoeken" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "Verzenden" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "Verzenden ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "Het versturen van een sms naar dit telefoonnummer is te duur voor {PRODU msgid "Sending malware or dangerous links" msgstr "Malware of gevaarlijke links versturen" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "Berichten versturen is uitgeschakeld in deze community" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "Sneltoetsen worden tijdens het opnemen gepauzeerd." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "Verkort het bericht en probeer het opnieuw." @@ -31780,8 +31804,8 @@ msgstr "Langzaam profiel laden" msgid "Slowmode" msgstr "Slowmodus" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "Slowmodus · wacht {remaining}" @@ -34920,6 +34944,11 @@ msgstr "Dit lid is niet langer lid van de community. Vernieuw en probeer het opn msgid "This member isn't connected to voice anymore." msgstr "Dit lid is niet meer verbonden met een spraakkanaal." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "Dit bericht kan alleen worden doorgestuurd naar kanalen met leeftijdsbeperking" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "Tijdstempels" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "Tip" @@ -36521,7 +36550,7 @@ msgstr "onbekende entiteit" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "Onbekende fout" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "Wachten op passkey…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "Wachten tot de slowmodus in {forwardChannelDisplayName} is verlopen." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "Wachten tot de slowmodus in een of meer geselecteerde kanalen is verlopen." @@ -39077,7 +39106,7 @@ msgstr "Uit slaapstand halen" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "Waarschuwing" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "Je hebt toegang nodig tot je huidige e-mailadres om het hier te wijzigen. Gebruik telefoonverificatie indien beschikbaar of neem contact op met de ondersteuning." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "Je hebt de machtiging \"{attachFilesPermissionLabel}\" nodig om bestanden in dit kanaal bij te voegen" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "Je hebt de machtiging \"{embedLinksPermissionLabel}\" nodig om links in dit kanaal in te sluiten" @@ -40432,11 +40461,6 @@ msgstr "Je hebt de machtiging \"{permissionLabel}\" nodig om hier emoji uit ande msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "Je hebt de \"{permissionLabel}\"-machtiging nodig om hier stickers van andere communities te gebruiken." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "Je hebt de machtiging \"{sendMessagesPermissionLabel}\" nodig om berichten in dit kanaal te versturen" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "Je verstuurt te snel berichten" msgid "You're streaming!" msgstr "Je streamt!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "Je hebt een time-out in deze community" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "Je hebt een time-out. Berichten, reacties en spraak zijn gepauzeerd totdat de time-out verloopt." diff --git a/fluxer_app/src/features/i18n/locales/no/messages.po b/fluxer_app/src/features/i18n/locales/no/messages.po index f37bfe0c5..2caafb826 100644 --- a/fluxer_app/src/features/i18n/locales/no/messages.po +++ b/fluxer_app/src/features/i18n/locales/no/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "... slå på kompakt modus. Bra!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(redigert)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# fellesskap er midlertidig utilgjengelig på grunn msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# tilkobling} other {# tilkoblinger}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# fil} other {# filer}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# gave} other {# gaver}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# bilde} other {# bilder}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# element} other {# elementer}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# sekund} other {# sekunder}}" msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, one {# forslag tilgjengelig} other {# forslag tilgjengelige}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# video} other {# videoer}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {Denne invitasjonen utløper om # time.} other {Denn msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {Invitasjonslenken din utløper om # time.} other {Invitasjonslenken din utløper om # timer.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# bilde} other {# bilder}}, {videoCount, plural, one {# video} other {# videoer}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@omtale" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/> la til <1/> i gruppen." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "Legg til en bot i et fellesskap med forespurte tillatelser" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "Legg til en kommentar (valgfritt)" @@ -6687,7 +6714,7 @@ msgstr "Kan ikke laste opp filer her" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "Kategoriinnstillinger" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "Forsiktig" @@ -7372,8 +7399,8 @@ msgstr "kanal" msgid "Channel" msgstr "Kanal" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "Kanal {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "Kommandoer" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "Kommentarer er deaktivert fordi én eller flere valgte kanaler har sakte modus aktivert. Kommentaren ville blitt blokkert av sakte modus rett etter videresendingen." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "Kommentarer er deaktivert fordi sakte modus er på i {forwardChannelDisplayName}. Kommentaren ville blitt blokkert av sakte modus rett etter videresendingen." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "Kommentarer er utilgjengelige når sakte modus er på." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "Feil ved visning av innhold" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "Feil under gjengivelse av LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "Videresend medieinnhold" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "Videresend melding" @@ -18216,7 +18243,7 @@ msgstr "Import er ikke tilgjengelig" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "Viktig" @@ -21355,7 +21382,7 @@ msgstr "Innstillinger for meldingsvisning er bare tilgjengelige på datamaskin." msgid "Message editing" msgstr "Redigering av meldinger" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "Melding videresendt" @@ -21404,7 +21431,7 @@ msgstr "Knapper i meldingsfeltet" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "Meldingen er for lang" @@ -23059,7 +23086,7 @@ msgstr "Ingen endringer å lagre" msgid "No channels available" msgstr "Ingen kanaler tilgjengelige" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "Ingen kanaler funnet" @@ -23670,7 +23697,7 @@ msgstr "Ikke sann eller usann" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "Åpne emoji i nettleser" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "Åpne emojivelger" @@ -29360,6 +29387,7 @@ msgstr "Forhåndsvisning ved spoling" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "Forhåndsvisning ved spoling" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "Søk etter brukernavn eller ID" msgid "Search channels" msgstr "Søk i kanaler" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "Søk i kanaler eller direktemeldingssamtaler" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "Send" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "Send ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "Det er for dyrt for {PRODUCT_NAME} å sende en SMS til dette telefonnumm msgid "Sending malware or dangerous links" msgstr "Sender skadelig programvare eller farlige lenker" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "Sending av meldinger er deaktivert i dette fellesskapet" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "Snarveier er satt på pause mens du registrerer en tastkombinasjon." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "Forkort meldingen og prøv igjen." @@ -31780,8 +31804,8 @@ msgstr "Treg profilinnlasting" msgid "Slowmode" msgstr "Sakte modus" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "Sakte modus · vent {remaining}" @@ -34920,6 +34944,11 @@ msgstr "Dette medlemmet er ikke lenger i fellesskapet. Oppdater og prøv igjen." msgid "This member isn't connected to voice anymore." msgstr "Dette medlemmet er ikke lenger koblet til tale." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "Denne meldingen kan bare videresendes til kanaler med aldersbegrensning" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "Tidsstempler" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "Tips" @@ -36521,7 +36550,7 @@ msgstr "ukjent objekt" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "Ukjent feil" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "Venter på passnøkkel …" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "Venter på at sakte modus i {forwardChannelDisplayName} skal utløpe." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "Venter på at sakte modus skal utløpe i én eller flere valgte kanaler." @@ -39077,7 +39106,7 @@ msgstr "Vekk fra hvilemodus" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "Advarsel" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "Du må ha tilgang til den nåværende e-postadressen din for å endre den herfra. Bruk bekreftelse via telefon hvis det er tilgjengelig, eller kontakt kundestøtte." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "Du trenger tillatelsen «{attachFilesPermissionLabel}» for å legge ved filer i denne kanalen" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "Du trenger tillatelsen «{embedLinksPermissionLabel}» for å bygge inn lenker i denne kanalen" @@ -40432,11 +40461,6 @@ msgstr "Du trenger tillatelsen «{permissionLabel}» for å bruke emojier fra an msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "Du trenger tillatelsen «{permissionLabel}» for å bruke klistremerker fra andre fellesskap her." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "Du trenger tillatelsen «{sendMessagesPermissionLabel}» for å sende meldinger i denne kanalen" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "Du sender meldinger for raskt" msgid "You're streaming!" msgstr "Du strømmer!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "Du har timeout i dette fellesskapet" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "Du har timeout. Meldinger, reaksjoner og tale er satt på pause til timeouten er over." diff --git a/fluxer_app/src/features/i18n/locales/pl/messages.po b/fluxer_app/src/features/i18n/locales/pl/messages.po index 71df87a0c..96cfd7b74 100644 --- a/fluxer_app/src/features/i18n/locales/pl/messages.po +++ b/fluxer_app/src/features/i18n/locales/pl/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "... włącz tryb zwarty. Super!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(edytowano)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# społeczność jest tymczasowo niedostępna z pow msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# połączenie} few {# połączenia} many {# połączeń} other {# połączenia}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# plik} few {# pliki} many {# plików} other {# pliku}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# prezent} few {# prezenty} many {# prezentów} other {# prezentów}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# obraz} few {# obrazy} many {# obrazów} other {# obrazu}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# element} few {# elementy} many {# elementów} other {# elementu}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# sekunda} few {# sekundy} many {# sekund} other {# msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, one {Dostępna jest # sugestia} few {Dostępne są # sugestie} many {Dostępnych jest # sugestii} other {Dostępne jest # sugestii}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# film} few {# filmy} many {# filmów} other {# filmu}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {To zaproszenie wygasa za # godzinę.} few {To zapro msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {Twój link z zaproszeniem wygaśnie za # godzinę.} few {Twój link z zaproszeniem wygaśnie za # godziny.} many {Twój link z zaproszeniem wygaśnie za # godzin.} other {Twój link z zaproszeniem wygaśnie za # godziny.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# obraz} few {# obrazy} many {# obrazów} other {# obrazu}}, {videoCount, plural, one {# film} few {# filmy} many {# filmów} other {# filmu}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@wzmianka" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/>: dodano <1/> do grupy." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "Dodaj bota do społeczności z żądanymi uprawnieniami" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "Dodaj komentarz (opcjonalnie)" @@ -6687,7 +6714,7 @@ msgstr "Nie można tu przesyłać plików" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "Ustawienia kategorii" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "Uwaga" @@ -7372,8 +7399,8 @@ msgstr "kanał" msgid "Channel" msgstr "Kanał" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "Kanał {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "Polecenia" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "Komentarze są wyłączone, ponieważ w co najmniej jednym wybranym kanale włączono tryb wolny. Komentarz zostałby przez niego zablokowany zaraz po przekazaniu wiadomości." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "Komentarze są wyłączone, ponieważ w kanale „{forwardChannelDisplayName}” włączono tryb wolny. Komentarz zostałby przez niego zablokowany zaraz po przekazaniu wiadomości." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "Komentarze są niedostępne, gdy włączony jest tryb wolny." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "Błąd podczas renderowania treści" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "Błąd renderowania LaTeX-a: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "Przekaż dalej multimedia" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "Przekaż wiadomość dalej" @@ -18216,7 +18243,7 @@ msgstr "Import niedostępny" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "Ważne" @@ -21355,7 +21382,7 @@ msgstr "Ustawienia wyświetlania wiadomości są dostępne tylko na komputerze." msgid "Message editing" msgstr "Edytowanie wiadomości" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "Wiadomość przesłana dalej" @@ -21404,7 +21431,7 @@ msgstr "Przyciski wprowadzania wiadomości" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "Wiadomość jest za długa" @@ -23059,7 +23086,7 @@ msgstr "Brak zmian do zapisania" msgid "No channels available" msgstr "Brak dostępnych kanałów" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "Nie znaleziono kanałów" @@ -23670,7 +23697,7 @@ msgstr "To nie jest prawda ani fałsz" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "Otwórz emoji w przeglądarce" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "Otwórz wybór emoji" @@ -29360,6 +29387,7 @@ msgstr "Podgląd podczas przewijania" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "Podgląd podczas przewijania" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "Szukaj po nazwie użytkownika lub ID" msgid "Search channels" msgstr "Szukaj kanałów" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "Szukaj kanałów lub rozmów prywatnych" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "Wyślij" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "Wyślij ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "Wysłanie SMS-a na ten numer telefonu jest zbyt kosztowne dla {PRODUCT_N msgid "Sending malware or dangerous links" msgstr "Wysyłanie złośliwego oprogramowania lub niebezpiecznych linków" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "Wysyłanie wiadomości jest wyłączone w tej społeczności" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "Skróty klawiszowe są wstrzymane podczas nagrywania." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "Skróć wiadomość i spróbuj ponownie." @@ -31780,8 +31804,8 @@ msgstr "Wolne ładowanie profilu" msgid "Slowmode" msgstr "Tryb wolny" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "Tryb wolny · czekaj {remaining}" @@ -34920,6 +34944,11 @@ msgstr "Tego użytkownika nie ma już w społeczności. Odśwież i spróbuj pon msgid "This member isn't connected to voice anymore." msgstr "Ten użytkownik nie jest już połączony z czatem głosowym." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "Tę wiadomość można przesłać dalej tylko do kanałów z ograniczeniami wiekowymi" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "Znaczniki czasu" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "Wskazówka" @@ -36521,7 +36550,7 @@ msgstr "nieznany podmiot" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "Nieznany błąd" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "Czekam na klucz dostępu…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "Oczekiwanie na koniec odstępu między wiadomościami wymaganego przez tryb wolny w kanale „{forwardChannelDisplayName}”." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "Oczekiwanie na koniec odstępu między wiadomościami wymaganego przez tryb wolny w co najmniej jednym z wybranych kanałów." @@ -39077,7 +39106,7 @@ msgstr "Wybudzenie" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "Ostrzeżenie" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "Aby zmienić adres e-mail, musisz mieć dostęp do obecnego. Jeśli to możliwe, użyj weryfikacji telefonicznej lub skontaktuj się z pomocą." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "Potrzebujesz uprawnienia „{attachFilesPermissionLabel}”, aby załączać pliki na tym kanale" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "Potrzebujesz uprawnienia „{embedLinksPermissionLabel}”, aby osadzać linki w tym kanale" @@ -40432,11 +40461,6 @@ msgstr "Potrzebujesz uprawnienia „{permissionLabel}”, aby używać tutaj emo msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "Aby używać naklejek z innych społeczności, potrzebujesz uprawnienia „{permissionLabel}”." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "Potrzebujesz uprawnienia „{sendMessagesPermissionLabel}”, aby wysyłać wiadomości na tym kanale" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "Wysyłasz wiadomości zbyt szybko" msgid "You're streaming!" msgstr "Transmitujesz na żywo!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "Masz nałożone czasowe ograniczenie w tej społeczności" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "Masz nałożone czasowe ograniczenie. Wysyłanie wiadomości, dodawanie reakcji i korzystanie z połączeń głosowych są zablokowane do jego wygaśnięcia." diff --git a/fluxer_app/src/features/i18n/locales/pt-BR/messages.po b/fluxer_app/src/features/i18n/locales/pt-BR/messages.po index 6649f3349..0a9f1e8a6 100644 --- a/fluxer_app/src/features/i18n/locales/pt-BR/messages.po +++ b/fluxer_app/src/features/i18n/locales/pt-BR/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "... ativar o modo denso. Boa!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(editado)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, =0 {# comunidades estão temporariamente indisponíveis msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, =0 {# conexões} one {# conexão} other {# conexões}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# arquivo} other {# arquivos}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, =0 {# presentes} one {# presente} other {# presentes}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# imagem} other {# imagens}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, =0 {# itens} one {# item} other {# itens}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, =0 {# segundos} one {# segundo} other {# segundos}}" msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, =0 {# sugestões disponíveis} one {# sugestão disponível} many {# sugestões disponíveis} other {# sugestões disponíveis}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# vídeo} other {# vídeos}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, =0 {Este convite expira em # horas.} one {Este convite e msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, =0 {Seu link de convite expira em # horas.} one {Seu link de convite expira em # hora.} other {Seu link de convite expira em # horas.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# imagem} other {# imagens}}, {videoCount, plural, one {# vídeo} other {# vídeos}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@menção" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/> adicionou <1/> ao grupo." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "Adicionar um bot a uma comunidade com as permissões solicitadas" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "Adicionar um comentário (opcional)" @@ -6687,7 +6714,7 @@ msgstr "Não é possível enviar arquivos aqui" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "Configurações de categoria" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "Atenção" @@ -7372,8 +7399,8 @@ msgstr "canal" msgid "Channel" msgstr "Canal" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "Canal {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "Comandos" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "Os comentários estão desativados porque um ou mais canais selecionados estão com o modo lento ativado. O comentário seria bloqueado pelo modo lento logo após o encaminhamento." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "Os comentários estão desativados porque o modo lento está ativado em {forwardChannelDisplayName}. O comentário seria bloqueado pelo modo lento logo após o encaminhamento." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "Os comentários não estão disponíveis enquanto o modo lento estiver ativado." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "Erro ao renderizar conteúdo" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "Erro ao renderizar LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "Encaminhar mídia" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "Encaminhar mensagem" @@ -18216,7 +18243,7 @@ msgstr "Importação indisponível" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "Importante" @@ -21355,7 +21382,7 @@ msgstr "As configurações de exibição de mensagens estão disponíveis apenas msgid "Message editing" msgstr "Edição de mensagem" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "Mensagem encaminhada" @@ -21404,7 +21431,7 @@ msgstr "Botões de entrada de mensagem" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "A mensagem é muito longa" @@ -23059,7 +23086,7 @@ msgstr "Nenhuma alteração para salvar" msgid "No channels available" msgstr "Nenhum canal disponível" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "Nenhum canal encontrado" @@ -23670,7 +23697,7 @@ msgstr "Não é verdadeiro ou falso" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "Abrir emoji no navegador" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "Abrir seletor de emojis" @@ -29360,6 +29387,7 @@ msgstr "Prévia ao percorrer o vídeo" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "Prévia ao percorrer o vídeo" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "Pesquisar por nome de usuário ou ID" msgid "Search channels" msgstr "Buscar canais" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "Pesquisar canais ou mensagens diretas" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "Enviar" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "Enviar ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "Enviar um SMS para este número de telefone é muito caro para o {PRODUC msgid "Sending malware or dangerous links" msgstr "Enviando malware ou links perigosos" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "O envio de mensagens está desativado nesta comunidade" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "Os atalhos ficam pausados durante a gravação." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "Encurte a mensagem e tente novamente." @@ -31780,8 +31804,8 @@ msgstr "Carregamento lento de perfil" msgid "Slowmode" msgstr "Modo lento" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "Modo lento · aguarde {remaining}" @@ -34920,6 +34944,11 @@ msgstr "Este membro não está mais na comunidade. Atualize e tente novamente." msgid "This member isn't connected to voice anymore." msgstr "Este membro não está mais conectado ao chat de voz." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "Esta mensagem só pode ser encaminhada para canais com restrição de idade" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "Horários" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "Dica" @@ -36521,7 +36550,7 @@ msgstr "entidade desconhecida" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "Erro desconhecido" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "Aguardando a chave de acesso…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "Aguardando o modo lento em {forwardChannelDisplayName} expirar." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "Aguardando o modo lento expirar em um ou mais canais selecionados." @@ -39077,7 +39106,7 @@ msgstr "Reativar" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "Aviso" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "Você precisa ter acesso ao seu e-mail atual para alterá-lo por aqui. Use a verificação por telefone, se disponível, ou entre em contato com o suporte." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "Você precisa da permissão \"{attachFilesPermissionLabel}\" para anexar arquivos neste canal" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "Você precisa da permissão \"{embedLinksPermissionLabel}\" para incorporar links neste canal" @@ -40432,11 +40461,6 @@ msgstr "Você precisa da permissão \"{permissionLabel}\" para usar emojis de ou msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "Você precisa da permissão \"{permissionLabel}\" para usar figurinhas de outras comunidades aqui." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "Você precisa da permissão \"{sendMessagesPermissionLabel}\" para enviar mensagens neste canal" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "Você está enviando mensagens muito rápido" msgid "You're streaming!" msgstr "Você está transmitindo!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "Você está temporariamente suspenso nesta comunidade" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "Você está temporariamente suspenso. O envio de mensagens, as reações e a participação em canais de voz ficam desativados até o fim da suspensão." diff --git a/fluxer_app/src/features/i18n/locales/ro/messages.po b/fluxer_app/src/features/i18n/locales/ro/messages.po index 87ab4ba72..84592e824 100644 --- a/fluxer_app/src/features/i18n/locales/ro/messages.po +++ b/fluxer_app/src/features/i18n/locales/ro/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "... activezi modul dens. Super!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(editat)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# comunitate este temporar indisponibilă din cauza msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# conexiune} few {# conexiuni} other {# de conexiuni}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# fișier} few {# fișiere} other {# de fișiere}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# cadou} few {# cadouri} other {# de cadouri}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# imagine} few {# imagini} other {# de imagini}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# element} few {# elemente} other {# de elemente}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# secundă} few {# secunde} other {# de secunde}}" msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, one {# sugestie disponibilă} few {# sugestii disponibile} other {# de sugestii disponibile}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# videoclip} few {# videoclipuri} other {# de videoclipuri}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {Această invitație expiră peste o oră.} few {Ace msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {Linkul tău de invitație expiră peste # oră.} few {Linkul tău de invitație expiră peste # ore.} other {Linkul tău de invitație expiră peste # de ore.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# imagine} few {# imagini} other {# de imagini}}, {videoCount, plural, one {# videoclip} few {# videoclipuri} other {# de videoclipuri}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@mention" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/> a adăugat pe <1/> în grup." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "Adaugă un bot într-o comunitate cu permisiunile solicitate" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "Adaugă un comentariu (opțional)" @@ -6687,7 +6714,7 @@ msgstr "Nu se pot încărca fișiere aici" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "Setări categorie" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "Atenție" @@ -7372,8 +7399,8 @@ msgstr "canal" msgid "Channel" msgstr "Canal" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "Canal {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "Comenzi" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "Comentariile sunt dezactivate deoarece unul sau mai multe canale selectate au modul lent activat. Comentariul ar fi blocat de modul lent imediat după redirecționare." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "Comentariile sunt dezactivate deoarece modul lent este activat în {forwardChannelDisplayName}. Comentariul ar fi blocat de modul lent imediat după redirecționare." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "Comentariile nu sunt disponibile când modul lent este activat." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "Eroare la redarea conținutului" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "Eroare la redarea LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "Redirecționează media" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "Redirecționează mesajul" @@ -18216,7 +18243,7 @@ msgstr "Import indisponibil" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "Important" @@ -21355,7 +21382,7 @@ msgstr "Setările de afișare a mesajelor sunt disponibile doar pe desktop." msgid "Message editing" msgstr "Editare mesaj" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "Mesaj redirecționat" @@ -21404,7 +21431,7 @@ msgstr "Butoane de introducere a mesajului" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "Mesajul este prea lung" @@ -23059,7 +23086,7 @@ msgstr "Nicio modificare de salvat" msgid "No channels available" msgstr "Niciun canal disponibil" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "Nu s-au găsit canale" @@ -23670,7 +23697,7 @@ msgstr "Nu este adevărat sau fals" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "Deschide emoji în browser" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "Deschide selectorul de emoji" @@ -29360,6 +29387,7 @@ msgstr "Previzualizare la glisare" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "Previzualizare la glisare" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "Caută după nume de utilizator sau ID" msgid "Search channels" msgstr "Caută canale" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "Caută canale sau DM-uri" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "Trimite" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "Trimite ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "Trimiterea unui SMS către acest număr de telefon este prea costisitoar msgid "Sending malware or dangerous links" msgstr "Trimiterea de malware sau linkuri periculoase" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "Trimiterea mesajelor este dezactivată în această comunitate" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "Comenzile rapide sunt suspendate în timpul înregistrării." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "Scurtează mesajul și încearcă din nou." @@ -31780,8 +31804,8 @@ msgstr "Încărcare lentă profil" msgid "Slowmode" msgstr "Mod lent" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "Mod lent · așteaptă {remaining}" @@ -34920,6 +34944,11 @@ msgstr "Acest membru nu mai este în comunitate. Reîmprospătează și încearc msgid "This member isn't connected to voice anymore." msgstr "Acest membru nu mai este conectat la canalul vocal." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "Acest mesaj poate fi trimis doar către canale cu restricție de vârstă" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "Marcaje temporale" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "Sfat" @@ -36521,7 +36550,7 @@ msgstr "entitate necunoscută" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "Eroare necunoscută" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "Se așteaptă cheia de acces…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "Se așteaptă expirarea modului lent în {forwardChannelDisplayName}." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "Se așteaptă expirarea modului lent în unul sau mai multe canale selectate." @@ -39077,7 +39106,7 @@ msgstr "Reactivare" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "Avertisment" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "Ai nevoie de acces la adresa de e-mail actuală pentru a o schimba de aici. Folosește verificarea prin telefon, dacă este disponibilă, sau contactează asistența." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "Ai nevoie de permisiunea „{attachFilesPermissionLabel}” pentru a atașa fișiere pe acest canal" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "Ai nevoie de permisiunea „{embedLinksPermissionLabel}” pentru a încorpora linkuri în acest canal" @@ -40432,11 +40461,6 @@ msgstr "Ai nevoie de permisiunea „{permissionLabel}” pentru a folosi emoji d msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "Ai nevoie de permisiunea „{permissionLabel}” pentru a folosi stickere din alte comunități aici." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "Ai nevoie de permisiunea „{sendMessagesPermissionLabel}” pentru a trimite mesaje pe acest canal" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "Trimiți mesaje prea repede" msgid "You're streaming!" msgstr "Transmiți live!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "Ești în timeout în această comunitate" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "Ești în timeout. Mesajele, reacțiile și vocea sunt suspendate până la expirarea timeoutului." diff --git a/fluxer_app/src/features/i18n/locales/ru/messages.po b/fluxer_app/src/features/i18n/locales/ru/messages.po index d30b327bb..c0cc91dd7 100644 --- a/fluxer_app/src/features/i18n/locales/ru/messages.po +++ b/fluxer_app/src/features/i18n/locales/ru/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "...включите плотный режим. Отлично!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(изменено)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# сообщество временно недос msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# подключение} few {# подключения} many {# подключений} other {# подключения}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# файл} few {# файла} many {# файлов} other {# файла}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# подарок} few {# подарка} many {# подарков} other {# подарков}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# изображение} few {# изображения} many {# изображений} other {# изображения}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# запись} few {# записи} many {# записей} other {# записей}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# секунда} few {# секунды} many {# с msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, one {Доступна # подсказка} few {Доступно # подсказки} many {Доступно # подсказок} other {Доступно # подсказки}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# видео} few {# видео} many {# видео} other {# видео}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {Срок действия приглашения и msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {Срок действия ссылки-приглашения истекает через # час.} few {Срок действия ссылки-приглашения истекает через # часа.} many {Срок действия ссылки-приглашения истекает через # часов.} other {Срок действия ссылки-приглашения истекает через # часа.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# изображение} few {# изображения} many {# изображений} other {# изображения}}, {videoCount, plural, one {# видео} few {# видео} many {# видео} other {# видео}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@упоминание" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/> добавил(а) <1/> в группу." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "Добавить бота в сообщество с запрошенными разрешениями" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "Добавить комментарий (необязательно)" @@ -6687,7 +6714,7 @@ msgstr "Сюда нельзя загружать файлы" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "Настройки категории" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "Внимание" @@ -7372,8 +7399,8 @@ msgstr "канал" msgid "Channel" msgstr "Канал" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "Канал {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "Команды" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "Комментарии отключены, так как в одном или нескольких выбранных каналах включен медленный режим. Комментарий будет заблокирован медленным режимом сразу после пересылки." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "Комментарии отключены, так как в канале «{forwardChannelDisplayName}» включен медленный режим. Комментарий будет заблокирован медленным режимом сразу после пересылки." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "Комментарии недоступны, пока включён медленный режим." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "Ошибка при отображении контента" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "Ошибка при рендеринге LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "Переслать медиафайл" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "Переслать сообщение" @@ -18216,7 +18243,7 @@ msgstr "Импорт недоступен" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "Важно" @@ -21355,7 +21382,7 @@ msgstr "Настройки отображения сообщений досту msgid "Message editing" msgstr "Редактирование сообщений" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "Сообщение переслано" @@ -21404,7 +21431,7 @@ msgstr "Кнопки ввода сообщения" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "Сообщение слишком длинное" @@ -23059,7 +23086,7 @@ msgstr "Нет изменений для сохранения" msgid "No channels available" msgstr "Нет доступных каналов" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "Каналы не найдены" @@ -23670,7 +23697,7 @@ msgstr "Не «да» и не «нет»" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "Открыть эмодзи в браузере" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "Открыть выбор эмодзи" @@ -29360,6 +29387,7 @@ msgstr "Предпросмотр при перемотке" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "Предпросмотр при перемотке" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "Поиск по имени пользователя или ID" msgid "Search channels" msgstr "Поиск каналов" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "Поиск каналов или личных чатов" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "Отправить" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "Отправить ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "Отправка SMS на этот номер слишком дорог msgid "Sending malware or dangerous links" msgstr "Отправка вредоносных программ или опасных ссылок" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "Отправка сообщений в этом сообществе отключена" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "Во время записи сочетания клавиш не срабатывают." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "Сократите сообщение и попробуйте снова." @@ -31780,8 +31804,8 @@ msgstr "Медленная загрузка профиля" msgid "Slowmode" msgstr "Медленный режим" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "Медленный режим · ждать {remaining}" @@ -34920,6 +34944,11 @@ msgstr "Этого участника больше нет в сообществ msgid "This member isn't connected to voice anymore." msgstr "Этот участник больше не подключен к голосовому каналу." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "Это сообщение можно переслать только в каналы с возрастным ограничением" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "Метки времени" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "Подсказка" @@ -36521,7 +36550,7 @@ msgstr "неизвестная сущность" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "Неизвестная ошибка" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "Ожидание ключа доступа…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "Ожидание окончания медленного режима в канале «{forwardChannelDisplayName}»." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "Ожидание окончания медленного режима в одном или нескольких выбранных каналах." @@ -39077,7 +39106,7 @@ msgstr "Пробуждение" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "Внимание" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "Чтобы изменить почту, вам нужен доступ к текущему адресу. Используйте подтверждение по телефону, если доступно, или обратитесь в поддержку." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "Чтобы прикреплять файлы в этом канале, вам нужно разрешение «{attachFilesPermissionLabel}»" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "Чтобы встраивать ссылки в этом канале, вам нужно разрешение «{embedLinksPermissionLabel}»" @@ -40432,11 +40461,6 @@ msgstr "Чтобы использовать здесь эмодзи из дру msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "Чтобы использовать здесь стикеры из других сообществ, вам нужно разрешение «{permissionLabel}»." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "Вам нужно разрешение «{sendMessagesPermissionLabel}», чтобы отправлять сообщения в этом канале" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "Вы отправляете сообщения слишком быстр msgid "You're streaming!" msgstr "Вы ведете трансляцию!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "У вас тайм-аут в этом сообществе" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "У вас тайм-аут. Сообщения, реакции и голосовая связь приостановлены до истечения тайм-аута." diff --git a/fluxer_app/src/features/i18n/locales/sv-SE/messages.po b/fluxer_app/src/features/i18n/locales/sv-SE/messages.po index b70e56556..decf4d1d7 100644 --- a/fluxer_app/src/features/i18n/locales/sv-SE/messages.po +++ b/fluxer_app/src/features/i18n/locales/sv-SE/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "... aktivera kompakt läge. Snyggt!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(redigerat)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# community är tillfälligt otillgänglig på grun msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# anslutning} other {# anslutningar}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# fil} other {# filer}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# present} other {# presenter}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# bild} other {# bilder}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# objekt} other {# objekt}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# sekund} other {# sekunder}}" msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, one {# förslag tillgängligt} other {# förslag tillgängliga}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# video} other {# videor}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {Den här inbjudan går ut om # timme.} other {Den h msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {Din inbjudningslänk upphör att gälla om # timme.} other {Din inbjudningslänk upphör att gälla om # timmar.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# bild} other {# bilder}}, {videoCount, plural, one {# video} other {# videor}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@-omnämnande" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/> lade till <1/> i gruppen." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "Lägg till en bot i en community med begärda behörigheter" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "Lägg till en kommentar (valfritt)" @@ -6687,7 +6714,7 @@ msgstr "Kan inte ladda upp filer här" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "Kategorinställningar" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "Varning" @@ -7372,8 +7399,8 @@ msgstr "kanal" msgid "Channel" msgstr "Kanal" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "Kanal {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "Kommandon" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "Kommentarer är inaktiverade eftersom en eller flera valda kanaler har långsamt läge aktiverat. Kommentaren skulle blockeras av långsamt läge direkt efter vidarebefordran." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "Kommentarer är inaktiverade eftersom långsamt läge är aktiverat i {forwardChannelDisplayName}. Kommentaren skulle blockeras av långsamt läge direkt efter vidarebefordran." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "Kommentarer är inte tillgängliga när långsamt läge är aktiverat." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "Det gick inte att visa innehållet" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "Det gick inte att rendera LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "Vidarebefordra medieobjekt" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "Vidarebefordra meddelande" @@ -18216,7 +18243,7 @@ msgstr "Import ej tillgänglig" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "Viktigt" @@ -21355,7 +21382,7 @@ msgstr "Inställningar för meddelandevisning är bara tillgängliga på datorn. msgid "Message editing" msgstr "Redigera meddelande" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "Meddelande vidarebefordrat" @@ -21404,7 +21431,7 @@ msgstr "Knappar för meddelandeinmatning" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "Meddelandet är för långt" @@ -23059,7 +23086,7 @@ msgstr "Inga ändringar att spara" msgid "No channels available" msgstr "Inga kanaler tillgängliga" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "Inga kanaler hittades" @@ -23670,7 +23697,7 @@ msgstr "Inte sant eller falskt" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "Öppna emoji i webbläsaren" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "Öppna emojiväljaren" @@ -29360,6 +29387,7 @@ msgstr "Förhandsvisning vid spolning" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "Förhandsvisning vid spolning" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "Sök efter användarnamn eller ID" msgid "Search channels" msgstr "Sök kanaler" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "Sök kanaler eller DM-konversationer" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "Skicka" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "Skicka ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "Att skicka ett SMS till det här telefonnumret är för dyrt för {PRODU msgid "Sending malware or dangerous links" msgstr "Skickar skadlig programvara eller farliga länkar" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "Det går inte att skicka meddelanden i den här communityn" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "Kortkommandon pausas under inspelningen." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "Korta ner meddelandet och försök igen." @@ -31780,8 +31804,8 @@ msgstr "Långsam profilinläsning" msgid "Slowmode" msgstr "Långsamt läge" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "Långsamt läge · vänta {remaining}" @@ -34920,6 +34944,11 @@ msgstr "Den här medlemmen är inte längre med i communityn. Uppdatera och för msgid "This member isn't connected to voice anymore." msgstr "Den här medlemmen är inte längre ansluten till röstkanalen." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "Det här meddelandet kan bara skickas till kanaler med åldersgräns" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "Tidsstämplar" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "Tips" @@ -36521,7 +36550,7 @@ msgstr "okänd entitet" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "Okänt fel" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "Väntar på lösennyckel…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "Väntar på att långsamt läge i {forwardChannelDisplayName} ska upphöra." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "Väntar på att väntetiden för långsamt läge ska löpa ut i en eller flera valda kanaler." @@ -39077,7 +39106,7 @@ msgstr "Väck" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "Varning" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "Du behöver åtkomst till din nuvarande e-postadress för att ändra den härifrån. Använd telefonverifiering om det finns tillgängligt eller kontakta supporten." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "Du behöver behörigheten \"{attachFilesPermissionLabel}\" för att bifoga filer i den här kanalen" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "Du behöver behörigheten \"{embedLinksPermissionLabel}\" för att kunna bädda in länkar i den här kanalen" @@ -40432,11 +40461,6 @@ msgstr "Du behöver behörigheten ”{permissionLabel}” för att använda emoj msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "Du behöver behörigheten ”{permissionLabel}” för att använda klistermärken från andra communities här." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "Du behöver behörigheten \"{sendMessagesPermissionLabel}\" för att skicka meddelanden i den här kanalen" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "Du skickar meddelanden för snabbt" msgid "You're streaming!" msgstr "Du sänder!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "Du har timeout i den här communityn" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "Du har timeout. Du kan inte skicka meddelanden, reagera eller delta i röstchatt förrän timeouten löper ut." diff --git a/fluxer_app/src/features/i18n/locales/th/messages.po b/fluxer_app/src/features/i18n/locales/th/messages.po index 6dc933093..23bc90a62 100644 --- a/fluxer_app/src/features/i18n/locales/th/messages.po +++ b/fluxer_app/src/features/i18n/locales/th/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "... เปิดโหมดกระชับแล้ว เยี่ยมเลย!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(แก้ไขแล้ว)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# คอมมูนิตี้ไม่พร้ msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# การเชื่อมต่อ} other {# การเชื่อมต่อ}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# ไฟล์} other {# ไฟล์}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {ของขวัญ # ชิ้น} other {ของขวัญ # ชิ้น}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# รูปภาพ} other {# รูปภาพ}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# รายการ} other {# รายการ}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# วินาที} other {# วินาที}} msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, other {มีคำแนะนำ # รายการ}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# วิดีโอ} other {# วิดีโอ}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {คำเชิญนี้จะหมดอาย msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {ลิงก์เชิญของคุณจะหมดอายุในอีก # ชั่วโมง} other {ลิงก์เชิญของคุณจะหมดอายุในอีก # ชั่วโมง}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# รูปภาพ} other {# รูปภาพ}}, {videoCount, plural, one {# วิดีโอ} other {# วิดีโอ}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "กล่าวถึง" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/> เพิ่ม <1/> เข้ากลุ่มแล้ว" @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "เพิ่มบอทเข้าสู่คอมมูนิตี้พร้อมสิทธิ์ที่ร้องขอ" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "เพิ่มความคิดเห็น (ไม่บังคับ)" @@ -6687,7 +6714,7 @@ msgstr "อัปโหลดไฟล์ที่นี่ไม่ได้" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "การตั้งค่าหมวดหมู่" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "ข้อควรระวัง" @@ -7372,8 +7399,8 @@ msgstr "ช่อง" msgid "Channel" msgstr "ช่อง" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "ช่อง {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "คำสั่ง" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "ปิดใช้งานความคิดเห็นเนื่องจากมีช่องที่เลือกไว้อย่างน้อยหนึ่งช่องเปิดโหมดจำกัดเวลาอยู่ ความคิดเห็นจะถูกบล็อกด้วยโหมดจำกัดเวลาทันทีหลังส่งต่อ" #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "ปิดใช้งานความคิดเห็นเนื่องจาก {forwardChannelDisplayName} เปิดโหมดจำกัดเวลาอยู่ ความคิดเห็นจะถูกบล็อกด้วยโหมดจำกัดเวลาทันทีหลังส่งต่อ" #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "ไม่สามารถแสดงความคิดเห็นได้เมื่อเปิดโหมดจำกัดเวลา" @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "แสดงเนื้อหาไม่ได้" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "เกิดข้อผิดพลาดในการเรนเดอร์ LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "ส่งต่อสื่อ" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "ส่งต่อข้อความ" @@ -18216,7 +18243,7 @@ msgstr "ไม่สามารถนำเข้าได้" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "สำคัญ" @@ -21355,7 +21382,7 @@ msgstr "การตั้งค่าการแสดงข้อความ msgid "Message editing" msgstr "แก้ไขข้อความ" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "ส่งต่อข้อความแล้ว" @@ -21404,7 +21431,7 @@ msgstr "ปุ่มป้อนข้อความ" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "ข้อความยาวเกินไป" @@ -23059,7 +23086,7 @@ msgstr "ไม่มีการเปลี่ยนแปลงที่ต้ msgid "No channels available" msgstr "ไม่มีช่องให้เลือก" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "ไม่พบช่อง" @@ -23670,7 +23697,7 @@ msgstr "ไม่ใช่จริงหรือเท็จ" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "เปิดอิโมจิในเบราว์เซอร์" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "เปิดตัวเลือกอิโมจิ" @@ -29360,6 +29387,7 @@ msgstr "ตัวอย่างขณะเลื่อนวิดีโอ" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "ตัวอย่างขณะเลื่อนวิดีโอ" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "ค้นหาด้วยชื่อผู้ใช้หรือ ID msgid "Search channels" msgstr "ค้นหาช่อง" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "ค้นหาช่องหรือข้อความส่วนตัว" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "ส่ง" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "ส่ง ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "การส่ง SMS ไปยังเบอร์นี้มีค msgid "Sending malware or dangerous links" msgstr "ส่งมัลแวร์หรือลิงก์อันตราย" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "การส่งข้อความในคอมมูนิตี้นี้ถูกปิดอยู่" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "ปุ่มลัดจะหยุดทำงานชั่วคราวระหว่างการบันทึก" #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "ย่อข้อความแล้วลองอีกครั้ง" @@ -31780,8 +31804,8 @@ msgstr "โหลดโปรไฟล์ช้า" msgid "Slowmode" msgstr "โหมดจำกัดเวลา" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "โหมดจำกัดเวลา · รอ {remaining}" @@ -34920,6 +34944,11 @@ msgstr "สมาชิกรายนี้ไม่ได้อยู่ใน msgid "This member isn't connected to voice anymore." msgstr "สมาชิกรายนี้ไม่ได้อยู่ในช่องเสียงแล้ว" +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "ข้อความนี้สามารถส่งต่อไปยังช่องที่มีการจำกัดอายุเท่านั้น" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "การประทับเวลา" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "เคล็ดลับ" @@ -36521,7 +36550,7 @@ msgstr "เอนทิตีที่ไม่รู้จัก" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "เกิดข้อผิดพลาดที่ไม่รู้จัก" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "กำลังรอพาสคีย์…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "กำลังรอให้โหมดจำกัดเวลาใน {forwardChannelDisplayName} สิ้นสุด" #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "กำลังรอให้โหมดจำกัดเวลาในช่องที่เลือกอย่างน้อยหนึ่งช่องสิ้นสุด" @@ -39077,7 +39106,7 @@ msgstr "ปลุกเครื่อง" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "คำเตือน" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "คุณต้องเข้าถึงอีเมลปัจจุบันได้จึงจะเปลี่ยนอีเมลจากตรงนี้ได้ ให้ใช้การยืนยันด้วยเบอร์โทรศัพท์หากมี หรือติดต่อฝ่ายสนับสนุน" #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "คุณต้องมีสิทธิ์ \"{attachFilesPermissionLabel}\" เพื่อแนบไฟล์ในช่องนี้" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "คุณต้องมีสิทธิ์ \"{embedLinksPermissionLabel}\" เพื่อฝังลิงก์ในช่องนี้" @@ -40432,11 +40461,6 @@ msgstr "คุณต้องมีสิทธิ์ \"{permissionLabel}\" เ msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "คุณต้องมีสิทธิ์ \"{permissionLabel}\" เพื่อใช้สติกเกอร์จากคอมมูนิตี้อื่นที่นี่" -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "คุณต้องมีสิทธิ์ \"{sendMessagesPermissionLabel}\" เพื่อส่งข้อความในช่องนี้" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "คุณส่งข้อความเร็วเกินไป" msgid "You're streaming!" msgstr "คุณกำลังสตรีมอยู่!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "คุณถูกพักการใช้งานชั่วคราวในคอมมูนิตี้นี้" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "คุณถูกพักการใช้งานชั่วคราว การส่งข้อความ รีแอ็กชัน และเสียงจะถูกระงับจนกว่าการพักการใช้งานจะสิ้นสุดลง" diff --git a/fluxer_app/src/features/i18n/locales/tr/messages.po b/fluxer_app/src/features/i18n/locales/tr/messages.po index a5a5e4d13..417777b78 100644 --- a/fluxer_app/src/features/i18n/locales/tr/messages.po +++ b/fluxer_app/src/features/i18n/locales/tr/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "... yoğun modu açın. Harika!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(düzenlendi)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# topluluk, flux kapasitörü arızası nedeniyle g msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# bağlantı} other {# bağlantı}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# dosya} other {# dosya}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# hediye} other {# hediye}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# resim} other {# resim}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# öğe} other {# öğe}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# saniye} other {# saniye}}" msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, one {# öneri mevcut} other {# öneri mevcut}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# video} other {# video}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {Bu davet # saat içinde sona erecek.} other {Bu dav msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {Davet bağlantınız # saat içinde sona erecek.} other {Davet bağlantınız # saat içinde sona erecek.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# resim} other {# resim}}, {videoCount, plural, one {# video} other {# video}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@mention" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/>, <1/> kişisini gruba ekledi." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "İstenen izinlerle bir topluluğa bot ekleme" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "Yorum ekle (isteğe bağlı)" @@ -6687,7 +6714,7 @@ msgstr "Buraya dosya yüklenemiyor" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "Kategori ayarları" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "Dikkat" @@ -7372,8 +7399,8 @@ msgstr "kanal" msgid "Channel" msgstr "Kanal" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "Kanal {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "Komutlar" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "Seçilen bir veya daha fazla kanalda yavaş mod açık olduğu için yorumlar devre dışı bırakıldı. Yorum, iletildikten hemen sonra yavaş mod tarafından engellenirdi." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "{forwardChannelDisplayName} kanalında yavaş mod açık olduğu için yorumlar devre dışı bırakıldı. Yorum, iletildikten hemen sonra yavaş mod tarafından engellenirdi." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "Yavaş mod açıkken yorumlar kullanılamaz." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "İçerik oluşturulurken hata oluştu" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "LaTeX oluşturulurken hata oluştu: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "Medyayı ilet" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "Mesajı ilet" @@ -18216,7 +18243,7 @@ msgstr "İçe aktarılamıyor" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "Önemli" @@ -21355,7 +21382,7 @@ msgstr "Mesaj görüntüleme ayarları yalnızca masaüstünde kullanılabilir." msgid "Message editing" msgstr "Mesaj düzenleme" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "Mesaj iletildi" @@ -21404,7 +21431,7 @@ msgstr "Mesaj giriş düğmeleri" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "Mesaj çok uzun" @@ -23059,7 +23086,7 @@ msgstr "Kaydedilecek değişiklik yok" msgid "No channels available" msgstr "Kanal yok" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "Kanal bulunamadı" @@ -23670,7 +23697,7 @@ msgstr "Doğru veya yanlış değil" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "Emojiyi tarayıcıda aç" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "Emoji seçiciyi aç" @@ -29360,6 +29387,7 @@ msgstr "Sarma önizlemesi" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "Sarma önizlemesi" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "Kullanıcı adına veya kimliğe göre ara" msgid "Search channels" msgstr "Kanallarda ara" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "Kanallarda veya DM'lerde ara" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "Gönder" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "Gönder ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "Bu telefon numarasına SMS göndermek {PRODUCT_NAME} için çok pahalı, msgid "Sending malware or dangerous links" msgstr "Kötü amaçlı yazılım veya tehlikeli bağlantılar gönderme" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "Bu toplulukta mesaj gönderme devre dışı bırakıldı" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "Kayıt sırasında klavye kısayolları duraklatılır." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "Mesajı kısaltıp tekrar deneyin." @@ -31780,8 +31804,8 @@ msgstr "Yavaş profil yüklemesi" msgid "Slowmode" msgstr "Yavaş mod" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "Yavaş mod · {remaining} bekleyin" @@ -34920,6 +34944,11 @@ msgstr "Bu üye artık toplulukta değil. Sayfayı yenileyip tekrar deneyin." msgid "This member isn't connected to voice anymore." msgstr "Bu üye artık sesli sohbete bağlı değil." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "Bu mesaj yalnızca yaş kısıtlaması olan kanallara iletilebilir" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "Zaman damgaları" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "İpucu" @@ -36521,7 +36550,7 @@ msgstr "bilinmeyen varlık" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "Bilinmeyen hata" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "Geçiş anahtarı bekleniyor…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "{forwardChannelDisplayName} kanalındaki yavaş modun süresinin dolması bekleniyor." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "Seçilen bir veya daha fazla kanalda yavaş modun süresinin dolması bekleniyor." @@ -39077,7 +39106,7 @@ msgstr "Uyandır" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "Uyarı" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "E-posta adresinizi buradan değiştirmek için mevcut e-postanıza erişmeniz gerekir. Mümkünse telefon doğrulamayı kullanın veya destekle iletişime geçin." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "Bu kanala dosya eklemek için \"{attachFilesPermissionLabel}\" iznine sahip olmanız gerekir" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "Bu kanalda bağlantı yerleştirmek için \"{embedLinksPermissionLabel}\" iznine sahip olmanız gerekir" @@ -40432,11 +40461,6 @@ msgstr "Burada diğer topluluklardan emoji kullanmak için \"{permissionLabel}\" msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "Burada diğer topluluklardan çıkartma kullanmak için \"{permissionLabel}\" iznine sahip olmanız gerekir." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "Bu kanalda mesaj göndermek için \"{sendMessagesPermissionLabel}\" iznine sahip olmanız gerekir" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "Çok hızlı mesaj gönderiyorsunuz" msgid "You're streaming!" msgstr "Yayın yapıyorsunuz!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "Bu toplulukta zaman aşımındasınız" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "Zaman aşımındasınız. Zaman aşımı süresi dolana kadar mesajlaşma, tepkiler ve sesli iletişim duraklatıldı." diff --git a/fluxer_app/src/features/i18n/locales/uk/messages.po b/fluxer_app/src/features/i18n/locales/uk/messages.po index 44694f5ba..6c052b60a 100644 --- a/fluxer_app/src/features/i18n/locales/uk/messages.po +++ b/fluxer_app/src/features/i18n/locales/uk/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "...увімкнете щільний режим. Чудово!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(змінено)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# спільнота тимчасово недос msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# підключення} few {# підключення} many {# підключень} other {# підключення}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# файл} few {# файли} many {# файлів} other {# файла}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# подарунок} few {# подарунки} many {# подарунків} other {# подарунків}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# зображення} few {# зображення} many {# зображень} other {# зображення}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# елемент} few {# елементи} many {# елементів} other {# елемента}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# секунда} few {# секунди} many {# с msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, one {Доступна # пропозиція} few {Доступні # пропозиції} many {Доступно # пропозицій} other {Доступно # пропозиції}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# відео} few {# відео} many {# відео} other {# відео}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {Це запрошення дійсне ще # го msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {Ваше посилання-запрошення дійсне ще # годину.} few {Ваше посилання-запрошення дійсне ще # години.} many {Ваше посилання-запрошення дійсне ще # годин.} other {Ваше посилання-запрошення дійсне ще # години.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# зображення} few {# зображення} many {# зображень} other {# зображення}}, {videoCount, plural, one {# відео} few {# відео} many {# відео} other {# відео}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "згадка" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/> додав(-ла) <1/> до групи." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "Додати бота до спільноти із запитаними дозволами" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "Додати коментар (необов'язково)" @@ -6687,7 +6714,7 @@ msgstr "Сюди не можна завантажити файли" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "Налаштування категорії" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "Обережно" @@ -7372,8 +7399,8 @@ msgstr "канал" msgid "Channel" msgstr "Канал" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "Канал {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "Команди" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "Коментарі вимкнено, оскільки в одному або кількох вибраних каналах увімкнено повільний режим. Коментар буде заблоковано повільним режимом одразу після пересилання." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "Коментарі вимкнено, оскільки в каналі «{forwardChannelDisplayName}» увімкнено повільний режим. Коментар буде заблоковано повільним режимом одразу після пересилання." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "Коментарі недоступні, коли ввімкнено повільний режим." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "Помилка відображення вмісту" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "Помилка відображення LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "Переслати медіа" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "Переслати повідомлення" @@ -18216,7 +18243,7 @@ msgstr "Імпорт недоступний" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "Важливо" @@ -21355,7 +21382,7 @@ msgstr "Налаштування відображення повідомлень msgid "Message editing" msgstr "Редагування повідомлень" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "Повідомлення переслано" @@ -21404,7 +21431,7 @@ msgstr "Кнопки введення повідомлень" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "Повідомлення задовге" @@ -23059,7 +23086,7 @@ msgstr "Немає змін для збереження" msgid "No channels available" msgstr "Немає доступних каналів" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "Канали не знайдено" @@ -23670,7 +23697,7 @@ msgstr "Не «так» і не «ні»" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "Відкрити емодзі в браузері" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "Відкрити панель емодзі" @@ -29360,6 +29387,7 @@ msgstr "Перегляд під час перемотування" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "Перегляд під час перемотування" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "Пошук за іменем користувача або ID" msgid "Search channels" msgstr "Пошук каналів" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "Пошук каналів або приватних чатів" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "Надіслати" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "Надіслати ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "Надсилання SMS на цей номер телефону зан msgid "Sending malware or dangerous links" msgstr "Надсилання шкідливих програм або небезпечних посилань" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "Надсилання повідомлень у цій спільноті вимкнено" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "Під час запису комбінації клавіш призупинено." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "Скоротіть повідомлення та спробуйте ще раз." @@ -31780,8 +31804,8 @@ msgstr "Повільне завантаження профілю" msgid "Slowmode" msgstr "Повільний режим" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "Повільний режим · зачекайте {remaining}" @@ -34920,6 +34944,11 @@ msgstr "Цього учасника більше немає в спільнот msgid "This member isn't connected to voice anymore." msgstr "Цей учасник більше не підключений до голосового чату." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "Це повідомлення можна пересилати лише на канали з обмеженим доступом за віком" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "Мітки часу" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "Підказка" @@ -36521,7 +36550,7 @@ msgstr "невідома сутність" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "Невідома помилка" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "Очікування ключа доступу…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "Очікування завершення повільного режиму в каналі «{forwardChannelDisplayName}»." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "Очікування завершення повільного режиму в одному або кількох вибраних каналах." @@ -39077,7 +39106,7 @@ msgstr "Пробудження" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "Попередження" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "Щоб змінити електронну пошту тут, вам потрібен доступ до поточної. Скористайтеся підтвердженням за телефоном, якщо доступно, або зверніться до служби підтримки." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "Щоб прикріплювати файли в цьому каналі, вам потрібен дозвіл «{attachFilesPermissionLabel}»" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "Вам потрібен дозвіл «{embedLinksPermissionLabel}», щоб вбудовувати посилання в цьому каналі" @@ -40432,11 +40461,6 @@ msgstr "Щоб використовувати тут емодзі з інших msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "Щоб використовувати тут стікери з інших спільнот, вам потрібен дозвіл «{permissionLabel}»." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "Вам потрібен дозвіл «{sendMessagesPermissionLabel}», щоб надсилати повідомлення в цьому каналі" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "Ви надто швидко надсилаєте повідомленн msgid "You're streaming!" msgstr "Ви транслюєте!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "У вас тайм-аут у цій спільноті" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "У вас тайм-аут. Обмін повідомленнями, реакції та голосовий зв'язок призупинено до закінчення тайм-ауту." diff --git a/fluxer_app/src/features/i18n/locales/vi/messages.po b/fluxer_app/src/features/i18n/locales/vi/messages.po index 26abfc7b8..43ea3c510 100644 --- a/fluxer_app/src/features/i18n/locales/vi/messages.po +++ b/fluxer_app/src/features/i18n/locales/vi/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "... bật chế độ dày đặc. Tuyệt!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(đã chỉnh sửa)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# cộng đồng hiện không khả dụng do lỗ msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# kết nối} other {# kết nối}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# tệp} other {# tệp}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# quà} other {# quà}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# ảnh} other {# ảnh}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# mục} other {# mục}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# giây} other {# giây}}" msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, other {Có # gợi ý}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# video} other {# video}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {Lời mời này sẽ hết hạn sau # giờ.} oth msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, other {Liên kết mời của bạn sẽ hết hạn sau # giờ.}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# ảnh} other {# ảnh}}, {videoCount, plural, one {# video} other {# video}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@mention" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/> đã thêm <1/> vào nhóm." @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "Thêm bot vào cộng đồng với các quyền được yêu cầu" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "Thêm bình luận (tùy chọn)" @@ -6687,7 +6714,7 @@ msgstr "Không thể tải tệp lên ở đây" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "Cài đặt danh mục" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "Thận trọng" @@ -7372,8 +7399,8 @@ msgstr "kênh" msgid "Channel" msgstr "Kênh" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "Kênh {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "Lệnh" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "Không thể bình luận vì một hoặc nhiều kênh đã chọn đang bật chế độ chậm. Bình luận sẽ bị chặn ngay sau khi chuyển tiếp." #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "Không thể bình luận vì kênh {forwardChannelDisplayName} đang bật chế độ chậm. Bình luận sẽ bị chặn ngay sau khi chuyển tiếp." #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "Không thể bình luận khi đang bật chế độ chậm." @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "Lỗi hiển thị nội dung" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "Lỗi khi hiển thị LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "Chuyển tiếp phương tiện" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "Chuyển tiếp tin nhắn" @@ -18216,7 +18243,7 @@ msgstr "Không thể nhập" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "Quan trọng" @@ -21355,7 +21382,7 @@ msgstr "Cài đặt hiển thị tin nhắn chỉ có trên máy tính." msgid "Message editing" msgstr "Chỉnh sửa tin nhắn" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "Đã chuyển tiếp tin nhắn" @@ -21404,7 +21431,7 @@ msgstr "Nút nhập tin nhắn" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "Tin nhắn quá dài" @@ -23059,7 +23086,7 @@ msgstr "Không có thay đổi nào để lưu" msgid "No channels available" msgstr "Không có kênh nào" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "Không tìm thấy kênh nào" @@ -23670,7 +23697,7 @@ msgstr "Không phải đúng hoặc sai" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "Mở biểu tượng cảm xúc trong trình duyệt" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "Mở bảng chọn biểu tượng cảm xúc" @@ -29360,6 +29387,7 @@ msgstr "Xem trước khi tua" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "Xem trước khi tua" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "Tìm theo tên người dùng hoặc ID" msgid "Search channels" msgstr "Tìm kênh" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "Tìm kênh hoặc tin nhắn trực tiếp" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "Gửi" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "Gửi ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "Việc gửi SMS đến số điện thoại này quá tốn kém đối msgid "Sending malware or dangerous links" msgstr "Gửi phần mềm độc hại hoặc liên kết nguy hiểm" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "Đã tắt tính năng gửi tin nhắn trong cộng đồng này" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "Các phím tắt tạm ngừng hoạt động trong khi ghi lại tổ hợp phím." #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "Rút gọn tin nhắn và thử lại." @@ -31780,8 +31804,8 @@ msgstr "Tải hồ sơ chậm" msgid "Slowmode" msgstr "Chế độ chậm" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "Chế độ chậm · chờ {remaining}" @@ -34920,6 +34944,11 @@ msgstr "Thành viên này không còn trong cộng đồng. Vui lòng làm mới msgid "This member isn't connected to voice anymore." msgstr "Thành viên này không còn kết nối với kênh thoại nữa." +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "Tin nhắn này chỉ có thể được chuyển tiếp đến các kênh có giới hạn độ tuổi" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "Dấu thời gian" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "Mẹo" @@ -36521,7 +36550,7 @@ msgstr "thực thể không xác định" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "Lỗi không xác định" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "Đang chờ khóa truy cập…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "Đang chờ chế độ chậm trong {forwardChannelDisplayName} hết hạn." #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "Đang chờ chế độ chậm trong một hoặc nhiều kênh đã chọn hết hạn." @@ -39077,7 +39106,7 @@ msgstr "Đánh thức" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "Cảnh báo" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "Bạn cần truy cập email hiện tại để thay đổi email từ đây. Hãy dùng xác minh qua điện thoại (nếu có) hoặc liên hệ bộ phận hỗ trợ." #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "Bạn cần quyền \"{attachFilesPermissionLabel}\" để đính kèm tệp trong kênh này" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "Bạn cần quyền \"{embedLinksPermissionLabel}\" để nhúng liên kết vào kênh này" @@ -40432,11 +40461,6 @@ msgstr "Bạn cần có quyền \"{permissionLabel}\" để sử dụng biểu t msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "Bạn cần có quyền \"{permissionLabel}\" để sử dụng nhãn dán từ các cộng đồng khác tại đây." -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "Bạn cần quyền \"{sendMessagesPermissionLabel}\" để gửi tin nhắn trong kênh này" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "Bạn đang gửi tin nhắn quá nhanh" msgid "You're streaming!" msgstr "Bạn đang phát trực tiếp!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "Bạn đang bị tạm dừng trong cộng đồng này" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "Bạn đang bị tạm dừng. Bạn không thể nhắn tin, bày tỏ cảm xúc hay dùng thoại cho đến khi hết thời gian tạm dừng." diff --git a/fluxer_app/src/features/i18n/locales/zh-CN/messages.po b/fluxer_app/src/features/i18n/locales/zh-CN/messages.po index 505f94534..7dda3c6d3 100644 --- a/fluxer_app/src/features/i18n/locales/zh-CN/messages.po +++ b/fluxer_app/src/features/i18n/locales/zh-CN/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "…开启紧凑模式。赞!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(已编辑)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, other {# 个社区因时空穿梭器故障暂时不可 msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, other {# 个连接}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# 个文件} other {# 个文件}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, other {# 份礼物}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# 张图片} other {# 张图片}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, other {# 项}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, other {# 秒}}" msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, other {有 # 条建议}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# 个视频} other {# 个视频}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, other {此邀请将在 # 小时后过期。}}" msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, other {你的邀请链接将在 # 小时后过期。}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# 张图片} other {# 张图片}},{videoCount, plural, one {# 个视频} other {# 个视频}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@提及" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/> 将 <1/> 加入了群聊。" @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "将机器人添加到社区并授予其请求的权限" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "添加评论(可选)" @@ -6687,7 +6714,7 @@ msgstr "无法在此上传文件" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "类别设置" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "注意" @@ -7372,8 +7399,8 @@ msgstr "频道" msgid "Channel" msgstr "频道" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "频道 {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "命令" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "评论已禁用,因为你选择的一个或多个频道开启了慢速模式。转发后,评论会立即被慢速模式拦截。" #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "由于“{forwardChannelDisplayName}”中开启了慢速模式,评论已禁用。转发后,评论会立即被慢速模式拦截。" #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "慢速模式开启时无法评论。" @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "内容渲染出错" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "渲染 LaTeX 时出错:{errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "转发媒体" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "转发消息" @@ -18216,7 +18243,7 @@ msgstr "无法导入" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "重要" @@ -21355,7 +21382,7 @@ msgstr "消息显示设置仅在桌面端可用。" msgid "Message editing" msgstr "编辑消息" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "消息已转发" @@ -21404,7 +21431,7 @@ msgstr "消息输入按钮" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "消息太长" @@ -23059,7 +23086,7 @@ msgstr "没有要保存的更改" msgid "No channels available" msgstr "没有可用频道" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "未找到频道" @@ -23670,7 +23697,7 @@ msgstr "不是真或假" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "在浏览器中打开表情" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "打开表情选择器" @@ -29360,6 +29387,7 @@ msgstr "拖动预览" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "拖动预览" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "按用户名或 ID 搜索" msgid "Search channels" msgstr "搜索频道" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "搜索频道或私信" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "发送" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "发送({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "向此手机号发送短信对 {PRODUCT_NAME} 来说费用太高,因 msgid "Sending malware or dangerous links" msgstr "发送恶意软件或危险链接" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "此社区已禁用发送消息" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "录制快捷键时,快捷键会暂停生效。" #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "请缩短消息后重试。" @@ -31780,8 +31804,8 @@ msgstr "慢速加载个人资料" msgid "Slowmode" msgstr "慢速模式" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "慢速模式 · 等待 {remaining}" @@ -34920,6 +34944,11 @@ msgstr "该成员已不在社区中。请刷新后重试。" msgid "This member isn't connected to voice anymore." msgstr "该成员已不在语音频道中。" +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "此消息只能转发到已设年龄限制的频道" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "时间戳" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "提示" @@ -36521,7 +36550,7 @@ msgstr "未知实体" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "未知错误" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "正在等待通行密钥…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "正在等待 {forwardChannelDisplayName} 的慢速模式结束。" #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "正在等待一个或多个所选频道的慢速模式结束。" @@ -39077,7 +39106,7 @@ msgstr "唤醒" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "警告" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "你需要能访问当前邮箱才能在此更改。如果可用,请使用手机验证,或联系支持团队。" #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "你需要“{attachFilesPermissionLabel}”权限才能在此频道中附加文件" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "你需要“{embedLinksPermissionLabel}”权限才能在此频道中嵌入链接" @@ -40432,11 +40461,6 @@ msgstr "你需要“{permissionLabel}”权限才能在此处使用其他社区 msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "你需要“{permissionLabel}”权限才能在此处使用其他社区的贴纸。" -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "你需要“{sendMessagesPermissionLabel}”权限才能在此频道中发送消息" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "你发送消息的速度太快了" msgid "You're streaming!" msgstr "你正在直播!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "你在此社区中已被禁言" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "你已被禁言。在禁言结束前,你无法发送消息、使用反应或加入语音。" diff --git a/fluxer_app/src/features/i18n/locales/zh-TW/messages.po b/fluxer_app/src/features/i18n/locales/zh-TW/messages.po index 92c2ded09..5485154d8 100644 --- a/fluxer_app/src/features/i18n/locales/zh-TW/messages.po +++ b/fluxer_app/src/features/i18n/locales/zh-TW/messages.po @@ -20,8 +20,10 @@ msgid "... turn dense mode on. Nice!" msgstr "…開啟緊湊模式。讚喔!" #. Button or menu action label in the channel and chat user message. Keep it concise. +#. Suffix after the message text in the forward modal preview when the forwarded message was edited. #: src/features/channel/components/MessageAttachments.tsx:378 #: src/features/channel/components/UserMessage.tsx:62 +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:26 msgid "(edited)" msgstr "(已編輯)" @@ -1125,12 +1127,22 @@ msgstr "{count, plural, one {# 個社群} other {# 個社群}}因時空電容器 msgid "{count, plural, one {# connection} other {# connections}}" msgstr "{count, plural, one {# 個連線} other {# 個連線}}" +#. Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:40 +msgid "{count, plural, one {# file} other {# files}}" +msgstr "{count, plural, one {# 個檔案} other {# 個檔案}}" + #. Developer tools debug menu label. Internal-only surface for developers; translators may keep this terse. #: src/features/channel/components/channel_header_components/developer_tools/AccountPremiumMenu.tsx:104 #: src/features/channel/components/channel_header_components/developer_tools/DeveloperOptionLabels.ts:40 msgid "{count, plural, one {# gift} other {# gifts}}" msgstr "{count, plural, one {# 份禮物} other {# 份禮物}}" +#. Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:30 +msgid "{count, plural, one {# image} other {# images}}" +msgstr "{count, plural, one {# 張圖片} other {# 張圖片}}" + #: src/features/guild/components/modals/guild_tabs/GuildAuditLogTabUtils.tsx:181 msgid "{count, plural, one {# item} other {# items}}" msgstr "{count, plural, one {# 個項目} other {# 個項目}}" @@ -1185,6 +1197,11 @@ msgstr "{count, plural, one {# 秒} other {# 秒}}" msgid "{count, plural, one {# suggestion available} other {# suggestions available}}" msgstr "{count, plural, one {有 # 個建議} other {有 # 個建議}}" +#. Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:35 +msgid "{count, plural, one {# video} other {# videos}}" +msgstr "{count, plural, one {# 個影片} other {# 個影片}}" + #. Compact age label shown beside a list row (DM list, invite list). count is a number of days; the "d" is an abbreviation of "days". Keep it as short as possible; it sits in a narrow column. #: src/features/ui/utils/ShortRelativeTimeLabels.ts:26 msgctxt "short-relative-time" @@ -1582,6 +1599,11 @@ msgstr "{hours, plural, one {此邀請將於 # 小時後過期。} other {此邀 msgid "{hours, plural, one {Your invite link expires in # hour.} other {Your invite link expires in # hours.}}" msgstr "{hours, plural, one {您的邀請連結將於 # 小時後過期。} other {您的邀請連結將於 # 小時後過期。}}" +#. Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:45 +msgid "{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}" +msgstr "{imageCount, plural, one {# 張圖片} other {# 張圖片}}, {videoCount, plural, one {# 個影片} other {# 個影片}}" + #. Accessible label for a disabled Discovery sidebar navigation item. {itemLabel} is the section name. #: src/features/discovery/discovery/DiscoverySidebar.tsx:31 msgid "{itemLabel}, coming soon" @@ -2234,6 +2256,11 @@ msgstr "@mention" msgid "/tts" msgstr "/tts" +#. Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show. +#: src/features/messaging/components/modals/ForwardMessagePreview.tsx:50 +msgid "+{count}" +msgstr "+{count}" + #: src/features/channel/components/RecipientAddMessage.tsx:25 msgid "<0/> added <1/> to the group." msgstr "<0/>已將<1/>加入群組。" @@ -3134,7 +3161,7 @@ msgid "Add a bot to a community with requested permissions" msgstr "將機器人新增至社群並授予要求的權限" #. Placeholder text in the optional comment field of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:91 +#: src/features/messaging/components/modals/ForwardModal.tsx:99 msgid "Add a comment (optional)" msgstr "新增留言(選填)" @@ -6687,7 +6714,7 @@ msgstr "無法在這裡上傳檔案" #: src/features/messaging/components/modals/AttachmentEditModal.tsx:133 #: src/features/messaging/components/modals/EditAltTextModal.tsx:190 #: src/features/messaging/components/modals/ExternalLinkWarningModal.tsx:111 -#: src/features/messaging/components/modals/ForwardModal.tsx:636 +#: src/features/messaging/components/modals/ForwardModal.tsx:650 #: src/features/messaging/components/modals/ImageCropModal.tsx:944 #: src/features/messaging/components/modals/MessageHistoryThresholdModal.tsx:107 #: src/features/moderation/components/modals/BanMemberModal.tsx:262 @@ -6926,7 +6953,7 @@ msgstr "類別設定" #. Markdown alert label for a caution callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:51 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:54 #: src/features/messaging/utils/markdown/Plaintext.ts:68 msgid "Caution" msgstr "注意" @@ -7372,8 +7399,8 @@ msgstr "頻道" msgid "Channel" msgstr "頻道" -#. Short label in the settings dialog forward channel selection. Preserve {id}; it is inserted by code. -#: src/features/app/components/dialogs/shared/UseForwardChannelObservations.ts:27 +#. Fallback name for an unnamed channel in the forward modal destination list. Preserve {id}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:87 msgid "Channel {id}" msgstr "頻道 {id}" @@ -8804,17 +8831,17 @@ msgid "Commands" msgstr "指令" #. Helper text in the forward modal explaining why the optional comment field is disabled when at least one selected target has slowmode active. -#: src/features/messaging/components/modals/ForwardModal.tsx:64 +#: src/features/messaging/components/modals/ForwardModal.tsx:71 msgid "Comments are disabled because one or more selected channels have slowmode on. The comment would be blocked by slowmode right after the forward." msgstr "由於所選頻道中至少有一個已開啟慢速模式,留言功能已停用。轉傳後,留言會立即被慢速模式阻擋。" #. Helper text in the forward modal explaining why the optional comment field is disabled for a single selected channel with slowmode. -#: src/features/messaging/components/modals/ForwardModal.tsx:58 +#: src/features/messaging/components/modals/ForwardModal.tsx:65 msgid "Comments are disabled because slowmode is on in {forwardChannelDisplayName}. The comment would be blocked by slowmode right after the forward." msgstr "由於「{forwardChannelDisplayName}」已開啟慢速模式,留言功能已停用。轉傳後,留言會立即被慢速模式阻擋。" #. Tooltip on the disabled comment field in the forward modal when slowmode blocks comments. -#: src/features/messaging/components/modals/ForwardModal.tsx:87 +#: src/features/messaging/components/modals/ForwardModal.tsx:95 msgid "Comments are unavailable while slowmode is on." msgstr "慢速模式開啟時無法留言。" @@ -14678,7 +14705,7 @@ msgid "Error rendering content" msgstr "內容顯示錯誤" #. Error message in the messaging code elements. Preserve {errorAsErrorMessageI18nMsgUnknownError}; it is inserted by code. -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:29 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:32 msgid "Error rendering LaTeX: {errorAsErrorMessageI18nMsgUnknownError}" msgstr "LaTeX 渲染錯誤:{errorAsErrorMessageI18nMsgUnknownError}" @@ -16097,7 +16124,7 @@ msgstr "轉傳媒體" #. Keyboard shortcut action label shown in the shortcuts list and keybind editor. Keep short, sentence case. #. Title of the forward message modal. #: src/features/input/state/input_keybind/shared.ts:25 -#: src/features/messaging/components/modals/ForwardModal.tsx:79 +#: src/features/messaging/components/modals/ForwardModal.tsx:86 msgid "Forward message" msgstr "轉傳訊息" @@ -18216,7 +18243,7 @@ msgstr "無法匯入" #. Markdown alert label for an important callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:43 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:46 #: src/features/messaging/utils/markdown/Plaintext.ts:60 msgid "Important" msgstr "重要" @@ -21355,7 +21382,7 @@ msgstr "訊息顯示設定僅供桌面版使用。" msgid "Message editing" msgstr "編輯訊息" -#: src/features/messaging/components/modals/ForwardModal.tsx:307 +#: src/features/messaging/components/modals/ForwardModal.tsx:371 msgid "Message forwarded" msgstr "訊息已轉傳" @@ -21404,7 +21431,7 @@ msgstr "訊息輸入按鈕" #. Error modal title in the forward modal when the optional comment exceeds the message length limit. #. Form validation error indicating the message exceeds the allowed length. -#: src/features/messaging/components/modals/ForwardModal.tsx:50 +#: src/features/messaging/components/modals/ForwardModal.tsx:57 #: src/features/ui/character_counter/CharacterCountMessages.ts:16 msgid "Message is too long" msgstr "訊息過長" @@ -23059,7 +23086,7 @@ msgstr "沒有要儲存的變更" msgid "No channels available" msgstr "沒有可用的頻道" -#: src/features/messaging/components/modals/ForwardModal.tsx:426 +#: src/features/messaging/components/modals/ForwardModal.tsx:445 #: src/features/search/components/search/ChannelFilterSheet.tsx:120 msgid "No channels found" msgstr "找不到任何頻道" @@ -23670,7 +23697,7 @@ msgstr "不是真或假" #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. #. Short label in the user profile modal. Keep it concise. #: src/features/app/components/pages/YouPage.tsx:186 -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:35 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:38 #: src/features/messaging/utils/markdown/Plaintext.ts:72 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:19 #: src/features/user/components/modals/user_profile_modal/UserNoteEditor.tsx:79 @@ -24311,7 +24338,7 @@ msgid "Open emoji in browser" msgstr "在瀏覽器中開啟表情符號" #. Accessible label for the emoji picker trigger button in the forward modal comment field. -#: src/features/messaging/components/modals/ForwardModal.tsx:95 +#: src/features/messaging/components/modals/ForwardModal.tsx:103 #: src/features/user/components/modals/tabs/my_profile_tab/BioEditor.tsx:27 msgid "Open emoji picker" msgstr "開啟表情符號選取器" @@ -29360,6 +29387,7 @@ msgstr "拖曳預覽" #. Button or menu action label in the theme studio studio search input. Keep it concise. #. Channel details bottom sheet label or action (channel type, settings, toast, confirmation, or notification option). #. Confirm button label in the reverse image search provider picker. Initiates the search. +#. Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to. #. Quick switcher tab label that searches all entity types. #. Title of the mobile channel search bottom sheet. #. Tooltip on the channel header search button that opens the message search input. @@ -29368,6 +29396,7 @@ msgstr "拖曳預覽" #: src/features/channel/components/bottomsheets/ChannelSearchBottomSheet.tsx:854 #: src/features/channel/components/channel_header/shared.ts:47 #: src/features/channel/components/shared/PickerSearchInput.tsx:21 +#: src/features/messaging/components/modals/ForwardModal.tsx:90 #: src/features/search/components/modals/SearchProviderPickerModal.tsx:43 #: src/features/search/utils/QuickSwitcherModalUtils.tsx:45 #: src/features/theme_studio/ui/StudioSearchInput.tsx:16 @@ -29407,11 +29436,6 @@ msgstr "依使用者名稱或 ID 搜尋" msgid "Search channels" msgstr "搜尋頻道" -#. Placeholder text in the channel picker search input of the forward modal. -#: src/features/messaging/components/modals/ForwardModal.tsx:83 -msgid "Search channels or DMs" -msgstr "搜尋頻道或私訊" - #. Accessible label and placeholder for the community search field in the Discovery page. #: src/features/discovery/discovery/DiscoveryNavbar.tsx:29 msgid "Search communities" @@ -30004,7 +30028,7 @@ msgid "Send" msgstr "傳送" #. Primary button label in the forward message modal. selectedCount is the number of selected destinations; selectionLimit is the maximum allowed. -#: src/features/messaging/components/modals/ForwardModal.tsx:99 +#: src/features/messaging/components/modals/ForwardModal.tsx:107 msgid "Send ({selectedCount}/{selectionLimit})" msgstr "傳送 ({selectedCount}/{selectionLimit})" @@ -30217,8 +30241,8 @@ msgstr "由於傳送簡訊到此電話號碼的費用對 {PRODUCT_NAME} 來說 msgid "Sending malware or dangerous links" msgstr "傳送惡意軟體或危險連結" -#. Short label in the settings dialog forward channel selection. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:14 +#. Short label under a destination row in the forward modal, shown when the community has messaging disabled. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:63 msgid "Sending messages is disabled in this community" msgstr "此社群已停用訊息傳送功能" @@ -30923,7 +30947,7 @@ msgid "Shortcuts are paused while recording." msgstr "錄製期間快速鍵會暫停作用。" #. Body of the error modal shown when the forward modal comment exceeds the message length limit. -#: src/features/messaging/components/modals/ForwardModal.tsx:54 +#: src/features/messaging/components/modals/ForwardModal.tsx:61 msgid "Shorten the message and try again." msgstr "請縮短訊息後再試一次。" @@ -31780,8 +31804,8 @@ msgstr "個人檔案載入緩慢" msgid "Slowmode" msgstr "慢速模式" -#. Short label in the settings dialog forward channel selection. Preserve {remaining}; it is inserted by code. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:37 +#. Short label under a destination row in the forward modal while slowmode blocks sending. Preserve {remaining}; it is inserted by code. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:82 msgid "Slowmode · wait {remaining}" msgstr "慢速模式 · 等待 {remaining}" @@ -34920,6 +34944,11 @@ msgstr "此成員已不在社群中。請重新整理並再試一次。" msgid "This member isn't connected to voice anymore." msgstr "此成員已不在語音連線中。" +#. Forward dialog error shown when the forwarded message contains age-restricted media and the target channel is not age-restricted. +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:77 +msgid "This message can only be forwarded to age-restricted channels" +msgstr "此訊息只能轉發至設有年齡限制的頻道" + #. IAR modal: tooltip on the delete card when the reported message is already deleted. #: src/features/moderation/components/report_modal/IARModalCopy.ts:117 msgid "This message has already been deleted." @@ -35351,7 +35380,7 @@ msgstr "時間戳記" #. Markdown alert label for a tip callout when copied as plaintext. #. Short label in the messaging block elements. Keep it concise. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:39 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:42 #: src/features/messaging/utils/markdown/Plaintext.ts:56 msgid "Tip" msgstr "提示" @@ -36521,7 +36550,7 @@ msgstr "不明實體" #. Fallback diagnostic text on the crash screen when an Error object has no message. #. Fallback error text shown when LaTeX rendering fails without an error message. #: src/features/app/components/ErrorFallback.tsx:25 -#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:34 +#: src/features/messaging/components/markdown/renderers/common/CodeElements.tsx:37 msgid "Unknown error" msgstr "不明錯誤" @@ -39056,12 +39085,12 @@ msgid "Waiting for passkey…" msgstr "正在等候通行金鑰…" #. Inline notice in the forward modal when slowmode is active in the selected target channel. forwardChannelDisplayName is the channel name. -#: src/features/messaging/components/modals/ForwardModal.tsx:70 +#: src/features/messaging/components/modals/ForwardModal.tsx:77 msgid "Waiting for slowmode in {forwardChannelDisplayName} to expire." msgstr "正在等待「{forwardChannelDisplayName}」的慢速模式結束。" #. Inline notice in the forward modal when slowmode is active in one or more selected target channels. -#: src/features/messaging/components/modals/ForwardModal.tsx:75 +#: src/features/messaging/components/modals/ForwardModal.tsx:82 msgid "Waiting for slowmode in one or more selected channels to expire." msgstr "正在等待一個或多個所選頻道的慢速模式結束。" @@ -39077,7 +39106,7 @@ msgstr "喚醒" #. Markdown alert label for a warning callout when copied as plaintext. #. Warning text in the messaging block elements. Keep the tone plain and specific. -#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:47 +#: src/features/messaging/components/markdown/renderers/common/BlockElements.tsx:50 #: src/features/messaging/utils/markdown/Plaintext.ts:64 msgid "Warning" msgstr "警告" @@ -40390,12 +40419,12 @@ msgid "You need access to your current email to change it from here. Use phone v msgstr "您需要存取目前的電子郵件,才能從這裡變更。如果可以,請使用電話驗證,或聯絡客服。" #. Forward dialog error shown when the forwarded message has attachments and the user lacks Attach Files in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:32 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:72 msgid "You need the \"{attachFilesPermissionLabel}\" permission to attach files in this channel" msgstr "您需要「{attachFilesPermissionLabel}」權限才能在此頻道中附加檔案" #. Forward dialog error shown when the forwarded message contains embeds and the user lacks Embed Links in the target channel. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:27 +#: src/features/app/components/dialogs/shared/UseForwardDestinations.ts:67 msgid "You need the \"{embedLinksPermissionLabel}\" permission to embed links in this channel" msgstr "您需要有「{embedLinksPermissionLabel}」權限才能在這個頻道中嵌入連結" @@ -40432,11 +40461,6 @@ msgstr "您需要「{permissionLabel}」權限才能在這裡使用來自其他 msgid "You need the \"{permissionLabel}\" permission to use stickers from other communities here." msgstr "您需要「{permissionLabel}」權限才能在這裡使用來自其他社群的貼圖。" -#. Forward dialog error shown when the user lacks the Send Messages permission in the target channel. Permission name is interpolated. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:22 -msgid "You need the \"{sendMessagesPermissionLabel}\" permission to send messages in this channel" -msgstr "您需要有「{sendMessagesPermissionLabel}」權限才能在此頻道中傳送訊息" - #: src/features/guild/components/modals/add_guild_modal/GuildCreateForm.tsx:208 #: src/features/guild/components/modals/add_guild_modal/TemplateImportForm.tsx:434 msgid "You need to claim your account before you can create a community." @@ -40679,11 +40703,6 @@ msgstr "您傳送訊息的速度太快了" msgid "You're streaming!" msgstr "您正在直播!" -#. Short label in the settings dialog forward channel selection. Keep the tone plain and specific. -#: src/features/app/components/dialogs/shared/ForwardChannelIndex.ts:18 -msgid "You're timed out in this community" -msgstr "您在此社群中被禁言" - #: src/features/channel/components/barriers/BarrierComponents.tsx:295 msgid "You're timed out. Messaging, reactions, and voice are paused until the timeout expires." msgstr "您已被禁言。在禁言結束前,訊息、反應和語音功能將會暫停。" diff --git a/fluxer_app/src/features/messaging/components/markdown/renderers/LinkRenderer.tsx b/fluxer_app/src/features/messaging/components/markdown/renderers/LinkRenderer.tsx index 06124e0d8..39c880d23 100644 --- a/fluxer_app/src/features/messaging/components/markdown/renderers/LinkRenderer.tsx +++ b/fluxer_app/src/features/messaging/components/markdown/renderers/LinkRenderer.tsx @@ -23,7 +23,7 @@ import * as InviteCommands from '@app/features/invite/commands/InviteCommands'; import * as InviteUtils from '@app/features/invite/utils/InviteUtils'; import jumpLinkStyles from '@app/features/messaging/components/markdown/renderers/MessageJumpLink.module.css'; import { - MarkdownContext, + isRestrictedInlineContext, type MarkdownRenderOptions, type RendererProps, } from '@app/features/messaging/components/markdown/renderers/RendererTypes'; @@ -647,7 +647,7 @@ export const LinkRenderer = observer(function LinkRenderer({ const jumpChannel = jumpTarget ? (Channels.getChannel(jumpTarget.channelId) ?? null) : null; const jumpGuild = jumpChannel?.guildId ? (Guilds.getGuild(jumpChannel.guildId) ?? null) : null; const settingsTarget = isAppProtocolUrl(url) ? parseUserSettingsDeepLink(url) : null; - const isInlineReplyContext = options.context === MarkdownContext.RESTRICTED_INLINE_REPLY; + const isInlineReplyContext = isRestrictedInlineContext(options.context); const shouldDisableInteractions = options.disableInteractions === true; if (inviteCode && StreamerMode.shouldHideInviteLinks) { return ( diff --git a/fluxer_app/src/features/messaging/components/markdown/renderers/RendererTypes.ts b/fluxer_app/src/features/messaging/components/markdown/renderers/RendererTypes.ts index 60512f9fe..b97f8d8e0 100644 --- a/fluxer_app/src/features/messaging/components/markdown/renderers/RendererTypes.ts +++ b/fluxer_app/src/features/messaging/components/markdown/renderers/RendererTypes.ts @@ -12,10 +12,15 @@ export const MarkdownContext = { RESTRICTED_USER_BIO: 2, RESTRICTED_EMBED_DESCRIPTION: 3, STANDARD_WITHOUT_JUMBO: 4, + RESTRICTED_INLINE_PREVIEW: 5, } as const; export type MarkdownContext = ValueOf; +export function isRestrictedInlineContext(context: MarkdownContext): boolean { + return context === MarkdownContext.RESTRICTED_INLINE_REPLY || context === MarkdownContext.RESTRICTED_INLINE_PREVIEW; +} + export interface MarkdownParseOptions { context: MarkdownContext; disableAnimatedEmoji?: boolean; diff --git a/fluxer_app/src/features/messaging/components/markdown/renderers/TextRenderer.tsx b/fluxer_app/src/features/messaging/components/markdown/renderers/TextRenderer.tsx index 7ec634847..390e84eb6 100644 --- a/fluxer_app/src/features/messaging/components/markdown/renderers/TextRenderer.tsx +++ b/fluxer_app/src/features/messaging/components/markdown/renderers/TextRenderer.tsx @@ -1,12 +1,15 @@ // SPDX-License-Identifier: AGPL-3.0-or-later -import {MarkdownContext, type RendererProps} from '@app/features/messaging/components/markdown/renderers/RendererTypes'; +import { + isRestrictedInlineContext, + type RendererProps, +} from '@app/features/messaging/components/markdown/renderers/RendererTypes'; import type {TextNode} from '@app/features/messaging/utils/markdown/parser/Nodes'; import type React from 'react'; export function TextRenderer({node, id, options}: RendererProps): React.ReactElement { let content = node.content; - if (options.context === MarkdownContext.RESTRICTED_INLINE_REPLY) { + if (isRestrictedInlineContext(options.context)) { content = content.replace(/\n/g, ' ').replace(/\s+/g, ' '); } return ( diff --git a/fluxer_app/src/features/messaging/components/markdown/renderers/common/BlockElements.tsx b/fluxer_app/src/features/messaging/components/markdown/renderers/common/BlockElements.tsx index d08365383..497d0f280 100644 --- a/fluxer_app/src/features/messaging/components/markdown/renderers/common/BlockElements.tsx +++ b/fluxer_app/src/features/messaging/components/markdown/renderers/common/BlockElements.tsx @@ -5,7 +5,10 @@ import { markdownBlockProps, markdownTableProps, } from '@app/features/messaging/components/markdown/renderers/common/MarkdownBlockAttributes'; -import {MarkdownContext, type RendererProps} from '@app/features/messaging/components/markdown/renderers/RendererTypes'; +import { + isRestrictedInlineContext, + type RendererProps, +} from '@app/features/messaging/components/markdown/renderers/RendererTypes'; import {renderTableNodeToMarkdown} from '@app/features/messaging/utils/markdown/Plaintext'; import {AlertType, TableAlignment} from '@app/features/messaging/utils/markdown/parser/Enums'; import type { @@ -94,7 +97,7 @@ export function BlockquoteRenderer({node, id, renderChildren}: RendererProps): React.ReactElement { const Tag = node.ordered ? 'ol' : 'ul'; - const isInlineContext = options.context === MarkdownContext.RESTRICTED_INLINE_REPLY; + const isInlineContext = isRestrictedInlineContext(options.context); if (!node.ordered) { return ( ): React.ReactElement { const Tag = `h${node.level}` as 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'; - const isInlineContext = options.context === MarkdownContext.RESTRICTED_INLINE_REPLY; + const isInlineContext = isRestrictedInlineContext(options.context); const headingRef = useRef(null); useEffect(() => { if (headingRef.current && !isInlineContext && node.level <= 3) { @@ -171,7 +174,7 @@ export function HeadingRenderer({node, id, renderChildren, options}: RendererPro } export function SubtextRenderer({node, id, renderChildren, options}: RendererProps): React.ReactElement { - const isInlineContext = options.context === MarkdownContext.RESTRICTED_INLINE_REPLY; + const isInlineContext = isRestrictedInlineContext(options.context); if (isInlineContext) { return {renderChildren(node.children)}; } diff --git a/fluxer_app/src/features/messaging/components/markdown/renderers/common/CodeElements.tsx b/fluxer_app/src/features/messaging/components/markdown/renderers/common/CodeElements.tsx index 62546213b..32bb81e28 100644 --- a/fluxer_app/src/features/messaging/components/markdown/renderers/common/CodeElements.tsx +++ b/fluxer_app/src/features/messaging/components/markdown/renderers/common/CodeElements.tsx @@ -11,7 +11,10 @@ import { MarkdownBlock, markdownBlockProps, } from '@app/features/messaging/components/markdown/renderers/common/MarkdownBlockAttributes'; -import {MarkdownContext, type RendererProps} from '@app/features/messaging/components/markdown/renderers/RendererTypes'; +import { + isRestrictedInlineContext, + type RendererProps, +} from '@app/features/messaging/components/markdown/renderers/RendererTypes'; import type {CodeBlockNode, InlineCodeNode} from '@app/features/messaging/utils/markdown/parser/Nodes'; import {Logger} from '@app/features/platform/utils/AppLogger'; import codeElementsStyles from '@app/features/theme/styles/CodeElements.module.css'; @@ -102,7 +105,7 @@ function shouldRenderKatexSource(content: string): boolean { export function CodeBlockRenderer({node, id, options}: RendererProps): React.ReactElement { const {content} = node; - if (options.context === MarkdownContext.RESTRICTED_INLINE_REPLY) { + if (isRestrictedInlineContext(options.context)) { return ( , options: MarkdownParseOptions): React } export function wrapRenderedContent(content: React.ReactNode, context: MarkdownContext): React.ReactNode { - if (context === MarkdownContext.RESTRICTED_INLINE_REPLY) { + if (isRestrictedInlineContext(context)) { return (
{content} diff --git a/fluxer_app/src/features/messaging/components/modals/ForwardMessagePreview.module.css b/fluxer_app/src/features/messaging/components/modals/ForwardMessagePreview.module.css new file mode 100644 index 000000000..b06ef8a01 --- /dev/null +++ b/fluxer_app/src/features/messaging/components/modals/ForwardMessagePreview.module.css @@ -0,0 +1,167 @@ +/* SPDX-License-Identifier: AGPL-3.0-or-later */ + +.preview { + position: relative; + display: flex; + align-items: center; + gap: 0.75rem; + padding-inline-start: 1rem; +} + +.preview::before { + content: ''; + position: absolute; + inset-block: 0; + inset-inline-start: 0; + width: 0.25rem; + border-radius: 0.125rem; + background-color: var(--background-modifier-accent); +} + +.content { + display: flex; + flex: 1; + flex-direction: column; + gap: 0.375rem; + min-width: 0; + padding: 0.25rem 0; +} + +.content .message { + --markup-restricted-inline-emoji-size: var(--message-line-height); + --markup-restricted-inline-emoji-baseline-shift: bottom; + display: -webkit-box; + overflow: hidden; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + text-overflow: ellipsis; + color: var(--text-primary); + font-size: 1rem; + line-height: var(--message-line-height); +} + +.content .messageWithAttachments { + -webkit-line-clamp: 1; +} + +.edited { + color: var(--text-tertiary); + font-size: var(--message-edited-label-font-size); + user-select: none; + -webkit-user-select: none; +} + +.attachmentRow { + display: flex; + flex-direction: row; + align-items: center; + gap: 0.375rem; + min-width: 0; +} + +.attachmentIcon { + flex-shrink: 0; + color: var(--text-tertiary); +} + +.attachmentSummary { + color: var(--text-tertiary); + font-size: 1rem; + font-weight: 500; + line-height: 1.25rem; +} + +.attachmentSummaryWithText { + font-size: 0.875rem; + line-height: 1.125rem; +} + +.thumbnailStack { + position: relative; + display: flex; + flex-shrink: 0; +} + +.thumbnail { + position: relative; + width: 3.5rem; + height: 3.5rem; + overflow: hidden; + border-radius: 0.5rem; +} + +.thumbnailImage { + display: block; + width: 100%; + height: 100%; + object-fit: cover; +} + +.thumbnailPlaceholder { + display: flex; + align-items: center; + justify-content: center; + background-color: var(--background-modifier-accent); +} + +.thumbnailPlaceholderIcon { + color: var(--text-tertiary); +} + +.thumbnailVideo { + background-color: #000; +} + +.thumbnailVideo .thumbnailImage { + opacity: 0.6; +} + +.thumbnailSensitive .thumbnailImage { + filter: blur(0.75rem); +} + +.thumbnailWithOverflow { + mask-image: + linear-gradient(#000, #000), + url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40'%3E%3Crect width='40' height='40' rx='12'/%3E%3C/svg%3E"); + mask-size: + 100% 100%, + 2.5rem 2.5rem; + mask-position: + 0 0, + right -0.75rem bottom -0.75rem; + mask-repeat: no-repeat; + mask-composite: exclude; +} + +:global([dir='rtl']) .thumbnailWithOverflow { + mask-position: + 0 0, + left -0.75rem bottom -0.75rem; +} + +.playIcon { + position: absolute; + inset: 0; + margin: auto; + color: var(--text-on-brand-primary); +} + +.overflowCount { + position: absolute; + bottom: 0; + inset-inline-end: 0; + display: flex; + align-items: center; + justify-content: center; + box-sizing: content-box; + min-width: 1rem; + height: 1rem; + padding: 0.25rem; + border-radius: 0.5rem; + background-color: var(--background-modifier-accent); + color: var(--text-primary); + font-size: 0.75rem; + font-weight: 600; + line-height: 1rem; +} diff --git a/fluxer_app/src/features/messaging/components/modals/ForwardMessagePreview.tsx b/fluxer_app/src/features/messaging/components/modals/ForwardMessagePreview.tsx new file mode 100644 index 000000000..3d586ea64 --- /dev/null +++ b/fluxer_app/src/features/messaging/components/modals/ForwardMessagePreview.tsx @@ -0,0 +1,245 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +import type {Channel} from '@app/features/channel/models/Channel'; +import type {ForwardMediaSelection} from '@app/features/messaging/commands/MessageCommands'; +import {SafeMarkdown} from '@app/features/messaging/components/markdown'; +import {MarkdownContext} from '@app/features/messaging/components/markdown/renderers/RendererTypes'; +import styles from '@app/features/messaging/components/modals/ForwardMessagePreview.module.css'; +import { + buildForwardMessagePreviewThumbnailURL, + type ForwardMessagePreviewAttachmentSummary, + type ForwardMessagePreviewThumbnail, + resolveForwardMessagePreviewContent, +} from '@app/features/messaging/components/modals/ForwardMessagePreviewContent'; +import type {Message} from '@app/features/messaging/models/MessagingMessage'; +import Permission from '@app/features/permissions/state/Permission'; +import {remFromPx} from '@app/features/theme/layout/RemFromPx'; +import markupStyles from '@app/features/theme/styles/Markup.module.css'; +import {Permissions} from '@fluxer/constants/src/ChannelConstants'; +import type {I18n} from '@lingui/core'; +import {msg} from '@lingui/core/macro'; +import {useLingui} from '@lingui/react/macro'; +import {type Icon, ImageIcon, ImagesIcon, PaperclipIcon, PlayCircleIcon} from '@phosphor-icons/react'; +import {clsx} from 'clsx'; +import {observer} from 'mobx-react-lite'; + +const EDITED_DESCRIPTOR = msg({ + message: '(edited)', + comment: 'Suffix after the message text in the forward modal preview when the forwarded message was edited.', +}); +const IMAGE_COUNT_DESCRIPTOR = msg({ + message: '{count, plural, one {# image} other {# images}}', + comment: + 'Attachment summary in the forward modal message preview when the message has images and no videos. count is the number of images.', +}); +const VIDEO_COUNT_DESCRIPTOR = msg({ + message: '{count, plural, one {# video} other {# videos}}', + comment: + 'Attachment summary in the forward modal message preview when the message has videos and no images. count is the number of videos.', +}); +const FILE_COUNT_DESCRIPTOR = msg({ + message: '{count, plural, one {# file} other {# files}}', + comment: + 'Attachment summary in the forward modal message preview when the message has no images or videos. count is the number of attached files.', +}); +const IMAGE_AND_VIDEO_COUNT_DESCRIPTOR = msg({ + message: '{imageCount, plural, one {# image} other {# images}}, {videoCount, plural, one {# video} other {# videos}}', + comment: + 'Attachment summary in the forward modal message preview when the message has both images and videos. imageCount and videoCount are the number of each.', +}); +const MORE_ATTACHMENTS_COUNT_DESCRIPTOR = msg({ + message: '+{count}', + comment: + 'Badge on the forward modal preview thumbnail. count is the number of other attachments that the thumbnail does not show.', +}); + +const ATTACHMENT_ICON_SIZE_WITH_TEXT = 18; +const ATTACHMENT_ICON_SIZE = 20; +const PLAY_ICON_SIZE = 24; +const PLACEHOLDER_ICON_SIZE = 24; + +interface ForwardMessagePreviewProps { + readonly message: Message; + readonly mediaSelection?: ForwardMediaSelection; + readonly embedChannel: Channel | null; +} + +interface ForwardMessagePreviewAttachmentRowProps { + readonly summary: ForwardMessagePreviewAttachmentSummary; + readonly hasText: boolean; +} + +interface ForwardMessagePreviewThumbnailFrameProps { + readonly thumbnail: ForwardMessagePreviewThumbnail; + readonly overflowCount: number; +} + +function canEmbedLinksIn(channel: Channel | null): boolean { + if (channel == null) return true; + if (channel.isPrivate()) return true; + return Permission.can(Permissions.EMBED_LINKS, channel); +} + +function formatAttachmentSummary(i18n: I18n, summary: ForwardMessagePreviewAttachmentSummary): string { + switch (summary.kind) { + case 'images_and_videos': + return i18n._(IMAGE_AND_VIDEO_COUNT_DESCRIPTOR, { + imageCount: summary.imageCount, + videoCount: summary.videoCount, + }); + case 'videos': + return i18n._(VIDEO_COUNT_DESCRIPTOR, {count: summary.count}); + case 'images': + return i18n._(IMAGE_COUNT_DESCRIPTOR, {count: summary.count}); + case 'files': + return i18n._(FILE_COUNT_DESCRIPTOR, {count: summary.count}); + } +} + +function resolveAttachmentSummaryIcon(summary: ForwardMessagePreviewAttachmentSummary): Icon { + switch (summary.kind) { + case 'images_and_videos': + return ImagesIcon; + case 'videos': + return PlayCircleIcon; + case 'images': + return summary.count === 1 ? ImageIcon : ImagesIcon; + case 'files': + return PaperclipIcon; + } +} + +function ForwardMessagePreviewAttachmentRow({summary, hasText}: ForwardMessagePreviewAttachmentRowProps) { + const {i18n} = useLingui(); + const SummaryIcon = resolveAttachmentSummaryIcon(summary); + return ( +
+ + + {formatAttachmentSummary(i18n, summary)} + +
+ ); +} + +function ForwardMessagePreviewThumbnailFrame({thumbnail, overflowCount}: ForwardMessagePreviewThumbnailFrameProps) { + const {i18n} = useLingui(); + const hasOverflow = overflowCount > 0; + return ( +
+
+ {thumbnail.showsFilePlaceholder ? ( + + ) : ( + + )} + {thumbnail.showsPlayIcon && ( + + )} +
+ {hasOverflow && ( + + {i18n._(MORE_ATTACHMENTS_COUNT_DESCRIPTOR, {count: overflowCount})} + + )} +
+ ); +} + +export const ForwardMessagePreview = observer(({message, mediaSelection, embedChannel}: ForwardMessagePreviewProps) => { + const {i18n} = useLingui(); + const preview = resolveForwardMessagePreviewContent({ + message, + mediaSelection, + canEmbedLinks: canEmbedLinksIn(embedChannel), + }); + const hasAttachments = preview.attachmentSummary != null; + return ( +
+
+ {preview.text != null && ( +
+ + {preview.isEdited && ( + + {' '} + {i18n._(EDITED_DESCRIPTOR)} + + )} +
+ )} + {preview.attachmentSummary != null && ( + + )} +
+ {preview.thumbnail != null && ( + + )} +
+ ); +}); diff --git a/fluxer_app/src/features/messaging/components/modals/ForwardMessagePreviewContent.test.ts b/fluxer_app/src/features/messaging/components/modals/ForwardMessagePreviewContent.test.ts new file mode 100644 index 000000000..d4e18f33f --- /dev/null +++ b/fluxer_app/src/features/messaging/components/modals/ForwardMessagePreviewContent.test.ts @@ -0,0 +1,350 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +import { + buildForwardMessagePreviewThumbnailURL, + type ForwardMessagePreviewMessage, + type ForwardMessagePreviewThumbnail, + resolveForwardMessagePreviewContent, +} from '@app/features/messaging/components/modals/ForwardMessagePreviewContent'; +import {EmbedMediaFlags, MessageAttachmentFlags, MessageTypes} from '@fluxer/constants/src/ChannelConstants'; +import type {MessageEmbed} from '@fluxer/schema/src/domains/message/EmbedSchemas'; +import type {MessageAttachment, MessageSnapshot} from '@fluxer/schema/src/domains/message/MessageResponseSchemas'; +import {describe, expect, it} from 'vitest'; + +function attachment(id: string, overrides: Partial = {}): MessageAttachment { + return { + id, + filename: `${id}.bin`, + size: 1024, + url: `https://cdn.example.com/attachments/${id}`, + proxy_url: `https://media.example.com/attachments/${id}`, + flags: 0, + ...overrides, + }; +} + +function image(id: string, overrides: Partial = {}): MessageAttachment { + return attachment(id, {content_type: 'image/png', width: 800, height: 600, ...overrides}); +} + +function video(id: string, overrides: Partial = {}): MessageAttachment { + return attachment(id, {content_type: 'video/mp4', width: 1920, height: 1080, ...overrides}); +} + +function file(id: string): MessageAttachment { + return attachment(id, {content_type: 'application/pdf'}); +} + +function embed(overrides: Partial = {}): MessageEmbed { + return {type: 'link', ...overrides}; +} + +function snapshot(overrides: Partial = {}): MessageSnapshot { + return {type: MessageTypes.DEFAULT, content: '', timestamp: '2026-09-01T12:00:00.000Z', ...overrides}; +} + +function message(overrides: Partial = {}): ForwardMessagePreviewMessage { + return { + attachments: [], + content: '', + editedTimestamp: null, + embeds: [], + mentionChannels: [], + messageSnapshots: undefined, + ...overrides, + }; +} + +function thumbnail(overrides: Partial = {}): ForwardMessagePreviewThumbnail { + return { + proxyUrl: 'https://media.example.com/attachments/a', + isVideo: false, + showsPlayIcon: false, + showsFilePlaceholder: false, + isSensitive: false, + width: null, + height: null, + ...overrides, + }; +} + +function searchParams(url: string): Record { + return Object.fromEntries(new URL(url).searchParams.entries()); +} + +describe('forward message preview content', () => { + it('previews plain message text with no attachment row or thumbnail', () => { + const preview = resolveForwardMessagePreviewContent({ + message: message({content: 'Lunch at noon?'}), + mediaSelection: undefined, + canEmbedLinks: true, + }); + expect(preview.text).toBe('Lunch at noon?'); + expect(preview.isEdited).toBe(false); + expect(preview.attachmentSummary).toBeNull(); + expect(preview.thumbnail).toBeNull(); + expect(preview.overflowCount).toBe(0); + }); + + it('previews the first snapshot of a forwarded message', () => { + const preview = resolveForwardMessagePreviewContent({ + message: message({ + messageSnapshots: [ + snapshot({content: 'Original words', attachments: [image('a')]}), + snapshot({content: 'Second snapshot'}), + ], + }), + mediaSelection: undefined, + canEmbedLinks: true, + }); + expect(preview.text).toBe('Original words'); + expect(preview.attachmentSummary).toEqual({kind: 'images', count: 1}); + expect(preview.thumbnail?.proxyUrl).toBe('https://media.example.com/attachments/a'); + }); + + it('marks the preview edited only when the forwarded message itself has text it edited', () => { + const editedMessage = resolveForwardMessagePreviewContent({ + message: message({content: 'Fixed typo', editedTimestamp: new Date('2026-09-02T08:00:00.000Z')}), + mediaSelection: undefined, + canEmbedLinks: true, + }); + expect(editedMessage.isEdited).toBe(true); + const editedWithoutContent = resolveForwardMessagePreviewContent({ + message: message({ + editedTimestamp: new Date('2026-09-02T08:00:00.000Z'), + embeds: [embed({url: 'https://example.com/a'})], + }), + mediaSelection: undefined, + canEmbedLinks: true, + }); + expect(editedWithoutContent.isEdited).toBe(false); + const forwardOfEditedMessage = resolveForwardMessagePreviewContent({ + message: message({ + messageSnapshots: [snapshot({content: 'Edited', edited_timestamp: '2026-09-02T08:00:00.000Z'})], + }), + mediaSelection: undefined, + canEmbedLinks: true, + }); + expect(forwardOfEditedMessage.isEdited).toBe(false); + }); + + it('keeps only the selected attachments and hides the text for an attachment selection', () => { + const preview = resolveForwardMessagePreviewContent({ + message: message({ + content: 'Holiday photos', + attachments: [image('a'), image('b'), image('c')], + embeds: [ + embed({ + url: 'https://example.com/trip', + thumbnail: {url: 'x', proxy_url: 'https://media.example.com/x', flags: 0}, + }), + ], + }), + mediaSelection: {attachmentIds: ['b']}, + canEmbedLinks: true, + }); + expect(preview.text).toBeNull(); + expect(preview.attachmentSummary).toEqual({kind: 'images', count: 1}); + expect(preview.thumbnail?.proxyUrl).toBe('https://media.example.com/attachments/b'); + expect(preview.overflowCount).toBe(0); + }); + + it('previews the selected embed urls for an embed selection', () => { + const preview = resolveForwardMessagePreviewContent({ + message: message({ + content: 'Two links', + attachments: [image('a')], + embeds: [ + embed({url: 'https://example.com/first'}), + embed({ + url: 'https://example.com/second', + thumbnail: {url: 'x', proxy_url: 'https://media.example.com/second-thumb', flags: 0}, + }), + ], + }), + mediaSelection: {embedIndices: [1]}, + canEmbedLinks: true, + }); + expect(preview.text).toBe('https://example.com/second'); + expect(preview.attachmentSummary).toBeNull(); + expect(preview.thumbnail?.proxyUrl).toBe('https://media.example.com/second-thumb'); + expect(preview.overflowCount).toBe(0); + }); + + it('falls back to the embed urls when the source has no text', () => { + const preview = resolveForwardMessagePreviewContent({ + message: message({embeds: [embed({url: 'https://example.com/a'}), embed({url: 'https://example.com/b'})]}), + mediaSelection: undefined, + canEmbedLinks: true, + }); + expect(preview.text).toBe('https://example.com/a\nhttps://example.com/b'); + }); + + it('falls back to the first embed description when no embed has a url', () => { + const preview = resolveForwardMessagePreviewContent({ + message: message({embeds: [embed({type: 'rich', description: 'Weekly notes'})]}), + mediaSelection: undefined, + canEmbedLinks: true, + }); + expect(preview.text).toBe('Weekly notes'); + }); + + it('drops embeds when the destination cannot embed links and the message has content', () => { + const linkEmbed = embed({ + url: 'https://example.com/a', + thumbnail: {url: 'x', proxy_url: 'https://media.example.com/a-thumb', flags: 0}, + }); + const withContent = resolveForwardMessagePreviewContent({ + message: message({content: 'See https://example.com/a', embeds: [linkEmbed]}), + mediaSelection: undefined, + canEmbedLinks: false, + }); + expect(withContent.text).toBe('See https://example.com/a'); + expect(withContent.thumbnail).toBeNull(); + const withoutContent = resolveForwardMessagePreviewContent({ + message: message({embeds: [linkEmbed]}), + mediaSelection: undefined, + canEmbedLinks: false, + }); + expect(withoutContent.text).toBe('https://example.com/a'); + expect(withoutContent.thumbnail?.proxyUrl).toBe('https://media.example.com/a-thumb'); + }); +}); + +describe('forward message preview attachment summary', () => { + function summarize(attachments: ReadonlyArray) { + return resolveForwardMessagePreviewContent({ + message: message({attachments}), + mediaSelection: undefined, + canEmbedLinks: true, + }).attachmentSummary; + } + + it('counts images and videos together when both are present', () => { + expect(summarize([image('a'), video('b'), image('c'), file('d')])).toEqual({ + kind: 'images_and_videos', + imageCount: 2, + videoCount: 1, + }); + }); + + it('counts only the videos when there are no images', () => { + expect(summarize([video('a'), file('b')])).toEqual({kind: 'videos', count: 1}); + }); + + it('counts only the images when there are no videos', () => { + expect(summarize([image('a'), image('b'), file('c')])).toEqual({kind: 'images', count: 2}); + }); + + it('counts every attachment as a file when none is a displayable image or video', () => { + expect(summarize([file('a'), file('b'), image('c', {width: undefined, height: undefined})])).toEqual({ + kind: 'files', + count: 3, + }); + }); +}); + +describe('forward message preview thumbnail', () => { + function preview(attachments: ReadonlyArray, embeds: ReadonlyArray = []) { + return resolveForwardMessagePreviewContent({ + message: message({attachments, embeds}), + mediaSelection: undefined, + canEmbedLinks: true, + }); + } + + it('shows a playable still frame when every attachment is a video', () => { + const result = preview([video('a'), video('b')]); + expect(result.thumbnail).toMatchObject({ + proxyUrl: 'https://media.example.com/attachments/a', + isVideo: true, + showsPlayIcon: true, + width: 1920, + height: 1080, + }); + expect(result.overflowCount).toBe(1); + }); + + it('shows the first attachment without a play icon when the attachments are mixed', () => { + const result = preview([video('a'), image('b'), file('c')]); + expect(result.thumbnail).toMatchObject({isVideo: true, showsPlayIcon: false}); + expect(result.overflowCount).toBe(2); + }); + + it('keeps the box and the overflow badge when the first attachment is not displayable media', () => { + const result = preview([file('a'), image('b')]); + expect(result.thumbnail).toMatchObject({ + proxyUrl: 'https://media.example.com/attachments/a', + showsFilePlaceholder: true, + isVideo: false, + showsPlayIcon: false, + }); + expect(result.overflowCount).toBe(1); + const unsized = preview([image('a', {width: undefined, height: undefined}), image('b')]); + expect(unsized.thumbnail).toMatchObject({showsFilePlaceholder: true}); + expect(unsized.overflowCount).toBe(1); + }); + + it('uses only the first embed thumbnail when there are no attachments', () => { + const result = preview( + [], + [ + embed({url: 'https://example.com/a'}), + embed({ + url: 'https://example.com/b', + thumbnail: {url: 'x', proxy_url: 'https://media.example.com/b', flags: 0}, + }), + ], + ); + expect(result.thumbnail).toBeNull(); + const withThumbnail = preview( + [], + [ + embed({ + url: 'https://example.com/a', + thumbnail: {url: 'x', proxy_url: 'https://media.example.com/a', flags: 0}, + }), + ], + ); + expect(withThumbnail.thumbnail).toMatchObject({proxyUrl: 'https://media.example.com/a', isVideo: false}); + }); + + it('marks spoiler and explicit media as sensitive', () => { + expect(preview([image('a', {flags: MessageAttachmentFlags.IS_SPOILER})]).thumbnail?.isSensitive).toBe(true); + expect(preview([image('a', {flags: MessageAttachmentFlags.CONTAINS_EXPLICIT_MEDIA})]).thumbnail?.isSensitive).toBe( + true, + ); + expect(preview([image('a', {nsfw: true})]).thumbnail?.isSensitive).toBe(true); + expect(preview([image('a')]).thumbnail?.isSensitive).toBe(false); + const explicitEmbed = embed({ + thumbnail: {url: 'x', proxy_url: 'https://media.example.com/x', flags: EmbedMediaFlags.CONTAINS_EXPLICIT_MEDIA}, + }); + expect(preview([], [explicitEmbed]).thumbnail?.isSensitive).toBe(true); + }); +}); + +describe('forward message preview thumbnail url', () => { + it('requests a square webp crop for images', () => { + const url = buildForwardMessagePreviewThumbnailURL(thumbnail()); + expect(searchParams(url)).toEqual({format: 'webp', width: '56', height: '56'}); + }); + + it('requests a still frame wide enough to cover the square for landscape video', () => { + const url = buildForwardMessagePreviewThumbnailURL(thumbnail({isVideo: true, width: 1920, height: 1080})); + expect(searchParams(url)).toEqual({format: 'webp', width: '100'}); + }); + + it('requests a still frame at the square width for portrait or unsized video', () => { + const portrait = buildForwardMessagePreviewThumbnailURL(thumbnail({isVideo: true, width: 1080, height: 1920})); + expect(searchParams(portrait)).toEqual({format: 'webp', width: '56'}); + const unsized = buildForwardMessagePreviewThumbnailURL(thumbnail({isVideo: true})); + expect(searchParams(unsized)).toEqual({format: 'webp', width: '56'}); + }); + + it('replaces media params already on the proxy url and keeps the rest', () => { + const url = buildForwardMessagePreviewThumbnailURL( + thumbnail({proxyUrl: 'https://media.example.com/attachments/a?ex=abc&width=10&format=png&animated=true'}), + ); + expect(searchParams(url)).toEqual({ex: 'abc', format: 'webp', width: '56', height: '56'}); + }); +}); diff --git a/fluxer_app/src/features/messaging/components/modals/ForwardMessagePreviewContent.ts b/fluxer_app/src/features/messaging/components/modals/ForwardMessagePreviewContent.ts new file mode 100644 index 000000000..4d61ba499 --- /dev/null +++ b/fluxer_app/src/features/messaging/components/modals/ForwardMessagePreviewContent.ts @@ -0,0 +1,271 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +import {isMediaAttachment} from '@app/features/channel/components/MessageAttachmentUtils'; +import type {ForwardMediaSelection} from '@app/features/messaging/commands/MessageCommands'; +import type {Message} from '@app/features/messaging/models/MessagingMessage'; +import { + buildMediaProxyURL, + snapMediaProxyImageSize, + stripMediaProxyParams, +} from '@app/features/messaging/utils/MediaProxyUtils'; +import {EmbedMediaFlags, MessageAttachmentFlags} from '@fluxer/constants/src/ChannelConstants'; +import type {MessageEmbed} from '@fluxer/schema/src/domains/message/EmbedSchemas'; +import type { + ChannelMention, + MessageAttachment, + MessageSnapshot, +} from '@fluxer/schema/src/domains/message/MessageResponseSchemas'; + +const FORWARD_MESSAGE_PREVIEW_THUMBNAIL_SIZE = 56; + +export type ForwardMessagePreviewMessage = Pick< + Message, + 'attachments' | 'content' | 'editedTimestamp' | 'embeds' | 'mentionChannels' | 'messageSnapshots' +>; + +export type ForwardMessagePreviewAttachmentSummary = + | {readonly kind: 'images_and_videos'; readonly imageCount: number; readonly videoCount: number} + | {readonly kind: 'videos'; readonly count: number} + | {readonly kind: 'images'; readonly count: number} + | {readonly kind: 'files'; readonly count: number}; + +export interface ForwardMessagePreviewThumbnail { + readonly proxyUrl: string; + readonly isVideo: boolean; + readonly showsPlayIcon: boolean; + readonly showsFilePlaceholder: boolean; + readonly isSensitive: boolean; + readonly width: number | null; + readonly height: number | null; +} + +export interface ForwardMessagePreviewContent { + readonly text: string | null; + readonly isEdited: boolean; + readonly mentionChannels: ReadonlyArray | undefined; + readonly attachmentSummary: ForwardMessagePreviewAttachmentSummary | null; + readonly thumbnail: ForwardMessagePreviewThumbnail | null; + readonly overflowCount: number; +} + +interface ResolveForwardMessagePreviewContentRequest { + readonly message: ForwardMessagePreviewMessage; + readonly mediaSelection: ForwardMediaSelection | undefined; + readonly canEmbedLinks: boolean; +} + +interface ForwardMessagePreviewSource { + readonly content: string; + readonly attachments: ReadonlyArray; + readonly embeds: ReadonlyArray; + readonly mentionChannels: ReadonlyArray | undefined; +} + +interface VisualAttachmentCounts { + readonly imageCount: number; + readonly videoCount: number; +} + +type PreviewAttachmentKind = 'image' | 'video' | 'file'; + +const EMPTY_ATTACHMENTS: ReadonlyArray = Object.freeze([]); +const EMPTY_EMBEDS: ReadonlyArray = Object.freeze([]); + +function readSnapshotContent(snapshot: MessageSnapshot): string { + if (snapshot.content == null) return ''; + return snapshot.content; +} + +function readSnapshotAttachments(snapshot: MessageSnapshot): ReadonlyArray { + if (snapshot.attachments == null) return EMPTY_ATTACHMENTS; + return snapshot.attachments; +} + +function resolvePreviewSource(message: ForwardMessagePreviewMessage): ForwardMessagePreviewSource { + const snapshot = message.messageSnapshots?.[0]; + if (snapshot == null) { + return { + content: message.content, + attachments: message.attachments, + embeds: message.embeds, + mentionChannels: message.mentionChannels, + }; + } + let embeds = EMPTY_EMBEDS; + if (snapshot.embeds != null) embeds = snapshot.embeds; + return { + content: readSnapshotContent(snapshot), + attachments: readSnapshotAttachments(snapshot), + embeds, + mentionChannels: snapshot.mention_channels, + }; +} + +function messageHasForwardableContent(message: ForwardMessagePreviewMessage): boolean { + if (message.content !== '') return true; + const snapshots = message.messageSnapshots; + if (snapshots == null) return false; + return snapshots.some( + (snapshot) => readSnapshotContent(snapshot) !== '' || readSnapshotAttachments(snapshot).length > 0, + ); +} + +function selectPreviewAttachments( + attachments: ReadonlyArray, + mediaSelection: ForwardMediaSelection | undefined, +): ReadonlyArray { + if (mediaSelection === undefined) return attachments; + const {attachmentIds, embedIndices} = mediaSelection; + if (attachmentIds !== undefined) return attachments.filter((attachment) => attachmentIds.includes(attachment.id)); + if (embedIndices !== undefined) return EMPTY_ATTACHMENTS; + return attachments; +} + +function selectPreviewEmbeds( + embeds: ReadonlyArray, + mediaSelection: ForwardMediaSelection | undefined, +): ReadonlyArray { + if (mediaSelection === undefined) return embeds; + const {attachmentIds, embedIndices} = mediaSelection; + if (embedIndices !== undefined) return embeds.filter((_embed, index) => embedIndices.includes(index)); + if (attachmentIds !== undefined) return EMPTY_EMBEDS; + return embeds; +} + +function resolvePreviewText( + source: ForwardMessagePreviewSource, + embeds: ReadonlyArray, + mediaSelection: ForwardMediaSelection | undefined, +): string { + let text = source.content; + const hasEmbedSelection = mediaSelection !== undefined && mediaSelection.embedIndices !== undefined; + if (hasEmbedSelection || (text === '' && embeds.length > 0)) { + text = embeds.map((embed) => embed.url ?? '').join('\n'); + } + if (text !== '') return text; + const firstEmbed = source.embeds[0]; + if (firstEmbed == null || firstEmbed.description == null) return text; + return firstEmbed.description; +} + +function classifyPreviewAttachment(attachment: MessageAttachment): PreviewAttachmentKind { + if (!isMediaAttachment(attachment)) return 'file'; + if (attachment.content_type?.startsWith('video/') === true) return 'video'; + return 'image'; +} + +function countVisualAttachments(attachments: ReadonlyArray): VisualAttachmentCounts { + let imageCount = 0; + let videoCount = 0; + for (const attachment of attachments) { + const kind = classifyPreviewAttachment(attachment); + if (kind === 'image') imageCount += 1; + if (kind === 'video') videoCount += 1; + } + return {imageCount, videoCount}; +} + +function summarizePreviewAttachments( + attachments: ReadonlyArray, + {imageCount, videoCount}: VisualAttachmentCounts, +): ForwardMessagePreviewAttachmentSummary | null { + if (attachments.length === 0) return null; + if (imageCount > 0 && videoCount > 0) return Object.freeze({kind: 'images_and_videos', imageCount, videoCount}); + if (videoCount > 0) return Object.freeze({kind: 'videos', count: videoCount}); + if (imageCount > 0) return Object.freeze({kind: 'images', count: imageCount}); + return Object.freeze({kind: 'files', count: attachments.length}); +} + +function isSensitiveAttachment(attachment: MessageAttachment): boolean { + if (attachment.nsfw === true) return true; + const sensitiveFlags = MessageAttachmentFlags.IS_SPOILER | MessageAttachmentFlags.CONTAINS_EXPLICIT_MEDIA; + return (attachment.flags & sensitiveFlags) !== 0; +} + +function resolveAttachmentThumbnail( + attachment: MessageAttachment, + showsPlayIcon: boolean, +): ForwardMessagePreviewThumbnail | null { + const kind = classifyPreviewAttachment(attachment); + const proxyUrl = attachment.proxy_url ?? attachment.url; + if (proxyUrl == null) return null; + return Object.freeze({ + proxyUrl, + isVideo: kind === 'video', + showsPlayIcon, + showsFilePlaceholder: kind === 'file', + isSensitive: isSensitiveAttachment(attachment), + width: attachment.width ?? null, + height: attachment.height ?? null, + }); +} + +function resolveEmbedThumbnail(embed: MessageEmbed | undefined): ForwardMessagePreviewThumbnail | null { + if (embed == null || embed.thumbnail == null) return null; + const {thumbnail} = embed; + if (thumbnail.proxy_url == null) return null; + const isSensitive = + embed.nsfw === true || thumbnail.nsfw === true || (thumbnail.flags & EmbedMediaFlags.CONTAINS_EXPLICIT_MEDIA) !== 0; + return Object.freeze({ + proxyUrl: thumbnail.proxy_url, + isVideo: false, + showsPlayIcon: false, + showsFilePlaceholder: false, + isSensitive, + width: thumbnail.width ?? null, + height: thumbnail.height ?? null, + }); +} + +function resolvePreviewThumbnail( + attachments: ReadonlyArray, + embeds: ReadonlyArray, + {videoCount}: VisualAttachmentCounts, +): ForwardMessagePreviewThumbnail | null { + const firstAttachment = attachments[0]; + if (firstAttachment == null) return resolveEmbedThumbnail(embeds[0]); + const everyAttachmentIsVideo = videoCount > 0 && videoCount === attachments.length; + return resolveAttachmentThumbnail(firstAttachment, everyAttachmentIsVideo); +} + +export function resolveForwardMessagePreviewContent({ + message, + mediaSelection, + canEmbedLinks, +}: ResolveForwardMessagePreviewContentRequest): ForwardMessagePreviewContent { + const source = resolvePreviewSource(message); + const attachments = selectPreviewAttachments(source.attachments, mediaSelection); + let embeds = EMPTY_EMBEDS; + if (canEmbedLinks || !messageHasForwardableContent(message)) { + embeds = selectPreviewEmbeds(source.embeds, mediaSelection); + } + const text = resolvePreviewText(source, embeds, mediaSelection); + const hasAttachmentSelection = mediaSelection !== undefined && mediaSelection.attachmentIds !== undefined; + const counts = countVisualAttachments(attachments); + const thumbnail = resolvePreviewThumbnail(attachments, embeds, counts); + let overflowCount = 0; + if (thumbnail != null && attachments.length > 1) overflowCount = attachments.length - 1; + return Object.freeze({ + text: text !== '' && !hasAttachmentSelection ? text : null, + isEdited: message.content !== '' && message.editedTimestamp != null, + mentionChannels: source.mentionChannels, + attachmentSummary: summarizePreviewAttachments(attachments, counts), + thumbnail, + overflowCount, + }); +} + +function resolveCoverWidthScale({width, height}: ForwardMessagePreviewThumbnail): number { + if (width == null || height == null || width <= 0 || height <= 0) return 1; + return Math.max(1, width / height); +} + +export function buildForwardMessagePreviewThumbnailURL(thumbnail: ForwardMessagePreviewThumbnail): string { + const sourceUrl = stripMediaProxyParams(thumbnail.proxyUrl); + if (!thumbnail.isVideo) { + const size = snapMediaProxyImageSize(FORWARD_MESSAGE_PREVIEW_THUMBNAIL_SIZE); + return buildMediaProxyURL(sourceUrl, {format: 'webp', width: size, height: size}); + } + const width = snapMediaProxyImageSize(FORWARD_MESSAGE_PREVIEW_THUMBNAIL_SIZE * resolveCoverWidthScale(thumbnail)); + return buildMediaProxyURL(sourceUrl, {format: 'webp', width}); +} diff --git a/fluxer_app/src/features/messaging/components/modals/ForwardModal.module.css b/fluxer_app/src/features/messaging/components/modals/ForwardModal.module.css index 79a170b1d..0148d6d8b 100644 --- a/fluxer_app/src/features/messaging/components/modals/ForwardModal.module.css +++ b/fluxer_app/src/features/messaging/components/modals/ForwardModal.module.css @@ -21,11 +21,23 @@ caret-color: var(--text-chat); } -.inputAreaContainer { +.destinationList { + display: flex; + flex-direction: column; + height: clamp(20rem, 48vh, 23.75rem); + min-height: 0; + max-height: clamp(20rem, 48vh, 23.75rem); +} + +.footerSection { position: relative; + display: flex; + flex-direction: column; + gap: 0.75rem; width: 100%; flex-shrink: 0; padding: 0.75rem 1rem; + border-top: 0.0625rem solid var(--background-modifier-accent); } .messageInputContainer { diff --git a/fluxer_app/src/features/messaging/components/modals/ForwardModal.tsx b/fluxer_app/src/features/messaging/components/modals/ForwardModal.tsx index 8c66be64f..9384cdecd 100644 --- a/fluxer_app/src/features/messaging/components/modals/ForwardModal.tsx +++ b/fluxer_app/src/features/messaging/components/modals/ForwardModal.tsx @@ -1,9 +1,13 @@ // SPDX-License-Identifier: AGPL-3.0-or-later import * as Modal from '@app/features/app/components/dialogs/Modal'; -import type {ForwardChannelOption} from '@app/features/app/components/dialogs/shared/ForwardChannelIndex'; -import {useForwardChannelSelection} from '@app/features/app/components/dialogs/shared/ForwardChannelSelection'; +import type {ForwardDestination} from '@app/features/app/components/dialogs/shared/ForwardDefaultDestinations'; +import {MAX_FORWARD_DESTINATIONS} from '@app/features/app/components/dialogs/shared/ForwardDestinationSelection'; import selectorStyles from '@app/features/app/components/dialogs/shared/SelectorModalStyles.module.css'; +import { + type ForwardDestinationOption, + useForwardDestinations, +} from '@app/features/app/components/dialogs/shared/UseForwardDestinations'; import {GroupDMAvatar} from '@app/features/app/components/shared/GroupDMAvatar'; import {Limits} from '@app/features/app/utils/UserLimits'; import * as PrivateChannelCommands from '@app/features/channel/commands/PrivateChannelCommands'; @@ -18,6 +22,7 @@ import {LexicalRichInput, type LexicalRichInputHandle} from '@app/features/lexic import * as MessageCommands from '@app/features/messaging/commands/MessageCommands'; import {MessageForwardFailedModal} from '@app/features/messaging/components/alerts/MessageForwardFailedModal'; import {showMessagingErrorModal} from '@app/features/messaging/components/alerts/MessagingErrorModalUtils'; +import {ForwardMessagePreview} from '@app/features/messaging/components/modals/ForwardMessagePreview'; import modalStyles from '@app/features/messaging/components/modals/ForwardModal.module.css'; import {shouldNavigateAfterForward} from '@app/features/messaging/components/modals/ForwardModalUtils'; import type {Message} from '@app/features/messaging/models/MessagingMessage'; @@ -25,6 +30,7 @@ import {focusChannelTextareaAfterNavigation} from '@app/features/messaging/utils import type {MentionSegment} from '@app/features/messaging/utils/TextareaSegmentManager'; import * as NavigationCommands from '@app/features/navigation/commands/NavigationCommands'; import {Logger} from '@app/features/platform/utils/AppLogger'; +import {shouldDisableAutofocusOnMobile} from '@app/features/platform/utils/AutofocusUtils'; import {remFromPx} from '@app/features/theme/layout/RemFromPx'; import {Button} from '@app/features/ui/button/Button'; import {Checkbox} from '@app/features/ui/checkbox/Checkbox'; @@ -38,15 +44,15 @@ import FocusRing from '@app/features/ui/focus_ring/FocusRing'; import {Popout} from '@app/features/ui/popover/PopoverPopout'; import MobileLayout from '@app/features/ui/state/MobileLayout'; import type {User} from '@app/features/user/models/User'; -import Users from '@app/features/user/state/Users'; import {ChannelTypes} from '@fluxer/constants/src/ChannelConstants'; import {MAX_MESSAGE_LENGTH_PREMIUM} from '@fluxer/constants/src/LimitConstants'; +import type {I18n} from '@lingui/core'; import {msg} from '@lingui/core/macro'; import {Trans, useLingui} from '@lingui/react/macro'; import {HashIcon, MagnifyingGlassIcon, NotePencilIcon, SmileyIcon, SpeakerHighIcon} from '@phosphor-icons/react'; import {clsx} from 'clsx'; import {observer} from 'mobx-react-lite'; -import {type MouseEvent, useCallback, useId, useMemo, useRef, useState} from 'react'; +import {type MouseEvent, useCallback, useEffect, useId, useRef, useState} from 'react'; const MESSAGE_IS_TOO_LONG_DESCRIPTOR = msg({ message: 'Message is too long', @@ -81,9 +87,10 @@ const FORWARD_MESSAGE_DESCRIPTOR = msg({ message: 'Forward message', comment: 'Title of the forward message modal.', }); -const SEARCH_CHANNELS_OR_DMS_DESCRIPTOR = msg({ - message: 'Search channels or DMs', - comment: 'Placeholder text in the channel picker search input of the forward modal.', +const SEARCH_DESCRIPTOR = msg({ + message: 'Search', + comment: + 'Placeholder and accessible label of the search input in the forward modal. It finds people, channels and group DMs to forward to.', }); const COMMENTS_ARE_UNAVAILABLE_WHILE_SLOWMODE_IS_ON_DESCRIPTOR = msg({ message: 'Comments are unavailable while slowmode is on.', @@ -104,6 +111,8 @@ const SEND_SELECTED_COUNT_DESCRIPTOR = msg({ }); const logger = new Logger('ForwardModal'); +const DESTINATION_ICON_SIZE = 32; + interface ForwardModalProps { message: Message; mediaSelection?: MessageCommands.ForwardMediaSelection; @@ -117,28 +126,6 @@ export interface ForwardModalSuccess { shouldNavigate: boolean; } -interface ForwardMediaCapability { - hasAttachments: boolean; - hasEmbeds: boolean; -} - -function resolveForwardMediaCapability( - mediaSelection: MessageCommands.ForwardMediaSelection | undefined, -): ForwardMediaCapability | undefined { - if (mediaSelection === undefined) { - return undefined; - } - let hasAttachments = false; - if (mediaSelection.attachmentIds !== undefined) { - hasAttachments = mediaSelection.attachmentIds.length > 0; - } - let hasEmbeds = false; - if (mediaSelection.embedIndices !== undefined) { - hasEmbeds = mediaSelection.embedIndices.length > 0; - } - return {hasAttachments, hasEmbeds}; -} - function resolveForwardSourceChannel( sourceChannel: Channel | null | undefined, messageChannelId: string, @@ -163,21 +150,48 @@ function resolveForwardReferenceGuildId(channel: Channel | null, message: Messag return null; } -async function openForwardChannels(options: ReadonlyArray): Promise> { +async function openForwardDestinations(destinations: ReadonlyArray): Promise> { const channelIds: Array = []; - for (const option of options) { - if (option.channel != null) { - channelIds.push(option.channel.id); + for (const destination of destinations) { + if (destination.type === 'channel') { + channelIds.push(destination.id); continue; } - if (option.recipient == null) { - throw new Error(`Forward destination ${option.key} has no channel or recipient`); - } - channelIds.push(await PrivateChannelCommands.ensureDMChannel(option.recipient.id)); + channelIds.push(await PrivateChannelCommands.ensureDMChannel(destination.id)); } return channelIds; } +function resolveCommentBlockedNotice( + i18n: I18n, + slowmodeEnabledOptions: ReadonlyArray, +): string | null { + if (slowmodeEnabledOptions.length === 0) { + return null; + } + if (slowmodeEnabledOptions.length === 1) { + return i18n._(COMMENTS_ARE_DISABLED_BECAUSE_SLOWMODE_IS_ON_IN_DESCRIPTOR, { + forwardChannelDisplayName: slowmodeEnabledOptions[0].displayName, + }); + } + return i18n._(COMMENTS_ARE_DISABLED_BECAUSE_ONE_OR_MORE_SELECTED_DESCRIPTOR); +} + +function resolveSendBlockedNotice( + i18n: I18n, + slowmodeActiveOptions: ReadonlyArray, +): string | null { + if (slowmodeActiveOptions.length === 0) { + return null; + } + if (slowmodeActiveOptions.length === 1) { + return i18n._(WAITING_FOR_SLOWMODE_IN_TO_EXPIRE_DESCRIPTOR, { + forwardChannelDisplayName: slowmodeActiveOptions[0].displayName, + }); + } + return i18n._(WAITING_FOR_SLOWMODE_IN_ONE_OR_MORE_SELECTED_DESCRIPTOR); +} + function focusForwardComment(handle: LexicalRichInputHandle | null): void { if (handle != null) { handle.focus(); @@ -191,32 +205,83 @@ function insertForwardEmoji(handle: LexicalRichInputHandle | null, emoji: FlatEm return handle.insertEmoji(emoji); } +function renderForwardDestinationIcon(option: ForwardDestinationOption) { + if (option.user != null) { + return ( +
+ +
+ ); + } + const channel = option.channel; + if (channel == null) { + return null; + } + if (channel.type === ChannelTypes.DM_PERSONAL_NOTES) { + return ( + + ); + } + if (channel.type === ChannelTypes.GROUP_DM) { + return ( +
+ +
+ ); + } + if (channel.type === ChannelTypes.GUILD_VOICE) { + return ( + + ); + } + return ( + + ); +} + const EMPTY_FORWARD_COMMENT_SEGMENTS: ReadonlyArray = Object.freeze([]); export const ForwardModal = observer( ({message, mediaSelection, onForwardSuccess, sourceChannel, user}: ForwardModalProps) => { const {i18n} = useLingui(); - const mediaSelectionCapability = useMemo(() => resolveForwardMediaCapability(mediaSelection), [mediaSelection]); const { - filteredChannels, - handleToggleChannel, - isChannelSelectionDisabled, - mostRecentlySelectedChannel, + composerChannel, + options, searchQuery, - selectedChannelOptions, + selected, selectedKeys, setSearchQuery, - maxSelections, - slowmodeActiveSelectedChannelOptions, - slowmodeEnabledSelectedChannelOptions, - } = useForwardChannelSelection({ - excludedChannelId: message.channelId, - message, - mediaSelection: mediaSelectionCapability, - }); + slowmodeActiveSelectedOptions, + slowmodeEnabledSelectedOptions, + toggleDestination, + } = useForwardDestinations({message, mediaSelection}); const [actualOptionalMessage, setActualOptionalMessage] = useState(''); const [isForwarding, setIsForwarding] = useState(false); const [expressionPickerOpen, setExpressionPickerOpen] = useState(false); + const searchInputRef = useRef(null); const containerRef = useRef(null); const [containerElement, setContainerElement] = useState(null); const setContainerNode = useCallback((node: HTMLDivElement | null) => { @@ -227,6 +292,13 @@ export const ForwardModal = observer( const commentNoticeId = useId(); const premiumMaxLength = Limits.getPremiumValue('max_message_length', MAX_MESSAGE_LENGTH_PREMIUM); const isMobileLayout = MobileLayout.enabled; + const shouldFocusSearch = !shouldDisableAutofocusOnMobile(); + useEffect(() => { + if (searchQuery !== '' || shouldDisableAutofocusOnMobile()) { + return; + } + searchInputRef.current?.focus(); + }, [searchQuery]); const handleOptionalMessageExceedsLimit = useCallback(() => { showMessagingErrorModal({ title: i18n._(MESSAGE_IS_TOO_LONG_DESCRIPTOR), @@ -238,31 +310,13 @@ export const ForwardModal = observer( const handleCommentChange = useCallback((_display: string, _segments: Array, wire: string) => { setActualOptionalMessage(dropTrailingEmptyBlockquoteLines(wire)); }, []); + const isAtSelectionLimit = selected.length >= MAX_FORWARD_DESTINATIONS; const isCommentOverLimit = actualOptionalMessage.length > user.maxMessageLength; - const isSendBlockedBySlowmode = slowmodeActiveSelectedChannelOptions.length > 0; - const isCommentBlockedBySlowmode = slowmodeEnabledSelectedChannelOptions.length > 0; + const isSendBlockedBySlowmode = slowmodeActiveSelectedOptions.length > 0; + const isCommentBlockedBySlowmode = slowmodeEnabledSelectedOptions.length > 0; const isCommentComposerDisabled = isCommentBlockedBySlowmode; - const commentBlockedNotice = useMemo(() => { - if (!isCommentBlockedBySlowmode) { - return null; - } - if (slowmodeEnabledSelectedChannelOptions.length === 1) { - return i18n._(COMMENTS_ARE_DISABLED_BECAUSE_SLOWMODE_IS_ON_IN_DESCRIPTOR, { - forwardChannelDisplayName: slowmodeEnabledSelectedChannelOptions[0].displayName, - }); - } - return i18n._(COMMENTS_ARE_DISABLED_BECAUSE_ONE_OR_MORE_SELECTED_DESCRIPTOR); - }, [i18n.locale, isCommentBlockedBySlowmode, slowmodeEnabledSelectedChannelOptions]); - const sendBlockedNotice = useMemo(() => { - if (!isSendBlockedBySlowmode) return null; - if (slowmodeActiveSelectedChannelOptions.length === 1) { - return i18n._(WAITING_FOR_SLOWMODE_IN_TO_EXPIRE_DESCRIPTOR, { - forwardChannelDisplayName: slowmodeActiveSelectedChannelOptions[0].displayName, - }); - } - return i18n._(WAITING_FOR_SLOWMODE_IN_ONE_OR_MORE_SELECTED_DESCRIPTOR); - }, [i18n.locale, isSendBlockedBySlowmode, slowmodeActiveSelectedChannelOptions]); - let commentNotice = sendBlockedNotice; + let commentNotice = resolveSendBlockedNotice(i18n, slowmodeActiveSelectedOptions); + const commentBlockedNotice = resolveCommentBlockedNotice(i18n, slowmodeEnabledSelectedOptions); if (commentBlockedNotice != null) { commentNotice = commentBlockedNotice; } @@ -276,7 +330,7 @@ export const ForwardModal = observer( } const isCommentCounterVisible = actualOptionalMessage.length > user.maxMessageLength * 0.8; const handleForward = async (skipNavigation = false) => { - if (selectedChannelOptions.length === 0) return; + if (selected.length === 0) return; if (isForwarding) return; if (isSendBlockedBySlowmode) return; if (!isCommentComposerDisabled && isCommentOverLimit) { @@ -297,7 +351,7 @@ export const ForwardModal = observer( attachmentIds = mediaSelection.attachmentIds; embedIndices = mediaSelection.embedIndices; } - const forwardedChannelIds = await openForwardChannels(selectedChannelOptions); + const forwardedChannelIds = await openForwardDestinations(selected); const forwarded = await MessageCommands.forward( forwardedChannelIds, { @@ -345,71 +399,22 @@ export const ForwardModal = observer( setIsForwarding(false); } }; - const getChannelIcon = (option: ForwardChannelOption) => { - const iconSize = 32; - const ch = option.channel; - if (ch == null || ch.type === ChannelTypes.DM) { - const user = ch == null ? option.recipient : Users.getUser(ch.recipientIds[0]); - if (!user) return null; - return ( -
- -
- ); - } - if (ch.type === ChannelTypes.DM_PERSONAL_NOTES) { - return ( - - ); - } - if (ch.type === ChannelTypes.GROUP_DM) { - return ( -
- -
- ); - } - if (ch.type === ChannelTypes.GUILD_VOICE) { - return ( - - ); - } - return ( - - ); - }; return ( - +
setSearchQuery(e.target.value)} - placeholder={i18n._(SEARCH_CHANNELS_OR_DMS_DESCRIPTOR)} + onChange={(event) => setSearchQuery(event.target.value)} + placeholder={i18n._(SEARCH_DESCRIPTOR)} + aria-label={i18n._(SEARCH_DESCRIPTOR)} maxLength={100} leftIcon={
- +
- {filteredChannels.length === 0 ? ( + {options.length === 0 ? (
No channels found
) : (
- {filteredChannels.map((option: ForwardChannelOption) => { + {options.map((option) => { const isSelected = selectedKeys.has(option.key); - const isDisabledForSelection = isChannelSelectionDisabled(option); - const isDisabled = isDisabledForSelection && !isSelected; - const {categoryName, disableReason, displayName, guildName} = option; + const isDisabled = !isSelected && (isAtSelectionLimit || option.disableReason != null); + const secondaryText = option.disableReason ?? option.detail; return (
-
+
+ ) => handleForward(event.shiftKey)} disabled={ - selectedChannelOptions.length === 0 || + selected.length === 0 || isForwarding || isSendBlockedBySlowmode || (!isCommentComposerDisabled && isCommentOverLimit) @@ -655,8 +660,8 @@ export const ForwardModal = observer( data-flx="messaging.forward-modal.button.forward" > {i18n._(SEND_SELECTED_COUNT_DESCRIPTOR, { - selectedCount: selectedKeys.size, - selectionLimit: maxSelections, + selectedCount: selected.length, + selectionLimit: MAX_FORWARD_DESTINATIONS, })} diff --git a/fluxer_app/src/features/messaging/utils/markdown/MarkdownParserFlags.ts b/fluxer_app/src/features/messaging/utils/markdown/MarkdownParserFlags.ts index c9aee765f..93cf8aee6 100644 --- a/fluxer_app/src/features/messaging/utils/markdown/MarkdownParserFlags.ts +++ b/fluxer_app/src/features/messaging/utils/markdown/MarkdownParserFlags.ts @@ -32,6 +32,8 @@ const RESTRICTED_INLINE_REPLY_FLAGS = ParserFlags.ALLOW_HEADINGS | ParserFlags.ALLOW_LISTS ); +const RESTRICTED_INLINE_PREVIEW_FLAGS = + RESTRICTED_INLINE_REPLY_FLAGS | ParserFlags.ALLOW_HEADINGS | ParserFlags.ALLOW_LISTS; const RESTRICTED_USER_BIO_FLAGS = STANDARD_FLAGS & ~( @@ -49,6 +51,8 @@ export function getParserFlagsForContext(context: MarkdownContext): number { switch (context) { case MarkdownContext.RESTRICTED_INLINE_REPLY: return RESTRICTED_INLINE_REPLY_FLAGS; + case MarkdownContext.RESTRICTED_INLINE_PREVIEW: + return RESTRICTED_INLINE_PREVIEW_FLAGS; case MarkdownContext.RESTRICTED_USER_BIO: return RESTRICTED_USER_BIO_FLAGS; case MarkdownContext.RESTRICTED_EMBED_DESCRIPTION: diff --git a/fluxer_app/src/features/navigation/state/SelectedChannel.ts b/fluxer_app/src/features/navigation/state/SelectedChannel.ts index 1ade00691..67e7dcd4e 100644 --- a/fluxer_app/src/features/navigation/state/SelectedChannel.ts +++ b/fluxer_app/src/features/navigation/state/SelectedChannel.ts @@ -37,7 +37,6 @@ class SelectedChannel { this, { sortedRecentVisits: computed, - recentChannels: computed, recentChannelVisits: computed, }, {autoBind: true}, @@ -110,14 +109,6 @@ class SelectedChannel { return sorted; } - get recentChannels(): ReadonlyArray { - const sorted = this.sortedRecentVisits; - const limit = Math.min(sorted.length, RECENT_CHANNEL_HISTORY_LIMIT); - const result: Array = new Array(limit); - for (let i = 0; i < limit; i++) result[i] = sorted[i].channelId; - return result; - } - get recentChannelVisits(): ReadonlyArray<{ channelId: string; guildId: string; diff --git a/fluxer_app/src/features/search/utils/LICENSE-UNICODE-3.0.txt b/fluxer_app/src/features/search/utils/LICENSE-UNICODE-3.0.txt new file mode 100644 index 000000000..28c86b4f6 --- /dev/null +++ b/fluxer_app/src/features/search/utils/LICENSE-UNICODE-3.0.txt @@ -0,0 +1,36 @@ +UNICODE LICENSE V3 + +COPYRIGHT AND PERMISSION NOTICE + +Copyright (c) 1991-2023 Unicode, Inc. + +NOTICE TO USER: Carefully read the following legal agreement. BY DOWNLOADING, +INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR SOFTWARE, YOU +UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS +OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, +DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +data files and any associated documentation (the "Data Files") or software and +any associated documentation (the "Software") to deal in the Data Files or +Software without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, and/or sell copies of the Data Files +or Software, and to permit persons to whom the Data Files or Software are +furnished to do so, provided that either (a) this copyright and permission +notice appear with all copies of the Data Files or Software, or (b) this +copyright and permission notice appear in associated Documentation. + +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD +PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN +THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL +DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING +OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA FILES OR +SOFTWARE. + +Except as contained in this notice, the name of a copyright holder shall not be +used in advertising or otherwise to promote the sale, use or other dealings in +these Data Files or Software without prior written authorization of the +copyright holder. diff --git a/fluxer_app/src/features/search/utils/SearchTextMatching.test.ts b/fluxer_app/src/features/search/utils/SearchTextMatching.test.ts new file mode 100644 index 000000000..168171dc4 --- /dev/null +++ b/fluxer_app/src/features/search/utils/SearchTextMatching.test.ts @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +import { + buildChannelSearchTerms, + consumeBestSearchTerm, + createSearchTerm, + escapeSearchPattern, + fuzzySearch, + getLoadedUnicodeConfusables, + loadUnicodeConfusables, + scoreSearchTerm, + stripCombiningMarks, + toConfusableSkeleton, +} from '@app/features/search/utils/SearchTextMatching'; +import {describe, expect, it} from 'vitest'; + +const PATTERN_SPECIAL_CHARACTERS = '-[]/{}()*+?.\\^$|'; + +describe('escapeSearchPattern', () => { + it('escapes every regex special character', () => { + const expected = [...PATTERN_SPECIAL_CHARACTERS].map((character) => `\\${character}`).join(''); + expect(escapeSearchPattern(PATTERN_SPECIAL_CHARACTERS)).toBe(expected); + }); + + it('leaves whitespace and other punctuation alone', () => { + expect(escapeSearchPattern('a b\tc#,!@&')).toBe('a b\tc#,!@&'); + }); + + it('produces a pattern that matches the literal text', () => { + const text = `gen (${PATTERN_SPECIAL_CHARACTERS}) chat`; + expect(new RegExp(`^${escapeSearchPattern(text)}$`).test(text)).toBe(true); + }); +}); + +describe('stripCombiningMarks', () => { + it('removes combining diacritics from precomposed and decomposed text', () => { + expect(stripCombiningMarks('José')).toBe('Jose'); + expect(stripCombiningMarks('cafe\u{301}')).toBe('cafe'); + }); + + it('keeps marks outside the combining diacritical block', () => { + expect(stripCombiningMarks('x\u{483}')).toBe('x\u{483}'); + }); +}); + +describe('fuzzySearch', () => { + it('matches an in-order subsequence', () => { + expect(fuzzySearch('gnrl', 'general')).toBe(true); + expect(fuzzySearch('lrg', 'general')).toBe(false); + }); + + it('requires equality when the lengths match', () => { + expect(fuzzySearch('gen', 'gen')).toBe(true); + expect(fuzzySearch('abc', 'abd')).toBe(false); + }); + + it('rejects a needle longer than the haystack', () => { + expect(fuzzySearch('general', 'gen')).toBe(false); + }); + + it('is case-sensitive', () => { + expect(fuzzySearch('G', 'general')).toBe(false); + }); + + it('compares UTF-16 code units', () => { + expect(fuzzySearch('\u{1f600}', 'a\u{1f600}b')).toBe(true); + }); +}); + +describe('scoreSearchTerm', () => { + it('ranks exact, prefix, contains, every word and fuzzy matches', () => { + expect(scoreSearchTerm('general', createSearchTerm('general'))).toBe(10); + expect(scoreSearchTerm('general-chat', createSearchTerm('general'))).toBe(7); + expect(scoreSearchTerm('my-general', createSearchTerm('general'))).toBe(5); + expect(scoreSearchTerm('general-chat', createSearchTerm('chat general'))).toBe(3); + expect(scoreSearchTerm('general', createSearchTerm('gnrl'))).toBe(1); + expect(scoreSearchTerm('general', createSearchTerm('xyz'))).toBe(0); + }); + + it('skips the fuzzy tier when fuzzy matching is off', () => { + expect(scoreSearchTerm('general', createSearchTerm('gnrl'), false)).toBe(0); + }); + + it('splits words on commas and spaces', () => { + expect(scoreSearchTerm('alice and bob', createSearchTerm('bob,alice'))).toBe(3); + }); +}); + +describe('buildChannelSearchTerms', () => { + it('builds one term per word and drops empty tokens', () => { + const terms = buildChannelSearchTerms('general'); + expect(terms.map((term) => [term.queryLower, term.isFullMatch])).toEqual([['general', false]]); + }); + + it('puts a full-phrase term first when the query has a space', () => { + const terms = buildChannelSearchTerms(' General Chat'); + expect(terms.map((term) => [term.queryLower, term.isFullMatch])).toEqual([ + [' general chat', true], + ['general', false], + ['chat', false], + ]); + }); + + it('lets only the first space of the full phrase match a dash', () => { + const [fullPhrase] = buildChannelSearchTerms('a b c'); + expect(fullPhrase.exactQuery.test('a-b c')).toBe(true); + expect(fullPhrase.exactQuery.test('a b c')).toBe(true); + expect(fullPhrase.exactQuery.test('a b-c')).toBe(false); + }); +}); + +describe('consumeBestSearchTerm', () => { + it('removes the winning word term and returns its score', () => { + const terms = [...buildChannelSearchTerms('chat general')]; + expect(consumeBestSearchTerm('general-chat', terms, true)).toBe(7); + expect(terms.map((term) => term.queryLower)).toEqual(['chat general', 'chat']); + }); + + it('empties the terms when the full phrase wins', () => { + const terms = [...buildChannelSearchTerms('general chat')]; + expect(consumeBestSearchTerm('general-chat', terms, true)).toBe(7); + expect(terms).toEqual([]); + }); + + it('keeps the terms when nothing matches', () => { + const terms = [...buildChannelSearchTerms('xyz')]; + expect(consumeBestSearchTerm('general', terms, true)).toBe(0); + expect(terms).toHaveLength(1); + }); +}); + +describe('unicode confusables', () => { + it('has no table before it loads', () => { + expect(getLoadedUnicodeConfusables()).toBeNull(); + }); + + it('loads the full Unicode 15.1 table once', async () => { + const confusables = await loadUnicodeConfusables(); + expect(confusables.size).toBe(6311); + expect(await loadUnicodeConfusables()).toBe(confusables); + expect(getLoadedUnicodeConfusables()).toBe(confusables); + }); + + it('maps known look-alikes', async () => { + const confusables = await loadUnicodeConfusables(); + expect(confusables.get('0')).toBe('O'); + expect(confusables.get('1')).toBe('l'); + expect(confusables.get('I')).toBe('l'); + expect(confusables.get('m')).toBe('rn'); + expect(confusables.get('\u{1d7ce}')).toBe('O'); + }); + + it('builds lowercase skeletons', async () => { + const confusables = await loadUnicodeConfusables(); + expect(toConfusableSkeleton('b0b', confusables)).toBe('bob'); + expect(toConfusableSkeleton('Il1|', confusables)).toBe('llll'); + expect(toConfusableSkeleton('mod', confusables)).toBe('rnod'); + }); + + it('only lowercases and decomposes without a table', () => { + expect(toConfusableSkeleton('B0B', new Map())).toBe('b0b'); + expect(toConfusableSkeleton('É', new Map())).toBe('e\u{301}'); + }); +}); diff --git a/fluxer_app/src/features/search/utils/SearchTextMatching.ts b/fluxer_app/src/features/search/utils/SearchTextMatching.ts new file mode 100644 index 000000000..4716f0d83 --- /dev/null +++ b/fluxer_app/src/features/search/utils/SearchTextMatching.ts @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +const SEARCH_PATTERN_SPECIAL_CHARACTERS = /[-[\]/{}()*+?.\\^$|]/g; +const COMBINING_MARKS = /[\u{300}-\u{36f}]/gu; +const QUERY_WORD_SEPARATORS = /[, ]+/; + +interface SearchTerm { + readonly containQuery: RegExp; + readonly exactQuery: RegExp; + readonly isFullMatch: boolean; + readonly queryLower: string; +} + +let loadedUnicodeConfusables: ReadonlyMap | null = null; +let pendingUnicodeConfusables: Promise> | null = null; + +export function escapeSearchPattern(text: string): string { + return text.replace(SEARCH_PATTERN_SPECIAL_CHARACTERS, '\\$&'); +} + +export function stripCombiningMarks(text: string): string { + return text.normalize('NFD').replace(COMBINING_MARKS, '').normalize('NFC'); +} + +export function toConfusableSkeleton(text: string, confusables: ReadonlyMap): string { + let skeleton = ''; + for (const character of text.normalize('NFD')) { + skeleton += confusables.get(character) ?? character; + } + return skeleton.normalize('NFD').toLocaleLowerCase(); +} + +export function fuzzySearch(needle: string, haystack: string): boolean { + if (needle.length > haystack.length) return false; + if (needle.length === haystack.length) return needle === haystack; + let searchFrom = 0; + for (let index = 0; index < needle.length; index++) { + searchFrom = haystack.indexOf(needle[index], searchFrom) + 1; + if (searchFrom === 0) return false; + } + return true; +} + +export function scoreSearchTerm(value: string, term: SearchTerm, fuzzy = true): number { + if (term.exactQuery.test(value)) return value.toLocaleLowerCase() === term.queryLower ? 10 : 7; + if (term.containQuery.test(value)) return 5; + const words = term.queryLower.split(QUERY_WORD_SEPARATORS); + if (words.every((word) => new RegExp(escapeSearchPattern(word), 'i').test(value))) return 3; + if (fuzzy && fuzzySearch(term.queryLower, value)) return 1; + return 0; +} + +export function consumeBestSearchTerm(value: string, terms: Array, fuzzy: boolean): number { + let bestScore = 0; + let bestIndex = -1; + for (let index = 0; index < terms.length; index++) { + const score = scoreSearchTerm(value, terms[index], fuzzy); + if (score <= bestScore) continue; + bestScore = score; + bestIndex = index; + } + if (bestIndex === -1) return 0; + if (terms[bestIndex].isFullMatch) { + terms.length = 0; + } else { + terms.splice(bestIndex, 1); + } + return bestScore; +} + +function buildSearchTerm(queryLower: string, pattern: string, isFullMatch: boolean): SearchTerm { + return Object.freeze({ + containQuery: new RegExp(pattern, 'i'), + exactQuery: new RegExp(`^${pattern}`, 'i'), + isFullMatch, + queryLower, + }); +} + +export function createSearchTerm(queryLower: string): SearchTerm { + return buildSearchTerm(queryLower, escapeSearchPattern(queryLower), false); +} + +export function buildChannelSearchTerms(query: string): ReadonlyArray { + const terms = query + .split(' ') + .filter((token) => token !== '') + .map((token) => createSearchTerm(token.toLocaleLowerCase())); + if (query.includes(' ')) { + const queryLower = query.toLocaleLowerCase(); + terms.unshift(buildSearchTerm(queryLower, escapeSearchPattern(queryLower).replace(' ', '( |-)'), true)); + } + return terms; +} + +function decodeCodePoints(encoded: string): string { + return String.fromCodePoint(...encoded.split(' ').map((codePoint) => Number.parseInt(codePoint, 16))); +} + +function decodeUnicodeConfusables(encoded: string): ReadonlyMap { + const confusables = new Map(); + for (const entry of encoded.split(',')) { + const separator = entry.indexOf(':'); + confusables.set(decodeCodePoints(entry.slice(0, separator)), decodeCodePoints(entry.slice(separator + 1))); + } + return confusables; +} + +export function getLoadedUnicodeConfusables(): ReadonlyMap | null { + return loadedUnicodeConfusables; +} + +export function loadUnicodeConfusables(): Promise> { + if (pendingUnicodeConfusables == null) { + pendingUnicodeConfusables = import('@app/features/search/utils/UnicodeConfusables') + .then(({UNICODE_CONFUSABLES}) => { + const confusables = decodeUnicodeConfusables(UNICODE_CONFUSABLES); + loadedUnicodeConfusables = confusables; + return confusables; + }) + .catch((error: unknown) => { + pendingUnicodeConfusables = null; + throw error; + }); + } + return pendingUnicodeConfusables; +} diff --git a/fluxer_app/src/features/search/utils/UnicodeConfusables.ts b/fluxer_app/src/features/search/utils/UnicodeConfusables.ts new file mode 100644 index 000000000..13ad7231a --- /dev/null +++ b/fluxer_app/src/features/search/utils/UnicodeConfusables.ts @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: Unicode-3.0 +// SPDX-FileCopyrightText: 1991-2023 Unicode, Inc. + +export const UNICODE_CONFUSABLES = + '5ad:596,5ae:598,5a8:599,5a4:59a,1ab4:6db,20db:6db,619:313,8f3:313,343:313,315:313,64f:313,65d:314,59c:301,59d:301,618:301,747:301,341:301,954:301,64e:301,340:300,953:300,30c:306,a67c:306,658:306,65a:306,36e:306,6e8:306 307,310:306 307,901:306 307,981:306 307,a81:306 307,b01:306 307,c00:306 307,c81:306 307,d01:306 307,114bf:306 307,1cd0:302,311:302,65b:302,7ee:302,a6f0:302,5af:30a,6df:30a,17d3:30a,309a:30a,652:30a,b82:30a,1036:30a,17c6:30a,11300:30a,e4d:30a,ecd:30a,366:30a,2dea:30a,8eb:308,7f3:308,64b:30b,8f0:30b,342:303,653:303,5c4:307,6ec:307,740:307,8ea:307,741:307,358:307,5b9:307,5ba:307,5c2:307,5c1:307,7ed:307,902:307,a02:307,a82:307,bcd:307,337:338,1ab7:328,322:328,345:328,1cd2:304,305:304,659:304,7eb:304,a6f1:304,1cda:30e,657:312,357:350,8ff:350,8f8:350,900:352,1ced:316,1cdc:329,656:329,1cd5:32b,347:333,8f9:354,8fa:355,309b:ff9e,309c:ff9f,336:335,302c:309,5c5:323,8ed:323,1cdd:323,5b4:323,65c:323,93c:323,9bc:323,a3c:323,abc:323,b3c:323,111ca:323,114c3:323,10a3a:323,8ee:324,1cde:324,f37:325,302d:325,327:326,321:326,339:326,1cd9:32d,1cd8:32e,952:331,320:331,8f1:64c,8e8:64c,8e5:64c,fc5e:fe72 651,8f2:64d,fc5f:fe74 651,fcf2:fe77 651,fc60:fe76 651,fcf3:fe79 651,fc61:fe78 651,61a:650,317:650,fcf4:fe7b 651,fc62:fe7a 651,fc63:fe7c 670,65f:655,30d:670,742:73c,a03:983,c03:983,c83:983,d03:983,d83:983,1038:983,114c1:983,17cb:e48,ec8:e48,ec9:e49,eca:e4a,ecb:e4b,a66f:20e9,2028:20,2029:20,1680:20,2000:20,2001:20,2002:20,2003:20,2004:20,2005:20,2006:20,2008:20,2009:20,200a:20,205f:20,a0:20,2007:20,202f:20,7fa:5f,fe4d:5f,fe4e:5f,fe4f:5f,2010:2d,2011:2d,2012:2d,2013:2d,fe58:2d,6d4:2d,2043:2d,2d7:2d,2212:2d,2796:2d,2cba:2d,2a29:2d 313,2e1a:2d 308,fb29:2d 307,2238:2d 307,2a2a:2d 323,a4fe:2d 2e,ff5e:301c,60d:2c,66b:2c,201a:2c,b8:2c,a4f9:2c,2e32:60c,66c:60c,37e:3b,2e35:61b,903:3a,a83:3a,ff1a:3a,589:3a,703:3a,704:3a,16ec:3a,fe30:3a,1803:3a,1809:3a,205a:3a,5c3:3a,2f8:3a,a789:3a,2236:3a,2d0:3a,a4fd:3a,2a74:3a 3a 3d,29f4:3a 2192,ff01:21,1c3:21,2d51:21,203c:21 21,2049:21 3f,294:3f,241:3f,97d:3f,13ae:3f,a6eb:3f,2048:3f 21,2047:3f 3f,2e2e:61f,1d16d:2e,2024:2e,701:2e,702:2e,a60e:2e,10a50:2e,660:2e,6f0:2e,a4f8:2e,a4fb:2e 2c,2025:2e 2e,a4fa:2e 2e,2026:2e 2e 2e,a6f4:a6f3 a6f3,30fb:b7,ff65:b7,16eb:b7,387:b7,2e31:b7,10101:b7,2022:b7,2027:b7,2219:b7,22c5:b7,a78f:b7,1427:b7,22ef:b7 b7 b7,2d48:b7 b7 b7,1444:b7 3c,22d7:b7 3e,1437:b7 3e,1440:b7 3e,152f:b7 34,147e:b7 62,1480:b7 62 307,147a:b7 64,1498:b7 4a,14b6:b7 4c,1476:b7 50,1457:b7 55,143a:b7 56,143c:b7 245,14ae:b7 393,140e:b7 394,1459:b7 548,140c:b7 1401,1410:b7 1404,1412:b7 1405,1414:b7 1406,1417:b7 140a,1419:b7 140b,143e:b7 1432,1442:b7 1434,1446:b7 1439,145b:b7 144f,1454:b7 1450,145d:b7 1450,145f:b7 1451,1461:b7 1455,1463:b7 1456,1474:b7 146b,1478:b7 146e,147c:b7 1470,1492:b7 1489,1494:b7 148b,1496:b7 148c,149a:b7 148e,149c:b7 1490,149e:b7 1491,14ac:b7 14a3,14b0:b7 14a6,14b2:b7 14a7,14b4:b7 14a8,14b8:b7 14ab,14c9:b7 14c0,18c6:b7 14c2,18c8:b7 14c3,18ca:b7 14c4,18cc:b7 14c5,14cb:b7 14c7,14cd:b7 14c8,14dc:b7 14d3,14de:b7 14d5,14e0:b7 14d6,14e2:b7 14d7,14e4:b7 14d8,14e6:b7 14da,14e8:b7 14db,14f6:b7 14ed,14f8:b7 14ef,14fa:b7 14f0,14fc:b7 14f1,14fe:b7 14f2,1500:b7 14f4,1502:b7 14f5,1517:b7 1510,1519:b7 1511,151b:b7 1512,151d:b7 1513,151f:b7 1514,1521:b7 1515,1523:b7 1516,1531:b7 1528,1533:b7 1529,1535:b7 152a,1537:b7 152b,1539:b7 152d,153b:b7 152e,18ce:b7 1543,18cf:b7 1546,18d0:b7 1547,18d1:b7 1548,18d2:b7 1549,18d3:b7 154b,154e:b7 154c,155b:b7 155a,1568:b7 1567,18b3:b7 18b1,18b6:b7 18b4,18b9:b7 18b8,18c2:b7 18c0,a830:964,965:964 964,1c3c:1c3b 1c3b,104b:104a 104a,1aa9:1aa8 1aa8,1aab:1aaa 1aa8,1b5f:1b5e 1b5e,10a57:10a56 10a56,1144c:1144b 1144b,11642:11641 11641,11c42:11c41 11c41,1c7f:1c7e 1c7e,55d:27,ff07:27,2018:27,2019:27,201b:27,2032:27,2035:27,55a:27,5f3:27,60:27,1fef:27,ff40:27,b4:27,384:27,1ffd:27,1fbd:27,1fbf:27,1ffe:27,2b9:27,374:27,2c8:27,2ca:27,2cb:27,2f4:27,2bb:27,2bd:27,2bc:27,2be:27,a78c:27,5d9:27,7f4:27,7f5:27,144a:27,16cc:27,16f51:27,16f52:27,1cd3:27 27,22:27 27,ff02:27 27,201c:27 27,201d:27 27,201f:27 27,2033:27 27,2036:27 27,3003:27 27,5f4:27 27,2dd:27 27,2ba:27 27,2f6:27 27,2ee:27 27,5f2:27 27,2034:27 27 27,2037:27 27 27,2057:27 27 27 27,181:27 42,18a:27 44,149:27 6e,1a4:27 50,1ac:27 54,1b3:27 59,ff3b:28,2768:28,2772:28,3014:28,fd3e:28,2e28:28 28,3220:28 30fc 29,2475:28 32 29,2487:28 32 4f 29,2476:28 33 29,2477:28 34 29,2478:28 35 29,2479:28 36 29,247a:28 37 29,247b:28 38 29,247c:28 39 29,249c:28 61 29,1f110:28 41 29,249d:28 62 29,1f111:28 42 29,249e:28 63 29,1f112:28 43 29,249f:28 64 29,1f113:28 44 29,24a0:28 65 29,1f114:28 45 29,24a1:28 66 29,1f115:28 46 29,24a2:28 67 29,1f116:28 47 29,24a3:28 68 29,1f117:28 48 29,24a4:28 69 29,24a5:28 6a 29,1f119:28 4a 29,24a6:28 6b 29,1f11a:28 4b 29,2474:28 6c 29,1f118:28 6c 29,24a7:28 6c 29,1f11b:28 4c 29,247f:28 6c 32 29,2480:28 6c 33 29,2481:28 6c 34 29,2482:28 6c 35 29,2483:28 6c 36 29,2484:28 6c 37 29,2485:28 6c 38 29,2486:28 6c 39 29,247e:28 6c 6c 29,247d:28 6c 4f 29,1f11c:28 4d 29,24a9:28 6e 29,1f11d:28 4e 29,24aa:28 6f 29,1f11e:28 4f 29,24ab:28 70 29,1f11f:28 50 29,24ac:28 71 29,1f120:28 51 29,24ad:28 72 29,1f121:28 52 29,24a8:28 72 6e 29,24ae:28 73 29,1f122:28 53 29,1f12a:28 53 29,24af:28 74 29,1f123:28 54 29,24b0:28 75 29,1f124:28 55 29,24b1:28 76 29,1f125:28 56 29,24b2:28 77 29,1f126:28 57 29,24b3:28 78 29,1f127:28 58 29,24b4:28 79 29,1f128:28 59 29,24b5:28 7a 29,1f129:28 5a 29,3200:28 1100 29,320e:28 ac00 29,3201:28 1102 29,320f:28 b098 29,3202:28 1103 29,3210:28 b2e4 29,3203:28 1105 29,3211:28 b77c 29,3204:28 1106 29,3212:28 b9c8 29,3205:28 1107 29,3213:28 bc14 29,3206:28 1109 29,3214:28 c0ac 29,3207:28 110b 29,3215:28 c544 29,321d:28 c624 c804 29,321e:28 c624 d6c4 29,3208:28 110c 29,3216:28 c790 29,321c:28 c8fc 29,3209:28 110e 29,3217:28 cc28 29,320a:28 110f 29,3218:28 ce74 29,320b:28 1110 29,3219:28 d0c0 29,320c:28 1111 29,321a:28 d30c 29,320d:28 1112 29,321b:28 d558 29,3226:28 4e03 29,3222:28 4e09 29,1f241:28 4e09 29,3228:28 4e5d 29,3221:28 4e8c 29,1f242:28 4e8c 29,3224:28 4e94 29,3239:28 4ee3 29,323d:28 4f01 29,3241:28 4f11 29,3227:28 516b 29,3225:28 516d 29,3238:28 52b4 29,1f247:28 52dd 29,3229:28 5341 29,323f:28 5354 29,3234:28 540d 29,323a:28 547c 29,3223:28 56db 29,322f:28 571f 29,323b:28 5b66 29,1f243:28 5b89 29,1f245:28 6253 29,1f248:28 6557 29,3230:28 65e5 29,322a:28 6708 29,3232:28 6709 29,322d:28 6728 29,1f240:28 672c 29,3231:28 682a 29,322c:28 6c34 29,322b:28 706b 29,1f244:28 70b9 29,3235:28 7279 29,1f246:28 76d7 29,323c:28 76e3 29,3233:28 793e 29,3237:28 795d 29,3240:28 796d 29,3242:28 81ea 29,3243:28 81f3 29,3236:28 8ca1 29,323e:28 8cc7 29,322e:28 91d1 29,ff3d:29,2769:29,2773:29,3015:29,fd3f:29,2e29:29 29,2774:7b,1d114:7b,2775:7d,301a:27e6,301b:27e7,27e8:276c,2329:276c,3008:276c,31db:276c,304f:276c,21fe8:276c,27e9:276d,232a:276d,3009:276d,ff3e:fe3f,2e3f:b6,204e:2a,66d:2a,2217:2a,1031f:2a,1735:2f,2041:2f,2215:2f,2044:2f,2571:2f,27cb:2f,29f8:2f,1d23a:2f,31d3:2f,3033:2f,2cc6:2f,30ce:2f,4e3f:2f,2f03:2f,29f6:2f 304,2afd:2f 2f,2afb:2f 2f 2f,ff3c:5c,fe68:5c,2216:5c,27cd:5c,29f5:5c,29f9:5c,1d20f:5c,1d23b:5c,31d4:5c,4e36:5c,2f02:5c,2cf9:5c 5c,244a:5c 5c,27c8:5c 1455,a778:26,af0:970,110bb:970,111c7:970,26ac:970,111db:a8fc,17d9:e4f,17d5:e5a,17da:e5b,f0c:f0b,f0e:f0d f0d,2c4:5e,2c6:5e,a67e:2c7,2d8:2c7,203e:2c9,fe49:2c9,fe4a:2c9,fe4b:2c9,fe4c:2c9,af:2c9,ffe3:2c9,2594:2c9,44a:2c9 62,a651:2c9 62 69,375:2cf,2fb:2ea,a716:2ea,a714:2eb,3002:2f3,2e30:b0,2da:b0,2218:b0,25cb:b0,25e6:b0,235c:b0 332,2364:b0 308,2103:b0 43,2109:b0 46,bf5:bf3,f1b:f1a f1a,f1f:f1a f1d,fce:f1d f1a,f1e:f1d f1d,24b8:a9,24c7:ae,24c5:2117,1d21b:2144,2bec:219e,2bed:219f,2bee:21a0,2bef:21a1,21b5:21b2,2965:21c3 21c2,296f:21c3 16da,1d6db:2202,1d715:2202,1d74f:2202,1d789:2202,1d7c3:2202,1e8cc:2202,1e8cd:2202 335,f0:2202 335,2300:2205,1d6c1:2207,1d6fb:2207,1d735:2207,1d76f:2207,1d7a9:2207,118a8:2207,2362:2207 308,236b:2207 334,2588:220e,25a0:220e,2a3f:2210,16ed:2b,2795:2b,1029b:2b,2a23:2b 302,2a22:2b 30a,2a24:2b 303,2214:2b 307,2a25:2b 323,2a26:2b 330,2a27:2b 2082,2797:f7,2039:3c,276e:3c,2c2:3c,1d236:3c,1438:3c,16b2:3c,22d6:3c b7,2cb4:3c b7,1445:3c b7,226a:3c 3c,22d8:3c 3c 3c,1400:3d,2e40:3d,30a0:3d,a4ff:3d,225a:3d 306,2259:3d 302,2257:3d 30a,2250:3d 307,2251:3d 307 323,2a6e:3d 20f0,2a75:3d 3d,2a76:3d 3d 3d,225e:3d 36b,203a:3e,276f:3e,2c3:3e,1d237:3e,1433:3e,16f3f:3e,1441:3e b7,2aa5:3e 3c,226b:3e 3e,2a20:3e 3e,22d9:3e 3e 3e,2053:7e,2dc:7e,1fc0:7e,223c:7e,2368:7e 308,2e1e:7e 307,2a6a:7e 307,2e1f:7e 323,1e8c8:2220,22c0:2227,222f:222e 222e,2230:222e 222e 222e,2e2b:2234,2e2a:2235,2e2c:2237,111de:2248,264e:224f,1f75e:224f,2263:2261,2a03:228d,2a04:228e,1d238:228f,1d239:2290,2a05:2293,2a06:2294,2a02:2297,235f:229b,1f771:22a0,1f755:22a1,25c1:22b2,25b7:22b3,2363:22c6 308,fe34:2307,25e0:2312,2a3d:2319,2325:2324,29c7:233b,25ce:233e,29be:233e,29c5:2342,29b0:2349,23c3:234b,23c2:234e,23c1:2355,23c6:236d,2638:2388,fe35:23dc,fe36:23dd,fe37:23de,fe38:23df,fe39:23e0,fe3a:23e1,25b1:23e5,23fc:23fb,fe31:2502,ff5c:2502,2503:2502,250f:250c,2523:251c,2590:258c,2597:2596,259d:2598,2610:25a1,ffed:25aa,25b8:25b6,25ba:25b6,2ce9:2627,1f70a:2629,1f312:263d,1f319:263d,23fe:263e,1f318:263e,29d9:299a,1f73a:29df,2a3e:2a1f,101a0:2ce8,2669:1d158 1d165,266a:1d158 1d165 1d16e,24ea:1f10d,21ba:1f10e,2d9:971,d4e:971,ff0d:30fc,2014:30fc,2015:30fc,2500:30fc,2501:30fc,31d0:30fc,a7f7:30fc,1173:30fc,3161:30fc,4e00:30fc,2f00:30fc,1196:30fc 30fc,d7b9:30fc 1161,d7ba:30fc 1165,d7bb:30fc 1165 4e28,d7bc:30fc 1169,1195:30fc 116e,1174:30fc 4e28,3162:30fc 4e28,1197:30fc 4e28 116e,1f10f:24 20e0,20a4:a3,3012:20b8,3036:20b8,1b5c:1b50,a9c6:a9d0,114d1:9e7,ce7:c67,1065:1041,2460:2780,2469:2789,23e8:2081 2080,1d7d0:32,1d7da:32,1d7e4:32,1d7ee:32,1d7f8:32,1fbf2:32,a75a:32,1a7:32,3e8:32,a644:32,14bf:32,a6ef:32,a9cf:662,6f2:662,ae8:968,114d2:9e8,ce8:c68,2461:2781,1bb:32 335,1f103:32 2c,2489:32 2e,33f5:32 32 65e5,336e:32 32 70b9,33f6:32 33 65e5,336f:32 33 70b9,33f7:32 34 65e5,3370:32 34 70b9,33f8:32 35 65e5,33f9:32 36 65e5,33fa:32 37 65e5,33fb:32 38 65e5,33fc:32 39 65e5,33f4:32 6c 65e5,336d:32 6c 70b9,249b:32 4f 2e,33f3:32 4f 65e5,336c:32 4f 70b9,de9:de8 dcf,def:de8 dd3,33e1:32 65e5,32c1:32 6708,335a:32 70b9,1d206:33,1d7d1:33,1d7db:33,1d7e5:33,1d7ef:33,1d7f9:33,1fbf3:33,a7ab:33,21c:33,1b7:33,a76a:33,2ccc:33,417:33,4e0:33,16f3b:33,118ca:33,6f3:663,1e8c9:663,ae9:969,2462:2782,498:33 326,1f104:33 2c,248a:33 2e,33fe:33 6c 65e5,33fd:33 4f 65e5,33e2:33 65e5,32c2:33 6708,335b:33 70b9,1d7d2:34,1d7dc:34,1d7e6:34,1d7f0:34,1d7fa:34,1fbf4:34,13ce:34,118af:34,6f4:664,aea:96a,2463:2783,1f105:34 2c,248b:34 2e,1530:34 b7,33e3:34 65e5,32c3:34 6708,335c:34 70b9,1d7d3:35,1d7dd:35,1d7e7:35,1d7f1:35,1d7fb:35,1fbf5:35,1bc:35,118bb:35,2464:2784,1f106:35 2c,248c:35 2e,33e4:35 65e5,32c4:35 6708,335d:35 70b9,1d7d4:36,1d7de:36,1d7e8:36,1d7f2:36,1d7fc:36,1fbf6:36,2cd2:36,431:36,13ee:36,118d5:36,6f6:666,114d6:9ec,2465:2785,1f107:36 2c,248d:36 2e,33e5:36 65e5,32c5:36 6708,335e:36 70b9,1d212:37,1d7d5:37,1d7df:37,1d7e9:37,1d7f3:37,1d7fd:37,1fbf7:37,104d2:37,118c6:37,2466:2786,1f108:37 2c,248e:37 2e,33e6:37 65e5,32c6:37 6708,335f:37 70b9,b03:38,9ea:38,a6a:38,1e8cb:38,1d7d6:38,1d7e0:38,1d7ea:38,1d7f4:38,1d7fe:38,1fbf8:38,223:38,222:38,1031a:38,aee:96e,2467:2787,1f109:38 2c,248f:38 2e,33e7:38 65e5,32c7:38 6708,3360:38 70b9,a67:39,b68:39,9ed:39,d6d:39,1d7d7:39,1d7e1:39,1d7eb:39,1d7f5:39,1d7ff:39,1fbf9:39,a76e:39,2cca:39,118cc:39,118ac:39,118d6:39,967:669,118e4:669,6f9:669,cef:c6f,2468:2788,1f10a:39 2c,2490:39 2e,33e8:39 65e5,32c8:39 6708,3361:39 70b9,237a:61,ff41:61,1d41a:61,1d44e:61,1d482:61,1d4b6:61,1d4ea:61,1d51e:61,1d552:61,1d586:61,1d5ba:61,1d5ee:61,1d622:61,1d656:61,1d68a:61,251:61,3b1:61,1d6c2:61,1d6fc:61,1d736:61,1d770:61,1d7aa:61,430:61,2df6:363,ff21:41,1d400:41,1d434:41,1d468:41,1d49c:41,1d4d0:41,1d504:41,1d538:41,1d56c:41,1d5a0:41,1d5d4:41,1d608:41,1d63c:41,1d670:41,391:41,1d6a8:41,1d6e2:41,1d71c:41,1d756:41,1d790:41,410:41,13aa:41,15c5:41,a4ee:41,16f40:41,102a0:41,2376:61 332,1ce:103,1cd:102,227:e5,226:c5,1e9a:1ea3,2100:61 2f 63,2101:61 2f 73,a733:61 61,a732:41 41,e6:61 65,4d5:61 65,c6:41 45,4d4:41 45,a735:61 6f,a734:41 4f,1f707:41 52,a737:61 75,a736:41 55,a739:61 76,a73b:61 76,a738:41 56,a73a:41 56,a73d:61 79,a73c:41 59,ab7a:1d00,2200:2c6f,1d217:2c6f,15c4:2c6f,a4ef:2c6f,1041f:2c70,1d41b:62,1d44f:62,1d483:62,1d4b7:62,1d4eb:62,1d51f:62,1d553:62,1d587:62,1d5bb:62,1d5ef:62,1d623:62,1d657:62,1d68b:62,184:62,42c:62,13cf:62,1472:62,15af:62,ff22:42,212c:42,1d401:42,1d435:42,1d469:42,1d4d1:42,1d505:42,1d539:42,1d56d:42,1d5a1:42,1d5d5:42,1d609:42,1d63d:42,1d671:42,a7b4:42,392:42,1d6a9:42,1d6e3:42,1d71d:42,1d757:42,1d791:42,412:42,13f4:42,15f7:42,a4d0:42,10282:42,102a1:42,10301:42,253:62 314,1473:62 307,183:62 304,182:62 304,411:62 304,180:62 335,48d:62 335,48c:62 335,463:62 335,462:62 335,147f:62 b7,1481:62 307 b7,1488:62 27,42b:62 6c,432:299,13fc:299,ff43:63,217d:63,1d41c:63,1d450:63,1d484:63,1d4b8:63,1d4ec:63,1d520:63,1d554:63,1d588:63,1d5bc:63,1d5f0:63,1d624:63,1d658:63,1d68c:63,1d04:63,3f2:63,2ca5:63,441:63,abaf:63,1043d:63,2ded:368,1f74c:43,118f2:43,118e9:43,ff23:43,216d:43,2102:43,212d:43,1d402:43,1d436:43,1d46a:43,1d49e:43,1d4d2:43,1d56e:43,1d5a2:43,1d5d6:43,1d60a:43,1d63e:43,1d672:43,3f9:43,2ca4:43,421:43,13df:43,a4da:43,102a2:43,10302:43,10415:43,1051c:43,a2:63 338,23c:63 338,20a1:43 20eb,1f16e:43 20e0,e7:63 326,4ab:63 326,c7:43 326,4aa:43 326,187:43 27,2105:63 2f 6f,2106:63 2f 75,1f16d:33c4 9 20dd,22f4:a793,25b:a793,3b5:a793,3f5:a793,1d6c6:a793,1d6dc:a793,1d700:a793,1d716:a793,1d73a:a793,1d750:a793,1d774:a793,1d78a:a793,1d7ae:a793,1d7c4:a793,2c89:a793,454:a793,511:a793,ab9b:a793,118ce:a793,10429:a793,20ac:a792,2c88:a792,404:a792,2377:a793 332,37d:a73f,3ff:a73e,217e:64,2146:64,1d41d:64,1d451:64,1d485:64,1d4b9:64,1d4ed:64,1d521:64,1d555:64,1d589:64,1d5bd:64,1d5f1:64,1d625:64,1d659:64,1d68d:64,501:64,13e7:64,146f:64,a4d2:64,216e:44,2145:44,1d403:44,1d437:44,1d46b:44,1d49f:44,1d4d3:44,1d507:44,1d53b:44,1d56f:44,1d5a3:44,1d5d7:44,1d60b:44,1d63f:44,1d673:44,13a0:44,15de:44,15ea:44,a4d3:44,257:64 314,256:64 328,18c:64 304,111:64 335,110:44 335,d0:44 335,189:44 335,20ab:64 335 331,a77a:a779,147b:64 b7,1487:64 27,2a4:64 21d,1f3:64 7a,2a3:64 7a,1f2:44 7a,1f1:44 5a,1c6:64 17e,1c5:44 17e,1c4:44 17d,2a5:64 291,ab70:1d05,2e39:1e9f,3b4:1e9f,1d6c5:1e9f,1d6ff:1e9f,1d739:1e9f,1d773:1e9f,1d7ad:1e9f,56e:1e9f,1577:1e9f,212e:65,ff45:65,212f:65,2147:65,1d41e:65,1d452:65,1d486:65,1d4ee:65,1d522:65,1d556:65,1d58a:65,1d5be:65,1d5f2:65,1d626:65,1d65a:65,1d68e:65,ab32:65,435:65,4bd:65,2df7:364,22ff:45,ff25:45,2130:45,1d404:45,1d438:45,1d46c:45,1d4d4:45,1d508:45,1d53c:45,1d570:45,1d5a4:45,1d5d8:45,1d60c:45,1d640:45,1d674:45,395:45,1d6ac:45,1d6e6:45,1d720:45,1d75a:45,1d794:45,415:45,2d39:45,13ac:45,a4f0:45,118a6:45,118ae:45,10286:45,11b:115,11a:114,247:65 338,246:45 338,4bf:65 328,ab7c:1d07,259:1dd,4d9:1dd,2203:18e,2d3a:18e,a4f1:18e,25a:1dd 2de,1d14:1dd 6f,ab41:1dd 6f 338,ab42:1dd 6f 335,4d8:18f,1d221:190,2107:190,510:190,13cb:190,16f2d:190,10401:190,1d9f:1d4b,1d08:25c,437:25c,499:25c 326,10442:25e,a79d:29a,1042a:29a,1d41f:66,1d453:66,1d487:66,1d4bb:66,1d4ef:66,1d523:66,1d557:66,1d58b:66,1d5bf:66,1d5f3:66,1d627:66,1d65b:66,1d68f:66,ab35:66,a799:66,17f:66,1e9d:66,584:66,1d213:46,2131:46,1d405:46,1d439:46,1d46d:46,1d4d5:46,1d509:46,1d53d:46,1d571:46,1d5a5:46,1d5d9:46,1d60d:46,1d641:46,1d675:46,a798:46,3dc:46,1d7ca:46,15b4:46,a4dd:46,118c2:46,118a2:46,10287:46,102a5:46,10525:46,192:66 326,191:46 326,1d6e:66 334,213b:46 41 58,fb00:66 66,fb03:66 66 69,fb04:66 66 6c,fb01:66 69,fb02:66 6c,2a9:66 14b,15b5:2132,a4de:2132,1d230:a7fb,15b7:a7fb,ff47:67,210a:67,1d420:67,1d454:67,1d488:67,1d4f0:67,1d524:67,1d558:67,1d58c:67,1d5c0:67,1d5f4:67,1d628:67,1d65c:67,1d690:67,261:67,1d83:67,18d:67,581:67,1d406:47,1d43a:47,1d46e:47,1d4a2:47,1d4d6:47,1d50a:47,1d53e:47,1d572:47,1d5a6:47,1d5da:47,1d60e:47,1d642:47,1d676:47,50c:47,13c0:47,13f3:47,a4d6:47,1da2:1d4d,260:67 314,1e7:11f,1e6:11e,1f5:123,1e5:67 335,1e4:47 335,193:47 27,50d:262,ab90:262,13fb:262,ff48:68,210e:68,1d421:68,1d489:68,1d4bd:68,1d4f1:68,1d525:68,1d559:68,1d58d:68,1d5c1:68,1d5f5:68,1d629:68,1d65d:68,1d691:68,4bb:68,570:68,13c2:68,ff28:48,210b:48,210c:48,210d:48,1d407:48,1d43b:48,1d46f:48,1d4d7:48,1d573:48,1d5a7:48,1d5db:48,1d60f:48,1d643:48,1d677:48,397:48,1d6ae:48,1d6e8:48,1d722:48,1d75c:48,1d796:48,2c8e:48,41d:48,13bb:48,157c:48,a4e7:48,102cf:48,1d78:1d34,266:68 314,a695:68 314,13f2:68 314,2c67:48 329,4a2:48 329,127:68 335,210f:68 335,45b:68 335,126:48 335,4c9:48 326,4c7:48 326,43d:29c,ab8b:29c,4a3:29c 329,4ca:29c 326,4c8:29c 326,50a:1f6,ab80:2c76,370:2c75,13a8:2c75,13b0:2c75,a6b1:2c75,a795:a727,2db:69,2373:69,ff49:69,2170:69,2139:69,2148:69,1d422:69,1d456:69,1d48a:69,1d4be:69,1d4f2:69,1d526:69,1d55a:69,1d58e:69,1d5c2:69,1d5f6:69,1d62a:69,1d65e:69,1d692:69,131:69,1d6a4:69,26a:69,269:69,3b9:69,1fbe:69,37a:69,1d6ca:69,1d704:69,1d73e:69,1d778:69,1d7b2:69,456:69,a647:69,4cf:69,ab75:69,13a5:69,118c3:69,24db:24be,2378:69 332,1d0:12d,1cf:12c,268:69 335,1d7b:69 335,1d7c:69 335,2171:69 69,2172:69 69 69,133:69 6a,2173:69 76,2178:69 78,ff4a:6a,2149:6a,1d423:6a,1d457:6a,1d48b:6a,1d4bf:6a,1d4f3:6a,1d527:6a,1d55b:6a,1d58f:6a,1d5c3:6a,1d5f7:6a,1d62b:6a,1d65f:6a,1d693:6a,3f3:6a,458:6a,ff2a:4a,1d409:4a,1d43d:4a,1d471:4a,1d4a5:4a,1d4d9:4a,1d50d:4a,1d541:4a,1d575:4a,1d5a9:4a,1d5dd:4a,1d611:4a,1d645:4a,1d679:4a,a7b2:4a,37f:4a,408:4a,13ab:4a,148d:4a,a4d9:4a,249:6a 335,248:4a 335,1499:4a b7,1d6a5:237,575:237,ab7b:1d0a,1d424:6b,1d458:6b,1d48c:6b,1d4c0:6b,1d4f4:6b,1d528:6b,1d55c:6b,1d590:6b,1d5c4:6b,1d5f8:6b,1d62c:6b,1d660:6b,1d694:6b,212a:4b,ff2b:4b,1d40a:4b,1d43e:4b,1d472:4b,1d4a6:4b,1d4da:4b,1d50e:4b,1d542:4b,1d576:4b,1d5aa:4b,1d5de:4b,1d612:4b,1d646:4b,1d67a:4b,39a:4b,1d6b1:4b,1d6eb:4b,1d725:4b,1d75f:4b,1d799:4b,2c94:4b,41a:4b,13e6:4b,16d5:4b,a4d7:4b,10518:4b,199:6b 314,2c69:4b 329,49a:4b 329,20ad:4b 335,a740:4b 335,49e:4b 335,198:4b 27,5c0:6c,7c:6c,2223:6c,23fd:6c,ffe8:6c,31:6c,661:6c,6f1:6c,10320:6c,1e8c7:6c,1d7cf:6c,1d7d9:6c,1d7e3:6c,1d7ed:6c,1d7f7:6c,1fbf1:6c,49:6c,ff29:6c,2160:6c,2110:6c,2111:6c,1d408:6c,1d43c:6c,1d470:6c,1d4d8:6c,1d540:6c,1d574:6c,1d5a8:6c,1d5dc:6c,1d610:6c,1d644:6c,1d678:6c,196:6c,ff4c:6c,217c:6c,2113:6c,1d425:6c,1d459:6c,1d48d:6c,1d4c1:6c,1d4f5:6c,1d529:6c,1d55d:6c,1d591:6c,1d5c5:6c,1d5f9:6c,1d62d:6c,1d661:6c,1d695:6c,1c0:6c,399:6c,1d6b0:6c,1d6ea:6c,1d724:6c,1d75e:6c,1d798:6c,2c92:6c,406:6c,4c0:6c,5d5:6c,5df:6c,627:6c,1ee00:6c,1ee80:6c,fe8e:6c,fe8d:6c,7ca:6c,2d4f:6c,16c1:6c,a4f2:6c,16f28:6c,1028a:6c,10309:6c,1d22a:4c,216c:4c,2112:4c,1d40b:4c,1d43f:4c,1d473:4c,1d4db:4c,1d50f:4c,1d543:4c,1d577:4c,1d5ab:4c,1d5df:4c,1d613:4c,1d647:4c,1d67b:4c,2cd0:4c,13de:4c,14aa:4c,a4e1:4c,16f16:4c,118a3:4c,118b2:4c,1041b:4c,10526:4c,fd3c:6c 30b,fd3d:6c 30b,142:6c 338,141:4c 338,26d:6c 328,197:6c 335,19a:6c 335,26b:6c 334,625:6c 655,fe88:6c 655,fe87:6c 655,673:6c 655,140:6c b7,13f:6c b7,14b7:6c b7,1f102:6c 2c,2488:6c 2e,5f1:6c 27,2493:6c 32 2e,33eb:6c 32 65e5,32cb:6c 32 6708,3364:6c 32 70b9,2494:6c 33 2e,33ec:6c 33 65e5,3365:6c 33 70b9,2495:6c 34 2e,33ed:6c 34 65e5,3366:6c 34 70b9,2496:6c 35 2e,33ee:6c 35 65e5,3367:6c 35 70b9,2497:6c 36 2e,33ef:6c 36 65e5,3368:6c 36 70b9,2498:6c 37 2e,33f0:6c 37 65e5,3369:6c 37 70b9,2499:6c 38 2e,33f1:6c 38 65e5,336a:6c 38 70b9,249a:6c 39 2e,33f2:6c 39 65e5,336b:6c 39 70b9,1c9:6c 6a,132:6c 4a,1c8:4c 6a,1c7:4c 4a,2016:6c 6c,2225:6c 6c,2161:6c 6c,1c1:6c 6c,5f0:6c 6c,10199:6c 335 6c 335,2492:6c 6c 2e,2162:6c 6c 6c,10198:6c 335 6c 335 53 335,33ea:6c 6c 65e5,32ca:6c 6c 6708,3363:6c 6c 70b9,42e:6c 4f,2491:6c 4f 2e,33e9:6c 4f 65e5,32c9:6c 4f 6708,3362:6c 4f 70b9,2aa:6c 73,20b6:6c 74,2163:6c 56,2168:6c 58,26e:6c 21d,2ab:6c 7a,675:6c 674,623:6c 674,fe84:6c 674,fe83:6c 674,672:6c 674,fdf3:6c 643 628 631,fdf2:6c 644 644 651 670 6f,33e0:6c 65e5,32c0:6c 6708,3359:6c 70b9,2cd1:29f,abae:29f,10443:29f,ff2d:4d,216f:4d,2133:4d,1d40c:4d,1d440:4d,1d474:4d,1d4dc:4d,1d510:4d,1d544:4d,1d578:4d,1d5ac:4d,1d5e0:4d,1d614:4d,1d648:4d,1d67c:4d,39c:4d,1d6b3:4d,1d6ed:4d,1d727:4d,1d761:4d,1d79b:4d,3fa:4d,2c98:4d,41c:4d,13b7:4d,15f0:4d,16d6:4d,a4df:4d,102b0:4d,10311:4d,4cd:4d 326,1f76b:4d 42,2de8:1ddf,1d427:6e,1d45b:6e,1d48f:6e,1d4c3:6e,1d4f7:6e,1d52b:6e,1d55f:6e,1d593:6e,1d5c7:6e,1d5fb:6e,1d62f:6e,1d663:6e,1d697:6e,578:6e,57c:6e,ff2e:4e,2115:4e,1d40d:4e,1d441:4e,1d475:4e,1d4a9:4e,1d4dd:4e,1d511:4e,1d579:4e,1d5ad:4e,1d5e1:4e,1d615:4e,1d649:4e,1d67d:4e,39d:4e,1d6b4:4e,1d6ee:4e,1d728:4e,1d762:4e,1d79c:4e,2c9a:4e,a4e0:4e,10513:4e,1018e:4e 30a,273:6e 328,19e:6e 329,3b7:6e 329,1d6c8:6e 329,1d702:6e 329,1d73c:6e 329,1d776:6e 329,1d7b0:6e 329,19d:4e 326,1d70:6e 334,1cc:6e 6a,1cb:4e 6a,1ca:4e 4a,2116:4e 6f,377:1d0e,438:1d0e,1044d:1d0e,146:272,c02:6f,c82:6f,d02:6f,d82:6f,966:6f,a66:6f,ae6:6f,be6:6f,c66:6f,ce6:6f,d66:6f,e50:6f,ed0:6f,1040:6f,665:6f,6f5:6f,ff4f:6f,2134:6f,1d428:6f,1d45c:6f,1d490:6f,1d4f8:6f,1d52c:6f,1d560:6f,1d594:6f,1d5c8:6f,1d5fc:6f,1d630:6f,1d664:6f,1d698:6f,1d0f:6f,1d11:6f,ab3d:6f,3bf:6f,1d6d0:6f,1d70a:6f,1d744:6f,1d77e:6f,1d7b8:6f,3c3:6f,1d6d4:6f,1d70e:6f,1d748:6f,1d782:6f,1d7bc:6f,2c9f:6f,43e:6f,10ff:6f,585:6f,5e1:6f,647:6f,1ee24:6f,1ee64:6f,1ee84:6f,feeb:6f,feec:6f,feea:6f,fee9:6f,6be:6f,fbac:6f,fbad:6f,fbab:6f,fbaa:6f,6c1:6f,fba8:6f,fba9:6f,fba7:6f,fba6:6f,6d5:6f,d20:6f,101d:6f,104ea:6f,118c8:6f,118d7:6f,1042c:6f,30:4f,7c0:4f,9e6:4f,b66:4f,3007:4f,114d0:4f,118e0:4f,1d7ce:4f,1d7d8:4f,1d7e2:4f,1d7ec:4f,1d7f6:4f,1fbf0:4f,ff2f:4f,1d40e:4f,1d442:4f,1d476:4f,1d4aa:4f,1d4de:4f,1d512:4f,1d546:4f,1d57a:4f,1d5ae:4f,1d5e2:4f,1d616:4f,1d64a:4f,1d67e:4f,39f:4f,1d6b6:4f,1d6f0:4f,1d72a:4f,1d764:4f,1d79e:4f,2c9e:4f,41e:4f,555:4f,2d54:4f,12d0:4f,b20:4f,104c2:4f,a4f3:4f,118b5:4f,10292:4f,102ab:4f,10404:4f,10516:4f,2070:ba,1d52:ba,1d2:14f,1d1:14e,6ff:6f 302,150:d6,f8:6f 338,ab3e:6f 338,d8:4f 338,2d41:4f 338,1fe:4f 338 301,275:6f 335,a74b:6f 335,4e9:6f 335,473:6f 335,ab8e:6f 335,abbb:6f 335,2296:4f 335,229d:4f 335,236c:4f 335,1d21a:4f 335,1f714:4f 335,19f:4f 335,a74a:4f 335,3b8:4f 335,3d1:4f 335,1d6c9:4f 335,1d6dd:4f 335,1d703:4f 335,1d717:4f 335,1d73d:4f 335,1d751:4f 335,1d777:4f 335,1d78b:4f 335,1d7b1:4f 335,1d7c5:4f 335,398:4f 335,3f4:4f 335,1d6af:4f 335,1d6b9:4f 335,1d6e9:4f 335,1d6f3:4f 335,1d723:4f 335,1d72d:4f 335,1d75d:4f 335,1d767:4f 335,1d797:4f 335,1d7a1:4f 335,4e8:4f 335,472:4f 335,2d31:4f 335,13be:4f 335,13eb:4f 335,ab74:6f 31b,fcd9:6f 670,1f101:4f 2c,1f100:4f 2e,1a1:6f 27,1a0:4f 27,13a4:4f 27,25:ba 2f 2080,66a:ba 2f 2080,2052:ba 2f 2080,2030:ba 2f 2080 2080,609:ba 2f 2080 2080,2031:ba 2f 2080 2080 2080,60a:ba 2f 2080 2080 2080,153:6f 65,152:4f 45,276:6f 1d07,221e:6f 6f,a74f:6f 6f,a699:6f 6f,a74e:4f 4f,a698:4f 4f,fcd7:6f 62c,fc51:6f 62c,fcd8:6f 645,fc52:6f 645,fd93:6f 645 62c,fd94:6f 645 645,fc53:6f 649,fc54:6f 649,d5f:6f d30 6f,1010:6f 102c,3358:4f 70b9,2184:254,1d10:254,37b:254,1044b:254,2183:186,3fd:186,a4db:186,10423:186,ab3f:254 338,ab62:254 65,1043f:277,2374:70,ff50:70,1d429:70,1d45d:70,1d491:70,1d4c5:70,1d4f9:70,1d52d:70,1d561:70,1d595:70,1d5c9:70,1d5fd:70,1d631:70,1d665:70,1d699:70,3c1:70,3f1:70,1d6d2:70,1d6e0:70,1d70c:70,1d71a:70,1d746:70,1d754:70,1d780:70,1d78e:70,1d7ba:70,1d7c8:70,2ca3:70,440:70,ff30:50,2119:50,1d40f:50,1d443:50,1d477:50,1d4ab:50,1d4df:50,1d513:50,1d57b:50,1d5af:50,1d5e3:50,1d617:50,1d64b:50,1d67f:50,3a1:50,1d6b8:50,1d6f2:50,1d72c:50,1d766:50,1d7a0:50,2ca2:50,420:50,13e2:50,146d:50,a4d1:50,10295:50,1a5:70 314,1d7d:70 335,1477:70 b7,1486:50 27,1d29:1d18,abb2:1d18,3c6:278,3d5:278,1d6d7:278,1d6df:278,1d711:278,1d719:278,1d74b:278,1d753:278,1d785:278,1d78d:278,1d7bf:278,1d7c7:278,2cab:278,444:278,1d42a:71,1d45e:71,1d492:71,1d4c6:71,1d4fa:71,1d52e:71,1d562:71,1d596:71,1d5ca:71,1d5fe:71,1d632:71,1d666:71,1d69a:71,51b:71,563:71,566:71,211a:51,1d410:51,1d444:51,1d478:51,1d4ac:51,1d4e0:51,1d514:51,1d57c:51,1d5b0:51,1d5e4:51,1d618:51,1d64c:51,1d680:51,2d55:51,2a0:71 314,1f700:51 45,1d90:24b,1d0b:138,3ba:138,3f0:138,1d6cb:138,1d6de:138,1d705:138,1d718:138,1d73f:138,1d752:138,1d779:138,1d78c:138,1d7b3:138,1d7c6:138,2c95:138,43a:138,abb6:138,49b:138 329,49f:138 335,1d42b:72,1d45f:72,1d493:72,1d4c7:72,1d4fb:72,1d52f:72,1d563:72,1d597:72,1d5cb:72,1d5ff:72,1d633:72,1d667:72,1d69b:72,ab47:72,ab48:72,1d26:72,2c85:72,433:72,ab81:72,1d216:52,211b:52,211c:52,211d:52,1d411:52,1d445:52,1d479:52,1d4e1:52,1d57d:52,1d5b1:52,1d5e5:52,1d619:52,1d64d:52,1d681:52,1a6:52,13a1:52,13d2:52,104b4:52,1587:52,a4e3:52,16f35:52,27d:72 328,27c:72 329,24d:72 335,493:72 335,1d72:72 334,491:72 27,118e3:72 6e,6d:72 6e,217f:72 6e,1d426:72 6e,1d45a:72 6e,1d48e:72 6e,1d4c2:72 6e,1d4f6:72 6e,1d52a:72 6e,1d55e:72 6e,1d592:72 6e,1d5c6:72 6e,1d5fa:72 6e,1d62e:72 6e,1d662:72 6e,1d696:72 6e,11700:72 6e,20a5:72 6e 338,271:72 6e 326,1d6f:72 6e 334,20a8:52 73,ab71:280,aba2:280,44f:1d19,1d73:27e 334,2129:27f,ff53:73,1d42c:73,1d460:73,1d494:73,1d4c8:73,1d4fc:73,1d530:73,1d564:73,1d598:73,1d5cc:73,1d600:73,1d634:73,1d668:73,1d69c:73,a731:73,1bd:73,455:73,abaa:73,118c1:73,10448:73,ff33:53,1d412:53,1d446:53,1d47a:53,1d4ae:53,1d4e2:53,1d516:53,1d54a:53,1d57e:53,1d5b2:53,1d5e6:53,1d61a:53,1d64e:53,1d682:53,405:53,54f:53,13d5:53,13da:53,a4e2:53,16f3a:53,10296:53,10420:53,282:73 328,1d74:73 334,a7b5:df,3b2:df,3d0:df,1d6c3:df,1d6fd:df,1d737:df,1d771:df,1d7ab:df,13f0:df,1f75c:73 73 73,fb06:73 74,222b:283,ab4d:283,2211:1a9,2140:1a9,3a3:1a9,1d6ba:1a9,1d6f4:1a9,1d72e:1a9,1d768:1a9,1d7a2:1a9,2d49:1a9,222c:283 283,222d:283 283 283,2a0c:283 283 283 283,1d42d:74,1d461:74,1d495:74,1d4c9:74,1d4fd:74,1d531:74,1d565:74,1d599:74,1d5cd:74,1d601:74,1d635:74,1d669:74,1d69d:74,22a4:54,27d9:54,1f768:54,ff34:54,1d413:54,1d447:54,1d47b:54,1d4af:54,1d4e3:54,1d517:54,1d54b:54,1d57f:54,1d5b3:54,1d5e7:54,1d61b:54,1d64f:54,1d683:54,3a4:54,1d6bb:54,1d6f5:54,1d72f:54,1d769:54,1d7a3:54,2ca6:54,422:54,13a2:54,a4d4:54,16f0a:54,118bc:54,10297:54,102b1:54,10315:54,1ad:74 314,2361:54 308,23e:54 338,21a:162,1ae:54 328,4ac:54 329,20ae:54 20eb,167:74 335,166:54 335,1d75:74 334,10a0:a786,a728:54 33,2a8:74 255,2121:54 45 4c,a777:74 66,2a6:74 73,2a7:74 283,a729:74 21d,3c4:1d1b,1d6d5:1d1b,1d70f:1d1b,1d749:1d1b,1d783:1d1b,1d7bd:1d1b,442:1d1b,ab72:1d1b,4ad:1d1b 329,163:1ab,21b:1ab,13bf:1ab,1d42e:75,1d462:75,1d496:75,1d4ca:75,1d4fe:75,1d532:75,1d566:75,1d59a:75,1d5ce:75,1d602:75,1d636:75,1d66a:75,1d69e:75,a79f:75,1d1c:75,ab4e:75,ab52:75,28b:75,3c5:75,1d6d6:75,1d710:75,1d74a:75,1d784:75,1d7be:75,57d:75,104f6:75,118d8:75,222a:55,22c3:55,1d414:55,1d448:55,1d47c:55,1d4b0:55,1d4e4:55,1d518:55,1d54c:55,1d580:55,1d5b4:55,1d5e8:55,1d61c:55,1d650:55,1d684:55,54d:55,1200:55,104ce:55,144c:55,a4f4:55,16f42:55,118b8:55,1d4:16d,1d3:16c,1d7e:75 335,ab9c:75 335,244:55 335,13cc:55 335,1458:55 b7,1467:55 27,1d6b:75 65,ab63:75 6f,1e43:ab51,57a:270,1223:270,2127:1b1,162e:1b1,1634:1b1,1d7f:28a 335,2228:76,22c1:76,ff56:76,2174:76,1d42f:76,1d463:76,1d497:76,1d4cb:76,1d4ff:76,1d533:76,1d567:76,1d59b:76,1d5cf:76,1d603:76,1d637:76,1d66b:76,1d69f:76,1d20:76,3bd:76,1d6ce:76,1d708:76,1d742:76,1d77c:76,1d7b6:76,475:76,5d8:76,11706:76,aba9:76,118c0:76,1d20d:56,667:56,6f7:56,2164:56,1d415:56,1d449:56,1d47d:56,1d4b1:56,1d4e5:56,1d519:56,1d54d:56,1d581:56,1d5b5:56,1d5e9:56,1d61d:56,1d651:56,1d685:56,474:56,2d38:56,13d9:56,142f:56,a6df:56,a4e6:56,16f08:56,118a0:56,1051d:56,10197:56 335,143b:56 b7,1f76c:56 42,2175:76 69,2176:76 69 69,2177:76 69 69 69,2165:56 6c,2166:56 6c 6c,2167:56 6c 6c 6c,1f708:56 1de4,1d27:28c,104d8:28c,668:245,6f8:245,39b:245,1d6b2:245,1d6ec:245,1d726:245,1d760:245,1d79a:245,41b:245,2d37:245,104b0:245,1431:245,a6ce:245,a4e5:245,16f3d:245,1028d:245,4c5:245 326,143d:245 b7,26f:77,1d430:77,1d464:77,1d498:77,1d4cc:77,1d500:77,1d534:77,1d568:77,1d59c:77,1d5d0:77,1d604:77,1d638:77,1d66c:77,1d6a0:77,1d21:77,461:77,51d:77,561:77,1170a:77,1170e:77,1170f:77,ab83:77,118ef:57,118e6:57,1d416:57,1d44a:57,1d47e:57,1d4b2:57,1d4e6:57,1d51a:57,1d54e:57,1d582:57,1d5b6:57,1d5ea:57,1d61e:57,1d652:57,1d686:57,51c:57,13b3:57,13d4:57,a4ea:57,47d:77 486 487,114c5:77 307,20a9:57 335,a761:77 326,1d0d:28d,43c:28d,ab87:28d,4ce:28d 326,166e:78,d7:78,292b:78,292c:78,2a2f:78,ff58:78,2179:78,1d431:78,1d465:78,1d499:78,1d4cd:78,1d501:78,1d535:78,1d569:78,1d59d:78,1d5d1:78,1d605:78,1d639:78,1d66d:78,1d6a1:78,445:78,1541:78,157d:78,2def:36f,166d:58,2573:58,10322:58,118ec:58,ff38:58,2169:58,1d417:58,1d44b:58,1d47f:58,1d4b3:58,1d4e7:58,1d51b:58,1d54f:58,1d583:58,1d5b7:58,1d5eb:58,1d61f:58,1d653:58,1d687:58,a7b3:58,3a7:58,1d6be:58,1d6f8:58,1d732:58,1d76c:58,1d7a6:58,2cac:58,425:58,2d5d:58,16b7:58,a4eb:58,10290:58,102b4:58,10317:58,10527:58,2a30:78 307,4b2:58 329,10196:58 335,217a:78 69,217b:78 69 69,216a:58 6c,216b:58 6c 6c,263:79,1d8c:79,ff59:79,1d432:79,1d466:79,1d49a:79,1d4ce:79,1d502:79,1d536:79,1d56a:79,1d59e:79,1d5d2:79,1d606:79,1d63a:79,1d66e:79,1d6a2:79,28f:79,1eff:79,ab5a:79,3b3:79,213d:79,1d6c4:79,1d6fe:79,1d738:79,1d772:79,1d7ac:79,443:79,4af:79,10e7:79,118dc:79,ff39:59,1d418:59,1d44c:59,1d480:59,1d4b4:59,1d4e8:59,1d51c:59,1d550:59,1d584:59,1d5b8:59,1d5ec:59,1d620:59,1d654:59,1d688:59,3a5:59,3d2:59,1d6bc:59,1d6f6:59,1d730:59,1d76a:59,1d7a4:59,2ca8:59,423:59,4ae:59,13a9:59,13bd:59,a4ec:59,16f43:59,118a4:59,102b2:59,1b4:79 314,24f:79 335,4b1:79 335,a5:59 335,24e:59 335,4b0:59 335,292:21d,a76b:21d,2ccd:21d,4e1:21d,10f3:21d,1d433:7a,1d467:7a,1d49b:7a,1d4cf:7a,1d503:7a,1d537:7a,1d56b:7a,1d59f:7a,1d5d3:7a,1d607:7a,1d63b:7a,1d66f:7a,1d6a3:7a,1d22:7a,ab93:7a,118c4:7a,102f5:5a,118e5:5a,ff3a:5a,2124:5a,2128:5a,1d419:5a,1d44d:5a,1d481:5a,1d4b5:5a,1d4e9:5a,1d585:5a,1d5b9:5a,1d5ed:5a,1d621:5a,1d655:5a,1d689:5a,396:5a,1d6ad:5a,1d6e7:5a,1d721:5a,1d75b:5a,1d795:5a,13c3:5a,a4dc:5a,118a9:5a,290:7a 328,1b6:7a 335,1b5:5a 335,225:7a 326,224:5a 326,1d76:7a 334,1bf:fe,3f8:fe,3f7:de,104c4:de,2079:a770,1d24:1a8,3e9:1a8,a645:1a8,44c:185,ab9f:185,44b:185 69,ab7e:242,2e4:2c1,a6cd:2a1,2299:298,2609:298,2a00:298,a668:298,2d59:298,104c3:298,213e:393,1d6aa:393,1d6e4:393,1d71e:393,1d758:393,1d792:393,2c84:393,413:393,13b1:393,14a5:393,16f07:393,492:393 335,14af:393 b7,490:393 27,2206:394,25b3:394,1f702:394,1d6ab:394,1d6e5:394,1d71f:394,1d759:394,1d793:394,2c86:394,2d60:394,1403:394,16f1a:394,10285:394,102a3:394,2359:394 332,140f:394 b7,142c:394 1420,1d7cb:3dd,1d6c7:3b6,1d701:3b6,1d73b:3b6,1d775:3b6,1d7af:3b6,2ce4:3d7,1d6cc:3bb,1d706:3bb,1d740:3bb,1d77a:3bb,1d7b4:3bb,2c96:3bb,104db:3bb,b5:3bc,1d6cd:3bc,1d707:3bc,1d741:3bc,1d77b:3bc,1d7b5:3bc,1d6cf:3be,1d709:3be,1d743:3be,1d77d:3be,1d7b7:3be,1d6b5:39e,1d6ef:39e,1d729:39e,1d763:39e,1d79d:39e,3d6:3c0,213c:3c0,1d6d1:3c0,1d6e1:3c0,1d70b:3c0,1d71b:3c0,1d745:3c0,1d755:3c0,1d77f:3c0,1d78f:3c0,1d7b9:3c0,1d7c9:3c0,1d28:3c0,43f:3c0,220f:3a0,213f:3a0,1d6b7:3a0,1d6f1:3a0,1d72b:3a0,1d765:3a0,1d79f:3a0,2ca0:3a0,41f:3a0,a6db:3a0,102ad:3d8,10312:3d8,3db:3c2,1d6d3:3c2,1d70d:3c2,1d747:3c2,1d781:3c2,1d7bb:3c2,1d6bd:3a6,1d6f7:3a6,1d731:3a6,1d76b:3a6,1d7a5:3a6,2caa:3a6,424:3a6,553:3a6,1240:3a6,16f0:3a6,102b3:3a6,ab53:3c7,ab55:3c7,1d6d8:3c7,1d712:3c7,1d74c:3c7,1d786:3c7,1d7c0:3c7,2cad:3c7,1d6d9:3c8,1d713:3c8,1d74d:3c8,1d787:3c8,1d7c1:3c8,471:3c8,104f9:3c8,1d6bf:3a8,1d6f9:3a8,1d733:3a8,1d76d:3a8,1d7a7:3a8,2cae:3a8,470:3a8,104d1:3a8,16d8:3a8,102b5:3a8,2375:3c9,a7b7:3c9,1d6da:3c9,1d714:3c9,1d74e:3c9,1d788:3c9,1d7c2:3c9,2cb1:3c9,a64d:3c9,2126:3a9,1d6c0:3a9,1d6fa:3a9,1d734:3a9,1d76e:3a9,1d7a8:3a9,162f:3a9,1635:3a9,102b6:3a9,2379:3c9 332,1f7d:1ff4,2630:2cb6,2cdc:3ec,497:436 329,496:416 329,1d20b:418,376:418,a6a1:418,10425:418,419:40d,48a:40d 326,45d:439,48b:439 326,104bc:4c3,1d2b:43b,4c6:43b 326,ab60:459,104eb:a669,1dee:2dec,104cd:40b,1d202:4fe,1d222:460,13c7:460,15ef:460,47c:460 486 487,18ed:460 b7,a7b6:a64c,4cc:4b7,4cb:4b6,4be:4bc 328,2cbd:448,2cbc:428,a650:42a 6c,2108:42d,1f701:a658,16f1c:a658,a992:2c3f,587:565 582,1294:571,fb14:574 565,fb15:574 56b,fb17:574 56d,fb13:574 576,2229:548,22c2:548,1d245:548,1260:548,144e:548,a4f5:548,145a:548 b7,1468:548 27,fb16:57e 576,20bd:554,2d3:559,2bf:559,2135:5d0,fb21:5d0,fb2f:fb2e,fb30:fb2e,fb4f:5d0 5dc,2136:5d1,2137:5d2,2138:5d3,fb22:5d3,fb23:5d4,fb39:fb1d,fb24:5db,fb25:5dc,fb26:5dd,fb20:5e2,fb27:5e8,fb2b:fb2a,fb49:fb2a,fb2d:fb2c,fb28:5ea,fe80:621,6fd:621 348,fe82:622,fe81:622,fb51:671,fb50:671,1ee01:628,1ee21:628,1ee61:628,1ee81:628,1eea1:628,fe91:628,fe92:628,fe90:628,fe8f:628,751:628 6db,8b6:628 6e2,8a1:628 654,fca0:628 6f,fce2:628 6f,fc9c:628 62c,fc05:628 62c,fc9d:628 62d,fc06:628 62d,fdc2:628 62d 649,fc9e:628 62e,fc07:628 62e,fcd2:628 62e,fc4b:628 62e,fd9e:628 62e 649,fc6a:628 631,fc6b:628 632,fc9f:628 645,fce1:628 645,fc6c:628 645,fc08:628 645,fc6d:628 646,fc6e:628 649,fc09:628 649,fc6f:628 649,fc0a:628 649,fb54:67b,fb55:67b,fb53:67b,fb52:67b,6d0:67b,fbe6:67b,fbe7:67b,fbe5:67b,fbe4:67b,fb5c:680,fb5d:680,fb5b:680,fb5a:680,8a9:754,767:754,2365:629,f6:629,fe94:629,fe93:629,6c3:629,1ee15:62a,1ee35:62a,1ee75:62a,1ee95:62a,1eeb5:62a,fe97:62a,fe98:62a,fe96:62a,fe95:62a,fca5:62a 6f,fce4:62a 6f,fca1:62a 62c,fc0b:62a 62c,fd50:62a 62c 645,fda0:62a 62c 649,fd9f:62a 62c 649,fca2:62a 62d,fc0c:62a 62d,fd52:62a 62d 62c,fd51:62a 62d 62c,fd53:62a 62d 645,fca3:62a 62e,fc0d:62a 62e,fd54:62a 62e 645,fda2:62a 62e 649,fda1:62a 62e 649,fc70:62a 631,fc71:62a 632,fca4:62a 645,fce3:62a 645,fc72:62a 645,fc0e:62a 645,fd55:62a 645 62c,fd56:62a 645 62d,fd57:62a 645 62e,fda4:62a 645 649,fda3:62a 645 649,fc73:62a 646,fc74:62a 649,fc0f:62a 649,fc75:62a 649,fc10:62a 649,fb60:67a,fb61:67a,fb5f:67a,fb5e:67a,fb64:67f,fb65:67f,fb63:67f,fb62:67f,1ee02:62c,1ee22:62c,1ee42:62c,1ee62:62c,1ee82:62c,1eea2:62c,fe9f:62c,fea0:62c,fe9e:62c,fe9d:62c,fca7:62c 62d,fc15:62c 62d,fda6:62c 62d 649,fdbe:62c 62d 649,fdfb:62c 644 20 62c 644 6c 644 6f,fca8:62c 645,fc16:62c 645,fd59:62c 645 62d,fd58:62c 645 62d,fda7:62c 645 649,fda5:62c 645 649,fd1d:62c 649,fd01:62c 649,fd1e:62c 649,fd02:62c 649,fb78:683,fb79:683,fb77:683,fb76:683,fb74:684,fb75:684,fb73:684,fb72:684,fb7c:686,fb7d:686,fb7b:686,fb7a:686,fb80:687,fb81:687,fb7f:687,fb7e:687,1ee07:62d,1ee27:62d,1ee47:62d,1ee67:62d,1ee87:62d,1eea7:62d,fea3:62d,fea4:62d,fea2:62d,fea1:62d,685:62d 6db,681:62d 654,772:62d 654,fca9:62d 62c,fc17:62d 62c,fdbf:62d 62c 649,fcaa:62d 645,fc18:62d 645,fd5b:62d 645 649,fd5a:62d 645 649,fd1b:62d 649,fcff:62d 649,fd1c:62d 649,fd00:62d 649,1ee17:62e,1ee37:62e,1ee57:62e,1ee77:62e,1ee97:62e,1eeb7:62e,fea7:62e,fea8:62e,fea6:62e,fea5:62e,fcab:62e 62c,fc19:62e 62c,fc1a:62e 62d,fcac:62e 645,fc1b:62e 645,fd1f:62e 649,fd03:62e 649,fd20:62e 649,fd04:62e 649,102e1:62f,1ee03:62f,1ee83:62f,1eea3:62f,feaa:62f,fea9:62f,688:62f 615,fb89:62f 615,fb88:62f 615,68e:62f 6db,fb87:62f 6db,fb86:62f 6db,6ee:62f 302,8ae:62f 324 323,1ee18:630,1ee98:630,1eeb8:630,feac:630,feab:630,fc5b:630 670,68b:68a 615,fb85:68c,fb84:68c,fb83:68d,fb82:68d,1ee13:631,1ee93:631,1eeb3:631,feae:631,fead:631,691:631 615,fb8d:631 615,fb8c:631 615,698:631 6db,fb8b:631 6db,fb8a:631 6db,692:631 306,8b9:631 306 307,6ef:631 302,76c:631 654,fc5c:631 670,fdf6:631 633 648 644,fdfc:631 649 6c 644,1ee06:632,1ee86:632,1eea6:632,feb0:632,feaf:632,8b2:632 302,771:697 615,1ee0e:633,1ee2e:633,1ee4e:633,1ee6e:633,1ee8e:633,1eeae:633,feb3:633,feb4:633,feb2:633,feb1:633,634:633 6db,1ee14:633 6db,1ee34:633 6db,1ee54:633 6db,1ee74:633 6db,1ee94:633 6db,1eeb4:633 6db,feb7:633 6db,feb8:633 6db,feb6:633 6db,feb5:633 6db,77e:633 302,fd31:633 6f,fce8:633 6f,fd32:633 6db 6f,fcea:633 6db 6f,fcad:633 62c,fd34:633 62c,fc1c:633 62c,fd2d:633 6db 62c,fd37:633 6db 62c,fd25:633 6db 62c,fd09:633 6db 62c,fd5d:633 62c 62d,fd5e:633 62c 649,fd69:633 6db 62c 649,fcae:633 62d,fd35:633 62d,fc1d:633 62d,fd2e:633 6db 62d,fd38:633 6db 62d,fd26:633 6db 62d,fd0a:633 6db 62d,fd5c:633 62d 62c,fd68:633 6db 62d 645,fd67:633 6db 62d 645,fdaa:633 6db 62d 649,fcaf:633 62e,fd36:633 62e,fc1e:633 62e,fd2f:633 6db 62e,fd39:633 6db 62e,fd27:633 6db 62e,fd0b:633 6db 62e,fda8:633 62e 649,fdc6:633 62e 649,fd2a:633 631,fd0e:633 631,fd29:633 6db 631,fd0d:633 6db 631,fcb0:633 645,fce7:633 645,fc1f:633 645,fd30:633 6db 645,fce9:633 6db 645,fd28:633 6db 645,fd0c:633 6db 645,fd61:633 645 62c,fd60:633 645 62d,fd5f:633 645 62d,fd6b:633 6db 645 62e,fd6a:633 6db 645 62e,fd63:633 645 645,fd62:633 645 645,fd6d:633 6db 645 645,fd6c:633 6db 645 645,fd17:633 649,fcfb:633 649,fd18:633 649,fcfc:633 649,fd19:633 6db 649,fcfd:633 6db 649,fd1a:633 6db 649,fcfe:633 6db 649,102f2:635,1ee11:635,1ee31:635,1ee51:635,1ee71:635,1ee91:635,1eeb1:635,febb:635,febc:635,feba:635,feb9:635,69e:635 6db,8af:635 324 323,fcb1:635 62d,fc20:635 62d,fd65:635 62d 62d,fd64:635 62d 62d,fda9:635 62d 649,fcb2:635 62e,fd2b:635 631,fd0f:635 631,fdf5:635 644 639 645,fdf9:635 644 649,fdf0:635 644 649,fdfa:635 644 649 20 6c 644 644 6f 20 639 644 649 6f 20 648 633 644 645,fcb3:635 645,fc21:635 645,fdc5:635 645 645,fd66:635 645 645,fd21:635 649,fd05:635 649,fd22:635 649,fd06:635 649,1ee19:636,1ee39:636,1ee59:636,1ee79:636,1ee99:636,1eeb9:636,febf:636,fec0:636,febe:636,febd:636,fcb4:636 62c,fc22:636 62c,fcb5:636 62d,fc23:636 62d,fd6e:636 62d 649,fdab:636 62d 649,fcb6:636 62e,fc24:636 62e,fd70:636 62e 645,fd6f:636 62e 645,fd2c:636 631,fd10:636 631,fcb7:636 645,fc25:636 645,fd23:636 649,fd07:636 649,fd24:636 649,fd08:636 649,102e8:637,1ee08:637,1ee68:637,1ee88:637,1eea8:637,fec3:637,fec4:637,fec2:637,fec1:637,69f:637 6db,fcb8:637 62d,fc26:637 62d,fd33:637 645,fd3a:637 645,fc27:637 645,fd72:637 645 62d,fd71:637 645 62d,fd73:637 645 645,fd74:637 645 649,fd11:637 649,fcf5:637 649,fd12:637 649,fcf6:637 649,1ee1a:638,1ee7a:638,1ee9a:638,1eeba:638,fec7:638,fec8:638,fec6:638,fec5:638,fcb9:638 645,fd3b:638 645,fc28:638 645,60f:639,1ee0f:639,1ee2f:639,1ee4f:639,1ee6f:639,1ee8f:639,1eeaf:639,fecb:639,fecc:639,feca:639,fec9:639,fcba:639 62c,fc29:639 62c,fdc4:639 62c 645,fd75:639 62c 645,fdf7:639 644 649 6f,fcbb:639 645,fc2a:639 645,fd77:639 645 645,fd76:639 645 645,fd78:639 645 649,fdb6:639 645 649,fd13:639 649,fcf7:639 649,fd14:639 649,fcf8:639 649,1ee1b:63a,1ee3b:63a,1ee5b:63a,1ee7b:63a,1ee9b:63a,1eebb:63a,fecf:63a,fed0:63a,fece:63a,fecd:63a,fcbc:63a 62c,fc2b:63a 62c,fcbd:63a 645,fc2c:63a 645,fd79:63a 645 645,fd7b:63a 645 649,fd7a:63a 645 649,fd15:63a 649,fcf9:63a 649,fd16:63a 649,fcfa:63a 649,1ee10:641,1ee30:641,1ee70:641,1ee90:641,1eeb0:641,fed3:641,fed4:641,fed2:641,fed1:641,6a7:641,fcbe:641 62c,fc2d:641 62c,fcbf:641 62d,fc2e:641 62d,fcc0:641 62e,fc2f:641 62e,fd7d:641 62e 645,fd7c:641 62e 645,fcc1:641 645,fc30:641 645,fdc1:641 645 649,fc7c:641 649,fc31:641 649,fc7d:641 649,fc32:641 649,1ee1e:6a1,1ee7e:6a1,8bb:6a1,66f:6a1,1ee1f:6a1,1ee5f:6a1,8bc:6a1,6a4:6a1 6db,fb6c:6a1 6db,fb6d:6a1 6db,fb6b:6a1 6db,fb6a:6a1 6db,6a8:6a1 6db,8a4:6a2 6db,fb70:6a6,fb71:6a6,fb6f:6a6,fb6e:6a6,1ee12:642,1ee32:642,1ee52:642,1ee72:642,1ee92:642,1eeb2:642,fed7:642,fed8:642,fed6:642,fed5:642,fcc2:642 62d,fc33:642 62d,fdf1:642 644 649,fcc3:642 645,fc34:642 645,fdb4:642 645 62d,fd7e:642 645 62d,fd7f:642 645 645,fdb2:642 645 649,fc7e:642 649,fc35:642 649,fc7f:642 649,fc36:642 649,1ee0a:643,1ee2a:643,1ee6a:643,fedb:643,fedc:643,feda:643,fed9:643,6a9:643,fb90:643,fb91:643,fb8f:643,fb8e:643,6aa:643,6ad:643 6db,fbd5:643 6db,fbd6:643 6db,fbd4:643 6db,fbd3:643 6db,763:643 6db,fc80:643 6c,fc37:643 6c,fcc4:643 62c,fc38:643 62c,fcc5:643 62d,fc39:643 62d,fcc6:643 62e,fc3a:643 62e,fcc7:643 644,fceb:643 644,fc81:643 644,fc3b:643 644,fcc8:643 645,fcec:643 645,fc82:643 645,fc3c:643 645,fdc3:643 645 645,fdbb:643 645 645,fdb7:643 645 649,fc83:643 649,fc3d:643 649,fc84:643 649,fc3e:643 649,762:6ac,fb94:6af,fb95:6af,fb93:6af,fb92:6af,8b0:6af,6b4:6af 6db,fb9c:6b1,fb9d:6b1,fb9b:6b1,fb9a:6b1,fb98:6b3,fb99:6b3,fb97:6b3,fb96:6b3,1ee0b:644,1ee2b:644,1ee4b:644,1ee8b:644,1eeab:644,fedf:644,fee0:644,fede:644,fedd:644,6b7:644 6db,6b5:644 306,fefc:644 6c,fefb:644 6c,fefa:644 6c 655,fef9:644 6c 655,fef8:644 6c 674,fef7:644 6c 674,fccd:644 6f,fef6:644 622,fef5:644 622,fcc9:644 62c,fc3f:644 62c,fd83:644 62c 62c,fd84:644 62c 62c,fdba:644 62c 645,fdbc:644 62c 645,fdac:644 62c 649,fcca:644 62d,fc40:644 62d,fdb5:644 62d 645,fd80:644 62d 645,fd82:644 62d 649,fd81:644 62d 649,fccb:644 62e,fc41:644 62e,fd86:644 62e 645,fd85:644 62e 645,fccc:644 645,fced:644 645,fc85:644 645,fc42:644 645,fd88:644 645 62d,fd87:644 645 62d,fdad:644 645 649,fc86:644 649,fc43:644 649,fc87:644 649,fc44:644 649,1ee0c:645,1ee2c:645,1ee6c:645,1ee8c:645,1eeac:645,fee3:645,fee4:645,fee2:645,fee1:645,8a7:645 6db,6fe:645 348,fc88:645 6c,fcce:645 62c,fc45:645 62c,fd8c:645 62c 62d,fd92:645 62c 62e,fd8d:645 62c 645,fdc0:645 62c 649,fccf:645 62d,fc46:645 62d,fd89:645 62d 62c,fd8a:645 62d 645,fdf4:645 62d 645 62f,fd8b:645 62d 649,fcd0:645 62e,fc47:645 62e,fd8e:645 62e 62c,fd8f:645 62e 645,fdb9:645 62e 649,fcd1:645 645,fc89:645 645,fc48:645 645,fdb1:645 645 649,fc49:645 649,fc4a:645 649,1ee0d:646,1ee2d:646,1ee4d:646,1ee6d:646,1ee8d:646,1eead:646,fee7:646,fee8:646,fee6:646,fee5:646,768:646 615,769:646 306,fcd6:646 6f,fcef:646 6f,fdb8:646 62c 62d,fdbd:646 62c 62d,fd98:646 62c 645,fd97:646 62c 645,fd99:646 62c 649,fdc7:646 62c 649,fcd3:646 62d,fc4c:646 62d,fd95:646 62d 645,fd96:646 62d 649,fdb3:646 62d 649,fcd4:646 62e,fc4d:646 62e,fc8a:646 631,fc8b:646 632,fcd5:646 645,fcee:646 645,fc8c:646 645,fc4e:646 645,fd9b:646 645 649,fd9a:646 645 649,fc8d:646 646,fc8e:646 649,fc4f:646 649,fc8f:646 649,fc50:646 649,6c2:6c0,fba5:6c0,fba4:6c0,102e4:648,1ee05:648,1ee85:648,1eea5:648,feee:648,feed:648,8b1:648,6cb:648 6db,fbdf:648 6db,fbde:648 6db,6c7:648 313,fbd8:648 313,fbd7:648 313,6c6:648 306,fbda:648 306,fbd9:648 306,6c9:648 302,fbe3:648 302,fbe2:648 302,6c8:648 670,fbdc:648 670,fbdb:648 670,676:648 674,624:648 674,fe86:648 674,fe85:648 674,677:648 313 674,fbdd:648 313 674,fdf8:648 633 644 645,fbe1:6c5,fbe0:6c5,66e:649,1ee1c:649,1ee7c:649,6ba:649,1ee1d:649,1ee5d:649,fb9f:649,fb9e:649,8bd:649,fbe8:649,fbe9:649,fef0:649,feef:649,64a:649,1ee09:649,1ee29:649,1ee49:649,1ee69:649,1ee89:649,1eea9:649,fef3:649,fef4:649,fef2:649,fef1:649,6cc:649,fbfe:649,fbff:649,fbfd:649,fbfc:649,6d2:649,fbaf:649,fbae:649,679:649 615,fb68:649 615,fb69:649 615,fb67:649 615,fb66:649 615,6bb:649 615,fba2:649 615,fba3:649 615,fba1:649 615,fba0:649 615,67e:649 6db,fb58:649 6db,fb59:649 6db,fb57:649 6db,fb56:649 6db,62b:649 6db,1ee16:649 6db,1ee36:649 6db,1ee76:649 6db,1ee96:649 6db,1eeb6:649 6db,fe9b:649 6db,fe9c:649 6db,fe9a:649 6db,fe99:649 6db,6bd:649 6db,6d1:649 6db,63f:649 6db,8b7:649 6db 6e2,756:649 306,6ce:649 306,8ba:649 306 307,63d:649 302,8a8:649 654,fc90:649 670,fc5d:649 670,fcde:649 6f,fcf1:649 6f,fce6:649 6db 6f,678:649 674,626:649 674,fe8b:649 674,fe8c:649 674,fe8a:649 674,fe89:649 674,fbeb:649 674 6c,fbea:649 674 6c,fc9b:649 674 6f,fce0:649 674 6f,fbed:649 674 6f,fbec:649 674 6f,fbf8:649 674 67b,fbf7:649 674 67b,fbf6:649 674 67b,fc97:649 674 62c,fc00:649 674 62c,fc98:649 674 62d,fc01:649 674 62d,fc99:649 674 62e,fc64:649 674 631,fc65:649 674 632,fc9a:649 674 645,fcdf:649 674 645,fc66:649 674 645,fc02:649 674 645,fc67:649 674 646,fbef:649 674 648,fbee:649 674 648,fbf1:649 674 648 313,fbf0:649 674 648 313,fbf3:649 674 648 306,fbf2:649 674 648 306,fbf5:649 674 648 670,fbf4:649 674 648 670,fbfb:649 674 649,fbfa:649 674 649,fc68:649 674 649,fbf9:649 674 649,fc03:649 674 649,fc69:649 674 649,fc04:649 674 649,fcda:649 62c,fc55:649 62c,fc11:649 6db 62c,fdaf:649 62c 649,fcdb:649 62d,fc56:649 62d,fdae:649 62d 649,fcdc:649 62e,fc57:649 62e,fc91:649 631,fc76:649 6db 631,fc92:649 632,fc77:649 6db 632,fcdd:649 645,fcf0:649 645,fc93:649 645,fc58:649 645,fca6:649 6db 645,fce5:649 6db 645,fc78:649 6db 645,fc12:649 6db 645,fd9d:649 645 645,fd9c:649 645 645,fdb0:649 645 649,fc94:649 646,fc79:649 6db 646,fc95:649 649,fc59:649 649,fc96:649 649,fc5a:649 649,fc7a:649 6db 649,fc13:649 6db 649,fc7b:649 6db 649,fc14:649 6db 649,fbb1:6d3,fbb0:6d3,102b8:2d40,205e:2d42,2e3d:2d42,2999:2d42,fe19:2d57,205d:2d57,22ee:2d57,544:1206,54c:1261,53b:12ae,54a:1323,906:905 93e,912:905 93e 946,913:905 93e 947,914:905 93e 948,904:905 946,911:905 949,90d:90f 945,90e:90f 946,910:90f 947,908:930 94d 907,abd:93d,111dc:a8fb,111cb:93a,ac1:941,ac2:942,a4b:946,a4d:94d,acd:94d,986:985 9be,9e0:98b 9c3,9e1:98b 9c3,11492:998,11494:99a,11496:99c,11498:99e,11499:99f,1149b:9a1,114aa:9a3,1149e:9a4,1149f:9a5,114a0:9a6,114a1:9a7,114a2:9a8,114a3:9aa,114a9:9ac,114a7:9ae,114a8:9af,114ab:9b0,1149d:9b2,114ad:9b7,114ae:9b8,114c4:9bd,114b0:9be,114b1:9bf,114b9:9c7,114bc:9cb,114be:9cc,114c2:9cd,114bd:9d7,a09:a73 a41,a0a:a73 a42,a06:a05 a3e,a10:a05 a48,a14:a05 a4c,a07:a72 a3f,a08:a72 a40,a0f:a72 a47,a86:a85 abe,a91:a85 abe ac5,a93:a85 abe ac7,a94:a85 abe ac8,a8d:a85 ac5,a8f:a85 ac7,a90:a85 ac8,b06:b05 b3e,bee:b85,bb0:b88,bbe:b88,beb:b88 bc1,be8:b89,d09:b89,b8a:b89 bb3,d0a:b89 d57,bed:b8e,bf7:b8e bb5,b9c:b90,d1c:b90,be7:b95,bea:b9a,bec:b9a bc1,bf2:b9a bc2,d3a:b9f bbf,d23:ba3,bfa:ba8 bc0,bf4:bae bc0,bf0:baf,d34:bb4,bd7:bb3,bc8:ba9,d36:bb6,bf8:bb7,d3f:bbf,d40:bbf,bca:bc6 b88,bcc:bc6 bb3,bcb:bc7 b88,c85:c05,c86:c06,c87:c07,c60:c0b c3e,c61:c0c c3e,c92:c12,c14:c12 c4c,c94:c12 c4c,c13:c12 c55,c93:c12 c55,c9c:c1c,c9e:c1e,c22:c21 323,ca3:c23,c25:c27 5bc,c2d:c2c 323,caf:c2f,c20:c30 5bc,cb1:c31,cb2:c32,c37:c35 323,c39:c35 c3e,c2e:c35 c41,c42:c41 c3e,c44:c43 c3e,ce1:c8c cbe,d08:d07 d57,d10:d0e d46,d13:d12 d3e,d14:d12 d57,d61:d1e,d6b:d26 d4d d30,d79:d28 d41,d0c:d28 d41,d19:d28 d41,d6f:d28 d4d,d7b:d28 d4d,d6c:d28 d4d d28,d5a:d28 d4d d2e,d31:d30,d6a:d30 d4d,d7c:d30 d4d,d6e:d35 d4d d30,d76:d39 d4d d2e,d42:d41,d43:d41,d48:d46 d46,dea:da2,deb:daf,11413:11434 11442 11412,11419:11434 11442 11418,11424:11434 11442 11423,1142a:11434 11442 11429,1142d:11434 11442 1142c,1142f:11434 11442 1142e,115d8:11582,115d9:11582,115da:11583,115db:11584,115dc:115b2,115dd:115b3,e03:e02,e14:e04,e15:e04,e21:e06,e88:e08,e0b:e0a,e0f:e0e,e17:e11,e9a:e1a,e9b:e1b,e9d:e1d,e9e:e1e,e9f:e1f,e26:e20,e8d:e22,17d4:e2f,e45:e32,e33:30a e32,17b7:e34,17b8:e35,17b9:e36,17ba:e37,eb8:e38,eb9:e39,e41:e40 e40,edc:eab e99,edd:eab ea1,eb3:30a eb2,f02:f60 f74 f82 f7f,f03:f60 f74 f82 f14,f6a:f62,f00:f68 f7c f7e,f77:fb2 f71 f80,f79:fb3 f71 f80,11cb2:11caa,1081:1002 103e,1000:1002 102c,1070:1003 103e,1066:1015 103e,101f:1015 102c,106f:1015 102c 103e,107e:107d 103e,1029:101e 103c,102a:101e 103c 1031 102c 103a,109e:1083 30a,17a3:17a2,19d0:199e,19d1:19b1,1a80:1a45,1a90:1a45,aa53:aa01,aa56:aa23,1b52:1b0d,1b53:1b11,1b58:1b28,a9a3:a99d,1896:185c,1855:1835,1ff6:13ef,140d:1401 b7,142b:1401 1420,1411:1404 b7,1413:1405 b7,142d:1405 1420,1415:1406 b7,1418:140a b7,142e:140a 1420,141a:140b b7,18dd:141e 18df,14d1:1421,1540:1429,143f:1432 b7,1443:1434 b7,2369:1435,1447:1439 b7,145c:144f b7,2e27:1450,2283:1450,145e:1450 b7,1469:1450 27,27c9:1450 2f,2ad7:1450 1455,1460:1451 b7,2e26:1455,2282:1455,1462:1455 b7,146a:1455 27,1464:1456 b7,1475:146b b7,1485:146b 27,1479:146e b7,147d:1470 b7,1603:1489,1493:1489 b7,1495:148b b7,1497:148c b7,149b:148e b7,1602:1490,149d:1490 b7,149f:1491 b7,14ad:14a3 b7,14b1:14a6 b7,14b3:14a7 b7,14b5:14a8 b7,14b9:14ab b7,14ca:14c0 b7,18c7:14c2 b7,18c9:14c3 b7,18cb:14c4 b7,18cd:14c5 b7,14cc:14c7 b7,14ce:14c8 b7,1604:14d3,14dd:14d3 b7,14df:14d5 b7,14e1:14d6 b7,14e3:14d7 b7,14e5:14d8 b7,1607:14da,14e7:14da b7,14e9:14db b7,14f7:14ed b7,14f9:14ef b7,14fb:14f0 b7,14fd:14f1 b7,14ff:14f2 b7,1501:14f4 b7,1503:14f5 b7,150c:150b 3c,150e:150b 62,150d:150b 1455,150f:150b 1490,1518:1510 b7,151a:1511 b7,151c:1512 b7,151e:1513 b7,1520:1514 b7,1522:1515 b7,1524:1516 b7,1532:1528 b7,1534:1529 b7,1536:152a b7,1538:152b b7,153a:152d b7,153c:152e b7,1622:1543,18e0:1543 b7,1623:1546,1624:154a,154f:154c b7,1583:1550 62,1584:1550 62 307,1581:1550 64,157f:1550 50,166f:1550 146b,157e:1550 146c,1580:1550 146e,1582:1550 1470,1585:1550 1483,155c:155a b7,18e3:155e b7,18e4:1566 b7,1569:1567 b7,18e5:156b b7,18e8:1586 b7,1591:1595 4a,1670:1595 1489,158e:1595 148a,158f:1595 148b,1590:1595 148c,1592:1595 148e,1593:1595 1490,1594:1595 1491,1673:1596 4a,1671:1596 148b,1672:1596 148c,1674:1596 148e,1675:1596 1490,1676:1596 1491,18ea:1597 b7,1677:15a7 b7,1678:15a8 b7,1679:15a9 b7,167a:15aa b7,167b:15ab b7,167c:15ac b7,167d:15ad b7,2aab:15d2,2aaa:15d5,a4f7:15e1,18f0:15f4 b7,18f2:161b b7,1dbb:1646,a4ed:1660,1dba:18d4,1d3e:18d6,18dc:18df 141e,2e1:18f3,2b3:18f4,2e2:18f5,18db:18f5,a6b0:16b9,16e1:16bc,237f:16bd,16c2:16bd,1d23f:16cb,2191:16cf,21bf:16d0,296e:16d0 21c2,2963:16d0 16da,2d63:16ef,21be:16da,2a21:16da,22c4:16dc,25c7:16dc,25ca:16dc,2662:16dc,1f754:16dc,118b7:16dc,10294:16dc,235a:16dc 332,22c8:16de,2a1d:16de,104d0:16e6,2195:16e8,10cfc:10c82,10cfa:10ca5,3131:1100,11a8:1100,1101:1100 1100,3132:1100 1100,11a9:1100 1100,11fa:1100 1102,115a:1100 1103,11c3:1100 1105,11fb:1100 1107,11aa:1100 1109,3133:1100 1109,11c4:1100 1109 1100,11fc:1100 110e,11fd:1100 110f,11fe:1100 1112,3134:1102,11ab:1102,1113:1102 1100,11c5:1102 1100,1114:1102 1102,3165:1102 1102,11ff:1102 1102,1115:1102 1103,3166:1102 1103,11c6:1102 1103,d7cb:1102 1105,1116:1102 1107,115b:1102 1109,11c7:1102 1109,3167:1102 1109,115c:1102 110c,11ac:1102 110c,3135:1102 110c,d7cc:1102 110e,11c9:1102 1110,115d:1102 1112,11ad:1102 1112,3136:1102 1112,11c8:1102 1140,3168:1102 1140,3137:1103,11ae:1103,1117:1103 1100,11ca:1103 1100,1104:1103 1103,3138:1103 1103,d7cd:1103 1103,d7ce:1103 1103 1107,115e:1103 1105,11cb:1103 1105,a960:1103 1106,a961:1103 1107,d7cf:1103 1107,a962:1103 1109,d7d0:1103 1109,d7d1:1103 1109 1100,a963:1103 110c,d7d2:1103 110c,d7d3:1103 110e,d7d4:1103 1110,3139:1105,11af:1105,a964:1105 1100,11b0:1105 1100,313a:1105 1100,a965:1105 1100 1100,d7d5:1105 1100 1100,11cc:1105 1100 1109,3169:1105 1100 1109,d7d6:1105 1100 1112,1118:1105 1102,11cd:1105 1102,a966:1105 1103,11ce:1105 1103,316a:1105 1103,a967:1105 1103 1103,11cf:1105 1103 1112,1119:1105 1105,11d0:1105 1105,d7d7:1105 1105 110f,a968:1105 1106,11b1:1105 1106,313b:1105 1106,11d1:1105 1106 1100,11d2:1105 1106 1109,d7d8:1105 1106 1112,a969:1105 1107,11b2:1105 1107,313c:1105 1107,d7d9:1105 1107 1103,a96a:1105 1107 1107,11d3:1105 1107 1109,316b:1105 1107 1109,a96b:1105 1107 110b,11d5:1105 1107 110b,d7da:1105 1107 1111,11d4:1105 1107 1112,a96c:1105 1109,11b3:1105 1109,313d:1105 1109,11d6:1105 1109 1109,111b:1105 110b,d7dd:1105 110b,a96d:1105 110c,a96e:1105 110f,11d8:1105 110f,11b4:1105 1110,313e:1105 1110,11b5:1105 1111,313f:1105 1111,111a:1105 1112,3140:1105 1112,113b:1105 1112,11b6:1105 1112,d7f2:1105 1112,11d7:1105 1140,316c:1105 1140,d7db:1105 114c,11d9:1105 1159,316d:1105 1159,d7dc:1105 1159 1112,3141:1106,11b7:1106,a96f:1106 1100,11da:1106 1100,d7de:1106 1102,d7df:1106 1102 1102,a970:1106 1103,11db:1106 1105,d7e0:1106 1106,111c:1106 1107,316e:1106 1107,11dc:1106 1107,d7e1:1106 1107 1109,a971:1106 1109,11dd:1106 1109,316f:1106 1109,11de:1106 1109 1109,111d:1106 110b,3171:1106 110b,11e2:1106 110b,d7e2:1106 110c,11e0:1106 110e,11e1:1106 1112,11df:1106 1140,3170:1106 1140,3142:1107,11b8:1107,111e:1107 1100,3172:1107 1100,111f:1107 1102,1120:1107 1103,3173:1107 1103,d7e3:1107 1103,11e3:1107 1105,d7e4:1107 1105 1111,d7e5:1107 1106,1108:1107 1107,3143:1107 1107,d7e6:1107 1107,112c:1107 1107 110b,3179:1107 1107 110b,1121:1107 1109,3144:1107 1109,11b9:1107 1109,1122:1107 1109 1100,3174:1107 1109 1100,1123:1107 1109 1103,3175:1107 1109 1103,d7e7:1107 1109 1103,1124:1107 1109 1107,1125:1107 1109 1109,1126:1107 1109 110c,a972:1107 1109 1110,112b:1107 110b,3178:1107 110b,11e6:1107 110b,1127:1107 110c,3176:1107 110c,d7e8:1107 110c,1128:1107 110e,d7e9:1107 110e,a973:1107 110f,1129:1107 1110,3177:1107 1110,112a:1107 1111,11e4:1107 1111,a974:1107 1112,11e5:1107 1112,3145:1109,11ba:1109,112d:1109 1100,317a:1109 1100,11e7:1109 1100,112e:1109 1102,317b:1109 1102,112f:1109 1103,317c:1109 1103,11e8:1109 1103,1130:1109 1105,11e9:1109 1105,1131:1109 1106,d7ea:1109 1106,1132:1109 1107,317d:1109 1107,11ea:1109 1107,1133:1109 1107 1100,d7eb:1109 1107 110b,110a:1109 1109,3146:1109 1109,11bb:1109 1109,d7ec:1109 1109 1100,d7ed:1109 1109 1103,a975:1109 1109 1107,1134:1109 1109 1109,1135:1109 110b,1136:1109 110c,317e:1109 110c,d7ef:1109 110c,1137:1109 110e,d7f0:1109 110e,1138:1109 110f,1139:1109 1110,d7f1:1109 1110,113a:1109 1111,d7ee:1109 1140,3147:110b,11bc:110b,1141:110b 1100,11ec:110b 1100,11ed:110b 1100 1100,1142:110b 1103,a976:110b 1105,1143:110b 1106,1144:110b 1107,1145:110b 1109,11f1:110b 1109,3182:110b 1109,1147:110b 110b,3180:110b 110b,11ee:110b 110b,1148:110b 110c,1149:110b 110e,11ef:110b 110f,114a:110b 1110,114b:110b 1111,a977:110b 1112,1146:110b 1140,11f2:110b 1140,3183:110b 1140,3148:110c,11bd:110c,d7f7:110c 1107,d7f8:110c 1107 1107,114d:110c 110b,110d:110c 110c,3149:110c 110c,d7f9:110c 110c,a978:110c 110c 1112,314a:110e,11be:110e,1152:110e 110f,1153:110e 1112,314b:110f,11bf:110f,314c:1110,11c0:1110,a979:1110 1110,314d:1111,11c1:1111,1156:1111 1107,11f3:1111 1107,d7fa:1111 1109,1157:1111 110b,3184:1111 110b,11f4:1111 110b,d7fb:1111 1110,a97a:1111 1112,314e:1112,11c2:1112,11f5:1112 1102,11f6:1112 1105,11f7:1112 1106,11f8:1112 1107,a97b:1112 1109,1158:1112 1112,3185:1112 1112,113d:113c 113c,113f:113e 113e,317f:1140,11eb:1140,d7f3:1140 1107,d7f4:1140 1107 110b,3181:114c,11f0:114c,d7f5:114c 1106,d7f6:114c 1112,114f:114e 114e,1151:1150 1150,3186:1159,11f9:1159,a97c:1159 1159,3164:1160,314f:1161,11a3:1161 30fc,1176:1161 1169,1177:1161 116e,1162:1161 4e28,3150:1161 4e28,3151:1163,1178:1163 1169,1179:1163 116d,11a4:1163 116e,1164:1163 4e28,3152:1163 4e28,3153:1165,117c:1165 30fc,117a:1165 1169,117b:1165 116e,1166:1165 4e28,3154:1165 4e28,3155:1167,11a5:1167 1163,117d:1167 1169,117e:1167 116e,1168:1167 4e28,3156:1167 4e28,3157:1169,116a:1169 1161,3158:1169 1161,116b:1169 1161 4e28,3159:1169 1161 4e28,11a6:1169 1163,11a7:1169 1163 4e28,117f:1169 1165,1180:1169 1165 4e28,d7b0:1169 1167,1181:1169 1167 4e28,1182:1169 1169,d7b1:1169 1169 4e28,1183:1169 116e,116c:1169 4e28,315a:1169 4e28,315b:116d,d7b2:116d 1161,d7b3:116d 1161 4e28,1184:116d 1163,3187:116d 1163,1186:116d 1163,1185:116d 1163 4e28,3188:116d 1163 4e28,d7b4:116d 1165,1187:116d 1169,1188:116d 4e28,3189:116d 4e28,315c:116e,1189:116e 1161,118a:116e 1161 4e28,116f:116e 1165,315d:116e 1165,118b:116e 1165 30fc,1170:116e 1165 4e28,315e:116e 1165 4e28,d7b5:116e 1167,118c:116e 1167 4e28,118d:116e 116e,1171:116e 4e28,315f:116e 4e28,d7b6:116e 4e28 4e28,3160:1172,118e:1172 1161,d7b7:1172 1161 4e28,118f:1172 1165,1190:1172 1165 4e28,1191:1172 1167,318a:1172 1167,1192:1172 1167 4e28,318b:1172 1167 4e28,d7b8:1172 1169,1193:1172 116e,1194:1172 4e28,318c:1172 4e28,318d:119e,d7c5:119e 1161,119f:119e 1165,d7c6:119e 1165 4e28,11a0:119e 116e,11a2:119e 119e,11a1:119e 4e28,318e:119e 4e28,30d8:3078,2341:303c,29c4:303c,a49e:a04a,a4ac:a050,a49c:a0c0,a4a8:a132,a4bf:a259,a4be:a2b1,a494:a2cd,a4c0:a3ab,a4c2:a3b5,a4ba:a3bf,a4b0:a3c2,a4a7:a458,22a5:a4d5,27c2:a4d5,1d21c:a4d5,a7b1:a4d5,a79e:a4e4,2141:a4e8,2142:a4f6,1d215:a4f6,1d22b:a4f6,16f26:a4f6,10411:a4f6,2143:16f00,11ae6:11ae5 11aef,11ae8:11ae5 11ae5,11ae9:11ae5 11ae5 11aef,11aea:11ae5 11ae5 11af0,11ae7:11ae5 11af0,11af4:11af3 11aef,11af6:11af3 11af3,11af7:11af3 11af3 11aef,11af8:11af3 11af3 11af0,11af5:11af3 11af0,11aec:11aeb 11aef,11aed:11aeb 11aeb,11aee:11aeb 11aeb 11aef,2295:102a8,2a01:102a8,1f728:102a8,a69a:102a8,25bd:102bc,1d214:102bc,1f704:102bc,29d6:102c0,a79b:1043a,a79a:10412,104a0:10486,103d1:10382,103d3:10393,12038:1039a,2625:1099e,132f9:1099e,3039:5344,f967:4e0d,2f800:4e3d,fa70:4e26,239c:4e28,239f:4e28,23a2:4e28,23a5:4e28,23aa:4e28,23ae:4e28,31d1:4e28,1175:4e28,3163:4e28,2f01:4e28,119c:4e28 30fc,1198:4e28 1161,1199:4e28 1163,d7bd:4e28 1163 1169,d7be:4e28 1163 4e28,d7bf:4e28 1167,d7c0:4e28 1167 4e28,119a:4e28 1169,d7c1:4e28 1169 4e28,d7c2:4e28 116d,119b:4e28 116e,d7c3:4e28 1172,119d:4e28 119e,d7c4:4e28 4e28,f905:4e32,2f801:4e38,f95e:4e39,2f802:4e41,31e0:4e59,2f04:4e59,31df:4e5a,2e83:4e5a,31d6:4e5b,2e82:4e5b,2ef2:4e80,f91b:4e82,31da:4e85,2f05:4e85,f9ba:4e86,30cb:4e8c,2f06:4e8c,2f803:20122,2f07:4ea0,f977:4eae,2f08:4eba,30a4:4ebb,2e85:4ebb,f9fd:4ec0,2f819:4ecc,f9a8:4ee4,2f804:4f60,5002:4f75,2f807:4f75,fa73:4f80,f92d:4f86,f9b5:4f8b,fa30:4fae,2f805:4fae,2f806:4fbb,f965:4fbf,503c:5024,f9d4:502b,2f808:507a,2f809:5099,2f80b:50cf,f9bb:50da,fa31:50e7,2f80a:50e7,2f80c:349e,2f09:513f,fa0c:5140,2e8e:5140,fa74:5145,fa32:514d,2f80e:514d,2f80f:5154,2f810:5164,2f0a:5165,2f814:5167,fa72:5168,f978:5169,30cf:516b,2f0b:516b,f9d1:516d,2f811:5177,2f812:2051c,2f91b:20525,fa75:5180,2f813:34b9,2f0c:5182,2f815:518d,2f816:2054b,2f8d2:5192,2f8d3:5195,2f9ca:34bb,2f8d4:6700,2f0d:5196,2f817:5197,2f818:51a4,2f0e:51ab,2f81a:51ac,fa71:51b5,2f81b:51b5,f92e:51b7,f979:51c9,f955:51cc,f954:51dc,fa15:51de,2f0f:51e0,2f80d:2063a,2f81d:51f5,2f10:51f5,2f11:5200,2e89:5202,2f81e:5203,fa00:5207,2f850:5207,f99c:5217,f9dd:5229,2f81f:34df,f9ff:523a,2f820:523b,2f821:5246,2f822:5272,2f823:5277,f9c7:5289,2f9d9:20804,30ab:529b,f98a:529b,2f12:529b,f99d:52a3,2f824:3515,2f992:52b3,fa76:52c7,2f825:52c7,fa33:52c9,2f826:52c9,f952:52d2,f92f:52de,fa34:52e4,2f827:52e4,f97f:52f5,2f13:52f9,fa77:52fa,2f828:52fa,2f829:5305,2f82a:5306,2f9dd:208de,2f14:5315,f963:5317,2f82b:5317,2f15:531a,2f16:5338,f9eb:533f,2f17:5341,3038:5341,303a:5345,2f82c:5349,fd6:534d,fd5:5350,fa35:5351,2f82d:5351,2f82e:535a,30c8:535c,2f18:535c,2f19:5369,2e8b:353e,2f82f:5373,f91c:5375,2f830:537d,2f831:537f,2f832:537f,2f833:537f,2f1a:5382,2f834:20a2c,2f1b:53b6,f96b:53c3,2f1c:53c8,2f836:53ca,2f837:53df,2f838:20b63,30ed:53e3,2f1d:53e3,56d7:53e3,2f1e:53e3,f906:53e5,2f839:53eb,2f83a:53f1,2f83b:5406,f9de:540f,f9ed:541d,2f83d:5438,f980:5442,2f83e:5448,2f83f:5468,2f83c:549e,2f840:54a2,f99e:54bd,439b:3588,2f841:54f6,2f842:5510,2f843:5553,555f:5553,fa79:5555,2f844:5563,2f845:5584,2f846:5584,f90b:5587,fa7a:5599,2f847:5599,fa36:559d,fa78:559d,2f848:55ab,2f849:55b3,fa0d:55c0,2f84a:55c2,fa7b:55e2,fa37:5606,2f84c:5606,2f84e:5651,2f84f:5674,fa38:5668,f9a9:56f9,2f84b:5716,2f84d:5717,2f1f:571f,58eb:571f,2f20:571f,2f855:578b,2f852:57ce,39b3:363d,2f853:57f4,2f854:580d,2f857:5831,2f856:5832,fa39:5840,fa10:585a,fa7c:585a,f96c:585e,586b:5861,58ff:58ab,2f858:58ac,fa7d:58b3,f94a:58d8,f942:58df,2f859:214e4,2f851:58ee,2f85a:58f2,2f85b:58f7,2f21:5902,2f85c:5906,2f22:590a,30bf:5915,2f23:5915,2f85d:591a,2f85e:5922,2f24:5927,fa7e:5944,f90c:5948,fa7f:5954,f909:5951,2f85f:5962,f981:5973,2f25:5973,2f860:216a8,2f861:216ea,2f865:59d8,2f862:59ec,2f863:5a1b,2f864:5a27,fa80:5a62,2f866:5a66,5b00:5aaf,2f867:36ee,2f868:36fc,2f986:5ab5,2f869:5b08,fa81:5b28,2f86a:5b3e,2f86b:5b3e,2f26:5b50,2f27:5b80,fa04:5b85,2f86c:219c8,2f86d:5bc3,2f86e:5bd8,f95f:5be7,f9aa:5be7,2f86f:5be7,f9bc:5bee,2f870:5bf3,2f871:21b18,2f28:5bf8,2f872:5bff,2f873:5c06,2f29:5c0f,2f875:5c22,2e90:5c22,2f2a:5c22,2e8f:5c23,2f876:3781,2f2b:5c38,f9bd:5c3f,2f877:5c60,f94b:5c62,fa3b:5c64,f9df:5c65,fa3c:5c6e,2f878:5c6e,2f2c:5c6e,2f8f8:21d0b,2f2d:5c71,2f879:5cc0,2f87a:5c8d,2f87b:21de4,2f87d:21de6,f9d5:5d19,2f87c:5d43,f921:5d50,2f87f:5d6b,2f87e:5d6e,2f880:5d7c,2f9f4:5db2,f9ab:5dba,2f2e:5ddb,2f882:5de2,30a8:5de5,2f2f:5de5,2f30:5df1,2e92:5df3,2f883:382f,2f884:5dfd,2f31:5dfe,5e32:5e21,2f885:5e28,2f886:5e3d,2f887:5e69,2f888:3862,2f889:22183,2f32:5e72,f98e:5e74,2f939:2219f,2e93:5e7a,2f33:5e7a,2f34:5e7f,fa01:5ea6,2f88a:387c,2f88b:5eb0,2f88c:5eb3,2f88d:5eb6,f928:5eca,2f88e:5eca,f9a2:5ec9,fa82:5ed2,fa0b:5ed3,fa83:5ed9,f982:5eec,2f35:5ef4,2f890:5efe,2f36:5efe,2f891:22331,2f892:22331,f943:5f04,2f37:5f0b,2f38:5f13,2f894:5f22,2f895:5f22,2f39:5f50,2e94:5f51,2f874:5f53,2f896:38c7,2f3a:5f61,2f899:5f62,fa84:5f69,2f89a:5f6b,2f3b:5f73,f9d8:5f8b,2f89b:38e3,2f89c:5f9a,f966:5fa9,fa85:5fad,2f3c:5fc3,2e96:5fc4,2e97:38fa,2f89d:5fcd,2f89e:5fd7,f9a3:5ff5,2f89f:5ff9,f960:6012,f9ac:601c,fa6b:6075,2f8a2:391c,2f8a1:393a,2f8a0:6081,fa3d:6094,2f8a3:6094,2f8a5:60c7,fa86:60d8,f9b9:60e1,2f8a4:226d4,fa88:6108,fa3e:6168,f9d9:6144,2f8a6:6148,2f8a7:614c,2f8a9:614c,fa87:614e,2f8a8:614e,fa8a:6160,2f8aa:617a,fa3f:618e,fa89:618e,2f8ab:618e,f98f:6190,2f8ad:61a4,2f8ae:61af,2f8ac:61b2,fad0:22844,facf:2284a,2f8af:61de,fa40:61f2,fa8b:61f2,2f8b0:61f2,f90d:61f6,2f8b1:61f6,f990:6200,2f3d:6208,2f8b2:6210,2f8b3:621b,f9d2:622e,fa8c:6234,2f3e:6236,6238:6236,2f3f:624b,2e98:624c,2f8b4:625d,2f8b5:62b1,f925:62c9,f95b:62cf,fa02:62d3,2f8b6:62d4,2f8ba:62fc,f973:62fe,2f8b8:22b0c,2f8b9:633d,2f8b7:6350,2f8bb:6368,f9a4:637b,2f8bc:6383,f975:63a0,2f8c1:63a9,fa8d:63c4,2f8bd:63e4,fa8f:6452,2f8be:22bf1,fa8e:641c,2f8bf:6422,2f8c0:63c5,2f8c3:6469,2f8c6:6477,2f8c4:647e,2f8c2:3a2e,6409:3a41,f991:649a,2f8c5:649d,f930:64c4,2f8c7:3a6c,2f40:652f,2f41:6534,2e99:6535,fa41:654f,2f8c8:654f,fa90:6556,2f8c9:656c,f969:6578,2f8ca:2300a,2f42:6587,2eeb:6589,2f43:6597,f9be:6599,2f44:65a4,2f45:65b9,f983:65c5,2f46:65e0,2e9b:65e1,fa42:65e2,2f8cb:65e3,2f47:65e5,f9e0:6613,66f6:3ada,2f8d1:3ae4,2f8cd:6649,6669:665a,fa12:6674,fa91:6674,fa43:6691,2f8cf:6691,f9c5:6688,2f8d0:3b08,2f8d5:669c,fa06:66b4,f98b:66c6,2f8ce:3b19,2f897:232b8,2f48:66f0,f901:66f4,2f8cc:66f8,2f49:6708,2f980:2335f,80a6:670c,80d0:670f,80ca:6710,8101:6713,80f6:3b35,f929:6717,fa92:6717,2f8d8:6717,8127:6718,fa93:671b,2f8d9:671b,5e50:3b3a,4420:3b3b,2f989:23393,81a7:6723,2f98a:2339c,2f4a:6728,f9e1:674e,2f8dc:6753,fa94:6756,2f8db:675e,2f8dd:233c3,67ff:676e,f9c8:677b,2f8e0:6785,f9f4:6797,2f8de:3b49,fad1:233d5,f9c9:67f3,2f8df:67fa,f9da:6817,2f8e5:681f,2f8e1:6852,2f8e3:2346d,f97a:6881,fa44:6885,2f8e2:6885,2f8e4:688e,f9e2:68a8,2f8e6:6914,2f8e8:6942,fad2:3b9d,2f8e7:3b9d,69e9:3ba3,6a27:699d,2f8e9:69a3,2f8ea:69ea,f914:6a02,f95c:6a02,f9bf:6a02,f94c:6a13,2f8ec:236a3,2f8eb:6aa8,f931:6ad3,2f8ed:6adb,f91d:6b04,2f8ee:3c18,2f4b:6b20,2f8ef:6b21,2f8f0:238a7,2f8f1:6b54,2f8f2:3c4e,2f4c:6b62,2eed:6b6f,2f8f3:6b72,f98c:6b77,fa95:6b79,2f4d:6b79,2e9e:6b7a,2f8f4:6b9f,f9a5:6bae,2f4e:6bb3,f970:6bba,fa96:6bba,2f8f5:6bba,2f8f6:6bbb,2f8f7:23a8d,2f4f:6bcb,2e9f:6bcd,2f8f9:23afa,2f50:6bd4,2f51:6bdb,2f52:6c0f,2ea0:6c11,2f53:6c14,2f54:6c34,2ea1:6c35,2ea2:6c3a,2f8fa:6c4e,2f8fe:6c67,f972:6c88,2f8fc:6cbf,f968:6ccc,2f8fd:6ccd,f9e3:6ce5,2f8fb:23cbc,f915:6d1b,fa05:6d1e,2f907:6d34,2f900:6d3e,f9ca:6d41,fa97:6d41,2f902:6d41,2f8ff:6d16,2f903:6d69,f92a:6d6a,fa45:6d77,2f901:6d77,2f904:6d78,2f905:6d85,2f906:23d1e,f9f5:6dcb,f94d:6dda,f9d6:6dea,2f90e:6df9,fa46:6e1a,2f908:6e2f,2f909:6e6e,6f59:6e88,fa99:6ecb,2f90b:6ecb,f9cb:6e9c,f9ec:6eba,2f90c:6ec7,f904:6ed1,fa98:6edb,2f90a:3d33,f94e:6f0f,fa47:6f22,fa9a:6f22,f992:6f23,2f90d:23ed1,2f90f:6f6e,2f910:23f5e,2f911:23f8e,2f912:6fc6,f922:6feb,f984:6ffe,2f915:701b,fa9b:701e,2f914:701e,2f913:7039,2f917:704a,2f916:3d96,2f55:706b,2ea3:706c,2f835:7070,2f919:7077,2f918:707d,f9fb:7099,2f91a:70ad,f99f:70c8,f916:70d9,fa48:716e,fa9c:716e,2f91d:24263,2f91c:7145,f993:7149,fa6c:242ee,2f91e:719c,f9c0:71ce,f9ee:71d0,2f91f:243ab,f932:7210,f91e:721b,2f920:7228,2f56:722a,fa49:722b,2ea4:722b,fa9e:7235,2f921:7235,2f57:7236,2f58:723b,2ea6:4e2c,2f59:723f,2f5a:7247,2f922:7250,2f5b:7259,2f923:24608,2f5c:725b,f946:7262,2f924:7280,2f925:7295,2f5d:72ac,2ea8:72ad,fa9f:72af,f9fa:72c0,2f926:24735,f92b:72fc,fa16:732a,faa0:732a,2f927:24814,f9a7:7375,2f928:737a,2f5e:7384,f961:7387,f9db:7387,2f5f:7389,2f929:738b,2f92a:3eac,2f92b:73a5,f9ad:73b2,2f92c:3eb8,2f92d:3eb8,f917:73de,f9cc:7409,f9e4:7406,fa4a:7422,2f92e:7447,2f92f:745c,f9ae:7469,faa1:7471,2f930:7471,2f931:7485,f994:7489,f9ef:7498,2f932:74ca,2f60:74dc,2f61:74e6,2f933:3f1b,faa2:7506,2f62:7518,2f63:751f,2f934:7524,2f64:7528,2f65:7530,faa3:753b,2f936:753e,2f935:24c36,f9cd:7559,f976:7565,f962:7570,2f938:7570,2f937:24c92,2f66:758b,2f67:7592,f9e5:75e2,2f93a:7610,faa5:761f,faa4:761d,f9c1:7642,f90e:7669,2f68:7676,2f69:767d,2f93b:24fa1,2f93c:24fb8,2f6a:76ae,2f6b:76bf,2f93d:25044,2f93e:3ffc,fa17:76ca,faa6:76ca,faa7:76db,f933:76e7,2f93f:4008,2f6c:76ee,faa8:76f4,2f940:76f4,2f942:250f2,2f941:250f3,f96d:7701,fad3:4018,2f943:25119,2f945:771e,2f946:771f,2f947:771f,2f944:25133,faaa:7740,faa9:774a,2f948:774a,9fc3:4039,fad4:4039,2f949:4039,6663:403f,2f94b:4046,2f94a:778b,fad5:25249,fa9d:77a7,2f6d:77db,2f6e:77e2,2f6f:77f3,2f94c:4096,2f94d:2541d,784f:7814,2f94e:784e,f9ce:786b,f93b:788c,2f94f:788c,fa4b:7891,f947:78ca,faab:78cc,2f950:78cc,f964:78fb,2f951:40e3,f985:792a,2f70:793a,2ead:793b,fa18:793c,fa4c:793e,fa4e:7948,fa4d:7949,2f952:25626,fa4f:7950,fa50:7956,2f953:7956,fa51:795d,fa19:795e,fa1a:7965,fa61:8996,fab8:8996,f93c:797f,2f954:2569a,fa52:798d,fa53:798e,fa1b:798f,2f956:798f,2f955:256c5,f9b6:79ae,2f71:79b8,2f72:79be,f995:79ca,2f958:412f,2f957:79eb,f956:7a1c,2f95a:7a4a,fa54:7a40,2f959:7a40,2f95b:7a4f,2f73:7a74,fa55:7a81,2f95c:2597c,faac:7ab1,f9f7:7acb,2f74:7acb,2eef:7adc,2f95d:25aa7,2f95e:25aa7,2f95f:7aee,2f75:7af9,f9f8:7b20,fa56:7bc0,faad:7bc0,2f960:4202,2f961:25bab,2f962:7bc6,2f964:4227,2f963:7bc9,2f965:25c80,fad6:25cd0,f9a6:7c3e,f944:7c60,2f76:7c73,faae:7c7b,f9f9:7c92,fa1d:7cbe,2f966:7cd2,fa03:7cd6,2f968:7ce8,2f967:42a0,2f969:7ce3,f97b:7ce7,2f77:7cf8,2eaf:7cf9,2f96b:25f86,2f96a:7d00,f9cf:7d10,f96a:7d22,f94f:7d2f,7d76:7d55,2f96c:7d63,faaf:7d5b,f93d:7da0,f957:7dbe,2f96e:7dc7,f996:7df4,fa57:7df4,fab0:7df4,2f96f:7e02,2f96d:4301,fa58:7e09,f950:7e37,fa59:7e41,2f970:7e45,2f898:261da,2f971:4334,2f78:7f36,2f972:26228,fab1:7f3e,2f973:26247,2f79:7f51,2eab:7f52,2eb2:7f52,2eb1:7f53,2f974:4359,fa5a:7f72,2f975:262d9,f9e6:7f79,2f976:7f7a,f90f:7f85,2f977:2633e,2f7a:7f8a,2f978:7f95,f9af:7f9a,fa1e:7fbd,2f7b:7fbd,2f979:7ffa,f934:8001,2f7c:8001,2eb9:8002,fa5b:8005,fab2:8005,2f97a:8005,2f7d:800c,2f97b:264da,2f7e:8012,2f97c:26523,2f7f:8033,f9b0:8046,2f97d:8060,2f97e:265a8,f997:806f,2f97f:8070,f945:807e,2f80:807f,2eba:8080,2f81:8089,f953:808b,2f8d6:80ad,2f982:80b2,2f981:43d5,2f8d7:43d9,8141:80fc,2f983:8103,2f985:813e,2f984:440b,2f8da:6721,2f987:267a7,2f988:267b5,6726:4443,f926:81d8,2f82:81e3,f9f6:81e8,2f83:81ea,fa5c:81ed,2f84:81f3,2f85:81fc,2f893:8201,2f98b:8201,2f98c:8204,2f86:820c,fa6d:8218,2f87:821b,2f88:821f,2f98e:446b,2f89:826e,f97c:826f,2f8a:8272,2f8b:8278,fa5d:8279,fa5e:8279,2ebe:8279,2ebf:8279,2ec0:8279,2f990:828b,2f98f:8291,2f991:829d,2f993:82b1,2f994:82b3,2f995:82bd,f974:82e5,2f998:82e5,2f996:82e6,2f997:26b3c,f9fe:8336,fab3:8352,2f99a:8363,2f999:831d,2f99c:8323,2f99d:83bd,2f9a0:8353,f93e:83c9,2f9a1:83ca,2f9a2:83cc,2f9a3:83dc,2f99e:83e7,fab4:83ef,f958:83f1,fa5f:8457,2f99f:8457,2f9a4:26c36,2f99b:83ad,f918:843d,f96e:8449,853f:848d,2f9a6:26cd5,2f9a5:26d6b,f999:84ee,2f9a8:84f1,2f9a9:84f3,f9c2:84fc,2f9aa:8516,2f9a7:452b,2f9ac:8564,2f9ad:26f2c,f923:85cd,2f9ae:455d,2f9b0:26fb1,2f9af:4561,f9f0:85fa,f935:8606,2f9b2:456b,fa20:8612,f91f:862d,2f9b1:270d2,8641:8637,f910:863f,2f8c:864d,2ec1:864e,2f9b3:8650,f936:865c,2f9b4:865c,2f9b5:8667,2f9b6:8669,2f8d:866b,2f9b7:86a9,2f9b8:8688,2f9ba:86e2,2f9b9:870e,2f9bc:8728,2f9bd:876b,2f9c0:87e1,fab5:8779,2f9bb:8779,2f9be:8786,2f9bf:45d7,2f9ab:273ca,f911:87ba,2f9c1:8801,2f9c2:45f9,f927:881f,2f8e:8840,fa08:884c,2f8f:884c,2f9c3:8860,2f9c4:8863,2f90:8863,2ec2:8864,f9a0:88c2,2f9c5:27667,f9e7:88cf,2f9c6:88d7,2f9c7:88de,f9e8:88e1,f912:88f8,2f9c9:88fa,2f9c8:4635,fa60:8910,fab6:8941,f924:8964,2f91:897e,2ec4:897f,2ec3:8980,fab7:8986,fa0a:898b,2f92:898b,2f9cb:278ae,2ec5:89c1,2f93:89d2,2f94:8a00,2f9cc:27966,8a7d:8a2e,8a1e:46b6,2f9cd:46be,2f9ce:46c7,2f9cf:8aa0,f96f:8aaa,f9a1:8aaa,fab9:8abf,fabb:8acb,f97d:8ad2,f941:8ad6,fabe:8aed,2f9d0:8aed,fa22:8af8,faba:8af8,f95d:8afe,fabd:8afe,fa62:8b01,fabc:8b01,fa63:8b39,fabf:8b39,f9fc:8b58,f95a:8b80,8b8f:8b86,fac0:8b8a,2f9d1:8b8a,2ec8:8ba0,2f95:8c37,2f96:8c46,f900:8c48,2f9d2:8c55,2f97:8c55,8c63:8c5c,2f98:8c78,2f9d3:27ca8,2f99:8c9d,2f9d4:8cab,2f9d5:8cc1,f948:8cc2,f903:8cc8,fa64:8cd3,fa65:8d08,fac1:8d08,2f9d6:8d1b,2ec9:8d1d,2f9a:8d64,2f9b:8d70,2f9d7:8d77,8d86:8d7f,fad7:27ed3,2f9d8:27f2f,2f9c:8db3,2f9da:8dcb,2f9db:8dbc,8dfa:8de5,f937:8def,2f9dc:8df0,8e9b:8e97,2f9d:8eab,f902:8eca,2f9e:8eca,2f9de:8ed4,8f27:8eff,f998:8f26,f9d7:8f2a,fac2:8f38,2f9df:8f38,fa07:8f3b,f98d:8f62,2ecb:8f66,2f9f:8f9b,2f98d:8f9e,f971:8fb0,2fa0:8fb0,2fa1:8fb5,fa66:8fb6,2ecc:8fb6,2ecd:8fb6,2f881:5de1,f99a:9023,fa25:9038,fa67:9038,fac3:9072,f9c3:907c,2f9e0:285d2,2f9e1:285ed,f913:908f,2fa2:9091,2f9e2:9094,f92c:90ce,90de:90ce,fa2e:90ce,2f9e3:90f1,fa26:90fd,2f9e5:2872e,2f9e4:9111,2f9e6:911b,2fa3:9149,f919:916a,fac4:9199,f9b7:91b4,2fa4:91c6,f9e9:91cc,2fa5:91cc,f97e:91cf,f90a:91d1,2fa6:91d1,f9b1:9234,2f9e7:9238,fac5:9276,2f9e8:92d7,2f9e9:92d8,2f9ea:927c,f93f:9304,f99b:934a,93ae:93ad,2f9eb:93f9,2f9ec:9415,2f9ed:28bfa,2ed0:9485,2ed1:9577,2fa7:9577,2ed2:9578,2ed3:957f,2fa8:9580,2f9ee:958b,2f9ef:4995,f986:95ad,2f9f0:95b7,2f9f1:28d77,2ed4:95e8,2fa9:961c,2ecf:961d,2ed6:961d,f9c6:962e,f951:964b,fa09:964d,f959:9675,f9d3:9678,fac6:967c,f9dc:9686,f9f1:96a3,2f9f2:49e6,2faa:96b6,fa2f:96b7,96b8:96b7,f9b8:96b7,2fab:96b9,2f9f3:96c3,f9ea:96e2,fa68:96e3,fac7:96e3,2fac:96e8,f9b2:96f6,f949:96f7,2f9f5:9723,2f9f6:29145,f938:9732,f9b3:9748,2fad:9751,2ed8:9752,fa1c:9756,fac8:9756,2f81c:291df,2fae:975e,2faf:9762,2f9f7:2921a,2fb0:9769,2f9f8:4a6e,2f9f9:4a76,2fb1:97cb,fac9:97db,2f9fa:97e0,2ed9:97e6,2fb2:97ed,2f9fb:2940a,2fb3:97f3,fa69:97ff,faca:97ff,2fb4:9801,2f9fc:4ab2,facb:980b,2f9fe:980b,2f9ff:980b,f9b4:9818,2fa00:9829,2f9fd:29496,fa6a:983b,facc:983b,f9d0:985e,2eda:9875,2fb5:98a8,2fa01:295b6,2edb:98ce,2fb6:98db,2edc:98de,2edd:98df,2fb7:98df,2edf:98e0,2fa02:98e2,fa2a:98ef,fa2b:98fc,2fa03:4b33,fa2c:9928,2fa04:9929,2ee0:9963,2fb8:9996,2fb9:9999,2fa05:99a7,2fba:99ac,2fa06:99c2,f91a:99f1,2fa07:99fe,f987:9a6a,2ee2:9a6c,2fbb:9aa8,2fa08:4bce,2fbc:9ad8,2fbd:9adf,2fa09:29b30,facd:9b12,2fa0a:9b12,2fbe:9b25,2fbf:9b2f,2fc0:9b32,2fc1:9b3c,2ee4:9b3c,2fc2:9b5a,f939:9b6f,2fa0b:9c40,f9f2:9c57,2ee5:9c7c,2fc3:9ce5,2fa0c:9cfd,2fa0d:4cce,2fa0f:9d67,2fa0e:4ced,2fa10:2a0ce,fa2d:9db4,2fa12:2a105,2fa11:4cf8,f93a:9dfa,2fa13:2a20e,f920:9e1e,9e43:9e42,2fc4:9e75,f940:9e7f,2fc5:9e7f,2fa14:2a291,f988:9e97,f9f3:9e9f,2fc6:9ea5,2ee8:9ea6,2fa15:9ebb,2fc7:9ebb,2f88f:2a392,2fc8:9ec3,2ee9:9ec4,2fc9:9ecd,f989:9ece,2fa16:4d56,2fca:9ed1,9ed2:9ed1,fa3a:58a8,2fa17:9ef9,2fcb:9ef9,2fcc:9efd,2fa19:9f05,2fa18:9efe,2fcd:9f0e,2fa1a:9f0f,2fce:9f13,2fa1b:9f16,2fcf:9f20,2fa1c:9f3b,2fd0:9f3b,fad8:9f43,2fd1:9f4a,2eec:9f50,2fd2:9f52,2fa1d:2a600,2eee:9f7f,f9c4:9f8d,2fd3:9f8d,fad9:9f8e,2ef0:9f99,f907:9f9c,f908:9f9c,face:9f9c,2fd4:9f9c,2ef3:9f9f,2fd5:9fa0'; diff --git a/fluxer_app/src/features/voice/engine/MediaEngineFacade.ts b/fluxer_app/src/features/voice/engine/MediaEngineFacade.ts index c10759b6d..0167961e6 100644 --- a/fluxer_app/src/features/voice/engine/MediaEngineFacade.ts +++ b/fluxer_app/src/features/voice/engine/MediaEngineFacade.ts @@ -67,7 +67,10 @@ import { sendVoiceStateDisconnect, syncVoiceStateToServer, } from '@app/features/voice/engine/VoiceChannelConnector'; -import type {VoiceConnectionFailureReason} from '@app/features/voice/engine/VoiceConnectionStateMachine'; +import type { + VoiceConnectionFailureReason, + VoiceConnectionLocalDisconnectReason, +} from '@app/features/voice/engine/VoiceConnectionStateMachine'; import VoiceDevicePermissionState from '@app/features/voice/engine/VoiceDevicePermissionState'; import {getEffectiveAudioState} from '@app/features/voice/engine/VoiceEffectiveAudioState'; import type {NormalizedVoiceState} from '@app/features/voice/engine/VoiceGatewayStateMachine'; @@ -639,6 +642,10 @@ class MediaEngineFacade extends Store { return voiceEngineV2AppConnectionHostAdapter.connectFailureReason; } + get localDisconnectReason(): VoiceConnectionLocalDisconnectReason { + return voiceEngineV2AppConnectionHostAdapter.localDisconnectReason; + } + get connectFailedTarget(): {guildId: string | null; channelId: string} | null { return voiceEngineV2AppConnectionHostAdapter.connectFailedTarget; } diff --git a/fluxer_app/src/index.tsx b/fluxer_app/src/index.tsx index 15d01bc09..3f9480907 100644 --- a/fluxer_app/src/index.tsx +++ b/fluxer_app/src/index.tsx @@ -111,6 +111,7 @@ async function bootstrapApp(): Promise { {registerServiceWorker}, {default: AccountManager}, {default: ChannelDisplayName}, + _channelFrecency, _geoIp, {default: Keybind}, {default: NewDeviceMonitoring}, @@ -126,6 +127,7 @@ async function bootstrapApp(): Promise { loadLazyModule(() => import('@app/features/platform/service_worker/Register')), loadLazyModule(() => import('@app/features/auth/state/AccountManager')), loadLazyModule(() => import('@app/features/channel/state/ChannelDisplayName')), + loadLazyModule(() => import('@app/features/channel/state/ChannelFrecency')), loadLazyModule(() => import('@app/features/app/state/GeoIP')), loadLazyModule(() => import('@app/features/input/state/InputKeybind')), loadLazyModule(() => import('@app/features/auth/state/NewDeviceMonitoring')), diff --git a/packages/schema/proto/fluxer/user/preferences/v1/preferences.proto b/packages/schema/proto/fluxer/user/preferences/v1/preferences.proto index cac04e1eb..8664a8b05 100644 --- a/packages/schema/proto/fluxer/user/preferences/v1/preferences.proto +++ b/packages/schema/proto/fluxer/user/preferences/v1/preferences.proto @@ -50,6 +50,7 @@ message SyncedPreferences { ChatInputSettings chat_input = 112; optional bool save_camera_uploads_to_device = 113; ReactionEmoji double_tap_reaction = 114; + ChannelFrecencyState channel_frecency = 115; } @@ -260,6 +261,15 @@ enum MfaMethod { MFA_METHOD_WEBAUTHN = 3; } +message ChannelFrecencyEntry { + uint32 total_uses = 1; + repeated int64 recent_uses_ms = 2; +} + +message ChannelFrecencyState { + map usage = 1; +} + message ChatInputSettings { optional bool convert_emoticons = 1; } diff --git a/packages/schema/src/gen/fluxer/user/preferences/v1/preferences_pb.ts b/packages/schema/src/gen/fluxer/user/preferences/v1/preferences_pb.ts index f3cba18a7..9dd250e04 100644 --- a/packages/schema/src/gen/fluxer/user/preferences/v1/preferences_pb.ts +++ b/packages/schema/src/gen/fluxer/user/preferences/v1/preferences_pb.ts @@ -10,7 +10,7 @@ import type { Message } from "@bufbuild/protobuf"; * Describes the file fluxer/user/preferences/v1/preferences.proto. */ export const file_fluxer_user_preferences_v1_preferences: GenFile = /*@__PURE__*/ - fileDesc("CixmbHV4ZXIvdXNlci9wcmVmZXJlbmNlcy92MS9wcmVmZXJlbmNlcy5wcm90bxIaZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEi2RQKEVN5bmNlZFByZWZlcmVuY2VzEkgKDWFjY2Vzc2liaWxpdHkYASABKAsyMS5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5BY2Nlc3NpYmlsaXR5U2V0dGluZ3MSUwoXYWNjZXNzaWJpbGl0eV9vdmVycmlkZXMYAiABKAsyMi5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5BY2Nlc3NpYmlsaXR5T3ZlcnJpZGVzEksKD3RleHR1YWxfcHJldmlldxgDIAEoCzIyLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLlRleHR1YWxQcmV2aWV3U2V0dGluZ3MSQgoMZW1vamlfcGlja2VyGBQgASgLMiwuZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuRW1vamlQaWNrZXJTdGF0ZRJGCg5zdGlja2VyX3BpY2tlchgVIAEoCzIuLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLlN0aWNrZXJQaWNrZXJTdGF0ZRJCCgxtZW1lc19waWNrZXIYFiABKAsyLC5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5NZW1lc1BpY2tlclN0YXRlEjUKBWVtb2ppGBcgASgLMiYuZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuRW1vamlTdGF0ZRJUChRlbW9qaV9zdGlja2VyX2xheW91dBgYIAEoCzI2LmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLkVtb2ppU3RpY2tlckxheW91dFNldHRpbmdzEkYKDWZhdm9yaXRlX2dpZnMYGSABKAsyLy5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5GYXZvcml0ZUdpZlNldHRpbmdzEj0KCWZhdm9yaXRlcxgoIAEoCzIqLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLkZhdm9yaXRlc1N0YXRlEksKD3JlY2VudF9tZW50aW9ucxgpIAEoCzIyLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLlJlY2VudE1lbnRpb25zU2V0dGluZ3MSPwoHc2lkZWJhchgqIAEoCzIuLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLlNpZGViYXJQcmVmZXJlbmNlcxJACgttZW1iZXJfbGlzdBgrIAEoCzIrLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLk1lbWJlckxpc3RTdGF0ZRJICg91bnJlYWRfY2hhbm5lbHMYLCABKAsyLy5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5VbnJlYWRDaGFubmVsc1N0YXRlEkoKEG1lbnRpb25fZnJlY2VuY3kYLSABKAsyMC5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5NZW50aW9uRnJlY2VuY3lTdGF0ZRI9CgduYWdiYXJzGDwgASgLMiwuZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuTmFnYmFyRGlzbWlzc2FscxJHChFkaXNtaXNzZWRfdXBzZWxscxg9IAEoCzIsLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLkRpc21pc3NlZFVwc2VsbHMSTgoVZ3VpbGRfbnNmd19hZ3JlZW1lbnRzGD4gASgLMi8uZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuR3VpbGROc2Z3QWdyZWVtZW50cxI8Cgl3aGF0c19uZXcYPyABKAsyKS5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5XaGF0c05ld1N0YXRlEj8KB3ByaXZhY3kYUCABKAsyLi5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5Qcml2YWN5UHJlZmVyZW5jZXMSUAoUbG9jYWxfc3BhbV9vdmVycmlkZXMYUSABKAsyMi5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5Mb2NhbFVzZXJTcGFtT3ZlcnJpZGVzEhUKDXNhbml0aXplX3VybHMYUiABKAgSOAoFc291bmQYZCABKAsyKS5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5Tb3VuZFNldHRpbmdzEkIKCnNwZWxsY2hlY2sYZSABKAsyLi5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5TcGVsbGNoZWNrU2V0dGluZ3MSSAoOc2VhcmNoX2VuZ2luZXMYZiABKAsyMC5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5TZWFyY2hFbmdpbmVTZXR0aW5ncxJPChFwZXJtaXNzaW9uX2xheW91dBhnIAEoCzI0LmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLlBlcm1pc3Npb25MYXlvdXRTZXR0aW5ncxJSChNndWlsZF9tZW1iZXJfbGF5b3V0GGggASgLMjUuZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuR3VpbGRNZW1iZXJMYXlvdXRTZXR0aW5ncxJLCg1ndWlsZF9mb2xkZXJzGGkgASgLMjQuZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuR3VpbGRGb2xkZXJFeHBhbmRlZFN0YXRlElAKFGhpZGRlbl9ndWlsZF9idXR0b25zGGogASgLMjIuZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuSGlkZGVuR3VpbGRMaXN0QnV0dG9ucxJPChNrZXlib2FyZF9tb2RlX2ludHJvGGsgASgLMjIuZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuS2V5Ym9hcmRNb2RlSW50cm9TdGF0ZRJRChBpbnB1dF9tb25pdG9yaW5nGGwgASgLMjcuZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuSW5wdXRNb25pdG9yaW5nUHJvbXB0c1N0YXRlEkQKDXZvaWNlX3Byb21wdHMYbSABKAsyLS5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5Wb2ljZVByb21wdHNTdGF0ZRJACgtzdWRvX3Byb21wdBhuIAEoCzIrLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLlN1ZG9Qcm9tcHRTdGF0ZRI9CghrZXliaW5kcxhvIAEoCzIrLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLktleWJpbmRTZXR0aW5ncxJBCgpjaGF0X2lucHV0GHAgASgLMi0uZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuQ2hhdElucHV0U2V0dGluZ3MSKgodc2F2ZV9jYW1lcmFfdXBsb2Fkc190b19kZXZpY2UYcSABKAhIAIgBARJGChNkb3VibGVfdGFwX3JlYWN0aW9uGHIgASgLMikuZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuUmVhY3Rpb25FbW9qaUIgCh5fc2F2ZV9jYW1lcmFfdXBsb2Fkc190b19kZXZpY2UisAEKElNwZWxsY2hlY2tTZXR0aW5ncxIUCgdlbmFibGVkGAEgASgISACIAQESEQoJbGFuZ3VhZ2VzGAIgAygJEhsKE3BlcnNvbmFsX2RpY3Rpb25hcnkYAyADKAkSGAoLYXV0b19kZXRlY3QYBCABKAhIAYgBARITCgZlbmdpbmUYBSABKAlIAogBAUIKCghfZW5hYmxlZEIOCgxfYXV0b19kZXRlY3RCCQoHX2VuZ2luZSLmAQoUU2VhcmNoRW5naW5lU2V0dGluZ3MSIgoVdGV4dF9zZWFyY2hfZW5naW5lX2lkGAEgASgJSACIAQESKwoecmV2ZXJzZV9pbWFnZV9zZWFyY2hfZW5naW5lX2lkGAIgASgJSAGIAQESJAoXdHJhbnNsYXRpb25fcHJvdmlkZXJfaWQYAyABKAlIAogBAUIYChZfdGV4dF9zZWFyY2hfZW5naW5lX2lkQiEKH19yZXZlcnNlX2ltYWdlX3NlYXJjaF9lbmdpbmVfaWRCGgoYX3RyYW5zbGF0aW9uX3Byb3ZpZGVyX2lkIrUBChJQcml2YWN5UHJlZmVyZW5jZXMSHwoXZGlzYWJsZV9zdHJlYW1fcHJldmlld3MYASABKAgSHAoPc2hvd19hY3RpdmVfbm93GAIgASgISACIAQESKgodcHJldXBsb2FkX21lc3NhZ2VfYXR0YWNobWVudHMYAyABKAhIAYgBAUISChBfc2hvd19hY3RpdmVfbm93QiAKHl9wcmV1cGxvYWRfbWVzc2FnZV9hdHRhY2htZW50cyJQChZMb2NhbFVzZXJTcGFtT3ZlcnJpZGVzEhgKEHNwYW1tZXJfdXNlcl9pZHMYASADKAkSHAoUbm90X3NwYW1tZXJfdXNlcl9pZHMYAiADKAkiKwoWVGV4dHVhbFByZXZpZXdTZXR0aW5ncxIRCgl3cmFwX3RleHQYASABKAgi3AEKElNpZGViYXJQcmVmZXJlbmNlcxIcChRpbmxpbmVfZG1zX2NvbGxhcHNlZBgBIAEoCBIsCh9zaG93X2NvbGxhcHNlZF91bnJlYWRfZG1zX2JhZGdlGAIgASgISACIAQESLwoic2hvd19pbmNvbWluZ19mcmllbmRfcmVxdWVzdF9iYWRnZRgDIAEoCEgBiAEBQiIKIF9zaG93X2NvbGxhcHNlZF91bnJlYWRfZG1zX2JhZGdlQiUKI19zaG93X2luY29taW5nX2ZyaWVuZF9yZXF1ZXN0X2JhZGdlIj0KD01lbWJlckxpc3RTdGF0ZRIZCgxtZW1iZXJzX29wZW4YASABKAhIAIgBAUIPCg1fbWVtYmVyc19vcGVuIjQKE1VucmVhZENoYW5uZWxzU3RhdGUSHQoVY29sbGFwc2VkX2NoYW5uZWxfaWRzGAEgAygJIqoBChZSZWNlbnRNZW50aW9uc1NldHRpbmdzEh0KEGluY2x1ZGVfZXZlcnlvbmUYASABKAhIAIgBARIaCg1pbmNsdWRlX3JvbGVzGAIgASgISAGIAQESGwoOaW5jbHVkZV9ndWlsZHMYAyABKAhIAogBAUITChFfaW5jbHVkZV9ldmVyeW9uZUIQCg5faW5jbHVkZV9yb2xlc0IRCg9faW5jbHVkZV9ndWlsZHMi/wEKFE1lbnRpb25GcmVjZW5jeVN0YXRlEkYKBnNjb3BlcxgBIAMoCzI2LmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLk1lbnRpb25GcmVjZW5jeVN0YXRlLlNjb3BlGjsKBUVudHJ5Eg8KB3VzZXJfaWQYASABKAkSDQoFY291bnQYAiABKA0SEgoKbGFzdF9hdF9tcxgDIAEoAxpiCgVTY29wZRIQCghndWlsZF9pZBgBIAEoCRJHCgdlbnRyaWVzGAIgAygLMjYuZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuTWVudGlvbkZyZWNlbmN5U3RhdGUuRW50cnki3QEKDkZhdm9yaXRlc1N0YXRlEj0KCGNoYW5uZWxzGAEgAygLMisuZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuRmF2b3JpdGVDaGFubmVsEkAKCmNhdGVnb3JpZXMYAiADKAsyLC5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5GYXZvcml0ZUNhdGVnb3J5Eh4KFmNvbGxhcHNlZF9jYXRlZ29yeV9pZHMYAyADKAkSGwoTaGlkZV9tdXRlZF9jaGFubmVscxgEIAEoCBINCgVtdXRlZBgFIAEoCCKTAQoPRmF2b3JpdGVDaGFubmVsEhIKCmNoYW5uZWxfaWQYASABKAkSEAoIZ3VpbGRfaWQYAiABKAkSFgoJcGFyZW50X2lkGAMgASgJSACIAQESEAoIcG9zaXRpb24YBCABKAUSFQoIbmlja25hbWUYBSABKAlIAYgBAUIMCgpfcGFyZW50X2lkQgsKCV9uaWNrbmFtZSI+ChBGYXZvcml0ZUNhdGVnb3J5EgoKAmlkGAEgASgJEgwKBG5hbWUYAiABKAkSEAoIcG9zaXRpb24YAyABKAUi+ggKEE5hZ2JhckRpc21pc3NhbHMSEwoLaW9zX2luc3RhbGwYASABKAgSEwoLcHdhX2luc3RhbGwYAiABKAgSGQoRcHVzaF9ub3RpZmljYXRpb24YAyABKAgSHAoUZGVza3RvcF9ub3RpZmljYXRpb24YBCABKAgSHAoUcHJlbWl1bV9ncmFjZV9wZXJpb2QYBSABKAgSFwoPcHJlbWl1bV9leHBpcmVkGAYgASgIEhoKEnByZW1pdW1fb25ib2FyZGluZxgHIAEoCBIeChZwcmVtaXVtX3RyaWFsX2V4cGlyaW5nGAggASgIEhYKDmdpZnRfaW52ZW50b3J5GAkgASgIEhgKEGRlc2t0b3BfZG93bmxvYWQYCiABKAgSHAoUZ3VpbGRfbWVtYmVyc2hpcF9jdGEYCyABKAgSFQoNdmlzaW9uYXJ5X21mYRgMIAEoCBIbChNsZWdhY3lfcGhvbmVfdW5saW5rGA4gASgIEmQKFXBlbmRpbmdfYnVsa19kZWxldGlvbhgPIAMoCzJFLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLk5hZ2JhckRpc21pc3NhbHMuUGVuZGluZ0J1bGtEZWxldGlvbkVudHJ5ElsKEGludml0ZXNfZGlzYWJsZWQYECADKAsyQS5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5OYWdiYXJEaXNtaXNzYWxzLkludml0ZXNEaXNhYmxlZEVudHJ5EmQKFWd1aWxkX21mYV9yZXF1aXJlbWVudBgRIAMoCzJFLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLk5hZ2JhckRpc21pc3NhbHMuR3VpbGRNZmFSZXF1aXJlbWVudEVudHJ5El8KEnByaWNlX2Fubm91bmNlbWVudBgSIAMoCzJDLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLk5hZ2JhckRpc21pc3NhbHMuUHJpY2VBbm5vdW5jZW1lbnRFbnRyeRJfChNsZWdhY3lfcHJpY2Vfb3B0X2luGBMgAygLMkIuZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuTmFnYmFyRGlzbWlzc2Fscy5MZWdhY3lQcmljZU9wdEluRW50cnkaOgoYUGVuZGluZ0J1bGtEZWxldGlvbkVudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCDoCOAEaNgoUSW52aXRlc0Rpc2FibGVkRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgIOgI4ARo6ChhHdWlsZE1mYVJlcXVpcmVtZW50RW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgIOgI4ARo4ChZQcmljZUFubm91bmNlbWVudEVudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCDoCOAEaNwoVTGVnYWN5UHJpY2VPcHRJbkVudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCDoCOAEiKgoQRGlzbWlzc2VkVXBzZWxscxIWCg5waWNrZXJfcHJlbWl1bRgBIAEoCCJoChNHdWlsZE5zZndBZ3JlZW1lbnRzEhoKEmFncmVlZF9jaGFubmVsX2lkcxgBIAMoCRIYChBhZ3JlZWRfZ3VpbGRfaWRzGAIgAygJEhsKE2FncmVlZF9jYXRlZ29yeV9pZHMYAyADKAkiUQoNV2hhdHNOZXdTdGF0ZRIkChdsYXN0X2Rpc21pc3NlZF9lbnRyeV9pZBgBIAEoCUgAiAEBQhoKGF9sYXN0X2Rpc21pc3NlZF9lbnRyeV9pZCKaAQoYUGVybWlzc2lvbkxheW91dFNldHRpbmdzEkAKBmxheW91dBgBIAEoDjIwLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLlBlcm1pc3Npb25MYXlvdXRNb2RlEjwKBGdyaWQYAiABKA4yLi5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5QZXJtaXNzaW9uR3JpZE1vZGUiWgoZR3VpbGRNZW1iZXJMYXlvdXRTZXR0aW5ncxI9CgRtb2RlGAEgASgOMi8uZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuR3VpbGRNZW1iZXJWaWV3TW9kZSI3ChhHdWlsZEZvbGRlckV4cGFuZGVkU3RhdGUSGwoTZXhwYW5kZWRfZm9sZGVyX2lkcxgBIAMoBiJGChZIaWRkZW5HdWlsZExpc3RCdXR0b25zEhcKD2Rvd25sb2FkX2J1dHRvbhgBIAEoCBITCgtoZWxwX2J1dHRvbhgCIAEoCCImChZLZXlib2FyZE1vZGVJbnRyb1N0YXRlEgwKBHNlZW4YASABKAgiLwobSW5wdXRNb25pdG9yaW5nUHJvbXB0c1N0YXRlEhAKCHNlZW5fY3RhGAEgASgIImQKEVZvaWNlUHJvbXB0c1N0YXRlEiQKHHNraXBfaGlkZV9vd25fY2FtZXJhX2NvbmZpcm0YASABKAgSKQohc2tpcF9oaWRlX293bl9zY3JlZW5zaGFyZV9jb25maXJtGAIgASgIInQKD1N1ZG9Qcm9tcHRTdGF0ZRJIChRsYXN0X3VzZWRfbWZhX21ldGhvZBgBIAEoDjIlLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLk1mYU1ldGhvZEgAiAEBQhcKFV9sYXN0X3VzZWRfbWZhX21ldGhvZCK6AQoPS2V5YmluZFNldHRpbmdzEkIKD2N1c3RvbV9rZXliaW5kcxgBIAMoCzIpLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLkN1c3RvbUtleWJpbmQSFQoNdHJhbnNtaXRfbW9kZRgCIAEoCRIqCh1wdXNoX3RvX3RhbGtfcmVsZWFzZV9kZWxheV9tcxgDIAEoDUgAiAEBQiAKHl9wdXNoX3RvX3RhbGtfcmVsZWFzZV9kZWxheV9tcyKFAQoNQ3VzdG9tS2V5YmluZBIKCgJpZBgBIAEoCRITCgZhY3Rpb24YAiABKAlIAIgBARI3CgVjb21ibxgDIAEoCzIoLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLktleWJpbmRDb21ibxIPCgdlbmFibGVkGAQgASgIQgkKB19hY3Rpb24izgIKDEtleWJpbmRDb21ibxILCgNrZXkYASABKAkSEQoEY29kZRgCIAEoCUgAiAEBEhQKDGN0cmxfb3JfbWV0YRgDIAEoCBIMCgRjdHJsGAQgASgIEgsKA2FsdBgFIAEoCBINCgVzaGlmdBgGIAEoCBIMCgRtZXRhGAcgASgIEhMKBmdsb2JhbBgIIAEoCEgBiAEBEhQKB2VuYWJsZWQYCSABKAhIAogBARIVCg1tb2RpZmllcl9vbmx5GAogASgIEhIKCmJvdGhfc2lkZXMYCyABKAgSGQoMbW91c2VfYnV0dG9uGAwgASgNSAOIAQESGwoOZ2FtZXBhZF9idXR0b24YDSABKA1IBIgBAUIHCgVfY29kZUIJCgdfZ2xvYmFsQgoKCF9lbmFibGVkQg8KDV9tb3VzZV9idXR0b25CEQoPX2dhbWVwYWRfYnV0dG9uIkkKEUNoYXRJbnB1dFNldHRpbmdzEh4KEWNvbnZlcnRfZW1vdGljb25zGAEgASgISACIAQFCFAoSX2NvbnZlcnRfZW1vdGljb25zIjUKDVJlYWN0aW9uRW1vamkSDwoCaWQYASABKAlIAIgBARIMCgRuYW1lGAIgASgJQgUKA19pZCqCAQoUUGVybWlzc2lvbkxheW91dE1vZGUSJgoiUEVSTUlTU0lPTl9MQVlPVVRfTU9ERV9VTlNQRUNJRklFRBAAEiAKHFBFUk1JU1NJT05fTEFZT1VUX01PREVfQ09NRlkQARIgChxQRVJNSVNTSU9OX0xBWU9VVF9NT0RFX0RFTlNFEAIqegoSUGVybWlzc2lvbkdyaWRNb2RlEiQKIFBFUk1JU1NJT05fR1JJRF9NT0RFX1VOU1BFQ0lGSUVEEAASHwobUEVSTUlTU0lPTl9HUklEX01PREVfU0lOR0xFEAESHQoZUEVSTUlTU0lPTl9HUklEX01PREVfR1JJRBACKoABChNHdWlsZE1lbWJlclZpZXdNb2RlEiYKIkdVSUxEX01FTUJFUl9WSUVXX01PREVfVU5TUEVDSUZJRUQQABIgChxHVUlMRF9NRU1CRVJfVklFV19NT0RFX1RBQkxFEAESHwobR1VJTERfTUVNQkVSX1ZJRVdfTU9ERV9HUklEEAIqVQoJTWZhTWV0aG9kEhoKFk1GQV9NRVRIT0RfVU5TUEVDSUZJRUQQABITCg9NRkFfTUVUSE9EX1RPVFAQARIXChNNRkFfTUVUSE9EX1dFQkFVVEhOEANiBnByb3RvMw", [file_fluxer_user_preferences_v1_accessibility, file_fluxer_user_preferences_v1_pickers]); + fileDesc("CixmbHV4ZXIvdXNlci9wcmVmZXJlbmNlcy92MS9wcmVmZXJlbmNlcy5wcm90bxIaZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEipRUKEVN5bmNlZFByZWZlcmVuY2VzEkgKDWFjY2Vzc2liaWxpdHkYASABKAsyMS5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5BY2Nlc3NpYmlsaXR5U2V0dGluZ3MSUwoXYWNjZXNzaWJpbGl0eV9vdmVycmlkZXMYAiABKAsyMi5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5BY2Nlc3NpYmlsaXR5T3ZlcnJpZGVzEksKD3RleHR1YWxfcHJldmlldxgDIAEoCzIyLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLlRleHR1YWxQcmV2aWV3U2V0dGluZ3MSQgoMZW1vamlfcGlja2VyGBQgASgLMiwuZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuRW1vamlQaWNrZXJTdGF0ZRJGCg5zdGlja2VyX3BpY2tlchgVIAEoCzIuLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLlN0aWNrZXJQaWNrZXJTdGF0ZRJCCgxtZW1lc19waWNrZXIYFiABKAsyLC5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5NZW1lc1BpY2tlclN0YXRlEjUKBWVtb2ppGBcgASgLMiYuZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuRW1vamlTdGF0ZRJUChRlbW9qaV9zdGlja2VyX2xheW91dBgYIAEoCzI2LmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLkVtb2ppU3RpY2tlckxheW91dFNldHRpbmdzEkYKDWZhdm9yaXRlX2dpZnMYGSABKAsyLy5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5GYXZvcml0ZUdpZlNldHRpbmdzEj0KCWZhdm9yaXRlcxgoIAEoCzIqLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLkZhdm9yaXRlc1N0YXRlEksKD3JlY2VudF9tZW50aW9ucxgpIAEoCzIyLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLlJlY2VudE1lbnRpb25zU2V0dGluZ3MSPwoHc2lkZWJhchgqIAEoCzIuLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLlNpZGViYXJQcmVmZXJlbmNlcxJACgttZW1iZXJfbGlzdBgrIAEoCzIrLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLk1lbWJlckxpc3RTdGF0ZRJICg91bnJlYWRfY2hhbm5lbHMYLCABKAsyLy5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5VbnJlYWRDaGFubmVsc1N0YXRlEkoKEG1lbnRpb25fZnJlY2VuY3kYLSABKAsyMC5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5NZW50aW9uRnJlY2VuY3lTdGF0ZRI9CgduYWdiYXJzGDwgASgLMiwuZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuTmFnYmFyRGlzbWlzc2FscxJHChFkaXNtaXNzZWRfdXBzZWxscxg9IAEoCzIsLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLkRpc21pc3NlZFVwc2VsbHMSTgoVZ3VpbGRfbnNmd19hZ3JlZW1lbnRzGD4gASgLMi8uZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuR3VpbGROc2Z3QWdyZWVtZW50cxI8Cgl3aGF0c19uZXcYPyABKAsyKS5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5XaGF0c05ld1N0YXRlEj8KB3ByaXZhY3kYUCABKAsyLi5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5Qcml2YWN5UHJlZmVyZW5jZXMSUAoUbG9jYWxfc3BhbV9vdmVycmlkZXMYUSABKAsyMi5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5Mb2NhbFVzZXJTcGFtT3ZlcnJpZGVzEhUKDXNhbml0aXplX3VybHMYUiABKAgSOAoFc291bmQYZCABKAsyKS5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5Tb3VuZFNldHRpbmdzEkIKCnNwZWxsY2hlY2sYZSABKAsyLi5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5TcGVsbGNoZWNrU2V0dGluZ3MSSAoOc2VhcmNoX2VuZ2luZXMYZiABKAsyMC5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5TZWFyY2hFbmdpbmVTZXR0aW5ncxJPChFwZXJtaXNzaW9uX2xheW91dBhnIAEoCzI0LmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLlBlcm1pc3Npb25MYXlvdXRTZXR0aW5ncxJSChNndWlsZF9tZW1iZXJfbGF5b3V0GGggASgLMjUuZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuR3VpbGRNZW1iZXJMYXlvdXRTZXR0aW5ncxJLCg1ndWlsZF9mb2xkZXJzGGkgASgLMjQuZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuR3VpbGRGb2xkZXJFeHBhbmRlZFN0YXRlElAKFGhpZGRlbl9ndWlsZF9idXR0b25zGGogASgLMjIuZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuSGlkZGVuR3VpbGRMaXN0QnV0dG9ucxJPChNrZXlib2FyZF9tb2RlX2ludHJvGGsgASgLMjIuZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuS2V5Ym9hcmRNb2RlSW50cm9TdGF0ZRJRChBpbnB1dF9tb25pdG9yaW5nGGwgASgLMjcuZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuSW5wdXRNb25pdG9yaW5nUHJvbXB0c1N0YXRlEkQKDXZvaWNlX3Byb21wdHMYbSABKAsyLS5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5Wb2ljZVByb21wdHNTdGF0ZRJACgtzdWRvX3Byb21wdBhuIAEoCzIrLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLlN1ZG9Qcm9tcHRTdGF0ZRI9CghrZXliaW5kcxhvIAEoCzIrLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLktleWJpbmRTZXR0aW5ncxJBCgpjaGF0X2lucHV0GHAgASgLMi0uZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuQ2hhdElucHV0U2V0dGluZ3MSKgodc2F2ZV9jYW1lcmFfdXBsb2Fkc190b19kZXZpY2UYcSABKAhIAIgBARJGChNkb3VibGVfdGFwX3JlYWN0aW9uGHIgASgLMikuZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuUmVhY3Rpb25FbW9qaRJKChBjaGFubmVsX2ZyZWNlbmN5GHMgASgLMjAuZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuQ2hhbm5lbEZyZWNlbmN5U3RhdGVCIAoeX3NhdmVfY2FtZXJhX3VwbG9hZHNfdG9fZGV2aWNlIrABChJTcGVsbGNoZWNrU2V0dGluZ3MSFAoHZW5hYmxlZBgBIAEoCEgAiAEBEhEKCWxhbmd1YWdlcxgCIAMoCRIbChNwZXJzb25hbF9kaWN0aW9uYXJ5GAMgAygJEhgKC2F1dG9fZGV0ZWN0GAQgASgISAGIAQESEwoGZW5naW5lGAUgASgJSAKIAQFCCgoIX2VuYWJsZWRCDgoMX2F1dG9fZGV0ZWN0QgkKB19lbmdpbmUi5gEKFFNlYXJjaEVuZ2luZVNldHRpbmdzEiIKFXRleHRfc2VhcmNoX2VuZ2luZV9pZBgBIAEoCUgAiAEBEisKHnJldmVyc2VfaW1hZ2Vfc2VhcmNoX2VuZ2luZV9pZBgCIAEoCUgBiAEBEiQKF3RyYW5zbGF0aW9uX3Byb3ZpZGVyX2lkGAMgASgJSAKIAQFCGAoWX3RleHRfc2VhcmNoX2VuZ2luZV9pZEIhCh9fcmV2ZXJzZV9pbWFnZV9zZWFyY2hfZW5naW5lX2lkQhoKGF90cmFuc2xhdGlvbl9wcm92aWRlcl9pZCK1AQoSUHJpdmFjeVByZWZlcmVuY2VzEh8KF2Rpc2FibGVfc3RyZWFtX3ByZXZpZXdzGAEgASgIEhwKD3Nob3dfYWN0aXZlX25vdxgCIAEoCEgAiAEBEioKHXByZXVwbG9hZF9tZXNzYWdlX2F0dGFjaG1lbnRzGAMgASgISAGIAQFCEgoQX3Nob3dfYWN0aXZlX25vd0IgCh5fcHJldXBsb2FkX21lc3NhZ2VfYXR0YWNobWVudHMiUAoWTG9jYWxVc2VyU3BhbU92ZXJyaWRlcxIYChBzcGFtbWVyX3VzZXJfaWRzGAEgAygJEhwKFG5vdF9zcGFtbWVyX3VzZXJfaWRzGAIgAygJIisKFlRleHR1YWxQcmV2aWV3U2V0dGluZ3MSEQoJd3JhcF90ZXh0GAEgASgIItwBChJTaWRlYmFyUHJlZmVyZW5jZXMSHAoUaW5saW5lX2Rtc19jb2xsYXBzZWQYASABKAgSLAofc2hvd19jb2xsYXBzZWRfdW5yZWFkX2Rtc19iYWRnZRgCIAEoCEgAiAEBEi8KInNob3dfaW5jb21pbmdfZnJpZW5kX3JlcXVlc3RfYmFkZ2UYAyABKAhIAYgBAUIiCiBfc2hvd19jb2xsYXBzZWRfdW5yZWFkX2Rtc19iYWRnZUIlCiNfc2hvd19pbmNvbWluZ19mcmllbmRfcmVxdWVzdF9iYWRnZSI9Cg9NZW1iZXJMaXN0U3RhdGUSGQoMbWVtYmVyc19vcGVuGAEgASgISACIAQFCDwoNX21lbWJlcnNfb3BlbiI0ChNVbnJlYWRDaGFubmVsc1N0YXRlEh0KFWNvbGxhcHNlZF9jaGFubmVsX2lkcxgBIAMoCSKqAQoWUmVjZW50TWVudGlvbnNTZXR0aW5ncxIdChBpbmNsdWRlX2V2ZXJ5b25lGAEgASgISACIAQESGgoNaW5jbHVkZV9yb2xlcxgCIAEoCEgBiAEBEhsKDmluY2x1ZGVfZ3VpbGRzGAMgASgISAKIAQFCEwoRX2luY2x1ZGVfZXZlcnlvbmVCEAoOX2luY2x1ZGVfcm9sZXNCEQoPX2luY2x1ZGVfZ3VpbGRzIv8BChRNZW50aW9uRnJlY2VuY3lTdGF0ZRJGCgZzY29wZXMYASADKAsyNi5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5NZW50aW9uRnJlY2VuY3lTdGF0ZS5TY29wZRo7CgVFbnRyeRIPCgd1c2VyX2lkGAEgASgJEg0KBWNvdW50GAIgASgNEhIKCmxhc3RfYXRfbXMYAyABKAMaYgoFU2NvcGUSEAoIZ3VpbGRfaWQYASABKAkSRwoHZW50cmllcxgCIAMoCzI2LmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLk1lbnRpb25GcmVjZW5jeVN0YXRlLkVudHJ5It0BCg5GYXZvcml0ZXNTdGF0ZRI9CghjaGFubmVscxgBIAMoCzIrLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLkZhdm9yaXRlQ2hhbm5lbBJACgpjYXRlZ29yaWVzGAIgAygLMiwuZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuRmF2b3JpdGVDYXRlZ29yeRIeChZjb2xsYXBzZWRfY2F0ZWdvcnlfaWRzGAMgAygJEhsKE2hpZGVfbXV0ZWRfY2hhbm5lbHMYBCABKAgSDQoFbXV0ZWQYBSABKAgikwEKD0Zhdm9yaXRlQ2hhbm5lbBISCgpjaGFubmVsX2lkGAEgASgJEhAKCGd1aWxkX2lkGAIgASgJEhYKCXBhcmVudF9pZBgDIAEoCUgAiAEBEhAKCHBvc2l0aW9uGAQgASgFEhUKCG5pY2tuYW1lGAUgASgJSAGIAQFCDAoKX3BhcmVudF9pZEILCglfbmlja25hbWUiPgoQRmF2b3JpdGVDYXRlZ29yeRIKCgJpZBgBIAEoCRIMCgRuYW1lGAIgASgJEhAKCHBvc2l0aW9uGAMgASgFIvoIChBOYWdiYXJEaXNtaXNzYWxzEhMKC2lvc19pbnN0YWxsGAEgASgIEhMKC3B3YV9pbnN0YWxsGAIgASgIEhkKEXB1c2hfbm90aWZpY2F0aW9uGAMgASgIEhwKFGRlc2t0b3Bfbm90aWZpY2F0aW9uGAQgASgIEhwKFHByZW1pdW1fZ3JhY2VfcGVyaW9kGAUgASgIEhcKD3ByZW1pdW1fZXhwaXJlZBgGIAEoCBIaChJwcmVtaXVtX29uYm9hcmRpbmcYByABKAgSHgoWcHJlbWl1bV90cmlhbF9leHBpcmluZxgIIAEoCBIWCg5naWZ0X2ludmVudG9yeRgJIAEoCBIYChBkZXNrdG9wX2Rvd25sb2FkGAogASgIEhwKFGd1aWxkX21lbWJlcnNoaXBfY3RhGAsgASgIEhUKDXZpc2lvbmFyeV9tZmEYDCABKAgSGwoTbGVnYWN5X3Bob25lX3VubGluaxgOIAEoCBJkChVwZW5kaW5nX2J1bGtfZGVsZXRpb24YDyADKAsyRS5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5OYWdiYXJEaXNtaXNzYWxzLlBlbmRpbmdCdWxrRGVsZXRpb25FbnRyeRJbChBpbnZpdGVzX2Rpc2FibGVkGBAgAygLMkEuZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuTmFnYmFyRGlzbWlzc2Fscy5JbnZpdGVzRGlzYWJsZWRFbnRyeRJkChVndWlsZF9tZmFfcmVxdWlyZW1lbnQYESADKAsyRS5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5OYWdiYXJEaXNtaXNzYWxzLkd1aWxkTWZhUmVxdWlyZW1lbnRFbnRyeRJfChJwcmljZV9hbm5vdW5jZW1lbnQYEiADKAsyQy5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5OYWdiYXJEaXNtaXNzYWxzLlByaWNlQW5ub3VuY2VtZW50RW50cnkSXwoTbGVnYWN5X3ByaWNlX29wdF9pbhgTIAMoCzJCLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLk5hZ2JhckRpc21pc3NhbHMuTGVnYWN5UHJpY2VPcHRJbkVudHJ5GjoKGFBlbmRpbmdCdWxrRGVsZXRpb25FbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAg6AjgBGjYKFEludml0ZXNEaXNhYmxlZEVudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCDoCOAEaOgoYR3VpbGRNZmFSZXF1aXJlbWVudEVudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCDoCOAEaOAoWUHJpY2VBbm5vdW5jZW1lbnRFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAg6AjgBGjcKFUxlZ2FjeVByaWNlT3B0SW5FbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAg6AjgBIioKEERpc21pc3NlZFVwc2VsbHMSFgoOcGlja2VyX3ByZW1pdW0YASABKAgiaAoTR3VpbGROc2Z3QWdyZWVtZW50cxIaChJhZ3JlZWRfY2hhbm5lbF9pZHMYASADKAkSGAoQYWdyZWVkX2d1aWxkX2lkcxgCIAMoCRIbChNhZ3JlZWRfY2F0ZWdvcnlfaWRzGAMgAygJIlEKDVdoYXRzTmV3U3RhdGUSJAoXbGFzdF9kaXNtaXNzZWRfZW50cnlfaWQYASABKAlIAIgBAUIaChhfbGFzdF9kaXNtaXNzZWRfZW50cnlfaWQimgEKGFBlcm1pc3Npb25MYXlvdXRTZXR0aW5ncxJACgZsYXlvdXQYASABKA4yMC5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5QZXJtaXNzaW9uTGF5b3V0TW9kZRI8CgRncmlkGAIgASgOMi4uZmx1eGVyLnVzZXIucHJlZmVyZW5jZXMudjEuUGVybWlzc2lvbkdyaWRNb2RlIloKGUd1aWxkTWVtYmVyTGF5b3V0U2V0dGluZ3MSPQoEbW9kZRgBIAEoDjIvLmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLkd1aWxkTWVtYmVyVmlld01vZGUiNwoYR3VpbGRGb2xkZXJFeHBhbmRlZFN0YXRlEhsKE2V4cGFuZGVkX2ZvbGRlcl9pZHMYASADKAYiRgoWSGlkZGVuR3VpbGRMaXN0QnV0dG9ucxIXCg9kb3dubG9hZF9idXR0b24YASABKAgSEwoLaGVscF9idXR0b24YAiABKAgiJgoWS2V5Ym9hcmRNb2RlSW50cm9TdGF0ZRIMCgRzZWVuGAEgASgIIi8KG0lucHV0TW9uaXRvcmluZ1Byb21wdHNTdGF0ZRIQCghzZWVuX2N0YRgBIAEoCCJkChFWb2ljZVByb21wdHNTdGF0ZRIkChxza2lwX2hpZGVfb3duX2NhbWVyYV9jb25maXJtGAEgASgIEikKIXNraXBfaGlkZV9vd25fc2NyZWVuc2hhcmVfY29uZmlybRgCIAEoCCJ0Cg9TdWRvUHJvbXB0U3RhdGUSSAoUbGFzdF91c2VkX21mYV9tZXRob2QYASABKA4yJS5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5NZmFNZXRob2RIAIgBAUIXChVfbGFzdF91c2VkX21mYV9tZXRob2QiugEKD0tleWJpbmRTZXR0aW5ncxJCCg9jdXN0b21fa2V5YmluZHMYASADKAsyKS5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5DdXN0b21LZXliaW5kEhUKDXRyYW5zbWl0X21vZGUYAiABKAkSKgodcHVzaF90b190YWxrX3JlbGVhc2VfZGVsYXlfbXMYAyABKA1IAIgBAUIgCh5fcHVzaF90b190YWxrX3JlbGVhc2VfZGVsYXlfbXMihQEKDUN1c3RvbUtleWJpbmQSCgoCaWQYASABKAkSEwoGYWN0aW9uGAIgASgJSACIAQESNwoFY29tYm8YAyABKAsyKC5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5LZXliaW5kQ29tYm8SDwoHZW5hYmxlZBgEIAEoCEIJCgdfYWN0aW9uIs4CCgxLZXliaW5kQ29tYm8SCwoDa2V5GAEgASgJEhEKBGNvZGUYAiABKAlIAIgBARIUCgxjdHJsX29yX21ldGEYAyABKAgSDAoEY3RybBgEIAEoCBILCgNhbHQYBSABKAgSDQoFc2hpZnQYBiABKAgSDAoEbWV0YRgHIAEoCBITCgZnbG9iYWwYCCABKAhIAYgBARIUCgdlbmFibGVkGAkgASgISAKIAQESFQoNbW9kaWZpZXJfb25seRgKIAEoCBISCgpib3RoX3NpZGVzGAsgASgIEhkKDG1vdXNlX2J1dHRvbhgMIAEoDUgDiAEBEhsKDmdhbWVwYWRfYnV0dG9uGA0gASgNSASIAQFCBwoFX2NvZGVCCQoHX2dsb2JhbEIKCghfZW5hYmxlZEIPCg1fbW91c2VfYnV0dG9uQhEKD19nYW1lcGFkX2J1dHRvbiJCChRDaGFubmVsRnJlY2VuY3lFbnRyeRISCgp0b3RhbF91c2VzGAEgASgNEhYKDnJlY2VudF91c2VzX21zGAIgAygDIsIBChRDaGFubmVsRnJlY2VuY3lTdGF0ZRJKCgV1c2FnZRgBIAMoCzI7LmZsdXhlci51c2VyLnByZWZlcmVuY2VzLnYxLkNoYW5uZWxGcmVjZW5jeVN0YXRlLlVzYWdlRW50cnkaXgoKVXNhZ2VFbnRyeRILCgNrZXkYASABKAkSPwoFdmFsdWUYAiABKAsyMC5mbHV4ZXIudXNlci5wcmVmZXJlbmNlcy52MS5DaGFubmVsRnJlY2VuY3lFbnRyeToCOAEiSQoRQ2hhdElucHV0U2V0dGluZ3MSHgoRY29udmVydF9lbW90aWNvbnMYASABKAhIAIgBAUIUChJfY29udmVydF9lbW90aWNvbnMiNQoNUmVhY3Rpb25FbW9qaRIPCgJpZBgBIAEoCUgAiAEBEgwKBG5hbWUYAiABKAlCBQoDX2lkKoIBChRQZXJtaXNzaW9uTGF5b3V0TW9kZRImCiJQRVJNSVNTSU9OX0xBWU9VVF9NT0RFX1VOU1BFQ0lGSUVEEAASIAocUEVSTUlTU0lPTl9MQVlPVVRfTU9ERV9DT01GWRABEiAKHFBFUk1JU1NJT05fTEFZT1VUX01PREVfREVOU0UQAip6ChJQZXJtaXNzaW9uR3JpZE1vZGUSJAogUEVSTUlTU0lPTl9HUklEX01PREVfVU5TUEVDSUZJRUQQABIfChtQRVJNSVNTSU9OX0dSSURfTU9ERV9TSU5HTEUQARIdChlQRVJNSVNTSU9OX0dSSURfTU9ERV9HUklEEAIqgAEKE0d1aWxkTWVtYmVyVmlld01vZGUSJgoiR1VJTERfTUVNQkVSX1ZJRVdfTU9ERV9VTlNQRUNJRklFRBAAEiAKHEdVSUxEX01FTUJFUl9WSUVXX01PREVfVEFCTEUQARIfChtHVUlMRF9NRU1CRVJfVklFV19NT0RFX0dSSUQQAipVCglNZmFNZXRob2QSGgoWTUZBX01FVEhPRF9VTlNQRUNJRklFRBAAEhMKD01GQV9NRVRIT0RfVE9UUBABEhcKE01GQV9NRVRIT0RfV0VCQVVUSE4QA2IGcHJvdG8z", [file_fluxer_user_preferences_v1_accessibility, file_fluxer_user_preferences_v1_pickers]); /** * @generated from message fluxer.user.preferences.v1.SyncedPreferences @@ -200,6 +200,11 @@ export type SyncedPreferences = Message<"fluxer.user.preferences.v1.SyncedPrefer * @generated from field: fluxer.user.preferences.v1.ReactionEmoji double_tap_reaction = 114; */ doubleTapReaction?: ReactionEmoji | undefined; + + /** + * @generated from field: fluxer.user.preferences.v1.ChannelFrecencyState channel_frecency = 115; + */ + channelFrecency?: ChannelFrecencyState | undefined; }; /** @@ -1044,6 +1049,45 @@ export type KeybindCombo = Message<"fluxer.user.preferences.v1.KeybindCombo"> & export const KeybindComboSchema: GenMessage = /*@__PURE__*/ messageDesc(file_fluxer_user_preferences_v1_preferences, 28); +/** + * @generated from message fluxer.user.preferences.v1.ChannelFrecencyEntry + */ +export type ChannelFrecencyEntry = Message<"fluxer.user.preferences.v1.ChannelFrecencyEntry"> & { + /** + * @generated from field: uint32 total_uses = 1; + */ + totalUses: number; + + /** + * @generated from field: repeated int64 recent_uses_ms = 2; + */ + recentUsesMs: bigint[]; +}; + +/** + * Describes the message fluxer.user.preferences.v1.ChannelFrecencyEntry. + * Use `create(ChannelFrecencyEntrySchema)` to create a new message. + */ +export const ChannelFrecencyEntrySchema: GenMessage = /*@__PURE__*/ + messageDesc(file_fluxer_user_preferences_v1_preferences, 29); + +/** + * @generated from message fluxer.user.preferences.v1.ChannelFrecencyState + */ +export type ChannelFrecencyState = Message<"fluxer.user.preferences.v1.ChannelFrecencyState"> & { + /** + * @generated from field: map usage = 1; + */ + usage: { [key: string]: ChannelFrecencyEntry }; +}; + +/** + * Describes the message fluxer.user.preferences.v1.ChannelFrecencyState. + * Use `create(ChannelFrecencyStateSchema)` to create a new message. + */ +export const ChannelFrecencyStateSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_fluxer_user_preferences_v1_preferences, 30); + /** * @generated from message fluxer.user.preferences.v1.ChatInputSettings */ @@ -1059,7 +1103,7 @@ export type ChatInputSettings = Message<"fluxer.user.preferences.v1.ChatInputSet * Use `create(ChatInputSettingsSchema)` to create a new message. */ export const ChatInputSettingsSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_fluxer_user_preferences_v1_preferences, 29); + messageDesc(file_fluxer_user_preferences_v1_preferences, 31); /** * @generated from message fluxer.user.preferences.v1.ReactionEmoji @@ -1081,7 +1125,7 @@ export type ReactionEmoji = Message<"fluxer.user.preferences.v1.ReactionEmoji"> * Use `create(ReactionEmojiSchema)` to create a new message. */ export const ReactionEmojiSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_fluxer_user_preferences_v1_preferences, 30); + messageDesc(file_fluxer_user_preferences_v1_preferences, 32); /** * @generated from enum fluxer.user.preferences.v1.PermissionLayoutMode