fix(self-hosting): use instance contacts and live product name (#3333)

This commit is contained in:
Hampus authored and GitHub committed 2026-10-09 01:39:35 +02:00
1 parent 454fefdb92
commit a5c1362f4a
308 files changed
+16533 -13512

No files matched your search

@@ -3,7 +3,7 @@
import {ConfirmModal} from '@app/features/app/components/dialogs/ConfirmModal';
import {SettingsSection} from '@app/features/app/components/dialogs/shared/SettingsSection';
import {SettingsTabContainer} from '@app/features/app/components/dialogs/shared/SettingsTabLayout';
import {PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import {MacPermissionsSettingsRow} from '@app/features/permissions/system/components/MacPermissionsSettingsRow';
import {
getAutostartStatus,
@@ -125,7 +125,7 @@ const DesktopSettingsTab: React.FC = observer(() => {
ModalCommands.push(
modal(() => (
<ConfirmModal
title={i18n._(RESTART_DESCRIPTOR, {productName: PRODUCT_NAME})}
title={i18n._(RESTART_DESCRIPTOR, {productName: RuntimeConfig.productName})}
description={
<Trans>
Tray icon changes only apply after a restart on Linux because the system tray protocol doesn't reliably
@@ -153,7 +153,7 @@ const DesktopSettingsTab: React.FC = observer(() => {
>
{isDesktop() && (
<Switch
label={i18n._(LAUNCH_PRODUCT_AT_LOGIN_DESCRIPTOR, {productName: PRODUCT_NAME})}
label={i18n._(LAUNCH_PRODUCT_AT_LOGIN_DESCRIPTOR, {productName: RuntimeConfig.productName})}
value={autostartEnabled}
disabled={autostartBusy}
onChange={handleAutostartChange}
@@ -189,7 +189,7 @@ const DesktopSettingsTab: React.FC = observer(() => {
label={isMac ? <Trans>Show menu bar icon</Trans> : <Trans>Show system tray icon</Trans>}
description={
trayChangePendingRestart && isLinux
? i18n._(RESTART_PRODUCT_FOR_TRAY_CHANGE_DESCRIPTOR, {productName: PRODUCT_NAME})
? i18n._(RESTART_PRODUCT_FOR_TRAY_CHANGE_DESCRIPTOR, {productName: RuntimeConfig.productName})
: undefined
}
value={desktopWindowBehavior.showTrayIcon}
@@ -9,7 +9,8 @@ import {
SettingsTabSection,
} from '@app/features/app/components/dialogs/shared/SettingsTabLayout';
import {ExternalLink} from '@app/features/app/components/shared/ExternalLink';
import {I18N_WEBLATE_DOMAIN, I18N_WEBLATE_URL, PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import {I18N_WEBLATE_DOMAIN, I18N_WEBLATE_URL} from '@app/features/app/config/I18nDisplayConstants';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import * as EmojiUtils from '@app/features/expressions/utils/EmojiUtils';
import Spellcheck from '@app/features/messaging/state/Spellcheck';
import type {SpellcheckEngine} from '@app/features/platform/types/Electron';
@@ -27,7 +28,7 @@ import * as LocaleUtils from '@app/features/user/utils/LocaleUtils';
import {TimeFormatTypes} from '@fluxer/constants/src/UserConstants';
import {getFormattedTime} from '@fluxer/date_utils/src/DateFormatting';
import {localeUses12Hour} from '@fluxer/date_utils/src/DateHourCycle';
import {msg} from '@lingui/core/macro';
import {msg, ph} from '@lingui/core/macro';
import {Trans, useLingui} from '@lingui/react/macro';
import {clsx} from 'clsx';
import {observer} from 'mobx-react-lite';
@@ -346,7 +347,7 @@ const LanguageTab = observer(() => {
<div className={styles.notice} data-flx="user.language-tab.notice">
<p className={styles.noticeText} data-flx="user.language-tab.notice-text">
<Trans>
Help translate {PRODUCT_NAME} into your language on{' '}
Help translate {ph({PRODUCT_NAME: RuntimeConfig.productName})} into your language on{' '}
<ExternalLink href={I18N_WEBLATE_URL} className={styles.link} data-flx="user.language-tab.link">
{I18N_WEBLATE_DOMAIN}
</ExternalLink>
@@ -414,12 +415,14 @@ const SpellcheckSettingsSection = observer(() => {
{
value: 'auto',
name: i18n._(RECOMMENDED_DESCRIPTOR),
desc: i18n._(USE_THE_IN_APP_HUNSPELL_ENGINE_WHEN_A_DESCRIPTOR, {productName: PRODUCT_NAME}),
desc: i18n._(USE_THE_IN_APP_HUNSPELL_ENGINE_WHEN_A_DESCRIPTOR, {productName: RuntimeConfig.productName}),
},
{
value: 'hunspell',
name: i18n._(IN_APP_HUNSPELL_DESCRIPTOR),
desc: i18n._(ALWAYS_USE_S_HUNSPELL_DICTIONARIES_DOWNLOADED_ON_DEMAND_DESCRIPTOR, {productName: PRODUCT_NAME}),
desc: i18n._(ALWAYS_USE_S_HUNSPELL_DICTIONARIES_DOWNLOADED_ON_DEMAND_DESCRIPTOR, {
productName: RuntimeConfig.productName,
}),
},
{
value: 'system',
@@ -469,8 +472,9 @@ const SpellcheckSettingsSection = observer(() => {
data-flx="user.language-tab.spellcheck-settings-section.spellcheck-restart-banner"
>
<Trans>
Reload {PRODUCT_NAME} to fully apply the engine change. Switching between in-app and system spellcheck
requires a renderer reload because Electron can't swap providers while running.
Reload {ph({PRODUCT_NAME: RuntimeConfig.productName})} to fully apply the engine change. Switching
between in-app and system spellcheck requires a renderer reload because Electron can't swap providers
while running.
</Trans>{' '}
<Button
small
@@ -545,8 +549,9 @@ const SpellcheckSettingsSection = observer(() => {
data-flx="user.language-tab.spellcheck-settings-section.spellcheck-hint--2"
>
<Trans>
In "Operating system" mode, dictionaries listed above are advisory. {PRODUCT_NAME} will pass these
language tags to your OS spellchecker when supported. Tags it doesn't recognize are ignored.
In "Operating system" mode, dictionaries listed above are advisory.{' '}
{ph({PRODUCT_NAME: RuntimeConfig.productName})} will pass these language tags to your OS
spellchecker when supported. Tags it doesn't recognize are ignored.
</Trans>
</div>
)}
@@ -7,7 +7,7 @@ import {StatusSlate} from '@app/features/app/components/dialogs/shared/StatusSla
import {computeVerticalDropPosition} from '@app/features/app/components/layout/dnd/DndDropPosition';
import type {ConnectionDragItem} from '@app/features/app/components/layout/types/DndTypes';
import {DragItemType} from '@app/features/app/components/layout/types/DndTypes';
import {BLUESKY_PROVIDER_NAME, PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import {BLUESKY_PROVIDER_NAME} from '@app/features/app/config/I18nDisplayConstants';
import {useMergeRefs} from '@app/features/app/hooks/useMergeRefs';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import * as ConnectionCommands from '@app/features/connection/commands/ConnectionCommands';
@@ -29,7 +29,7 @@ import {useDragAutoScroll} from '@app/features/ui/hooks/useDragAutoScroll';
import {Tooltip} from '@app/features/ui/tooltip/Tooltip';
import styles from '@app/features/user/components/modals/tabs/LinkedAccountsTab.module.css';
import {type ConnectionType, ConnectionTypes} from '@fluxer/constants/src/ConnectionConstants';
import {msg} from '@lingui/core/macro';
import {msg, ph} from '@lingui/core/macro';
import {Trans, useLingui} from '@lingui/react/macro';
import {DotsSixVerticalIcon, GlobeSimpleIcon, PencilSimpleIcon, TrashIcon, UserListIcon} from '@phosphor-icons/react';
import {clsx} from 'clsx';
@@ -379,8 +379,8 @@ const LinkedAccountsTab: React.FC = observer(() => {
title={i18n._(CONNECTIONS_DESCRIPTOR)}
description={
<Trans>
Link external accounts and domains to your {PRODUCT_NAME} profile. Verified connections will be displayed
on your profile for others to see.
Link external accounts and domains to your {ph({PRODUCT_NAME: RuntimeConfig.productName})} profile.
Verified connections will be displayed on your profile for others to see.
</Trans>
}
data-flx="user.linked-accounts-tab.connections"
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import {GET_PREMIUM_DESCRIPTOR} from '@app/features/i18n/utils/CommonMessageDescriptors';
import {ComponentBus} from '@app/features/platform/utils/ComponentBus';
import * as PremiumModalCommands from '@app/features/premium/commands/PremiumModalCommands';
@@ -37,7 +38,7 @@ import {buildSettingsDeviceOptions} from '@app/features/voice/utils/SettingsDevi
import {hasHigherVideoQuality} from '@app/features/voice/utils/VideoQualityEntitlement';
import {resolveEffectiveDeviceId} from '@app/features/voice/utils/VoiceDeviceManager';
import type {I18n} from '@lingui/core';
import {msg} from '@lingui/core/macro';
import {msg, ph} from '@lingui/core/macro';
import {Trans, useLingui} from '@lingui/react/macro';
import {CrownIcon, GearIcon} from '@phosphor-icons/react';
import {observer} from 'mobx-react-lite';
@@ -227,13 +228,14 @@ export const VideoTab: React.FC<VideoTabProps> = observer(
</div>
<p className={styles.deviceNoticeDescription} data-flx="user.video-tab.device-notice-description">
{permissionStatus === 'denied' ? (
<Trans comment="Shown in video settings on the macOS app when camera access is denied. {PRODUCT_NAME} is the app name. Keep 'System Settings', 'Privacy & Security' and the permission name as macOS shows them in this language.">
Allow {PRODUCT_NAME} to access your camera in System Settings → Privacy & Security → Camera.
<Trans comment="Shown in video settings on the macOS app when camera access is denied. {ph({PRODUCT_NAME: RuntimeConfig.productName})} is the app name. Keep 'System Settings', 'Privacy & Security' and the permission name as macOS shows them in this language.">
Allow {ph({PRODUCT_NAME: RuntimeConfig.productName})} to access your camera in System Settings →
Privacy & Security → Camera.
</Trans>
) : permissionStatus === 'granted' ? (
<Trans>Connect a camera and try again.</Trans>
) : (
i18n._(PRODUCT_NEEDS_CAMERA_ACCESS_DESCRIPTOR, {productName: PRODUCT_NAME})
i18n._(PRODUCT_NEEDS_CAMERA_ACCESS_DESCRIPTOR, {productName: RuntimeConfig.productName})
)}
</p>
</div>
@@ -2,7 +2,8 @@
import {ConfirmModal} from '@app/features/app/components/dialogs/ConfirmModal';
import {SettingsTabSection} from '@app/features/app/components/dialogs/shared/SettingsTabLayout';
import {DESKTOP_DOWNLOAD_URL, PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import {DESKTOP_DOWNLOAD_URL} from '@app/features/app/config/I18nDisplayConstants';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import {getCachedNumberFormat} from '@app/features/i18n/utils/IntlCache';
import {KeybindRecorder} from '@app/features/input/components/KeybindRecorder';
import Keybind, {getDefaultKeybind} from '@app/features/input/state/InputKeybind';
@@ -65,7 +66,7 @@ import {
} from '@app/features/voice/utils/VoiceMessageDescriptors';
import type {VoiceProcessingMode} from '@app/features/voice/utils/VoiceProcessingProfile';
import {VOICE_VOLUME_MAX_PERCENT} from '@app/features/voice/utils/VoiceVolumeUtils';
import {msg} from '@lingui/core/macro';
import {msg, ph} from '@lingui/core/macro';
import {Trans, useLingui} from '@lingui/react/macro';
import {observer} from 'mobx-react-lite';
import type React from 'react';
@@ -315,8 +316,8 @@ export const VoiceTab: React.FC<VoiceTabProps> = observer(({voiceSettings, autoR
description={
<p data-flx="user.voice-tab.set-push-to-talk-enabled.p">
<Trans>
In a browser, push-to-talk only works while the {PRODUCT_NAME} tab is focused. Install the desktop app
for system-wide push-to-talk.
In a browser, push-to-talk only works while the {ph({PRODUCT_NAME: RuntimeConfig.productName})} tab is
focused. Install the desktop app for system-wide push-to-talk.
</Trans>
</p>
}
@@ -437,7 +438,7 @@ export const VoiceTab: React.FC<VoiceTabProps> = observer(({voiceSettings, autoR
{!isNativeDesktop
? i18n._(PUSH_TO_TALK_BROWSER_LIMITED_DESCRIPTION_DESCRIPTOR)
: i18n._(PUSH_TO_TALK_PERMISSION_LIMITED_DESCRIPTION_DESCRIPTOR, {
productName: PRODUCT_NAME,
productName: RuntimeConfig.productName,
permissionName: i18n._(macPermissionNameDescriptor('input-monitoring')),
})}
</WarningAlert>
@@ -543,19 +544,20 @@ export const VoiceTab: React.FC<VoiceTabProps> = observer(({voiceSettings, autoR
<p className={styles.deviceNoticeDescription} data-flx="user.voice-tab.device-notice-description">
{permissionStatus === 'denied' ? (
isNativeDesktop ? (
<Trans comment="Shown in voice settings on the macOS app when microphone access is denied. {PRODUCT_NAME} is the app name. Keep 'System Settings', 'Privacy & Security' and the permission name as macOS shows them in this language.">
Allow {PRODUCT_NAME} to access your microphone in System Settings → Privacy & Security →
Microphone.
<Trans comment="Shown in voice settings on the macOS app when microphone access is denied. {ph({PRODUCT_NAME: RuntimeConfig.productName})} is the app name. Keep 'System Settings', 'Privacy & Security' and the permission name as macOS shows them in this language.">
Allow {ph({PRODUCT_NAME: RuntimeConfig.productName})} to access your microphone in System Settings
→ Privacy & Security → Microphone.
</Trans>
) : (
<Trans>
Allow {PRODUCT_NAME} to access your microphone. Check your browser's address bar or settings.
Allow {ph({PRODUCT_NAME: RuntimeConfig.productName})} to access your microphone. Check your
browser's address bar or settings.
</Trans>
)
) : permissionStatus === 'granted' ? (
<Trans>Connect a microphone and try again.</Trans>
) : (
i18n._(PRODUCT_NEEDS_MICROPHONE_ACCESS_DESCRIPTOR, {productName: PRODUCT_NAME})
i18n._(PRODUCT_NEEDS_MICROPHONE_ACCESS_DESCRIPTOR, {productName: RuntimeConfig.productName})
)}
</p>
</div>
@@ -669,8 +671,9 @@ export const VoiceTab: React.FC<VoiceTabProps> = observer(({voiceSettings, autoR
data-flx="user.voice-tab.warning-alert"
>
<Trans>
Looks like you're using {externalProcessor.name}. Stacking {PRODUCT_NAME}'s processing on top can cause
pumping or distortion. Direct input passes your audio through untouched.
Looks like you're using {externalProcessor.name}. Stacking{' '}
{ph({PRODUCT_NAME: RuntimeConfig.productName})}'s processing on top can cause pumping or distortion.
Direct input passes your audio through untouched.
</Trans>
</WarningAlert>
)}
@@ -3,7 +3,7 @@
import * as AccessibilityCommands from '@app/features/accessibility/commands/AccessibilityCommands';
import Accessibility from '@app/features/accessibility/state/Accessibility';
import {resolveMotionPreferencesModel} from '@app/features/accessibility/state/MotionPreferencesMachine';
import {PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import {Switch} from '@app/features/ui/components/form/FormSwitch';
import type {RadioOption} from '@app/features/ui/radio_group/RadioGroup';
import {RadioGroup} from '@app/features/ui/radio_group/RadioGroup';
@@ -165,7 +165,7 @@ export const AnimationTabContent: React.FC = observer(() => {
label={
mobileLayout.enabled
? i18n._(AUTOMATICALLY_PLAY_GIFS_DESCRIPTOR)
: i18n._(AUTOMATICALLY_PLAY_GIFS_WHEN_IS_FOCUSED_DESCRIPTOR, {productName: PRODUCT_NAME})
: i18n._(AUTOMATICALLY_PLAY_GIFS_WHEN_IS_FOCUSED_DESCRIPTOR, {productName: RuntimeConfig.productName})
}
description={gifDescription()}
value={motion.effectiveGifAutoPlay}
@@ -3,7 +3,7 @@
import * as AccessibilityCommands from '@app/features/accessibility/commands/AccessibilityCommands';
import Accessibility from '@app/features/accessibility/state/Accessibility';
import {ConfirmModal} from '@app/features/app/components/dialogs/ConfirmModal';
import {PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import * as ModalCommands from '@app/features/ui/commands/ModalCommands';
import {modal} from '@app/features/ui/commands/ModalCommands';
import {Switch} from '@app/features/ui/components/form/FormSwitch';
@@ -15,7 +15,7 @@ import {
setDesktopWindowBehaviorSettings,
} from '@app/features/ui/utils/DesktopWindowBehaviorUtils';
import type {DesktopWindowBehaviorSettings} from '@app/types/electron.d';
import {msg} from '@lingui/core/macro';
import {msg, ph} from '@lingui/core/macro';
import {Trans, useLingui} from '@lingui/react/macro';
import {observer} from 'mobx-react-lite';
import {useCallback, useLayoutEffect, useState} from 'react';
@@ -106,10 +106,11 @@ function useChromiumScrollingRestartModal() {
ModalCommands.push(
modal(() => (
<ConfirmModal
title={i18n._(RESTART_PRODUCT_DESCRIPTOR, {productName: PRODUCT_NAME})}
title={i18n._(RESTART_PRODUCT_DESCRIPTOR, {productName: RuntimeConfig.productName})}
description={
<Trans>
{PRODUCT_NAME} needs to restart before Chromium's native scrolling settings change how scrolling works.
{ph({PRODUCT_NAME: RuntimeConfig.productName})} needs to restart before Chromium's native scrolling
settings change how scrolling works.
</Trans>
}
primaryText={i18n._(RESTART_NOW_DESCRIPTOR)}
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {ConfirmModal} from '@app/features/app/components/dialogs/ConfirmModal';
import {PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import {
getCachedDesktopTroubleshootingSettings,
getDesktopTroubleshootingSettings,
@@ -21,7 +21,7 @@ import {
} from '@app/features/ui/utils/DesktopWindowBehaviorUtils';
import {getElectronAPI} from '@app/features/ui/utils/NativeUtils';
import type {DesktopTroubleshootingSettings, DesktopWindowBehaviorSettings} from '@app/types/electron.d';
import {msg} from '@lingui/core/macro';
import {msg, ph} from '@lingui/core/macro';
import {Trans, useLingui} from '@lingui/react/macro';
import {observer} from 'mobx-react-lite';
import {useCallback, useLayoutEffect, useState} from 'react';
@@ -162,8 +162,13 @@ export const NativeTitleBarControl = observer(() => {
ModalCommands.push(
modal(() => (
<ConfirmModal
title={i18n._(RESTART_PRODUCT_DESCRIPTOR, {productName: PRODUCT_NAME})}
description={<Trans>{PRODUCT_NAME} needs to restart for the title bar change to take effect.</Trans>}
title={i18n._(RESTART_PRODUCT_DESCRIPTOR, {productName: RuntimeConfig.productName})}
description={
<Trans>
{ph({PRODUCT_NAME: RuntimeConfig.productName})} needs to restart for the title bar change to take
effect.
</Trans>
}
primaryText={i18n._(RESTART_NOW_DESCRIPTOR)}
primaryVariant="primary"
secondaryText={i18n._(LATER_DESCRIPTOR)}
@@ -206,11 +211,14 @@ export const HardwareAccelerationControl = observer(() => {
}
description={
value ? (
<Trans>{PRODUCT_NAME} needs to restart for hardware acceleration to take effect.</Trans>
<Trans>
{ph({PRODUCT_NAME: RuntimeConfig.productName})} needs to restart for hardware acceleration to take
effect.
</Trans>
) : (
<Trans>
{PRODUCT_NAME} needs to restart to disable Chromium's hardware acceleration. Use this only if you're
troubleshooting graphics glitches or high GPU usage.
{ph({PRODUCT_NAME: RuntimeConfig.productName})} needs to restart to disable Chromium's hardware
acceleration. Use this only if you're troubleshooting graphics glitches or high GPU usage.
</Trans>
)
}
@@ -6,7 +6,7 @@ import Accessibility, {
ZOOM_LEVEL_MAX,
ZOOM_LEVEL_MIN,
} from '@app/features/accessibility/state/Accessibility';
import {PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import {APP_ZOOM_LEVEL_DESCRIPTOR} from '@app/features/i18n/utils/CommonMessageDescriptors';
import {getCachedNumberFormat} from '@app/features/i18n/utils/IntlCache';
import Keybind from '@app/features/input/state/InputKeybind';
@@ -180,7 +180,7 @@ export function useAppZoomLevelDescription(): string {
const {i18n} = useLingui();
return useMemo(() => {
if (shouldWarnAboutFirefoxWebZoomShortcuts()) {
return i18n._(ADJUST_THE_OVERALL_ZOOM_LEVEL_OF_THE_APP_DESCRIPTOR, {productName: PRODUCT_NAME});
return i18n._(ADJUST_THE_OVERALL_ZOOM_LEVEL_OF_THE_APP_DESCRIPTOR, {productName: RuntimeConfig.productName});
}
const zoomIn = formatKeyCombo(i18n, Keybind.getByAction('system_zoom_in').combo);
const zoomOut = formatKeyCombo(i18n, Keybind.getByAction('system_zoom_out').combo);
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {StatusSlate} from '@app/features/app/components/dialogs/shared/StatusSlate';
import {PRODUCT_API_NAME} from '@app/features/app/config/I18nDisplayConstants';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import type {DeveloperApplication} from '@app/features/devtools/models/DeveloperApplication';
import FocusRing from '@app/features/ui/focus_ring/FocusRing';
import styles from '@app/features/user/components/modals/tabs/applications_tab/ApplicationsTab.module.css';
@@ -31,7 +31,7 @@ export const ApplicationsList: React.FC<ApplicationsListProps> = observer(({appl
<StatusSlate
Icon={AppWindowIcon}
title={<Trans>No applications yet</Trans>}
description={i18n._(FIRST_APPLICATION_DESCRIPTION_DESCRIPTOR, {apiName: PRODUCT_API_NAME})}
description={i18n._(FIRST_APPLICATION_DESCRIPTION_DESCRIPTOR, {apiName: `${RuntimeConfig.productName} API`})}
data-flx="user.applications-tab.applications-list.status-slate"
/>
</div>
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {SettingsTabSection} from '@app/features/app/components/dialogs/shared/SettingsTabLayout';
import {PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import {REACTIONS_DESCRIPTOR} from '@app/features/i18n/utils/CommonMessageDescriptors';
import {formatPermissionLabel} from '@app/features/permissions/utils/PermissionUtils';
import {Switch} from '@app/features/ui/components/form/FormSwitch';
@@ -113,7 +113,7 @@ export const DisplayTabContent: React.FC = observer(() => {
data-flx="user.chat-settings-tab.display-tab.display-tab-content.switch-group-item.update"
/>
<SwitchGroupItem
label={i18n._(WHEN_UPLOADED_DIRECTLY_TO_DESCRIPTOR, {productName: PRODUCT_NAME})}
label={i18n._(WHEN_UPLOADED_DIRECTLY_TO_DESCRIPTOR, {productName: RuntimeConfig.productName})}
value={userSettings.inlineAttachmentMedia}
onChange={(value) => UserSettingsCommands.update({inlineAttachmentMedia: value})}
data-flx="user.chat-settings-tab.display-tab.display-tab-content.switch-group-item.update--2"
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import {LimitResolver} from '@app/features/app/utils/LimitResolverAdapter';
import {isLimitToggleEnabled} from '@app/features/app/utils/LimitUtils';
import Guilds from '@app/features/guild/state/Guilds';
@@ -387,7 +387,7 @@ export const EntranceSoundSection: React.FC = observer(() => {
case 'dms':
return i18n._(USED_IN_DIRECT_MESSAGE_CALLS_IF_YOU_DO_DESCRIPTOR);
case 'guild':
return i18n._(USED_IN_THIS_COMMUNITY_IF_YOU_DO_NOT_DESCRIPTOR, {productName: PRODUCT_NAME});
return i18n._(USED_IN_THIS_COMMUNITY_IF_YOU_DO_NOT_DESCRIPTOR, {productName: RuntimeConfig.productName});
}
},
[i18n],
@@ -1,10 +1,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {
CANARY_DESKTOP_ENTRY_NAME,
DESKTOP_ENTRY_NAME,
PRODUCT_NAME,
} from '@app/features/app/config/I18nDisplayConstants';
import {CANARY_DESKTOP_ENTRY_NAME, DESKTOP_ENTRY_NAME} from '@app/features/app/config/I18nDisplayConstants';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import {TRY_AGAIN_DESCRIPTOR} from '@app/features/i18n/utils/CommonMessageDescriptors';
import GlobalShortcuts from '@app/features/input/state/GlobalShortcuts';
import Keybind from '@app/features/input/state/InputKeybind';
@@ -477,7 +474,7 @@ const BoundPortalShortcuts: React.FC<{'data-flx': string}> = observer(({'data-fl
</h3>
<p className={styles.customSubtitle} data-flx="user.system-shortcuts-section.bound.subtitle">
{i18n._(desktop === 'hyprland' ? HYPRLAND_BOUND_DESCRIPTION_DESCRIPTOR : BOUND_DESCRIPTION_DESCRIPTOR, {
productName: PRODUCT_NAME,
productName: RuntimeConfig.productName,
})}
</p>
{GlobalShortcuts.portalRecovering ? (
@@ -531,7 +528,7 @@ const BoundPortalShortcuts: React.FC<{'data-flx': string}> = observer(({'data-fl
{desktop === 'hyprland' ? null : (
<p className={styles.permissionSectionHelper} data-flx="user.system-shortcuts-section.bound.keys-reserved">
{i18n._(shouldShowDirectInputSwitch() ? KEYS_RESERVED_DIRECT_INPUT_DESCRIPTOR : KEYS_RESERVED_DESCRIPTOR, {
productName: PRODUCT_NAME,
productName: RuntimeConfig.productName,
})}
</p>
)}
@@ -566,7 +563,7 @@ const PortalStateSection: React.FC<{'data-flx': string}> = observer(({'data-flx'
>
{i18n._(
GlobalShortcuts.linux?.desktop === 'hyprland' ? HYPRLAND_NOT_SET_UP_DESCRIPTOR : NOT_SET_UP_DESCRIPTOR,
{productName: PRODUCT_NAME},
{productName: RuntimeConfig.productName},
)}
</WarningAlert>
);
@@ -614,7 +611,7 @@ const PortalStateSection: React.FC<{'data-flx': string}> = observer(({'data-flx'
}
data-flx={`${dataFlx}.unsupported`}
>
{i18n._(UNSUPPORTED_DESCRIPTOR, {productName: PRODUCT_NAME})}
{i18n._(UNSUPPORTED_DESCRIPTOR, {productName: RuntimeConfig.productName})}
</WarningAlert>
);
case 'error':
@@ -671,12 +668,12 @@ const DirectInputSwitch: React.FC<{'data-flx': string}> = observer(({'data-flx':
<>
{!directInput.enabled && isPushToTalkDesktopOnly() ? (
<WarningAlert data-flx={`${dataFlx}.push-to-talk-warning`}>
{i18n._(DIRECT_INPUT_PUSH_TO_TALK_WARNING_DESCRIPTOR, {productName: PRODUCT_NAME})}
{i18n._(DIRECT_INPUT_PUSH_TO_TALK_WARNING_DESCRIPTOR, {productName: RuntimeConfig.productName})}
</WarningAlert>
) : null}
<Switch
label={i18n._(DIRECT_INPUT_LABEL_DESCRIPTOR)}
description={i18n._(getDirectInputDescription(directInput.available), {productName: PRODUCT_NAME})}
description={i18n._(getDirectInputDescription(directInput.available), {productName: RuntimeConfig.productName})}
value={directInput.enabled}
onChange={(value) => void GlobalShortcuts.setDirectInputEnabled(value)}
disabled={GlobalShortcuts.pendingAction !== null}
@@ -702,7 +699,7 @@ export const SystemShortcutsSection: React.FC<{'data-flx'?: string}> = observer(
if (GlobalShortcuts.legacyWaylandNeedsUpdate) {
return (
<WarningAlert title={i18n._(SYSTEM_WIDE_SHORTCUTS_DESCRIPTOR)} data-flx={`${dataFlx}.update`}>
{i18n._(UPDATE_DESCRIPTOR, {productName: PRODUCT_NAME})}
{i18n._(UPDATE_DESCRIPTOR, {productName: RuntimeConfig.productName})}
</WarningAlert>
);
}
@@ -719,7 +716,7 @@ export const SystemShortcutsSection: React.FC<{'data-flx'?: string}> = observer(
<DirectInputSwitch data-flx={`${dataFlx}.switch.direct-input`} />
{showDirectInputError ? (
<WarningAlert data-flx={`${dataFlx}.direct-input-error`}>
{i18n._(DIRECT_INPUT_ERROR_DESCRIPTOR, {productName: PRODUCT_NAME})}
{i18n._(DIRECT_INPUT_ERROR_DESCRIPTOR, {productName: RuntimeConfig.productName})}
</WarningAlert>
) : null}
</div>
@@ -734,8 +731,8 @@ const HyprlandPushToTalkCard: React.FC<{portalAppId: string | null; 'data-flx':
<div className={styles.customSection} data-flx={dataFlx}>
<p className={styles.permissionSectionHelper} data-flx={`${dataFlx}.text`}>
{portalAppId
? i18n._(PTT_HYPRLAND_DESCRIPTOR, {productName: PRODUCT_NAME})
: i18n._(PTT_HYPRLAND_NO_APP_ID_DESCRIPTOR, {productName: PRODUCT_NAME})}
? i18n._(PTT_HYPRLAND_DESCRIPTOR, {productName: RuntimeConfig.productName})
: i18n._(PTT_HYPRLAND_NO_APP_ID_DESCRIPTOR, {productName: RuntimeConfig.productName})}
</p>
{portalAppId ? (
<HyprlandBindLines portalAppId={portalAppId} actions={['voice_push_to_talk']} data-flx={`${dataFlx}.lines`} />
@@ -751,7 +748,7 @@ export const SystemShortcutsPushToTalkAlert: React.FC<{'data-flx'?: string}> = o
if (GlobalShortcuts.legacyWaylandNeedsUpdate) {
return (
<WarningAlert data-flx={`${dataFlx}.update`}>
{i18n._(UPDATE_DESCRIPTOR, {productName: PRODUCT_NAME})}
{i18n._(UPDATE_DESCRIPTOR, {productName: RuntimeConfig.productName})}
</WarningAlert>
);
}
@@ -760,7 +757,7 @@ export const SystemShortcutsPushToTalkAlert: React.FC<{'data-flx'?: string}> = o
if (hasDirectInputError()) {
return (
<WarningAlert data-flx={`${dataFlx}.direct-input-error`}>
{i18n._(DIRECT_INPUT_ERROR_DESCRIPTOR, {productName: PRODUCT_NAME})}
{i18n._(DIRECT_INPUT_ERROR_DESCRIPTOR, {productName: RuntimeConfig.productName})}
</WarningAlert>
);
}
@@ -776,7 +773,7 @@ export const SystemShortcutsPushToTalkAlert: React.FC<{'data-flx'?: string}> = o
actions={<SetUpButton label={i18n._(SET_UP_DESCRIPTOR)} data-flx={`${dataFlx}.button.set-up`} />}
data-flx={`${dataFlx}.not-set-up`}
>
{i18n._(PTT_NOT_SET_UP_DESCRIPTOR, {productName: PRODUCT_NAME})}
{i18n._(PTT_NOT_SET_UP_DESCRIPTOR, {productName: RuntimeConfig.productName})}
</WarningAlert>
);
case 'binding':
@@ -787,7 +784,7 @@ export const SystemShortcutsPushToTalkAlert: React.FC<{'data-flx'?: string}> = o
actions={<SetUpButton label={i18n._(TRY_AGAIN_DESCRIPTOR)} data-flx={`${dataFlx}.button.retry-declined`} />}
data-flx={`${dataFlx}.declined`}
>
{i18n._(PTT_DECLINED_DESCRIPTOR, {productName: PRODUCT_NAME})}
{i18n._(PTT_DECLINED_DESCRIPTOR, {productName: RuntimeConfig.productName})}
</WarningAlert>
);
case 'error':
@@ -805,7 +802,7 @@ export const SystemShortcutsPushToTalkAlert: React.FC<{'data-flx'?: string}> = o
actions={portal.canRecheck ? <CheckAgainButton data-flx={`${dataFlx}.button.check-again`} /> : undefined}
data-flx={`${dataFlx}.unsupported`}
>
{i18n._(PTT_UNSUPPORTED_DESCRIPTOR, {productName: PRODUCT_NAME})}
{i18n._(PTT_UNSUPPORTED_DESCRIPTOR, {productName: RuntimeConfig.productName})}
</WarningAlert>
);
case 'bound': {
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import GlobalShortcuts from '@app/features/input/state/GlobalShortcuts';
import Keybind, {type KeybindCommand} from '@app/features/input/state/InputKeybind';
import {
@@ -62,11 +62,11 @@ export const SystemShortcutRowHint = observer(
<div data-flx={`${dataFlx}.focused`}>
{variant === 'voice-tab'
? i18n._(IN_APP_KEY_DESCRIPTOR, {
productName: PRODUCT_NAME,
productName: RuntimeConfig.productName,
settingsTabName: getUserSettingsTabLabel(i18n, 'keybinds'),
sectionName: i18n._(SYSTEM_WIDE_SHORTCUTS_DESCRIPTOR),
})
: i18n._(WORKS_WHILE_FOCUSED_DESCRIPTOR, {productName: PRODUCT_NAME})}
: i18n._(WORKS_WHILE_FOCUSED_DESCRIPTOR, {productName: RuntimeConfig.productName})}
</div>
{showTrigger ? (
<div data-flx={`${dataFlx}.trigger`}>
@@ -2,7 +2,7 @@
import * as Modal from '@app/features/app/components/dialogs/Modal';
import {SettingsTabSection} from '@app/features/app/components/dialogs/shared/SettingsTabLayout';
import {PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import {COMMUNITY_MEMBERS_DESCRIPTOR} from '@app/features/i18n/utils/CommonMessageDescriptors';
import {Button} from '@app/features/ui/button/Button';
import * as ModalCommands from '@app/features/ui/commands/ModalCommands';
@@ -110,7 +110,7 @@ export function TimezoneProfileSettings({
return (
<SettingsTabSection
title={i18n._(PROFILE_LOCAL_TIME_DESCRIPTOR)}
description={i18n._(PROFILE_LOCAL_TIME_SUMMARY_DESCRIPTOR, {productName: PRODUCT_NAME})}
description={i18n._(PROFILE_LOCAL_TIME_SUMMARY_DESCRIPTOR, {productName: RuntimeConfig.productName})}
data-flx="user.my-profile-tab.timezone-profile-settings.section"
>
<Button
@@ -194,13 +194,13 @@ function TimezoneProfileSettingsModal({
<Modal.ContentLayout data-flx="user.my-profile-tab.timezone-profile-settings.modal-content-layout">
<Modal.Description data-flx="user.my-profile-tab.timezone-profile-settings.privacy-note">
{i18n._(TIMEZONE_PRIVACY_NOTE_DESCRIPTOR, {
productName: PRODUCT_NAME,
productName: RuntimeConfig.productName,
timezoneIdentifierExample: TIMEZONE_IDENTIFIER_EXAMPLE,
})}
</Modal.Description>
<Combobox<string, false, TimeZoneSelectOption>
label={i18n._(TIMEZONE_DESCRIPTOR)}
description={i18n._(TIMEZONE_HELP_DESCRIPTOR, {productName: PRODUCT_NAME})}
description={i18n._(TIMEZONE_HELP_DESCRIPTOR, {productName: RuntimeConfig.productName})}
placeholder={i18n._(SEARCH_TIMEZONES_DESCRIPTOR)}
value={localTimezone ?? ''}
options={options}
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import {ENABLE_NOTIFICATIONS_DESCRIPTOR} from '@app/features/i18n/utils/CommonMessageDescriptors';
import {usePushSubscriptions} from '@app/features/notification/hooks/usePushSubscriptions';
import * as NotificationUtils from '@app/features/notification/utils/NotificationUtils';
@@ -161,7 +161,9 @@ export const Notifications: FC<NotificationsProps> = observer(
isDesktop()
? i18n._(USES_THE_OS_NOTIFICATION_CENTER_FOR_PER_CHANNEL_DESCRIPTOR)
: isPwa
? i18n._(GET_NOTIFIED_WHEN_YOU_RECEIVE_MESSAGES_YOU_MAY_DESCRIPTOR, {productName: PRODUCT_NAME})
? i18n._(GET_NOTIFIED_WHEN_YOU_RECEIVE_MESSAGES_YOU_MAY_DESCRIPTOR, {
productName: RuntimeConfig.productName,
})
: i18n._(GET_NOTIFIED_WHEN_YOU_RECEIVE_MESSAGES_YOU_MAY_2_DESCRIPTOR)
}
value={browserNotificationsEnabled}
@@ -187,7 +189,9 @@ export const Notifications: FC<NotificationsProps> = observer(
{i18n._(PUSH_SUBSCRIPTIONS_FOR_THIS_DEVICE_DESCRIPTOR)}
</h3>
<p className={styles.pushDescription} data-flx="user.notifications-tab.notifications.push-description">
{i18n._(USES_PUSH_NOTIFICATIONS_WHEN_INSTALLED_AS_A_MOBILE_DESCRIPTOR, {productName: PRODUCT_NAME})}
{i18n._(USES_PUSH_NOTIFICATIONS_WHEN_INSTALLED_AS_A_MOBILE_DESCRIPTOR, {
productName: RuntimeConfig.productName,
})}
</p>
</div>
<div className={styles.pushButtons} data-flx="user.notifications-tab.notifications.push-buttons">
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import {Combobox as FormCombobox} from '@app/features/ui/components/form/FormCombobox';
import styles from '@app/features/user/components/modals/tabs/notifications_tab/PushSettings.module.css';
import {msg} from '@lingui/core/macro';
@@ -60,7 +60,9 @@ export const PushSettings: React.FC<PushSettingsProps> = observer(
{i18n._(PUSH_NOTIFICATION_INACTIVE_TIMEOUT_DESCRIPTOR)}
</label>
<p className={styles.description} data-flx="user.notifications-tab.push-settings.description">
{i18n._(AVOIDS_SENDING_PUSH_NOTIFICATIONS_TO_YOUR_MOBILE_DEVICES_DESCRIPTOR, {productName: PRODUCT_NAME})}
{i18n._(AVOIDS_SENDING_PUSH_NOTIFICATIONS_TO_YOUR_MOBILE_DEVICES_DESCRIPTOR, {
productName: RuntimeConfig.productName,
})}
</p>
</div>
)}
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {Routes} from '@app/app/Routes';
import {PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import * as PremiumModalCommands from '@app/features/premium/commands/PremiumModalCommands';
import PlutoniumPageRollout from '@app/features/premium/state/PlutoniumPageRollout';
@@ -101,7 +101,7 @@ export const UserProfileBadges: React.FC<UserProfileBadgesProps> = observer(
type: 'icon',
key: 'staff',
iconUrl: staffBadgeUrl,
tooltip: i18n._(STAFF_DESCRIPTOR, {productName: PRODUCT_NAME}),
tooltip: i18n._(STAFF_DESCRIPTOR, {productName: RuntimeConfig.productName}),
url: Routes.careers(),
});
}
@@ -110,7 +110,7 @@ export const UserProfileBadges: React.FC<UserProfileBadgesProps> = observer(
type: 'icon',
key: 'partner',
iconUrl: partnerBadgeUrl,
tooltip: i18n._(PARTNER_DESCRIPTOR, {productName: PRODUCT_NAME}),
tooltip: i18n._(PARTNER_DESCRIPTOR, {productName: RuntimeConfig.productName}),
url: Routes.partners(),
});
}
@@ -119,7 +119,7 @@ export const UserProfileBadges: React.FC<UserProfileBadgesProps> = observer(
type: 'icon',
key: 'bug_hunter',
iconUrl: bugHunterBadgeUrl,
tooltip: i18n._(BUG_HUNTER_DESCRIPTOR, {productName: PRODUCT_NAME}),
tooltip: i18n._(BUG_HUNTER_DESCRIPTOR, {productName: RuntimeConfig.productName}),
url: Routes.bugs(),
});
}
@@ -131,11 +131,14 @@ export const UserProfileBadges: React.FC<UserProfileBadgesProps> = observer(
if (!selfHosted && profile.premiumType === UserPremiumTypes.LIFETIME) {
if (profile.premiumSince) {
const premiumSinceFormatted = DateUtils.getFormattedShortDate(profile.premiumSince);
tooltipText = i18n._(VISIONARY_SINCE_DESCRIPTOR, {productName: PRODUCT_NAME, premiumSinceFormatted});
tooltipText = i18n._(VISIONARY_SINCE_DESCRIPTOR, {
productName: RuntimeConfig.productName,
premiumSinceFormatted,
});
} else {
tooltipText = i18n._(VISIONARY_DESCRIPTOR, {productName: PRODUCT_NAME});
tooltipText = i18n._(VISIONARY_DESCRIPTOR, {productName: RuntimeConfig.productName});
}
badgeUrl = Routes.helpArticle('visionary');
badgeUrl = Routes.helpArticle('visionary') ?? undefined;
} else if (profile.premiumSince) {
const premiumSinceFormatted = DateUtils.getFormattedShortDate(profile.premiumSince);
tooltipText = i18n._(SUBSCRIBER_SINCE_DESCRIPTOR, {
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {BLUESKY_PROVIDER_NAME, PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import {BLUESKY_PROVIDER_NAME} from '@app/features/app/config/I18nDisplayConstants';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import {GuildIcon} from '@app/features/guild/components/popouts/GuildIcon';
import {AddRoleButton, RoleList} from '@app/features/guild/components/RoleManagement';
import type {GuildRole} from '@app/features/guild/models/GuildRole';
@@ -290,7 +291,10 @@ export const UserProfileMembershipInfo: React.FC<{profile: Profile; user: User}>
className={styles.membershipDate}
data-flx="user.user-profile-shared.user-profile-membership-info.membership-date"
>
<Tooltip text={PRODUCT_NAME} data-flx="user.user-profile-shared.user-profile-membership-info.tooltip">
<Tooltip
text={RuntimeConfig.productName}
data-flx="user.user-profile-shared.user-profile-membership-info.tooltip"
>
<div
className={styles.membershipIcon}
data-flx="user.user-profile-shared.user-profile-membership-info.membership-icon"
@@ -350,7 +354,7 @@ export const UserProfileMembershipInfo: React.FC<{profile: Profile; user: User}>
className={styles.membershipTitle}
data-flx="user.user-profile-shared.user-profile-membership-info.membership-title--2"
>
{i18n._(PRODUCT_MEMBER_SINCE_DESCRIPTOR, {productName: PRODUCT_NAME})}
{i18n._(PRODUCT_MEMBER_SINCE_DESCRIPTOR, {productName: RuntimeConfig.productName})}
</span>
<span
className={styles.membershipDateText}
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {Routes} from '@app/app/Routes';
import {VOICE_CHANNEL_DESCRIPTOR} from '@app/features/i18n/utils/CommonMessageDescriptors';
import {Platform} from '@app/features/platform/types/Platform';
import type {SearchableSettingDescriptor} from '@app/features/user/components/settings_utils/search_index/SearchIndexTypes';
@@ -157,6 +158,7 @@ export const appearanceIndex: Array<SearchableSettingDescriptor> = [
description: HELP_CENTER_BUTTON_IN_THE_SIDEBAR_DESCRIPTOR,
audience: 'advanced',
tags: ['appearance'],
isVisible: () => Routes.help() != null,
},
{
id: 'appearance-show-download-button',