From bd2312ad3e492d130b4e729ee0dc45f1209930db Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Tue, 23 Sep 2025 07:42:35 +0200 Subject: [PATCH 1/4] feat: add start of the pro base settings screen --- preload.js | 1 + ts/components/buttons/panel/PanelButton.tsx | 5 + ts/components/dialog/debug/FeatureFlags.tsx | 7 +- .../debug/playgrounds/ProPlaygroundPage.tsx | 5 + .../user-settings/UserSettingsDialog.tsx | 3 + .../pages/DefaultSettingsPage.tsx | 25 +- .../pages/PrivacySettingsPage.tsx | 2 +- .../pages/user-pro/ProSettingsPage.tsx | 323 ++++++++++++++++++ .../user-settings/pages/userSettingsHooks.tsx | 4 + ts/components/icon/lucide.ts | 2 + ts/data/settings-key.ts | 10 + ts/hooks/useHasPro.ts | 24 ++ ts/react.d.ts | 15 +- ts/state/ducks/modalDialog.tsx | 5 +- .../ducks/types/releasedFeaturesReduxTypes.ts | 1 + 15 files changed, 421 insertions(+), 11 deletions(-) create mode 100644 ts/components/dialog/user-settings/pages/user-pro/ProSettingsPage.tsx diff --git a/preload.js b/preload.js index 68a925d9c..b27aebee6 100644 --- a/preload.js +++ b/preload.js @@ -67,6 +67,7 @@ window.sessionFeatureFlags = { showPopoverAnchors: false, proAvailable: !isEmpty(process.env.SESSION_PRO), mockCurrentUserHasPro: !isEmpty(process.env.SESSION_USER_HAS_PRO), + mockCurrentUserHasProExpired: !isEmpty(process.env.SESSION_USER_HAS_PRO_EXPIRED), mockOthersHavePro: !isEmpty(process.env.SESSION_OTHERS_HAVE_PRO), mockMessageProFeatures: [], // Note: some stuff are init when the app starts, so fsTTL30s should only be set from the env itself (before app starts) diff --git a/ts/components/buttons/panel/PanelButton.tsx b/ts/components/buttons/panel/PanelButton.tsx index bf4cd0a71..04221eb22 100644 --- a/ts/components/buttons/panel/PanelButton.tsx +++ b/ts/components/buttons/panel/PanelButton.tsx @@ -18,6 +18,8 @@ export const StyledContent = styled.div<{ disabled: boolean }>` `; const StyledPanelLabel = styled.p` + display: flex; + gap: var(--margins-xs); color: var(--text-secondary-color); margin: 0; align-self: flex-start; @@ -38,9 +40,11 @@ const StyledPanelLabelWithDescription = styled.div` export function PanelLabelWithDescription({ title, + extraInlineNode, description, }: { title: TrArgs; + extraInlineNode?: ReactNode; description?: TrArgs; }) { return ( @@ -48,6 +52,7 @@ export function PanelLabelWithDescription({ {/* less space between the label and the description */} + {extraInlineNode} {description ? ( diff --git a/ts/components/dialog/debug/FeatureFlags.tsx b/ts/components/dialog/debug/FeatureFlags.tsx index 2afc47169..51dbcae30 100644 --- a/ts/components/dialog/debug/FeatureFlags.tsx +++ b/ts/components/dialog/debug/FeatureFlags.tsx @@ -29,7 +29,12 @@ const handleFeatureFlagToggle = ({ flag, parentFlag, forceUpdate }: FeatureFlagT forceUpdate(); - if (flag === 'proAvailable' || flag === 'mockCurrentUserHasPro' || flag === 'mockOthersHavePro') { + if ( + flag === 'proAvailable' || + flag === 'mockCurrentUserHasPro' || + flag === 'mockOthersHavePro' || + flag === 'mockCurrentUserHasProExpired' + ) { ConvoHub.use() .getConversations() .forEach(convo => { diff --git a/ts/components/dialog/debug/playgrounds/ProPlaygroundPage.tsx b/ts/components/dialog/debug/playgrounds/ProPlaygroundPage.tsx index f8eda262d..07919a494 100644 --- a/ts/components/dialog/debug/playgrounds/ProPlaygroundPage.tsx +++ b/ts/components/dialog/debug/playgrounds/ProPlaygroundPage.tsx @@ -29,6 +29,11 @@ export function ProPlaygroundPage() { flag="mockCurrentUserHasPro" value={useFeatureFlag('mockCurrentUserHasPro')} /> + { if (!modalState?.userSettingsPage) { @@ -42,6 +43,8 @@ export const UserSettingsDialog = (modalState: UserSettingsModalState) => { return ; case 'network': return ; + case 'pro': + return ; case 'message-requests': // the `message-request` is not a page of the user settings page, but a page in the left pane header currently. return null; diff --git a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx index 3e2d8c99c..95c8b3ca0 100644 --- a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx @@ -6,7 +6,6 @@ import { useOurConversationUsername, useOurAvatarPath } from '../../../../hooks/ import { UserUtils, ToastUtils } from '../../../../session/utils'; import { resetConversationExternal } from '../../../../state/ducks/conversations'; import { - updateSessionProInfoModal, onionPathModal, updateConversationDetailsModal, userSettingsModal, @@ -26,7 +25,6 @@ import { SessionIconButton, SessionLucideIconButton } from '../../../icon/Sessio import { QRView } from '../../../qrview/QrView'; import { ModalBasicHeader } from '../../../SessionWrapperModal'; import { showLinkVisitWarningDialog } from '../../OpenUrlModal'; -import { SessionProInfoVariant } from '../../SessionProInfoModal'; import { ModalPencilIcon } from '../../shared/ModalPencilButton'; import { ProfileHeader, ProfileName } from '../components'; import type { ProfileDialogModes } from '../ProfileDialogModes'; @@ -36,6 +34,11 @@ import { setDebugMode } from '../../../../state/ducks/debug'; import { useHideRecoveryPasswordEnabled } from '../../../../state/selectors/settings'; import { OnionStatusLight } from '../../OnionStatusPathDialog'; import { UserSettingsModalContainer } from '../components/UserSettingsModalContainer'; +import { + useCurrentNeverHadPro, + useCurrentUserHasExpiredPro, + useCurrentUserHasPro, +} from '../../../../hooks/useHasPro'; const handleKeyQRMode = (mode: ProfileDialogModes, setMode: (mode: ProfileDialogModes) => void) => { switch (mode) { @@ -92,10 +95,14 @@ function SessionProSection() { const dispatch = useDispatch(); const isProAvailable = useIsProAvailable(); + const userHasPro = useCurrentUserHasPro(); + const currentUserHasExpiredPro = useCurrentUserHasExpiredPro(); + const currentNeverHadPro = useCurrentNeverHadPro(); if (!isProAvailable) { return null; } + return ( } - text={{ token: 'appPro' }} + text={{ + token: userHasPro + ? 'sessionProBeta' + : currentUserHasExpiredPro + ? 'proPlanRenew' + : 'upgradeSession', + }} onClick={() => { - dispatch(updateSessionProInfoModal({ variant: SessionProInfoVariant.GENERIC })); + if (currentNeverHadPro) { + // FIXME: will be defined later + return; + } + dispatch(userSettingsModal({ userSettingsPage: 'pro' })); }} dataTestId="session-pro-settings-menu-item" color="var(--renderer-span-primary-color)" diff --git a/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx b/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx index 890b01cb0..6119bb426 100644 --- a/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx @@ -234,7 +234,7 @@ export function PrivacySettingsPage(modalState: UserSettingsModalState) { }} toggleDataTestId={'enable-typing-indicators-settings-toggle'} rowDataTestId={'enable-typing-indicators-settings-row'} - />{' '} + /> diff --git a/ts/components/dialog/user-settings/pages/user-pro/ProSettingsPage.tsx b/ts/components/dialog/user-settings/pages/user-pro/ProSettingsPage.tsx new file mode 100644 index 000000000..fdbca51ab --- /dev/null +++ b/ts/components/dialog/user-settings/pages/user-pro/ProSettingsPage.tsx @@ -0,0 +1,323 @@ +import { isNumber } from 'lodash'; +import { useMemo } from 'react'; +import styled from 'styled-components'; +import { useDispatch } from 'react-redux'; +import { ModalBasicHeader } from '../../../../SessionWrapperModal'; +import { useUserSettingsBackAction, useUserSettingsCloseAction } from '../userSettingsHooks'; +import type { UserSettingsModalState } from '../../../../../state/ducks/modalDialog'; +import { ModalBackButton } from '../../../shared/ModalBackButton'; +import { UserSettingsModalContainer } from '../../components/UserSettingsModalContainer'; +import { ModalFlexContainer } from '../../../shared/ModalFlexContainer'; +import { PanelButtonGroup, PanelLabelWithDescription } from '../../../../buttons/panel/PanelButton'; +import { SettingsExternalLinkBasic } from '../../components/SettingsExternalLinkBasic'; +import { showLinkVisitWarningDialog } from '../../../OpenUrlModal'; +import { PanelIconButton, PanelIconLucideIcon } from '../../../../buttons/panel/PanelIconButton'; +import { LUCIDE_ICONS_UNICODE } from '../../../../icon/lucide'; +import { SettingsChevronBasic } from '../../components/SettingsChevronBasic'; +import { SettingsToggleBasic } from '../../components/SettingsToggleBasic'; +import { SessionTooltip } from '../../../../SessionTooltip'; +import { tr } from '../../../../../localization/localeTools'; +import { LucideIcon } from '../../../../icon/LucideIcon'; +import { Storage } from '../../../../../util/storage'; +import { SettingsKey } from '../../../../../data/settings-key'; +import { getBrowserLocale } from '../../../../../util/i18n/shared'; +import { SessionIcon } from '../../../../icon'; +import { ProIconButton } from '../../../../buttons/ProButton'; + +const SectionFlexContainer = styled.div` + display: flex; + flex-direction: column; + align-items: center; + width: 100%; +`; + +const HeroImageBgContainer = styled.div` + height: 170px; +`; + +const HeroImageBg = styled.div` + position: absolute; + left: 0; + right: 0; + justify-items: center; + + &::before { + content: ''; + position: absolute; + top: -40%; + left: -40%; + width: 180%; + height: 180%; + background: radial-gradient( + circle, + color-mix(in srgb, var(--primary-color) 15%, transparent) 0%, + transparent 70% + ); + + filter: blur(60px); + z-index: -1; /* behind the logo */ + } +`; + +const HeroImageLabelContainer = styled.div` + display: flex; + flex-direction: row; + align-items: center; + gap: var(--margins-sm); + padding: var(--margins-md); +`; + +function ProHeroImage() { + return ( + + + + + + full-brand-text + + + + + + ); +} + +const StatsContainer = styled.div``; + +const StatsRowContainer = styled.div` + display: flex; + gap: var(--margins-sm); + padding: var(--margins-md); +`; + +const StatsItemContainer = styled.div` + display: flex; + flex-direction: column; + gap: var(--margins-sm); + align-items: center; + flex-direction: row; + width: 50%; +`; + +const StatsLabel = styled.div` + font-size: var(--font-size-md); + color: var(--text-primary-color); + font-weight: 700; +`; + +function ProStats() { + const proLongerMessagesSent = Storage.get(SettingsKey.proLongerMessagesSent) || 3000; + const proPinnedConversations = Storage.get(SettingsKey.proPinnedConversations) || 0; + const proBadgesSent = Storage.get(SettingsKey.proBadgesSent) || 0; + const proGroupsUpgraded = Storage.get(SettingsKey.proGroupsUpgraded) || 0; + + const formatter = useMemo( + () => + new Intl.NumberFormat(getBrowserLocale(), { + notation: 'compact', + compactDisplay: 'short', // Uses 'K', 'M', 'B' etc. + }), + [] + ); + + if ( + !isNumber(proBadgesSent) || + !isNumber(proPinnedConversations) || + !isNumber(proLongerMessagesSent) || + !isNumber(proGroupsUpgraded) + ) { + return null; + } + + return ( + + + + + } + /> + + + + + + + {tr('proLongerMessagesSent', { + count: proLongerMessagesSent, + total: formatter.format(proLongerMessagesSent).toLocaleLowerCase(), + })} + + + + + + {tr('proPinnedConversations', { + count: proPinnedConversations, + total: formatter.format(proPinnedConversations).toLocaleLowerCase(), + })} + + + + + + + + {tr('proBadgesSent', { + count: proBadgesSent, + total: formatter.format(proBadgesSent).toLocaleLowerCase(), + })} + + + + + + {tr('proGroupsUpgraded', { + count: proGroupsUpgraded, + total: formatter.format(proGroupsUpgraded).toLocaleLowerCase(), + })} + + + + + + + + + + ); +} + +function ProSettings() { + return ( + + + + { + throw new Error('Not implemented (and {time} is not implemented)'); + }} + /> + { + throw new Error('Not implemented, and state {false} too'); + }} + active={false} + /> + + + ); +} + +function ProFeatures() { + return ( + + + PLOP + + ); +} + +function ManagePro() { + return ( + + + + {}} + color={'var(--danger-color)'} + iconElement={} + /> + {}} + color={'var(--danger-color)'} + iconElement={} + /> + + + ); +} + +function ProHelp() { + const dispatch = useDispatch(); + return ( + + + + + showLinkVisitWarningDialog('https://getsession.org/pro-roadmap', dispatch) + } + /> + + showLinkVisitWarningDialog('https://getsession.org/pro-roadmap', dispatch) + } + /> + + + ); +} + +export function ProSettingsPage(modalState: UserSettingsModalState) { + const backAction = useUserSettingsBackAction(modalState); + const closeAction = useUserSettingsCloseAction(modalState); + + return ( + : undefined} + /> + } + onClose={closeAction || undefined} + > + + + + + + + + + + ); +} diff --git a/ts/components/dialog/user-settings/pages/userSettingsHooks.tsx b/ts/components/dialog/user-settings/pages/userSettingsHooks.tsx index 1ae07de49..cee150e75 100644 --- a/ts/components/dialog/user-settings/pages/userSettingsHooks.tsx +++ b/ts/components/dialog/user-settings/pages/userSettingsHooks.tsx @@ -41,6 +41,8 @@ export function useUserSettingsTitle(page: UserSettingsModalState | undefined) { : page.passwordAction === 'change' ? tr('passwordChange') : tr('passwordSet'); + case 'pro': + return ''; case 'default': case undefined: return tr('sessionSettings'); @@ -72,6 +74,7 @@ export function useUserSettingsCloseAction(props: UserSettingsModalState) { case 'blocked-contacts': case 'password': case 'network': + case 'pro': return () => dispatch(userSettingsModal(null)); default: @@ -109,6 +112,7 @@ export function useUserSettingsBackAction(modalState: UserSettingsModalState) { case 'privacy': case 'preferences': case 'network': + case 'pro': settingsPageToDisplayOnBack = 'default'; break; default: diff --git a/ts/components/icon/lucide.ts b/ts/components/icon/lucide.ts index 2adcb4942..0335fbc25 100644 --- a/ts/components/icon/lucide.ts +++ b/ts/components/icon/lucide.ts @@ -12,6 +12,7 @@ export enum LUCIDE_ICONS_UNICODE { CHEVRON_LEFT = '', CHEVRON_RIGHT = '', CHEVRON_UP = '', + CIRCLE_ALERT = '', CIRCLE_CHECK = '', CIRCLE_ELLIPSES = '', CIRCLE_HELP = '', @@ -151,6 +152,7 @@ export function isIconToMirrorRtl(unicode: LUCIDE_ICONS_UNICODE) { case LUCIDE_ICONS_UNICODE.USER_ROUND_X: case LUCIDE_ICONS_UNICODE.USERS_ROUND: case LUCIDE_ICONS_UNICODE.X: + case LUCIDE_ICONS_UNICODE.CIRCLE_ALERT: return false; default: assertUnreachable(unicode, 'isIconToMirrorRtl: unknown case'); diff --git a/ts/data/settings-key.ts b/ts/data/settings-key.ts index ee5707eb8..663db0965 100644 --- a/ts/data/settings-key.ts +++ b/ts/data/settings-key.ts @@ -16,6 +16,12 @@ const hasLinkPreviewPopupBeenDisplayed = 'hasLinkPreviewPopupBeenDisplayed'; const hasFollowSystemThemeEnabled = 'hasFollowSystemThemeEnabled'; const hideRecoveryPassword = 'hideRecoveryPassword'; +// Pro stats counters +const proLongerMessagesSent = 'proLongerMessagesSent'; +const proPinnedConversations = 'proPinnedConversations'; +const proBadgesSent = 'proBadgesSent'; +const proGroupsUpgraded = 'proGroupsUpgraded'; + // user config tracking timestamps (to discard incoming messages which would make a change we reverted in the last config message we merged) const latestUserProfileEnvelopeTimestamp = 'latestUserProfileEnvelopeTimestamp'; const latestUserGroupEnvelopeTimestamp = 'latestUserGroupEnvelopeTimestamp'; @@ -53,6 +59,10 @@ export const SettingsKey = { hideRecoveryPassword, showOnboardingAccountJustCreated, lastMessageGroupsRegenerated, + proLongerMessagesSent, + proPinnedConversations, + proBadgesSent, + proGroupsUpgraded, } as const; export const KNOWN_BLINDED_KEYS_ITEM = 'KNOWN_BLINDED_KEYS_ITEM'; diff --git a/ts/hooks/useHasPro.ts b/ts/hooks/useHasPro.ts index 01c6a8403..8af9bea69 100644 --- a/ts/hooks/useHasPro.ts +++ b/ts/hooks/useHasPro.ts @@ -2,6 +2,9 @@ import { UserUtils } from '../session/utils'; import { useIsProAvailable } from './useIsProAvailable'; import { useIsProUser } from './useParamSelector'; +/** + * Returns true if pro is available, and the current user has pro (active, not expired) + */ export function useCurrentUserHasPro() { const isProAvailable = useIsProAvailable(); const weArePro = useIsProUser(UserUtils.getOurPubKeyStrFromCache()); @@ -9,6 +12,27 @@ export function useCurrentUserHasPro() { return isProAvailable && weArePro; } +/** + * Returns true if pro is available, and the current user has expired pro. + */ +export function useCurrentUserHasExpiredPro() { + const isProAvailable = useIsProAvailable(); + // FIXME: we will need to have this coming from libsession (and stored in redux I guess) + + return isProAvailable && window.sessionFeatureFlags.mockCurrentUserHasProExpired; +} + +/** + * Returns true if pro is available, but the current user has never had pro. + * (i.e. the user does not have pro currently and doesn't have an expired pro either) + */ +export function useCurrentNeverHadPro() { + const isProAvailable = useIsProAvailable(); + const currentUserHasPro = useCurrentUserHasPro(); + const currentUserHasExpiredPro = useCurrentUserHasExpiredPro(); + return isProAvailable && !currentUserHasPro && !currentUserHasExpiredPro; +} + export function useUserHasPro(convoId?: string) { const isProAvailable = useIsProAvailable(); const userIsPro = useIsProUser(convoId); diff --git a/ts/react.d.ts b/ts/react.d.ts index 72a752bb8..ef9959151 100644 --- a/ts/react.d.ts +++ b/ts/react.d.ts @@ -95,12 +95,13 @@ declare module 'react' { | 'conversation-trimming' | 'auto-update' | 'auto-dark-mode' - | 'hide-menu-bar'; + | 'hide-menu-bar' + | 'pro-badge-visible'; type SettingsRadio = | `set-notifications-${'message' | 'name' | 'count'}` | `send-with-${'enterForSend' | 'enterForNewLine'}`; - type SettingsChevron = `blocked-contacts`; + type SettingsChevron = 'blocked-contacts' | 'update-plan'; type SettingsInlineButtons = | 'set-password' @@ -108,7 +109,13 @@ declare module 'react' { | 'remove-password' | 'export-logs' | 'hide-recovery-password'; - type SettingsExternalLinkButtons = 'faq' | 'translate' | 'support' | 'feedback'; + type SettingsExternalLinkButtons = + | 'faq' + | 'translate' + | 'support' + | 'feedback' + | 'pro-faq' + | 'pro-support'; type SettingsMenuItems = | 'message-requests' @@ -189,6 +196,8 @@ declare module 'react' { | 'back' | 'modal-back' | 'create-group' + | 'cancel-pro' + | 'request-refund' | `${ConfirmButtons}-confirm` | `${CancelButtons}-cancel` | `clear-${ClearButtons}` diff --git a/ts/state/ducks/modalDialog.tsx b/ts/state/ducks/modalDialog.tsx index cb6523a4d..11b9664c0 100644 --- a/ts/state/ducks/modalDialog.tsx +++ b/ts/state/ducks/modalDialog.tsx @@ -25,7 +25,8 @@ export type UserSettingsPage = | 'clear-data' | 'password' | 'preferences' - | 'network'; + | 'network' + | 'pro'; export type WithUserSettingsPage = | { userSettingsPage: Exclude } @@ -162,7 +163,7 @@ export const initialModalState: ModalState = { groupMembersModal: null, userProfileModal: null, nickNameModal: null, - userSettingsModal: null, + userSettingsModal: { userSettingsPage: 'pro' }, onionPathModal: null, enterPasswordModal: null, deleteAccountModal: null, diff --git a/ts/state/ducks/types/releasedFeaturesReduxTypes.ts b/ts/state/ducks/types/releasedFeaturesReduxTypes.ts index 65b54acad..591f7a3d3 100644 --- a/ts/state/ducks/types/releasedFeaturesReduxTypes.ts +++ b/ts/state/ducks/types/releasedFeaturesReduxTypes.ts @@ -13,6 +13,7 @@ export type SessionFeatureFlags = { debugInputCommands: boolean; proAvailable: boolean; mockCurrentUserHasPro: boolean; + mockCurrentUserHasProExpired: boolean; mockOthersHavePro: boolean; mockMessageProFeatures: Array; fsTTL30s: boolean; From d8d564eccddbd86b44f4549ae1e730a147b81750 Mon Sep 17 00:00:00 2001 From: ThomasSession <171472362+ThomasSession@users.noreply.github.com> Date: Wed, 24 Sep 2025 03:54:01 +0000 Subject: [PATCH 2/4] [Automated] Update translations from Crowdin --- _locales/az/messages.json | 6 ------ _locales/cs/messages.json | 6 ------ _locales/en/messages.json | 19 +++++++++++++------ _locales/nl/messages.json | 6 ------ _locales/uk/messages.json | 5 ----- 5 files changed, 13 insertions(+), 29 deletions(-) diff --git a/_locales/az/messages.json b/_locales/az/messages.json index 69ae0076b..3b5cc3e2f 100644 --- a/_locales/az/messages.json +++ b/_locales/az/messages.json @@ -851,16 +851,13 @@ "proExpired": "Müddəti bitib", "proExpiredDescription": "Təəssüf ki, Pro planınızın müddəti bitib. Session Pro tətbiqinin eksklüziv imtiyazlarına və özəlliklərinə erişimi davam etdirmək üçün yeniləyin.", "proExpiringSoon": "Tezliklə bitir", - "proExpiringSoonDescription": "Pro planınızın müddəti {time} vaxtında bitir. Session Pro tətbiqinin eksklüziv imtiyazlarına və özəlliklərinə erişimi davam etdirmək üçün planınızı güncəlləyin.", "proExpiringTime": "Pro, {time} vaxtında başa çatır", "proFaq": "Pro TVS", - "proFaqDescription": "Session TVS-da tez-tez verilən suallara cavab tapın.", "proFeatureListAnimatedDisplayPicture": "GIF və WebP ekran şəkilləri yüklə", "proFeatureListLargerGroups": "300 üzvə qədər daha da böyük qrup söhbətləri", "proFeatureListLoadsMore": "Üstəgəl, daha çox eksklüziv özəlliklər", "proFeatureListLongerMessages": "10,000 xarakterə qədər mesajlar", "proFeatureListPinnedConversations": "Limitsiz danışığı sancın", - "proFeatures": "Pro özəllikləri", "proGroupActivated": "Qrup aktivləşdirildi", "proGroupActivatedDescription": "Bu qurun tutumu artıb! Qrup admininin sayəsində artıq 300 nəfərə qədər üzvü dəstəkləyə bilər", "proGroupsUpgraded": "{count, plural, one [{total} qrup yüksəldildi] other [{total} qrup yüksəldildi]}", @@ -877,8 +874,6 @@ "proPinnedConversations": "{count, plural, one [{total} sancılmış danışıq] other [{total} sancılmış danışıq]}", "proPlanActivatedAuto": "Session Pro planınız aktivdir!

Planınız avtomatik olaraq {date} tarixində başqa bir {current_plan} üçün yenilənəcək. Planınıza edilən güncəlləmələr növbəti Pro yenilənməsi zamanı qüvvəyə minəcək.", "proPlanActivatedAutoShort": "Session Pro planınız aktivdir!

Planınız avtomatik olaraq {date} tarixində başqa bir {current_plan} üçün yenilənəcək.", - "proPlanActivatedNotAuto": "Session Pro planınızın müddəti {date} tarixində bitir.

Eksklüziv Pro özəlliklərinə kəsintisiz erişimi təmin etmək üçün planınızı indi güncəlləyin.", - "proPlanExpireDate": "Session Pro planınızın müddəti {date} tarixində bitir.", "proPlanNotFound": "Pro planı tapılmadı", "proPlanNotFoundDescription": "Hesabınız üçün heç bir aktiv plan tapılmadı. Bunun bir səhv olduğunu düşünürsünüzsə, lütfən kömək üçün Session dəstəyi ilə əlaqə saxlayın.", "proPlanPlatformRefund": "Başda {platform_store} Mağazası üzərindən Session Pro üçün qeydiyyatdan keçdiyinizə görə, geri ödəmə tələbini göndərmək üçün eyni {platform_account} hesabını istifadə etməlisiniz.", @@ -898,7 +893,6 @@ "proRefundDescription": "Getməyinizə məyus olduq. Geri ödəmə tələb etməzdən əvvəl bilməli olduğunuz şeylər.", "proRefundNextSteps": "{platform_account} hazırda geri ödəniş tələbinizi emal edir. Bu, adətən 24-48 saat çəkir. Onların qərarından asılı olaraq, Session tətbiqində Pro statusunuzun dəyişdiyini görə bilərsiniz.", "proRefundRequestSessionSupport": "Geri qaytarma tələbiniz Session Dəstək komandası tərəfindən icra olunacaq.

Aşağıdakı düyməyə basaraq və geri ödəniş formunu dolduraraq geri ödəniş tələbinizi göndərin.

Session Dəstək komandası, geri ödəniş tələblərini adətən 24-72 saat ərzində emal edir, yüksək tələb həcminə görə bu proses daha uzun çəkə bilər.", - "proRefundRequestStorePolicies": "Geri ödəniş tələbiniz yalnız {platform_account} veb saytında {platform_account} hesabı üzərindən icra olunacaq.

{platform_account} geri ödəniş siyasətlərinə əsasən, Session gəlişdiriciləri, geri ödəniş tələblərinin nəticəsinə təsir edə bilməz. Bu, tələbin qəbul olunub-olunmaması ilə yanaşı, tam və ya qismən geri ödənişin verilib-verilməməsini də əhatə edir.", "proRefundSupport": "Geri ödəmə tələbinizlə bağlı daha çox güncəlləmə üçün lütfən {platform_account} ilə əlaqə saxlayın. {platform_account} geri ödəniş siyasətlərinə əsasən, Session gəlişdiriciləri, geri ödəniş tələblərinin nəticəsinə təsir edə bilməz.

{platform_store} Geri ödəmə dəstəyi", "proRefunding": "Pro geri ödəməsi", "proRefundingDescription": "Session Pro planları üçün geri ödəmələr yalnız {platform_store} Mağazası vasitəsilə {platform_account} tərəfindən həyata keçirilir.

{platform_account} geri ödəniş siyasətlərinə əsasən, Session gəlişdiriciləri, geri ödəniş tələblərinin nəticəsinə təsir edə bilməz. Bu, tələbin qəbul olunub-olunmaması ilə yanaşı, tam və ya qismən geri ödənişin verilib-verilməməsini də əhatə edir.", diff --git a/_locales/cs/messages.json b/_locales/cs/messages.json index 51793cf0c..055961714 100644 --- a/_locales/cs/messages.json +++ b/_locales/cs/messages.json @@ -853,16 +853,13 @@ "proExpired": "Platnost vypršela", "proExpiredDescription": "Bohužel, váš tarif Pro vypršel. Obnovte jej, abyste nadále měli přístup k exkluzivním výhodám a funkcím Session Pro.", "proExpiringSoon": "Brzy vyprší", - "proExpiringSoonDescription": "Váš tarif Pro vyprší za {time}. Aktualizujte si tarif, abyste i nadále měli přístup k exkluzivním výhodám a funkcím Session Pro.", "proExpiringTime": "Pro vyprší za {time}", "proFaq": "Pro FAQ", - "proFaqDescription": "Najděte odpovědi na časté dotazy v nápovědě Session.", "proFeatureListAnimatedDisplayPicture": "Nahrajte GIF a WebP jako zobrazovaný obrázek", "proFeatureListLargerGroups": "Větší soukromé skupiny až 300 členů", "proFeatureListLoadsMore": "A další exkluzivních funkce", "proFeatureListLongerMessages": "Zprávy až do 10000 znaků", "proFeatureListPinnedConversations": "Připněte neomezený počet konverzací", - "proFeatures": "Funkce Pro", "proGroupActivated": "Skupina aktivována", "proGroupActivatedDescription": "Tato skupina má navýšenou kapacitu! Může podporovat až 300 členů, protože správce skupiny má", "proGroupsUpgraded": "{count, plural, one [{total} skupina navýšena] few [{total} skupiny navýšeny] many [{total} skupin navýšeno] other [{total} skupin navýšeno]}", @@ -879,8 +876,6 @@ "proPinnedConversations": "{count, plural, one [{total} připnutá konverzace] few [{total} připnuté konverzace] many [{total} připnutých konverzací] other [{total} připnutých konverzací]}", "proPlanActivatedAuto": "Váš tarif Session Pro je aktivní!

Váš tarif se automaticky obnoví na další {current_plan} dne {date}. Změny tarifu se projeví při příštím obnovení Pro.", "proPlanActivatedAutoShort": "Váš tarif Session Pro je aktivní!

Tarif se automaticky obnoví na další {current_plan} dne {date}.", - "proPlanActivatedNotAuto": "Váš tarif Session Pro vyprší dne {date}.

Aktualizujte si tarif nyní, abyste měli i nadále nepřerušený přístup k exkluzivním funkcím Pro.", - "proPlanExpireDate": "Váš tarif Session Pro vyprší dne {date}.", "proPlanNotFound": "Pro nebyl nalezen", "proPlanNotFoundDescription": "Pro váš účet nebyl nalezen žádný aktivní tarif. Pokud si myslíte, že se jedná o chybu, kontaktujte podporu Session a požádejte o pomoc.", "proPlanPlatformRefund": "Protože jste se původně zaregistrovali do Session Pro přes obchod {platform_store}, budete muset pro žádost o vrácení peněz použít stejný účet {platform_account}.", @@ -900,7 +895,6 @@ "proRefundDescription": "Mrzí nás, že to rušíte. Než požádáte o vrácení peněz, přečtěte si informace, které byste měli vědět.", "proRefundNextSteps": "{platform_account} nyní zpracovává vaši žádost o vrácení peněz. Obvykle to trvá 24–48 hodin. V závislosti na jejich rozhodnutí se může váš stav Pro v aplikaci Session změnit.", "proRefundRequestSessionSupport": "Váš požadavek na vrácení peněz bude zpracován podporou Session.

Požádejte o vrácení peněz kliknutím na tlačítko níže a vyplněním formuláře žádosti o vrácení peněz.

Ačkoliv se podpora Session snaží zpracovat žádosti o vrácení peněz během 24–72 hodin, může zpracování trvat i déle, v případě že je vyřizováno mnoho žádostí.", - "proRefundRequestStorePolicies": "Vaši žádost o vrácení peněz bude vyřizovat výhradně {platform_account} prostřednictvím webových stránek {platform_account}.

Vzhledem k pravidlům vracení peněz {platform_account} nemají vývojáři Session žádný vliv na výsledek žádostí o vrácení peněz. To zahrnuje i rozhodnutí, zda bude žádost schválena nebo zamítnuta, a také, zda bude vrácena část peněz, nebo všechny peníze.", "proRefundSupport": "Pro další informace o vaší žádosti o vrácení peněz kontaktujte prosím {platform_account}. Vzhledem k zásadám pro vrácení peněz {platform_account} nemají vývojáři aplikace Session žádnou možnost ovlivnit výsledek žádosti o vrácení.

Podpora vrácení peněz {platform_store}", "proRefunding": "Vracení peněz za Pro", "proRefundingDescription": "Vrácení peněz za tarify Session Pro je vyřizováno výhradně prostřednictvím {platform_account} v obchodě {platform_store}.

Vzhledem k pravidlům vracení peněz služby {platform_account} nemají vývojáři Session žádný vliv na výsledek žádostí o vrácení peněz. To zahrnuje i rozhodnutí, zda bude žádost schválena nebo zamítnuta, a také, zda bude vrácena část peněz, nebo všechny peníze.", diff --git a/_locales/en/messages.json b/_locales/en/messages.json index a7f3ecc60..ee0488ddf 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -848,27 +848,30 @@ "proBadges": "Badges", "proBadgesDescription": "Show your support for Session with an exclusive badge next to your display name.", "proBadgesSent": "{count, plural, one [{total} Pro Badge Sent] other [{total} Pro Badges Sent]}", + "proBetaFeatures": "Pro Beta Features", "proBilledAnnually": "{price} Billed Annually", "proBilledMonthly": "{price} Billed Monthly", "proBilledQuarterly": "{price} Billed Quarterly", "proCallToActionLongerMessages": "Want to send longer messages? Send more text and unlock premium features with Session Pro", "proCallToActionPinnedConversations": "Want more pins? Organize your chats and unlock premium features with Session Pro", "proCallToActionPinnedConversationsMoreThan": "Want more than 5 pins? Organize your chats and unlock premium features with Session Pro", + "proCancellation": "Cancellation", + "proCancellationDescription": "Canceling your {app pro} plan will prevent your plan from automatically renewing before your Pro plan expires. Canceling Pro does not result in a refund. You will continue to be able to use Session Pro features until your plan expires. \r\n\r\nBecause you originally signed up for Session Pro via a {platform_account}, you'll need to use the same {platform_account} to cancel your plan.", + "proCancellationOptions": "Two ways to cancel your plan:", "proDiscountTooltip": "Your current plan is already discounted by {percent}% of the full Session Pro price.", "proErrorRefreshingStatus": "Error refreshing Pro status", "proExpired": "Expired", "proExpiredDescription": "Unfortunately, your Pro plan has expired. Renew to keep accessing the exclusive perks and features of Session Pro.", "proExpiringSoon": "Expiring Soon", - "proExpiringSoonDescription": "Your Pro plan is expiring in {time}. Update your plan to keep accessing the exclusive perks and features of Session Pro.", + "proExpiringSoonDescription": "Your Pro plan is expiring in {time}. Update your plan to keep accessing the exclusive perks and features of Session Pro.", "proExpiringTime": "Pro expiring in {time}", "proFaq": "Pro FAQ", - "proFaqDescription": "Find answers to common questions in the Session FAQ.", + "proFaqDescription": "Find answers to common questions in the Session Pro FAQ.", "proFeatureListAnimatedDisplayPicture": "Upload GIF and WebP display pictures", "proFeatureListLargerGroups": "Larger group chats up to 300 members", "proFeatureListLoadsMore": "Plus loads more exclusive features", "proFeatureListLongerMessages": "Messages up to 10,000 characters", "proFeatureListPinnedConversations": "Pin unlimited conversations", - "proFeatures": "Pro Features", "proGroupActivated": "Group Activated", "proGroupActivatedDescription": "This group has expanded capacity! It can support up to 300 members because a group admin has", "proGroupsUpgraded": "{count, plural, one [{total} Group Upgraded] other [{total} Groups Upgraded]}", @@ -877,6 +880,7 @@ "proIncreasedMessageLengthFeature": "Increased Message Length", "proLargerGroups": "Larger Groups", "proLargerGroupsDescription": "Groups you are an admin in are automatically upgraded to support 300 members.", + "proLargerGroupsTooltip": "Larger group chats (up to 300 members) are coming soon for all Pro Beta users!", "proLongerMessages": "Longer Messages", "proLongerMessagesDescription": "You can send messages up to 10,000 characters in all conversations.", "proLongerMessagesSent": "{count, plural, one [{total} Longer Message Sent] other [{total} Longer Messages Sent]}", @@ -885,9 +889,9 @@ "proPinnedConversations": "{count, plural, one [{total} Pinned Conversation] other [{total} Pinned Conversations]}", "proPlanActivatedAuto": "Your Session Pro plan is active!

Your plan will automatically renew for another {current_plan} on {date}. Updates to your plan take effect when Pro is next renewed.", "proPlanActivatedAutoShort": "Your Session Pro plan is active!

Your plan will automatically renew for another {current_plan} on {date}.", - "proPlanActivatedNotAuto": "Your Session Pro plan will expire on {date}.

Update your plan now to ensure uninterrupted access to exclusive Pro features.", + "proPlanActivatedNotAuto": "Your Session Pro plan will expire on {date}.

Update your plan now to ensure uninterrupted access to exclusive Pro features.", "proPlanError": "Pro Plan Error", - "proPlanExpireDate": "Your Session Pro plan will expire on {date}.", + "proPlanExpireDate": "Your Session Pro plan will expire on {date}.", "proPlanLoading": "Pro Plan Loading", "proPlanLoadingDescription": "Information about your Pro plan is still being loaded. You cannot update your plan until this process is complete.", "proPlanLoadingEllipsis": "Pro plan loading...", @@ -912,10 +916,11 @@ "proRefundDescription": "We’re sorry to see you go. Here's what you need to know before requesting a refund.", "proRefundNextSteps": "{platform_account} is now processing your refund request. This typically takes 24-48 hours. Depending on their decision, you may see your Pro status change in Session.", "proRefundRequestSessionSupport": "Your refund request will be handled by Session Support.

Request a refund by hitting the button below and completing the refund request form.

While Session Support strives to process refund requests within 24-72 hours, processing may take longer during times of high request volume.", - "proRefundRequestStorePolicies": "Your refund request will be handled exclusively by {platform_account} through the {platform_account} website.

Due to {platform_account} refund policies, Session developers have no ability to influence the outcome of refund requests. This includes whether the request is approved or denied, as well as whether a full or partial refund is issued.", + "proRefundRequestStorePolicies": "Your refund request will be handled exclusively by {platform_account} through the {platform_account} website.

Due to {platform_account} refund policies, Session developers have no ability to influence the outcome of refund requests. This includes whether the request is approved or denied, as well as whether a full or partial refund is issued.", "proRefundSupport": "Please contact {platform_account} for further updates on your refund request. Due to {platform_account} refund policies, Session developers have no ability to influence the outcome of refund requests.

{platform_store} Refund Support", "proRefunding": "Refunding Pro", "proRefundingDescription": "Refunds for Session Pro plans are handled exclusively by {platform_account} through the {platform_store} Store.

Due to {platform_account} refund policies, Session developers have no ability to influence the outcome of refund requests. This includes whether the request is approved or denied, as well as whether a full or partial refund is issued.", + "proRenewBeta": "Renew Pro Beta", "proRequestedRefund": "Refund Requested", "proSendMore": "Send more with", "proSettings": "Pro Settings", @@ -994,6 +999,7 @@ "removePasswordFail": "Failed to remove password", "removePasswordModalDescription": "Remove your current password for Session. Locally stored data will be re-encrypted with a randomly generated key, stored on your device.", "renew": "Renew", + "renewingPro": "Renewing Pro", "reply": "Reply", "requestRefund": "Request Refund", "resend": "Resend", @@ -1124,6 +1130,7 @@ "updated": "Last updated {relative_time} ago", "updates": "Updates", "updating": "Updating...", + "upgradeSession": "Upgrade Session", "upgradeTo": "Upgrade to", "uploading": "Uploading", "urlCopy": "Copy URL", diff --git a/_locales/nl/messages.json b/_locales/nl/messages.json index f7c96909a..71959bb35 100644 --- a/_locales/nl/messages.json +++ b/_locales/nl/messages.json @@ -849,15 +849,12 @@ "proExpired": "Verlopen", "proExpiredDescription": "Helaas is je Pro abonnement verlopen. Verleng om toegang te blijven houden tot de exclusieve voordelen en functies van Session Pro.", "proExpiringSoon": "Verloopt binnenkort", - "proExpiringSoonDescription": "Je Pro abonnement verloopt over {time}. Werk je abonnement bij om toegang te blijven houden tot de exclusieve voordelen en functies van Session Pro.", "proFaq": "Pro FAQ", - "proFaqDescription": "Vind antwoorden op veelgestelde vragen in de Session FAQ.", "proFeatureListAnimatedDisplayPicture": "Upload GIF- en WebP-profielfoto's", "proFeatureListLargerGroups": "Groepsgesprekken tot wel 300 leden", "proFeatureListLoadsMore": "En nog veel meer exclusieve functies", "proFeatureListLongerMessages": "Berichten tot 10.000 tekens", "proFeatureListPinnedConversations": "Onbeperkt gesprekken vastzetten", - "proFeatures": "Pro functies", "proGroupActivated": "Groep geactiveerd", "proGroupActivatedDescription": "Deze groep heeft een grotere capaciteit! Er kunnen nu tot 300 leden deelnemen omdat een groepsbeheerder een", "proImportantDescription": "Het aanvragen van een terugbetaling is definitief. Indien goedgekeurd, wordt je Pro abonnement onmiddellijk geannuleerd en verlies je de toegang tot alle Pro functies.", @@ -871,8 +868,6 @@ "proPercentOff": "{percent}% korting", "proPlanActivatedAuto": "Je Session Pro abonnement is actief!

Je abonnement wordt automatisch verlengd voor een nieuw {current_plan} op {date}. Wijzigingen aan je abonnement gaan in wanneer Pro de volgende keer wordt verlengd.", "proPlanActivatedAutoShort": "Je Session Pro abonnement is actief!

Je abonnement wordt automatisch verlengd met een {current_plan} op {date}.", - "proPlanActivatedNotAuto": "Je Session Pro abonnement verloopt op {date}.

Werk je abonnement nu bij om ononderbroken toegang te behouden tot exclusieve Pro functies.", - "proPlanExpireDate": "Je Session Pro abonnement verloopt op {date}.", "proPlanNotFound": "Pro abonnement niet gevonden", "proPlanNotFoundDescription": "Er is geen actief abonnement gevonden voor je account. Als je denkt dat dit een vergissing is, neem dan contact op met de ondersteuning van Session voor hulp.", "proPlanPlatformRefund": "Omdat je je oorspronkelijk hebt aangemeld voor Session Pro via de {platform_store} winkel, moet je hetzelfde {platform_account} gebruiken om een terugbetaling aan te vragen.", @@ -892,7 +887,6 @@ "proRefundDescription": "Het spijt ons dat je vertrekt. Dit moet je weten voordat je een terugbetaling aanvraagt.", "proRefundNextSteps": "{platform_account} verwerkt nu je terugbetalingsverzoek. Dit duurt meestal 24-48 uur. Afhankelijk van hun beslissing kan je Pro status wijzigen in Session.", "proRefundRequestSessionSupport": "Je restitutieverzoek wordt afgehandeld door Session Support.

Vraag een restitutie aan door op de knop hieronder te drukken en het restitutieformulier in te vullen.

Hoewel Session Support ernaar streeft om restitutieverzoeken binnen 24-72 uur te verwerken, kan het tijdens drukte langer duren.", - "proRefundRequestStorePolicies": "Je terugbetalingsverzoek wordt uitsluitend afgehandeld door {platform_account} via de website van {platform_account}.

Vanwege het restitutiebeleid van {platform_account} hebben ontwikkelaars van Session geen invloed op de uitkomst van terugbetalingsverzoeken. Dit geldt zowel voor de goedkeuring of afwijzing van het verzoek als voor het wel of niet toekennen van een volledige of gedeeltelijke terugbetaling.", "proRefundSupport": "Neem contact op met {platform_account} voor verdere updates over je restitutieverzoek. Vanwege het restitutiebeleid van {platform_account} hebben de ontwikkelaars van Session geen invloed op de uitkomst van restitutieverzoeken.

{platform_store} Terugbetalingsondersteuning", "proRefunding": "Terugbetalen Pro", "proRefundingDescription": "Terugbetalingen voor Session Pro abonnementen worden uitsluitend afgehandeld door {platform_account} via de {platform_store} Store.

Vanwege het restitutiebeleid van {platform_account} hebben ontwikkelaars van Session geen invloed op de uitkomst van terugbetalingsverzoeken. Dit geldt zowel voor de goedkeuring of afwijzing van het verzoek als voor het wel of niet toekennen van een volledige of gedeeltelijke terugbetaling.", diff --git a/_locales/uk/messages.json b/_locales/uk/messages.json index f2611b322..d9b927538 100644 --- a/_locales/uk/messages.json +++ b/_locales/uk/messages.json @@ -848,16 +848,13 @@ "proExpired": "Підписка сплила", "proExpiredDescription": "На жаль, підписка Pro сплила. Онови її задля збереження переваг і можливостей Session Pro.", "proExpiringSoon": "Невдовзі спливе підписка", - "proExpiringSoonDescription": "Підписка Pro спливе {time}. Онови підписку задля збереження переваг і можливостей Session Pro.", "proExpiringTime": "Pro спливає за {time}", "proFaq": "Pro ЧАП", - "proFaqDescription": "Відповіді на загальні запитання знайдеш у ЧаПи Session.", "proFeatureListAnimatedDisplayPicture": "Завантажуйте GIF та WebP аватари", "proFeatureListLargerGroups": "Більша кількість — до 300 учасників — групових чатів", "proFeatureListLoadsMore": "Та велика кількість ексклюзивних можливостей", "proFeatureListLongerMessages": "Повідомлення до 10 000 символів", "proFeatureListPinnedConversations": "Закріплюйте необмежену кількість бесід", - "proFeatures": "Можливості Pro", "proGroupActivated": "Групу активовано", "proGroupActivatedDescription": "У цієї групи розширено можливості! Тепер вона може вміщати до 300 учасників, тому що адміністратор групи має", "proImportantDescription": "Вимагання повернення грошей закінчено. В разі схвалення твою підписку Pro негайно скасують і ти втратиш всі можливості Pro.", @@ -870,8 +867,6 @@ "proMessageInfoFeatures": "У цьому повідомленні наявні наступні функції Session Pro:", "proPlanActivatedAuto": "Для тебе діє підписка Session Pro.

{date} твою підписку буде самодійно поновлено як {current_plan}. Оновлення підписки настане під час наступного оновлення Pro.", "proPlanActivatedAutoShort": "Для тебе діє підписка Session Pro.

{date} твою підписку буде самодійно поновлено як {current_plan}.", - "proPlanActivatedNotAuto": "Твоя підписка Session Pro спливе {date}.

Для збереження особливих можливостей подовж свою підписку.", - "proPlanExpireDate": "Підписка Session Pro спливе {date}.", "proPlanNotFound": "Передплата Pro не знайдена", "proPlanRecover": "Відновити передплату Pro", "proPlanRenew": "Оновити підписку Pro", From 6145e1af6dd633efb5167ef86826d491db886818 Mon Sep 17 00:00:00 2001 From: Bilb <1544279+Bilb@users.noreply.github.com> Date: Wed, 24 Sep 2025 04:27:00 +0000 Subject: [PATCH 3/4] [Automated] Update translations from Crowdin --- _locales/az/messages.json | 7 ------- _locales/cs/messages.json | 7 ------- _locales/en/messages.json | 23 ++++++++++++++++------- _locales/nl/messages.json | 7 ------- _locales/uk/messages.json | 5 ----- 5 files changed, 16 insertions(+), 33 deletions(-) diff --git a/_locales/az/messages.json b/_locales/az/messages.json index 69ae0076b..f812ae881 100644 --- a/_locales/az/messages.json +++ b/_locales/az/messages.json @@ -851,16 +851,13 @@ "proExpired": "Müddəti bitib", "proExpiredDescription": "Təəssüf ki, Pro planınızın müddəti bitib. Session Pro tətbiqinin eksklüziv imtiyazlarına və özəlliklərinə erişimi davam etdirmək üçün yeniləyin.", "proExpiringSoon": "Tezliklə bitir", - "proExpiringSoonDescription": "Pro planınızın müddəti {time} vaxtında bitir. Session Pro tətbiqinin eksklüziv imtiyazlarına və özəlliklərinə erişimi davam etdirmək üçün planınızı güncəlləyin.", "proExpiringTime": "Pro, {time} vaxtında başa çatır", "proFaq": "Pro TVS", - "proFaqDescription": "Session TVS-da tez-tez verilən suallara cavab tapın.", "proFeatureListAnimatedDisplayPicture": "GIF və WebP ekran şəkilləri yüklə", "proFeatureListLargerGroups": "300 üzvə qədər daha da böyük qrup söhbətləri", "proFeatureListLoadsMore": "Üstəgəl, daha çox eksklüziv özəlliklər", "proFeatureListLongerMessages": "10,000 xarakterə qədər mesajlar", "proFeatureListPinnedConversations": "Limitsiz danışığı sancın", - "proFeatures": "Pro özəllikləri", "proGroupActivated": "Qrup aktivləşdirildi", "proGroupActivatedDescription": "Bu qurun tutumu artıb! Qrup admininin sayəsində artıq 300 nəfərə qədər üzvü dəstəkləyə bilər", "proGroupsUpgraded": "{count, plural, one [{total} qrup yüksəldildi] other [{total} qrup yüksəldildi]}", @@ -877,15 +874,12 @@ "proPinnedConversations": "{count, plural, one [{total} sancılmış danışıq] other [{total} sancılmış danışıq]}", "proPlanActivatedAuto": "Session Pro planınız aktivdir!

Planınız avtomatik olaraq {date} tarixində başqa bir {current_plan} üçün yenilənəcək. Planınıza edilən güncəlləmələr növbəti Pro yenilənməsi zamanı qüvvəyə minəcək.", "proPlanActivatedAutoShort": "Session Pro planınız aktivdir!

Planınız avtomatik olaraq {date} tarixində başqa bir {current_plan} üçün yenilənəcək.", - "proPlanActivatedNotAuto": "Session Pro planınızın müddəti {date} tarixində bitir.

Eksklüziv Pro özəlliklərinə kəsintisiz erişimi təmin etmək üçün planınızı indi güncəlləyin.", - "proPlanExpireDate": "Session Pro planınızın müddəti {date} tarixində bitir.", "proPlanNotFound": "Pro planı tapılmadı", "proPlanNotFoundDescription": "Hesabınız üçün heç bir aktiv plan tapılmadı. Bunun bir səhv olduğunu düşünürsünüzsə, lütfən kömək üçün Session dəstəyi ilə əlaqə saxlayın.", "proPlanPlatformRefund": "Başda {platform_store} Mağazası üzərindən Session Pro üçün qeydiyyatdan keçdiyinizə görə, geri ödəmə tələbini göndərmək üçün eyni {platform_account} hesabını istifadə etməlisiniz.", "proPlanPlatformRefundLong": "Başda {platform_store} Mağazası üzərindən Session Pro üçün qeydiyyatdan keçdiyinizə görə, geri qaytarma tələbiniz Session Dəstək komandası tərəfindən icra olunacaq.

Aşağıdakı düyməyə basaraq və geri ödəniş formunu dolduraraq geri ödəmə tələbinizi göndərin.

Session Dəstək komandası, geri ödəmə tələblərini adətən 24-72 saat ərzində emal edir, yüksək tələb həcminə görə bu proses daha uzun çəkə bilər.", "proPlanRecover": "Pro planını geri qaytar", "proPlanRenew": "Pro planını yenilə", - "proPlanRenewDesktop": "Hazırda, Pro planları, yalnızca {platform_store} və {platform_store} Mağazaları vasitəsilə satın alına və yenilənə bilər. Session Masaüstü istifadə etdiyinizə görə planınızı burada yeniləyə bilməzsiniz.

Session Pro gəlişdiriciləri, istifadəçilərin Pro planlarını {platform_store} və {platform_store} Mağazalarından kənarda almağına imkan verəcək alternativ ödəniş variantları üzərində ciddi şəkildə çalışırlar. Pro Yol Xəritəsi", "proPlanRenewDesktopLinked": "{platform_store} və ya {platform_store} Mağazaları vasitəsilə planınızı Session quraşdırılmış və əlaqələndirilmiş cihazda Session Pro ayarlarında yeniləyin.", "proPlanRenewDesktopStore": "Pro üçün qeydiyyatdan keçdiyiniz {platform_account} hesabınızla {platform_store} veb saytında planınızı yeniləyin.", "proPlanRenewSupport": "Session Pro planınız yeniləndi! Session Network dəstək verdiyiniz üçün təşəkkürlər.", @@ -898,7 +892,6 @@ "proRefundDescription": "Getməyinizə məyus olduq. Geri ödəmə tələb etməzdən əvvəl bilməli olduğunuz şeylər.", "proRefundNextSteps": "{platform_account} hazırda geri ödəniş tələbinizi emal edir. Bu, adətən 24-48 saat çəkir. Onların qərarından asılı olaraq, Session tətbiqində Pro statusunuzun dəyişdiyini görə bilərsiniz.", "proRefundRequestSessionSupport": "Geri qaytarma tələbiniz Session Dəstək komandası tərəfindən icra olunacaq.

Aşağıdakı düyməyə basaraq və geri ödəniş formunu dolduraraq geri ödəniş tələbinizi göndərin.

Session Dəstək komandası, geri ödəniş tələblərini adətən 24-72 saat ərzində emal edir, yüksək tələb həcminə görə bu proses daha uzun çəkə bilər.", - "proRefundRequestStorePolicies": "Geri ödəniş tələbiniz yalnız {platform_account} veb saytında {platform_account} hesabı üzərindən icra olunacaq.

{platform_account} geri ödəniş siyasətlərinə əsasən, Session gəlişdiriciləri, geri ödəniş tələblərinin nəticəsinə təsir edə bilməz. Bu, tələbin qəbul olunub-olunmaması ilə yanaşı, tam və ya qismən geri ödənişin verilib-verilməməsini də əhatə edir.", "proRefundSupport": "Geri ödəmə tələbinizlə bağlı daha çox güncəlləmə üçün lütfən {platform_account} ilə əlaqə saxlayın. {platform_account} geri ödəniş siyasətlərinə əsasən, Session gəlişdiriciləri, geri ödəniş tələblərinin nəticəsinə təsir edə bilməz.

{platform_store} Geri ödəmə dəstəyi", "proRefunding": "Pro geri ödəməsi", "proRefundingDescription": "Session Pro planları üçün geri ödəmələr yalnız {platform_store} Mağazası vasitəsilə {platform_account} tərəfindən həyata keçirilir.

{platform_account} geri ödəniş siyasətlərinə əsasən, Session gəlişdiriciləri, geri ödəniş tələblərinin nəticəsinə təsir edə bilməz. Bu, tələbin qəbul olunub-olunmaması ilə yanaşı, tam və ya qismən geri ödənişin verilib-verilməməsini də əhatə edir.", diff --git a/_locales/cs/messages.json b/_locales/cs/messages.json index 51793cf0c..07a08b64a 100644 --- a/_locales/cs/messages.json +++ b/_locales/cs/messages.json @@ -853,16 +853,13 @@ "proExpired": "Platnost vypršela", "proExpiredDescription": "Bohužel, váš tarif Pro vypršel. Obnovte jej, abyste nadále měli přístup k exkluzivním výhodám a funkcím Session Pro.", "proExpiringSoon": "Brzy vyprší", - "proExpiringSoonDescription": "Váš tarif Pro vyprší za {time}. Aktualizujte si tarif, abyste i nadále měli přístup k exkluzivním výhodám a funkcím Session Pro.", "proExpiringTime": "Pro vyprší za {time}", "proFaq": "Pro FAQ", - "proFaqDescription": "Najděte odpovědi na časté dotazy v nápovědě Session.", "proFeatureListAnimatedDisplayPicture": "Nahrajte GIF a WebP jako zobrazovaný obrázek", "proFeatureListLargerGroups": "Větší soukromé skupiny až 300 členů", "proFeatureListLoadsMore": "A další exkluzivních funkce", "proFeatureListLongerMessages": "Zprávy až do 10000 znaků", "proFeatureListPinnedConversations": "Připněte neomezený počet konverzací", - "proFeatures": "Funkce Pro", "proGroupActivated": "Skupina aktivována", "proGroupActivatedDescription": "Tato skupina má navýšenou kapacitu! Může podporovat až 300 členů, protože správce skupiny má", "proGroupsUpgraded": "{count, plural, one [{total} skupina navýšena] few [{total} skupiny navýšeny] many [{total} skupin navýšeno] other [{total} skupin navýšeno]}", @@ -879,15 +876,12 @@ "proPinnedConversations": "{count, plural, one [{total} připnutá konverzace] few [{total} připnuté konverzace] many [{total} připnutých konverzací] other [{total} připnutých konverzací]}", "proPlanActivatedAuto": "Váš tarif Session Pro je aktivní!

Váš tarif se automaticky obnoví na další {current_plan} dne {date}. Změny tarifu se projeví při příštím obnovení Pro.", "proPlanActivatedAutoShort": "Váš tarif Session Pro je aktivní!

Tarif se automaticky obnoví na další {current_plan} dne {date}.", - "proPlanActivatedNotAuto": "Váš tarif Session Pro vyprší dne {date}.

Aktualizujte si tarif nyní, abyste měli i nadále nepřerušený přístup k exkluzivním funkcím Pro.", - "proPlanExpireDate": "Váš tarif Session Pro vyprší dne {date}.", "proPlanNotFound": "Pro nebyl nalezen", "proPlanNotFoundDescription": "Pro váš účet nebyl nalezen žádný aktivní tarif. Pokud si myslíte, že se jedná o chybu, kontaktujte podporu Session a požádejte o pomoc.", "proPlanPlatformRefund": "Protože jste se původně zaregistrovali do Session Pro přes obchod {platform_store}, budete muset pro žádost o vrácení peněz použít stejný účet {platform_account}.", "proPlanPlatformRefundLong": "Protože jste si původně zakoupili Session Pro přes obchod {platform_store}, váš požadavek na vrácení peněz bude zpracován podporou Session.

Požádejte o vrácení peněz kliknutím na tlačítko níže a vyplněním formuláře žádosti o vrácení peněz.

Ačkoliv se podpora Session snaží zpracovat žádosti o vrácení peněz během 24–72 hodin, může zpracování trvat i déle, pokud dochází k vysokému počtu žádostí.", "proPlanRecover": "Znovu nabýt tarif Pro", "proPlanRenew": "Obnovit tarif Pro", - "proPlanRenewDesktop": "V současnosti lze tarify Pro zakoupit a obnovit pouze prostřednictvím obchodů {platform_store} nebo {platform_store}. Protože používáte Session Desktop, nemůžete zde svůj plán obnovit.

Vývojáři Session Pro intenzivně pracují na alternativních platebních možnostech, které by uživatelům umožnily zakoupit tarify Pro mimo obchody {platform_store} a {platform_store}. Plán vývoje Pro", "proPlanRenewDesktopLinked": "Obnovte svůj tarif v nastavení Session Pro na propojeném zařízení s nainstalovanou aplikací Session prostřednictvím obchodu {platform_store} nebo {platform_store}.", "proPlanRenewDesktopStore": "Obnovte svůj tarif na webu {platform_store} pomocí účtu {platform_account}, se kterým jste si pořídili Pro.", "proPlanRenewSupport": "Váš tarif Session Pro byl obnoven! Děkujeme, že podporujete síť Session Network.", @@ -900,7 +894,6 @@ "proRefundDescription": "Mrzí nás, že to rušíte. Než požádáte o vrácení peněz, přečtěte si informace, které byste měli vědět.", "proRefundNextSteps": "{platform_account} nyní zpracovává vaši žádost o vrácení peněz. Obvykle to trvá 24–48 hodin. V závislosti na jejich rozhodnutí se může váš stav Pro v aplikaci Session změnit.", "proRefundRequestSessionSupport": "Váš požadavek na vrácení peněz bude zpracován podporou Session.

Požádejte o vrácení peněz kliknutím na tlačítko níže a vyplněním formuláře žádosti o vrácení peněz.

Ačkoliv se podpora Session snaží zpracovat žádosti o vrácení peněz během 24–72 hodin, může zpracování trvat i déle, v případě že je vyřizováno mnoho žádostí.", - "proRefundRequestStorePolicies": "Vaši žádost o vrácení peněz bude vyřizovat výhradně {platform_account} prostřednictvím webových stránek {platform_account}.

Vzhledem k pravidlům vracení peněz {platform_account} nemají vývojáři Session žádný vliv na výsledek žádostí o vrácení peněz. To zahrnuje i rozhodnutí, zda bude žádost schválena nebo zamítnuta, a také, zda bude vrácena část peněz, nebo všechny peníze.", "proRefundSupport": "Pro další informace o vaší žádosti o vrácení peněz kontaktujte prosím {platform_account}. Vzhledem k zásadám pro vrácení peněz {platform_account} nemají vývojáři aplikace Session žádnou možnost ovlivnit výsledek žádosti o vrácení.

Podpora vrácení peněz {platform_store}", "proRefunding": "Vracení peněz za Pro", "proRefundingDescription": "Vrácení peněz za tarify Session Pro je vyřizováno výhradně prostřednictvím {platform_account} v obchodě {platform_store}.

Vzhledem k pravidlům vracení peněz služby {platform_account} nemají vývojáři Session žádný vliv na výsledek žádostí o vrácení peněz. To zahrnuje i rozhodnutí, zda bude žádost schválena nebo zamítnuta, a také, zda bude vrácena část peněz, nebo všechny peníze.", diff --git a/_locales/en/messages.json b/_locales/en/messages.json index a7f3ecc60..bde54a092 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -848,27 +848,30 @@ "proBadges": "Badges", "proBadgesDescription": "Show your support for Session with an exclusive badge next to your display name.", "proBadgesSent": "{count, plural, one [{total} Pro Badge Sent] other [{total} Pro Badges Sent]}", + "proBetaFeatures": "Pro Beta Features", "proBilledAnnually": "{price} Billed Annually", "proBilledMonthly": "{price} Billed Monthly", "proBilledQuarterly": "{price} Billed Quarterly", "proCallToActionLongerMessages": "Want to send longer messages? Send more text and unlock premium features with Session Pro", "proCallToActionPinnedConversations": "Want more pins? Organize your chats and unlock premium features with Session Pro", "proCallToActionPinnedConversationsMoreThan": "Want more than 5 pins? Organize your chats and unlock premium features with Session Pro", + "proCancellation": "Cancellation", + "proCancellationDescription": "Canceling your Session Pro plan will prevent your plan from automatically renewing before your Pro plan expires. Canceling Pro does not result in a refund. You will continue to be able to use Session Pro features until your plan expires.

\nBecause you originally signed up for Session Pro via a {platform_account}, you'll need to use the same {platform_account} to cancel your plan.", + "proCancellationOptions": "Two ways to cancel your plan:", "proDiscountTooltip": "Your current plan is already discounted by {percent}% of the full Session Pro price.", "proErrorRefreshingStatus": "Error refreshing Pro status", "proExpired": "Expired", "proExpiredDescription": "Unfortunately, your Pro plan has expired. Renew to keep accessing the exclusive perks and features of Session Pro.", "proExpiringSoon": "Expiring Soon", - "proExpiringSoonDescription": "Your Pro plan is expiring in {time}. Update your plan to keep accessing the exclusive perks and features of Session Pro.", + "proExpiringSoonDescription": "Your Pro plan is expiring in {time}. Update your plan to keep accessing the exclusive perks and features of Session Pro.", "proExpiringTime": "Pro expiring in {time}", "proFaq": "Pro FAQ", - "proFaqDescription": "Find answers to common questions in the Session FAQ.", + "proFaqDescription": "Find answers to common questions in the Session Pro FAQ.", "proFeatureListAnimatedDisplayPicture": "Upload GIF and WebP display pictures", "proFeatureListLargerGroups": "Larger group chats up to 300 members", "proFeatureListLoadsMore": "Plus loads more exclusive features", "proFeatureListLongerMessages": "Messages up to 10,000 characters", "proFeatureListPinnedConversations": "Pin unlimited conversations", - "proFeatures": "Pro Features", "proGroupActivated": "Group Activated", "proGroupActivatedDescription": "This group has expanded capacity! It can support up to 300 members because a group admin has", "proGroupsUpgraded": "{count, plural, one [{total} Group Upgraded] other [{total} Groups Upgraded]}", @@ -877,17 +880,19 @@ "proIncreasedMessageLengthFeature": "Increased Message Length", "proLargerGroups": "Larger Groups", "proLargerGroupsDescription": "Groups you are an admin in are automatically upgraded to support 300 members.", + "proLargerGroupsTooltip": "Larger group chats (up to 300 members) are coming soon for all Pro Beta users!", "proLongerMessages": "Longer Messages", "proLongerMessagesDescription": "You can send messages up to 10,000 characters in all conversations.", "proLongerMessagesSent": "{count, plural, one [{total} Longer Message Sent] other [{total} Longer Messages Sent]}", "proMessageInfoFeatures": "This message used the following Session Pro features:", + "proOptionsRenewalSubtitle": "Currently, there are three ways to renew:", "proPercentOff": "{percent}% Off", "proPinnedConversations": "{count, plural, one [{total} Pinned Conversation] other [{total} Pinned Conversations]}", "proPlanActivatedAuto": "Your Session Pro plan is active!

Your plan will automatically renew for another {current_plan} on {date}. Updates to your plan take effect when Pro is next renewed.", "proPlanActivatedAutoShort": "Your Session Pro plan is active!

Your plan will automatically renew for another {current_plan} on {date}.", - "proPlanActivatedNotAuto": "Your Session Pro plan will expire on {date}.

Update your plan now to ensure uninterrupted access to exclusive Pro features.", + "proPlanActivatedNotAuto": "Your Session Pro plan will expire on {date}.

Update your plan now to ensure uninterrupted access to exclusive Pro features.", "proPlanError": "Pro Plan Error", - "proPlanExpireDate": "Your Session Pro plan will expire on {date}.", + "proPlanExpireDate": "Your Session Pro plan will expire on {date}.", "proPlanLoading": "Pro Plan Loading", "proPlanLoadingDescription": "Information about your Pro plan is still being loaded. You cannot update your plan until this process is complete.", "proPlanLoadingEllipsis": "Pro plan loading...", @@ -898,7 +903,7 @@ "proPlanPlatformRefundLong": "Because you originally signed up for Session Pro via the {platform_store} Store, your refund request will be processed by Session Support.

Request a refund by hitting the button below and completing the refund request form.

While Session Support strives to process refund requests within 24-72 hours, processing may take longer during times of high request volume.", "proPlanRecover": "Recover Pro Plan", "proPlanRenew": "Renew Pro Plan", - "proPlanRenewDesktop": "Currently, Pro plans can only be purchased and renewed via the {platform_store} or {platform_store} Stores. Because you are using Session Desktop, you're not able to renew your plan here.

Session Pro developers are working hard on alternative payment options to allow users to purchase Pro plans outside of the {platform_store} and {platform_store} Stores. Pro Roadmap", + "proPlanRenewDesktop": "Currently, Pro plans can only be purchased and renewed via the {platform_store} or {platform_store} Stores. Because you are using Session Desktop, you're not able to renew your plan here.

Session Pro developers are working hard on alternative payment options to allow users to purchase Pro plans outside of the {platform_store} and {platform_store} Stores. Pro Roadmap {icon}", "proPlanRenewDesktopLinked": "Renew your plan in the Session Pro settings on a linked device with Session installed via the {platform_store} or {platform_store} Store.", "proPlanRenewDesktopStore": "Renew your plan on the {platform_store} website using the {platform_account} you signed up for Pro with.", "proPlanRenewStart": "Renew your Session Pro plan to start using powerful Session Pro Beta features again.", @@ -912,10 +917,12 @@ "proRefundDescription": "We’re sorry to see you go. Here's what you need to know before requesting a refund.", "proRefundNextSteps": "{platform_account} is now processing your refund request. This typically takes 24-48 hours. Depending on their decision, you may see your Pro status change in Session.", "proRefundRequestSessionSupport": "Your refund request will be handled by Session Support.

Request a refund by hitting the button below and completing the refund request form.

While Session Support strives to process refund requests within 24-72 hours, processing may take longer during times of high request volume.", - "proRefundRequestStorePolicies": "Your refund request will be handled exclusively by {platform_account} through the {platform_account} website.

Due to {platform_account} refund policies, Session developers have no ability to influence the outcome of refund requests. This includes whether the request is approved or denied, as well as whether a full or partial refund is issued.", + "proRefundRequestStorePolicies": "Your refund request will be handled exclusively by {platform_account} through the {platform_account} website.

Due to {platform_account} refund policies, Session developers have no ability to influence the outcome of refund requests. This includes whether the request is approved or denied, as well as whether a full or partial refund is issued.", "proRefundSupport": "Please contact {platform_account} for further updates on your refund request. Due to {platform_account} refund policies, Session developers have no ability to influence the outcome of refund requests.

{platform_store} Refund Support", "proRefunding": "Refunding Pro", "proRefundingDescription": "Refunds for Session Pro plans are handled exclusively by {platform_account} through the {platform_store} Store.

Due to {platform_account} refund policies, Session developers have no ability to influence the outcome of refund requests. This includes whether the request is approved or denied, as well as whether a full or partial refund is issued.", + "proRenewBeta": "Renew Pro Beta", + "proRenewingNoAccessBilling": "Currently, Pro plans can only be purchased and renewed via the {platform_store} or {platform_store} Stores. Because you installed Session using the {buildVariant}, you're not able to renew your plan here.

Session Pro developers are working hard on alternative payment options to allow users to purchase Pro plans outside of the {platform_store} and {platform_store} Stores. Pro Roadmap {icon}", "proRequestedRefund": "Refund Requested", "proSendMore": "Send more with", "proSettings": "Pro Settings", @@ -994,6 +1001,7 @@ "removePasswordFail": "Failed to remove password", "removePasswordModalDescription": "Remove your current password for Session. Locally stored data will be re-encrypted with a randomly generated key, stored on your device.", "renew": "Renew", + "renewingPro": "Renewing Pro", "reply": "Reply", "requestRefund": "Request Refund", "resend": "Resend", @@ -1124,6 +1132,7 @@ "updated": "Last updated {relative_time} ago", "updates": "Updates", "updating": "Updating...", + "upgradeSession": "Upgrade Session", "upgradeTo": "Upgrade to", "uploading": "Uploading", "urlCopy": "Copy URL", diff --git a/_locales/nl/messages.json b/_locales/nl/messages.json index f7c96909a..434857f64 100644 --- a/_locales/nl/messages.json +++ b/_locales/nl/messages.json @@ -849,15 +849,12 @@ "proExpired": "Verlopen", "proExpiredDescription": "Helaas is je Pro abonnement verlopen. Verleng om toegang te blijven houden tot de exclusieve voordelen en functies van Session Pro.", "proExpiringSoon": "Verloopt binnenkort", - "proExpiringSoonDescription": "Je Pro abonnement verloopt over {time}. Werk je abonnement bij om toegang te blijven houden tot de exclusieve voordelen en functies van Session Pro.", "proFaq": "Pro FAQ", - "proFaqDescription": "Vind antwoorden op veelgestelde vragen in de Session FAQ.", "proFeatureListAnimatedDisplayPicture": "Upload GIF- en WebP-profielfoto's", "proFeatureListLargerGroups": "Groepsgesprekken tot wel 300 leden", "proFeatureListLoadsMore": "En nog veel meer exclusieve functies", "proFeatureListLongerMessages": "Berichten tot 10.000 tekens", "proFeatureListPinnedConversations": "Onbeperkt gesprekken vastzetten", - "proFeatures": "Pro functies", "proGroupActivated": "Groep geactiveerd", "proGroupActivatedDescription": "Deze groep heeft een grotere capaciteit! Er kunnen nu tot 300 leden deelnemen omdat een groepsbeheerder een", "proImportantDescription": "Het aanvragen van een terugbetaling is definitief. Indien goedgekeurd, wordt je Pro abonnement onmiddellijk geannuleerd en verlies je de toegang tot alle Pro functies.", @@ -871,15 +868,12 @@ "proPercentOff": "{percent}% korting", "proPlanActivatedAuto": "Je Session Pro abonnement is actief!

Je abonnement wordt automatisch verlengd voor een nieuw {current_plan} op {date}. Wijzigingen aan je abonnement gaan in wanneer Pro de volgende keer wordt verlengd.", "proPlanActivatedAutoShort": "Je Session Pro abonnement is actief!

Je abonnement wordt automatisch verlengd met een {current_plan} op {date}.", - "proPlanActivatedNotAuto": "Je Session Pro abonnement verloopt op {date}.

Werk je abonnement nu bij om ononderbroken toegang te behouden tot exclusieve Pro functies.", - "proPlanExpireDate": "Je Session Pro abonnement verloopt op {date}.", "proPlanNotFound": "Pro abonnement niet gevonden", "proPlanNotFoundDescription": "Er is geen actief abonnement gevonden voor je account. Als je denkt dat dit een vergissing is, neem dan contact op met de ondersteuning van Session voor hulp.", "proPlanPlatformRefund": "Omdat je je oorspronkelijk hebt aangemeld voor Session Pro via de {platform_store} winkel, moet je hetzelfde {platform_account} gebruiken om een terugbetaling aan te vragen.", "proPlanPlatformRefundLong": "Omdat je je oorspronkelijk hebt aangemeld voor Session Pro via de {platform_store} winkel, wordt je restitutieverzoek afgehandeld door Session Support.

Vraag een restitutie aan door op de knop hieronder te drukken en het restitutieformulier in te vullen.

Hoewel Session Support ernaar streeft om restitutieverzoeken binnen 24-72 uur te verwerken, kan het tijdens drukte langer duren", "proPlanRecover": "Pro abonnement herstellen", "proPlanRenew": "Pro abonnement verlengen", - "proPlanRenewDesktop": "Momenteel kunnen Pro abonnementen alleen worden gekocht en verlengd via de {platform_store}- of {platform_store} winkels. Omdat je Session Desktop gebruikt, kun je je abonnement hier niet verlengen.

De ontwikkelaars van Session Pro werken hard aan alternatieve betaalmogelijkheden, zodat gebruikers Pro abonnementen buiten de {platform_store}- en {platform_store} winkels kunnen aanschaffen. Pro Routekaart", "proPlanRenewDesktopLinked": "Verleng je abonnement in de Session Pro instellingen op een gekoppeld apparaat met Session geïnstalleerd via de {platform_store} of {platform_store} winkel.", "proPlanRenewDesktopStore": "Verleng je abonnement op de {platform_store} website met het {platform_account} waarmee je je voor Pro hebt aangemeld.", "proPlanRenewSupport": "Je Session Pro abonnement is verlengd! Bedankt voor je steun aan de Session Network.", @@ -892,7 +886,6 @@ "proRefundDescription": "Het spijt ons dat je vertrekt. Dit moet je weten voordat je een terugbetaling aanvraagt.", "proRefundNextSteps": "{platform_account} verwerkt nu je terugbetalingsverzoek. Dit duurt meestal 24-48 uur. Afhankelijk van hun beslissing kan je Pro status wijzigen in Session.", "proRefundRequestSessionSupport": "Je restitutieverzoek wordt afgehandeld door Session Support.

Vraag een restitutie aan door op de knop hieronder te drukken en het restitutieformulier in te vullen.

Hoewel Session Support ernaar streeft om restitutieverzoeken binnen 24-72 uur te verwerken, kan het tijdens drukte langer duren.", - "proRefundRequestStorePolicies": "Je terugbetalingsverzoek wordt uitsluitend afgehandeld door {platform_account} via de website van {platform_account}.

Vanwege het restitutiebeleid van {platform_account} hebben ontwikkelaars van Session geen invloed op de uitkomst van terugbetalingsverzoeken. Dit geldt zowel voor de goedkeuring of afwijzing van het verzoek als voor het wel of niet toekennen van een volledige of gedeeltelijke terugbetaling.", "proRefundSupport": "Neem contact op met {platform_account} voor verdere updates over je restitutieverzoek. Vanwege het restitutiebeleid van {platform_account} hebben de ontwikkelaars van Session geen invloed op de uitkomst van restitutieverzoeken.

{platform_store} Terugbetalingsondersteuning", "proRefunding": "Terugbetalen Pro", "proRefundingDescription": "Terugbetalingen voor Session Pro abonnementen worden uitsluitend afgehandeld door {platform_account} via de {platform_store} Store.

Vanwege het restitutiebeleid van {platform_account} hebben ontwikkelaars van Session geen invloed op de uitkomst van terugbetalingsverzoeken. Dit geldt zowel voor de goedkeuring of afwijzing van het verzoek als voor het wel of niet toekennen van een volledige of gedeeltelijke terugbetaling.", diff --git a/_locales/uk/messages.json b/_locales/uk/messages.json index f2611b322..d9b927538 100644 --- a/_locales/uk/messages.json +++ b/_locales/uk/messages.json @@ -848,16 +848,13 @@ "proExpired": "Підписка сплила", "proExpiredDescription": "На жаль, підписка Pro сплила. Онови її задля збереження переваг і можливостей Session Pro.", "proExpiringSoon": "Невдовзі спливе підписка", - "proExpiringSoonDescription": "Підписка Pro спливе {time}. Онови підписку задля збереження переваг і можливостей Session Pro.", "proExpiringTime": "Pro спливає за {time}", "proFaq": "Pro ЧАП", - "proFaqDescription": "Відповіді на загальні запитання знайдеш у ЧаПи Session.", "proFeatureListAnimatedDisplayPicture": "Завантажуйте GIF та WebP аватари", "proFeatureListLargerGroups": "Більша кількість — до 300 учасників — групових чатів", "proFeatureListLoadsMore": "Та велика кількість ексклюзивних можливостей", "proFeatureListLongerMessages": "Повідомлення до 10 000 символів", "proFeatureListPinnedConversations": "Закріплюйте необмежену кількість бесід", - "proFeatures": "Можливості Pro", "proGroupActivated": "Групу активовано", "proGroupActivatedDescription": "У цієї групи розширено можливості! Тепер вона може вміщати до 300 учасників, тому що адміністратор групи має", "proImportantDescription": "Вимагання повернення грошей закінчено. В разі схвалення твою підписку Pro негайно скасують і ти втратиш всі можливості Pro.", @@ -870,8 +867,6 @@ "proMessageInfoFeatures": "У цьому повідомленні наявні наступні функції Session Pro:", "proPlanActivatedAuto": "Для тебе діє підписка Session Pro.

{date} твою підписку буде самодійно поновлено як {current_plan}. Оновлення підписки настане під час наступного оновлення Pro.", "proPlanActivatedAutoShort": "Для тебе діє підписка Session Pro.

{date} твою підписку буде самодійно поновлено як {current_plan}.", - "proPlanActivatedNotAuto": "Твоя підписка Session Pro спливе {date}.

Для збереження особливих можливостей подовж свою підписку.", - "proPlanExpireDate": "Підписка Session Pro спливе {date}.", "proPlanNotFound": "Передплата Pro не знайдена", "proPlanRecover": "Відновити передплату Pro", "proPlanRenew": "Оновити підписку Pro", From 98596b9060aa1b1a320bff0484e1e458d7f2a801 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Wed, 24 Sep 2025 07:19:11 +0200 Subject: [PATCH 4/4] chore: added decent pro plan bg effect --- .../pages/DefaultSettingsPage.tsx | 2 +- .../pages/user-pro/ProSettingsPage.tsx | 209 ++++++++++++++++-- ts/components/icon/lucide.ts | 2 + 3 files changed, 199 insertions(+), 14 deletions(-) diff --git a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx index 95c8b3ca0..3ba3383b9 100644 --- a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx @@ -115,7 +115,7 @@ function SessionProSection() { token: userHasPro ? 'sessionProBeta' : currentUserHasExpiredPro - ? 'proPlanRenew' + ? 'proRenewBeta' : 'upgradeSession', }} onClick={() => { diff --git a/ts/components/dialog/user-settings/pages/user-pro/ProSettingsPage.tsx b/ts/components/dialog/user-settings/pages/user-pro/ProSettingsPage.tsx index fdbca51ab..9c30e1faf 100644 --- a/ts/components/dialog/user-settings/pages/user-pro/ProSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/user-pro/ProSettingsPage.tsx @@ -1,5 +1,5 @@ import { isNumber } from 'lodash'; -import { useMemo } from 'react'; +import { useMemo, type ReactNode } from 'react'; import styled from 'styled-components'; import { useDispatch } from 'react-redux'; import { ModalBasicHeader } from '../../../../SessionWrapperModal'; @@ -8,21 +8,30 @@ import type { UserSettingsModalState } from '../../../../../state/ducks/modalDia import { ModalBackButton } from '../../../shared/ModalBackButton'; import { UserSettingsModalContainer } from '../../components/UserSettingsModalContainer'; import { ModalFlexContainer } from '../../../shared/ModalFlexContainer'; -import { PanelButtonGroup, PanelLabelWithDescription } from '../../../../buttons/panel/PanelButton'; +import { + PanelButtonGroup, + PanelLabelWithDescription, + StyledContent, + StyledPanelButton, +} from '../../../../buttons/panel/PanelButton'; import { SettingsExternalLinkBasic } from '../../components/SettingsExternalLinkBasic'; import { showLinkVisitWarningDialog } from '../../../OpenUrlModal'; import { PanelIconButton, PanelIconLucideIcon } from '../../../../buttons/panel/PanelIconButton'; -import { LUCIDE_ICONS_UNICODE } from '../../../../icon/lucide'; +import { LUCIDE_ICONS_UNICODE, type WithLucideUnicode } from '../../../../icon/lucide'; import { SettingsChevronBasic } from '../../components/SettingsChevronBasic'; import { SettingsToggleBasic } from '../../components/SettingsToggleBasic'; import { SessionTooltip } from '../../../../SessionTooltip'; -import { tr } from '../../../../../localization/localeTools'; +import { tr, type TrArgs } from '../../../../../localization/localeTools'; import { LucideIcon } from '../../../../icon/LucideIcon'; import { Storage } from '../../../../../util/storage'; import { SettingsKey } from '../../../../../data/settings-key'; import { getBrowserLocale } from '../../../../../util/i18n/shared'; import { SessionIcon } from '../../../../icon'; import { ProIconButton } from '../../../../buttons/ProButton'; +import { StyledPanelButtonSeparator } from '../../../../buttons/panel/StyledPanelButtonGroupSeparator'; +import { useIsDarkTheme } from '../../../../../state/theme/selectors/theme'; +import { Flex } from '../../../../basic/Flex'; +import { Localizer } from '../../../../basic/Localizer'; const SectionFlexContainer = styled.div` display: flex; @@ -32,29 +41,31 @@ const SectionFlexContainer = styled.div` `; const HeroImageBgContainer = styled.div` - height: 170px; + height: 230px; `; const HeroImageBg = styled.div` position: absolute; left: 0; right: 0; + top: 17%; + justify-items: center; &::before { content: ''; position: absolute; - top: -40%; + top: 20%; left: -40%; width: 180%; - height: 180%; + height: 80%; background: radial-gradient( circle, color-mix(in srgb, var(--primary-color) 15%, transparent) 0%, transparent 70% ); + filter: blur(45px); - filter: blur(60px); z-index: -1; /* behind the logo */ } `; @@ -69,7 +80,7 @@ const HeroImageLabelContainer = styled.div` function ProHeroImage() { return ( - + @@ -234,11 +245,183 @@ function ProSettings() { ); } +function ProFeatureItem({ + textElement, + iconElement, + onClick, +}: { + iconElement: ReactNode; + textElement: ReactNode; + onClick?: () => Promise; +}) { + const isDarkTheme = useIsDarkTheme(); + return ( + <> + + + {iconElement} + {textElement} + + + + + ); +} + +const ProFeatureTextContainer = styled.div` + display: flex; + flex-direction: column; + gap: var(--margins-xs); + align-items: flex-start; + text-align: start; +`; + +const ProFeatureTitle = styled.div` + color: var(--text-primary-color); + font-size: var(--font-size-md); + font-weight: 700; +`; + +const ProFeatureDescription = styled.div` + font-size: 12px; // just because 13px does not look good + color: var(--text-secondary-color); +`; + +const StyledFeatureIcon = styled.div` + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + width: 42px; + height: 42px; + padding: 0; + border-radius: var(--margins-xs); + color: var(--black-color); +`; + +type WithProFeaturePosition = { position: number }; + +function ProFeatureIconElement({ unicode, position }: WithLucideUnicode & WithProFeaturePosition) { + const bgStyle = + position === 0 + ? 'linear-gradient(135deg, #57C9FA 0%, #C993FF 100%)' + : position === 1 + ? 'linear-gradient(135deg, #C993FF 0%, #FF95EF 100%)' + : position === 2 + ? 'linear-gradient(135deg, #FF95EF 0%, #FF9C8E 100%)' + : position === 3 + ? 'linear-gradient(135deg, #FF9C8E 0%, #FCB159 100%)' + : position === 4 + ? 'linear-gradient(135deg, #FCB159 0%, #FAD657 100%)' + : 'none'; + + return ( + + + + + + ); +} + +const proFeatures: Array< + { + id: + | 'proLongerMessages' + | 'proUnlimitedPins' + | 'proAnimatedDisplayPictures' + | 'proBadges' + | 'plusLoadsMore'; + title: TrArgs; + description: TrArgs; + } & WithLucideUnicode +> = [ + { + id: 'proLongerMessages', + title: { token: 'proLongerMessages' as const }, + description: { token: 'proLongerMessagesDescription' as const }, + unicode: LUCIDE_ICONS_UNICODE.MESSAGE_SQUARE, + }, + { + id: 'proUnlimitedPins', + title: { token: 'proUnlimitedPins' as const }, + description: { token: 'proUnlimitedPinsDescription' as const }, + unicode: LUCIDE_ICONS_UNICODE.PIN, + }, + { + id: 'proAnimatedDisplayPictures', + title: { token: 'proAnimatedDisplayPictures' as const }, + description: { token: 'proAnimatedDisplayPicturesDescription' as const }, + unicode: LUCIDE_ICONS_UNICODE.SQUARE_PLAY, + }, + { + id: 'proBadges', + title: { token: 'proBadges' as const }, + description: { token: 'proBadgesDescription' as const }, + unicode: LUCIDE_ICONS_UNICODE.RECTANGLE_ELLIPSES, + }, + { + id: 'plusLoadsMore', + title: { token: 'plusLoadsMore' as const }, + description: { + token: 'plusLoadsMoreDescription' as const, + icon: LUCIDE_ICONS_UNICODE.EXTERNAL_LINK_ICON, + }, + unicode: LUCIDE_ICONS_UNICODE.CIRCLE_PLUS, + }, +]; + function ProFeatures() { + const dispatch = useDispatch(); + return ( - - PLOP + + + {proFeatures.map((m, i) => { + return ( + { + showLinkVisitWarningDialog('https://getsession.org/pro-roadmap', dispatch); + } + : undefined + } + iconElement={} + textElement={ + + + {m.id === 'proBadges' && ( + + )} + + + + + + + } + /> + ); + })} + ); } @@ -278,7 +461,7 @@ function ProHelp() { text={{ token: 'proFaq' }} subText={{ token: 'proFaqDescription' }} onClick={async () => - showLinkVisitWarningDialog('https://getsession.org/pro-roadmap', dispatch) + showLinkVisitWarningDialog('https://getsession.org/faq#pro', dispatch) } /> - showLinkVisitWarningDialog('https://getsession.org/pro-roadmap', dispatch) + showLinkVisitWarningDialog('https://getsession.org/pro-form', dispatch) } />
diff --git a/ts/components/icon/lucide.ts b/ts/components/icon/lucide.ts index 0335fbc25..10315f5ce 100644 --- a/ts/components/icon/lucide.ts +++ b/ts/components/icon/lucide.ts @@ -60,6 +60,7 @@ export enum LUCIDE_ICONS_UNICODE { SMILE_PLUS = '', SQUARE = '', SQUARE_CODE = '', + SQUARE_PLAY = '', SUN_MEDIUM = '', TIMER = '', TRASH2 = '', @@ -141,6 +142,7 @@ export function isIconToMirrorRtl(unicode: LUCIDE_ICONS_UNICODE) { case LUCIDE_ICONS_UNICODE.SMILE_PLUS: case LUCIDE_ICONS_UNICODE.SQUARE: case LUCIDE_ICONS_UNICODE.SQUARE_CODE: + case LUCIDE_ICONS_UNICODE.SQUARE_PLAY: case LUCIDE_ICONS_UNICODE.SUN_MEDIUM: case LUCIDE_ICONS_UNICODE.TIMER: case LUCIDE_ICONS_UNICODE.TRASH2: