Эх сурвалжийг харах

[web] Paywall and other AI text edits (#31993)

* Update Compile timeout copy

* Update Collaborator limit copy

* Update Track changes copy

* Update History copy and "Start free trial" button

* Remove unnecessary children passed to StartFreeTrialButton

* Update Dropbox copy

* Update Github copy

* Update Git copy

* Update Reference managers copy

* Update Symbol palette copy

* Update Onboarding prompt copy

* Update Subscriptions page (on free account) copy

* `bin/run web npm run extract-translations`

* Add split-test assignment in subscription page

* Fix tests

* Update services/web/modules/symbol-palette/frontend/js/components/symbol-palette-overlay.tsx

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update services/web/modules/onboarding/app/views/onboarding/try_premium.pug

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update services/web/modules/onboarding/app/views/onboarding/try_premium.pug

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Replace `Github` to `GitHub` in translations

* Update "non Overleaf" to "non-Overleaf"

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
GitOrigin-RevId: 56ee2735899de18f820b229bc226249322ac0c87
Antoine Clausse 5 сар өмнө
parent
commit
d5a65e906f

+ 1 - 1
services/web/app/src/Features/Subscription/SubscriptionController.mjs

@@ -184,7 +184,7 @@ async function userSubscriptionPage(req, res) {
     res,
     'combined-user-management'
   )
-
+  await SplitTestHandler.promises.getAssignment(req, res, 'plans-2026-phase-1')
   const groupPricingDiscount = await SplitTestHandler.promises.getAssignment(
     req,
     res,

+ 10 - 0
services/web/frontend/extracted-translations.json

@@ -47,6 +47,7 @@
   "accepted_invite": "",
   "accepting": "",
   "access_all_premium_features": "",
+  "access_all_premium_features_ai": "",
   "access_all_premium_features_including_more_collaborators_real_time_track_changes_and_a_longer_compile_time": "",
   "access_denied": "",
   "access_edit_your_projects": "",
@@ -692,6 +693,7 @@
   "get_discounted_plan": "",
   "get_early_access_with_ai_assist_add_on": "",
   "get_exclusive_access_to_labs": "",
+  "get_full_project_history": "",
   "get_in_touch": "",
   "get_language_suggestions": "",
   "get_more_compile_time": "",
@@ -699,6 +701,7 @@
   "get_most_subscription_by_checking_overleaf": "",
   "get_most_subscription_by_checking_overleaf_ai_writefull": "",
   "get_real_time_track_changes": "",
+  "get_unlimited_ai": "",
   "git": "",
   "git_authentication_token": "",
   "git_authentication_token_create_modal_info_1": "",
@@ -1351,6 +1354,7 @@
   "please_set_main_file": "",
   "please_try_again_in_a_few_moments": "",
   "please_wait": "",
+  "plus_additional_collaborators_and_more": "",
   "plus_additional_collaborators_document_history_track_changes_and_more": "",
   "plus_more": "",
   "plus_x_additional_licenses_for_a_total_of_y_licenses": "",
@@ -1850,6 +1854,8 @@
   "sync_to_dropbox": "",
   "sync_to_github": "",
   "sync_with_a_github_repository": "",
+  "sync_with_dropbox": "",
+  "sync_with_github": "",
   "synctex_error_recompile_and_try_again": "",
   "synctex_failed": "",
   "syntax_checks": "",
@@ -2078,6 +2084,7 @@
   "university_school": "",
   "unknown": "",
   "unknown_group": "",
+  "unlimited_ai": "",
   "unlimited_ai_use": "",
   "unlimited_collaborators_per_project": "",
   "unlimited_collabs": "",
@@ -2123,6 +2130,7 @@
   "upgrade_plan": "",
   "upgrade_summary": "",
   "upgrade_to_add_more_collaborators_and_access_collaboration_features": "",
+  "upgrade_to_add_more_collaborators_and_more": "",
   "upgrade_to_get_feature": "",
   "upgrade_to_review": "",
   "upgrade_your_subscription": "",
@@ -2240,6 +2248,7 @@
   "why_not_pause_instead": "",
   "wide": "",
   "will_lose_edit_access_on_date": "",
+  "with_overleaf_subscription_you_also_get": "",
   "with_premium_subscription_you_also_get": "",
   "word_count_lower": "",
   "words": "",
@@ -2273,6 +2282,7 @@
   "you_are_on_a_paid_plan_contact_support_to_find_out_more": "",
   "you_are_on_x_plan_as_a_confirmed_member_of_institution_y": "",
   "you_are_on_x_plan_as_member_of_group_subscription_y_administered_by_z": "",
+  "you_are_using_our_free_plan": "",
   "you_can_also_choose_to_view_anonymously_or_leave_the_project": "",
   "you_can_also_right_click_a_file_to_set_it_as_main": "",
   "you_can_buy_this_plan_but_not_as_a_trial": "",

+ 6 - 4
services/web/frontend/js/features/history/components/change-list/owner-paywall-prompt.tsx

@@ -3,10 +3,12 @@ import { useCallback, useEffect, useState } from 'react'
 import * as eventTracking from '../../../../infrastructure/event-tracking'
 import StartFreeTrialButton from '../../../../shared/components/start-free-trial-button'
 import UpgradeBenefits from '@/shared/components/upgrade-benefits'
+import { useFeatureFlag } from '@/shared/context/split-test-context'
 
 export function OwnerPaywallPrompt() {
   const { t } = useTranslation()
   const [clickedFreeTrialButton, setClickedFreeTrialButton] = useState(false)
+  const plans2026 = useFeatureFlag('plans-2026-phase-1')
 
   useEffect(() => {
     eventTracking.send('subscription-funnel', 'editor-click-feature', 'history')
@@ -19,7 +21,9 @@ export function OwnerPaywallPrompt() {
 
   return (
     <div className="history-paywall-prompt">
-      <h2 className="history-paywall-heading">{t('premium_feature')}</h2>
+      <h2 className="history-paywall-heading">
+        {plans2026 ? t('get_full_project_history') : t('premium_feature')}
+      </h2>
       <p>{t('currently_seeing_only_24_hrs_history')}</p>
       <p>
         <strong>
@@ -32,9 +36,7 @@ export function OwnerPaywallPrompt() {
           source="history"
           buttonProps={{ variant: 'premium' }}
           handleClick={handleFreeTrialClick}
-        >
-          {t('start_free_trial')}
-        </StartFreeTrialButton>
+        />
       </p>
       {clickedFreeTrialButton ? (
         <p className="small">{t('refresh_page_after_starting_free_trial')}</p>

+ 7 - 4
services/web/frontend/js/features/pdf-preview/components/timeout-upgrade-prompt-new.tsx

@@ -8,10 +8,10 @@ import getMeta from '@/utils/meta'
 import { populateEditorRedesignSegmentation } from '@/shared/hooks/use-editor-analytics'
 import CompileTimeoutPaywallModal from '@/features/pdf-preview/components/compile-timeout-paywall-modal'
 import { isSplitTestEnabled } from '@/utils/splitTestUtils'
+import { useFeatureFlag } from '@/shared/context/split-test-context'
 
 function TimeoutUpgradePromptNew() {
   const { isProjectOwner } = useDetachCompileContext()
-
   const isCompileTimeoutTargetPlansEnabled = isSplitTestEnabled(
     'compile-timeout-target-plans'
   )
@@ -61,6 +61,7 @@ const CompileTimeout = memo(function CompileTimeout({
   isCompileTimeoutTargetPlansEnabled,
 }: CompileTimeoutProps) {
   const { t } = useTranslation()
+  const plans2026 = useFeatureFlag('plans-2026-phase-1')
   const extraSearchParams = useMemo(() => {
     return {
       itm_content: 'new-editor',
@@ -93,9 +94,11 @@ const CompileTimeout = memo(function CompileTimeout({
             {isProjectOwner ? (
               <p>
                 <strong>{t('upgrade_for_more_compile_time')}</strong>{' '}
-                {t(
-                  'plus_additional_collaborators_document_history_track_changes_and_more'
-                )}
+                {plans2026
+                  ? t('plus_additional_collaborators_and_more')
+                  : t(
+                      'plus_additional_collaborators_document_history_track_changes_and_more'
+                    )}
               </p>
             ) : (
               <Trans

+ 6 - 2
services/web/frontend/js/features/review-panel/components/upgrade-track-changes-modal.tsx

@@ -18,11 +18,13 @@ import OLRow from '@/shared/components/ol/ol-row'
 import OLCol from '@/shared/components/ol/ol-col'
 import MaterialIcon from '@/shared/components/material-icon'
 import { useEditorContext } from '@/shared/context/editor-context'
+import { useFeatureFlag } from '@/shared/context/split-test-context'
 
 function UpgradeTrackChangesModal() {
   const { t } = useTranslation()
   const { project } = useProjectContext()
   const user = useUserContext()
+  const plans2026 = useFeatureFlag('plans-2026-phase-1')
   const {
     upgradeTrackChangesModal: { show, location = 'unknown' },
     setUpgradeTrackChangesModal,
@@ -72,7 +74,9 @@ function UpgradeTrackChangesModal() {
               {[
                 t('see_suggestions_from_collaborators'),
                 t('accept_or_reject_individual_edits'),
-                t('access_all_premium_features'),
+                plans2026
+                  ? t('access_all_premium_features_ai')
+                  : t('access_all_premium_features'),
               ].map(translation => (
                 <li key={translation}>
                   <MaterialIcon type="check" className="check-icon" />
@@ -94,7 +98,7 @@ function UpgradeTrackChangesModal() {
                     })
                   }
                 >
-                  {t('try_it_for_free')}
+                  {plans2026 ? t('try_for_free') : t('try_it_for_free')}
                 </OLButton>
               ) : (
                 <OLButton

+ 7 - 3
services/web/frontend/js/features/share-project-modal/components/collaborators-limit-upgrade.tsx

@@ -5,10 +5,12 @@ import { useUserContext } from '@/shared/context/user-context'
 import StartFreeTrialButton from '@/shared/components/start-free-trial-button'
 import OLButton from '@/shared/components/ol/ol-button'
 import addMoreEditorsImage from '../images/add-more-editors.svg'
+import { useFeatureFlag } from '@/shared/context/split-test-context'
 
 export default function CollaboratorsLimitUpgrade() {
   const { t } = useTranslation()
   const user = useUserContext()
+  const plans2026 = useFeatureFlag('plans-2026-phase-1')
 
   return (
     <div className="invite-warning">
@@ -18,9 +20,11 @@ export default function CollaboratorsLimitUpgrade() {
         title={t('add_more_collaborators')}
         content={
           <p>
-            {t(
-              'upgrade_to_add_more_collaborators_and_access_collaboration_features'
-            )}
+            {plans2026
+              ? t('upgrade_to_add_more_collaborators_and_more')
+              : t(
+                  'upgrade_to_add_more_collaborators_and_access_collaboration_features'
+                )}
           </p>
         }
         isActionBelowContent

+ 19 - 10
services/web/frontend/js/features/subscription/components/dashboard/free-plan.tsx

@@ -1,30 +1,39 @@
 import { useTranslation, Trans } from 'react-i18next'
 import WritefullManagedBundleAddOn from '@/features/subscription/components/dashboard/states/active/change-plan/modals/writefull-bundle-management-modal'
 import getMeta from '@/utils/meta'
+import { useFeatureFlag } from '@/shared/context/split-test-context'
 
 function FreePlan() {
   const { t } = useTranslation()
   const hasAiAssistViaWritefull = getMeta('ol-hasAiAssistViaWritefull')
-
+  const plans2026 = useFeatureFlag('plans-2026-phase-1')
   return (
     <>
-      <Trans
-        i18nKey="on_free_plan_upgrade_to_access_features"
-        components={[
-          // eslint-disable-next-line react/jsx-key, jsx-a11y/anchor-has-content
-          <a href="/learn/how-to/Overleaf_premium_features" target="_blank" />,
-        ]}
-      />
+      {plans2026 ? (
+        t('you_are_using_our_free_plan')
+      ) : (
+        <Trans
+          i18nKey="on_free_plan_upgrade_to_access_features"
+          components={[
+            // eslint-disable-next-line react/jsx-key, jsx-a11y/anchor-has-content
+            <a
+              href="/learn/how-to/Overleaf_premium_features"
+              target="_blank"
+            />,
+          ]}
+        />
+      )}
       :
       <ul>
         <li>{t('invite_more_collabs')}</li>
-        <li>{t('realtime_track_changes')}</li>
+        {plans2026 && <li>{t('get_unlimited_ai')}</li>}
+        {!plans2026 && <li>{t('realtime_track_changes')}</li>}
         <li>{t('full_doc_history')}</li>
         <li>{t('reference_search')}</li>
         <li>{t('reference_sync')}</li>
         <li>{t('dropbox_integration_lowercase')}</li>
         <li>{t('github_integration_lowercase')}</li>
-        <li>{t('priority_support')}</li>
+        {!plans2026 && <li>{t('priority_support')}</li>}
       </ul>
       <a className="btn btn-primary me-1" href="/user/subscription/plans">
         {t('upgrade_now')}

+ 6 - 1
services/web/frontend/js/shared/components/start-free-trial-button.tsx

@@ -3,6 +3,7 @@ import { useTranslation } from 'react-i18next'
 import { startFreeTrial } from '@/main/account-upgrade'
 import * as eventTracking from '../../infrastructure/event-tracking'
 import OLButton from '@/shared/components/ol/ol-button'
+import { useFeatureFlag } from '@/shared/context/split-test-context'
 
 type StartFreeTrialButtonProps = {
   source: string
@@ -26,6 +27,7 @@ export default function StartFreeTrialButton({
   extraSearchParams,
 }: StartFreeTrialButtonProps) {
   const { t } = useTranslation()
+  const plans2026 = useFeatureFlag('plans-2026-phase-1')
 
   useEffect(() => {
     const eventSegmentation: { [key: string]: unknown } = {
@@ -64,7 +66,10 @@ export default function StartFreeTrialButton({
 
   return (
     <OLButton {...buttonProps} onClick={onClick}>
-      {children || t('start_free_trial')}
+      {children ||
+        (plans2026
+          ? t('start_free_trial_without_exclamation')
+          : t('start_free_trial'))}
     </OLButton>
   )
 }

+ 3 - 1
services/web/frontend/js/shared/components/upgrade-benefits.tsx

@@ -2,6 +2,7 @@ import MaterialIcon from '@/shared/components/material-icon'
 import { useTranslation } from 'react-i18next'
 import { memo } from 'react'
 import classNames from 'classnames'
+import { useFeatureFlag } from '@/shared/context/split-test-context'
 
 function Check() {
   return <MaterialIcon type="check" />
@@ -9,13 +10,14 @@ function Check() {
 
 function UpgradeBenefits({ className }: { className?: string }) {
   const { t } = useTranslation()
+  const plans2026 = useFeatureFlag('plans-2026-phase-1')
 
   return (
     <ul className={classNames('list-unstyled upgrade-benefits', className)}>
       <li>
         <Check />
         &nbsp;
-        {t('unlimited_projects')}
+        {plans2026 ? t('unlimited_ai') : t('unlimited_projects')}
       </li>
       <li>
         <Check />

+ 1 - 1
services/web/locales/cs.json

@@ -308,7 +308,7 @@
   "unlimited_collabs": "Neomezený počet spolupracovníků",
   "unlimited_projects": "Neomezený počet projektů",
   "unlink": "Odpojit",
-  "unlink_github_repository": "Odlinkovat Github repozitář",
+  "unlink_github_repository": "Odlinkovat GitHub repozitář",
   "unlink_github_warning": "Všechny projekty synchronizované s GitHubem budou odpojeny a déle nesynchronizovány. Opravdu chcete váš GitHub účet odpojit?",
   "unlinking": "Odlinkovávám",
   "unpublish": "Zrušit publikování",

+ 3 - 3
services/web/locales/da.json

@@ -150,8 +150,8 @@
   "ask_proj_owner_to_unlink_from_current_github": "Anmod ejeren af dette projekt (<0>__projectOwnerEmail__</0>) om at afkoble projektet fra det nuværende GitHub repository og forbind til et andet repository.",
   "ask_proj_owner_to_upgrade_for_full_history": "Du må bede projektets ejer om at opgradere, for at få adgang til projektets fulde historie.",
   "ask_proj_owner_to_upgrade_for_references_search": "Du må bede projektets ejer om at opgradere, for at bruge søgning i referencerne.",
-  "ask_repo_owner_to_reconnect": "Anmod ejeren af Github repository’et (<0>__repoOwnerEmail__</0>) om at genforbinde projektet.",
-  "ask_repo_owner_to_renew_overleaf_subscription": "Anmod ejeren af Github repository’et (<0>__repoOwnerEmail__</0>) om at forny deres __appName__ abonnement og genforbinde projektet.",
+  "ask_repo_owner_to_reconnect": "Anmod ejeren af GitHub repository’et (<0>__repoOwnerEmail__</0>) om at genforbinde projektet.",
+  "ask_repo_owner_to_renew_overleaf_subscription": "Anmod ejeren af GitHub repository’et (<0>__repoOwnerEmail__</0>) om at forny deres __appName__ abonnement og genforbinde projektet.",
   "at_most_x_libraries_can_be_selected": "Der kan vælges maksimalt __maxCount__ biblioteker",
   "august": "August",
   "author": "Forfatter",
@@ -702,7 +702,7 @@
   "github_no_master_branch_error": "Dette repository kan ikke forbindes, da det ikke har nogen default branch.  Du må først sørge for, at projektet har en default branch",
   "github_private_description": "Du vælger hvem der kan se, og committe til, dette repository.",
   "github_public_description": "Alle kan se dette repository. Du kan vælge hvem der kan comitte.",
-  "github_repository_diverged": "Default branch i det forbundne repository er blevet force-push’et. Det kan desynkronisere Overleaf og Github at pull’e ændringer efter et force push. Det vil muligvis være nødvendigt at push’e ændringer efter pullet for blive synkroniseret igen.",
+  "github_repository_diverged": "Default branch i det forbundne repository er blevet force-push’et. Det kan desynkronisere Overleaf og GitHub at pull’e ændringer efter et force push. Det vil muligvis være nødvendigt at push’e ændringer efter pullet for blive synkroniseret igen.",
   "github_successfully_linked_description": "Vi har linket din GitHub konto til __appName__. Du kan nu eksportere dine __appName__ projekter til GitHub, eller importere projekter fra dine GitHub repositories.",
   "github_symlink_error": "Dit GitHub repository indeholder symbolske lænkefiler, som ikke på nuværende tidpunkt er understøttet af Overleaf. Du må prøve igen, efter du har fjernet de filer.",
   "github_sync": "GitHub synkronisering",

+ 15 - 3
services/web/locales/en.json

@@ -50,6 +50,7 @@
   "accepted_invite": "Accepted invite",
   "accepting_invite_as": "You are accepting this invite as",
   "access_all_premium_features": "Access all premium features, including more collaborators, full project history, and a longer compile time.",
+  "access_all_premium_features_ai": "Access all premium features, including more collaborators, more compile time, and unlimited AI.",
   "access_all_premium_features_including_more_collaborators_real_time_track_changes_and_a_longer_compile_time": "Access all premium features, including more collaborators, real-time track changes, and a longer compile time.",
   "access_denied": "Access Denied",
   "access_edit_your_projects": "Access and edit your projects",
@@ -891,6 +892,7 @@
   "get_discounted_plan": "Get discounted plan",
   "get_early_access_with_ai_assist_add_on": "Get early access with the AI Assist add-on",
   "get_exclusive_access_to_labs": "Get exclusive access to early-stage experiments when you join Overleaf Labs. All we ask in return is your honest feedback to help us develop and improve.",
+  "get_full_project_history": "Get full project history",
   "get_in_touch": "Get in touch",
   "get_in_touch_having_problems": "<a href=\"__link__\">Get in touch with support</a> if you’re having problems",
   "get_involved": "Get involved",
@@ -901,6 +903,7 @@
   "get_most_subscription_by_checking_overleaf_ai_writefull": "Get the most out of your subscription by checking out <0>Overleaf’s features</0>, <1>Overleaf’s AI features</1> and <2>Writefull’s features</2>.",
   "get_real_time_track_changes": "Get real-time track changes",
   "get_the_best_overleaf_experience": "Get the best Overleaf experience",
+  "get_unlimited_ai": "Get unlimited use of AI features",
   "git": "Git",
   "git_authentication_token": "Git authentication token",
   "git_authentication_token_create_modal_info_1": "This is your Git authentication token. You should enter this when prompted for a password.",
@@ -924,7 +927,8 @@
   "github_empty_repository_error": "It looks like your GitHub repository is empty or not yet available. Create a new file on GitHub.com then try again.",
   "github_file_name_error": "This repository cannot be imported, because it contains file(s) with an invalid filename:",
   "github_file_sync_error": "We are unable to sync the following files:",
-  "github_git_and_dropbox_integrations": "<0>Github</0>, <0>Git</0> and <0>Dropbox</0> integrations",
+  "github_git_and_dropbox_integrations": "<0>GitHub</0>, <0>Git</0> and <0>Dropbox</0> integrations",
+  "github_git_and_reference_manager_integrations": "GitHub, Git and reference manager integrations",
   "github_git_folder_error": "This project contains a .git folder at the top level, indicating that it is already a git repository. The Overleaf GitHub sync service cannot sync git histories. Please remove the .git folder and try again.",
   "github_integration": "GitHub integration",
   "github_integration_lowercase": "Git and GitHub integration",
@@ -1757,6 +1761,7 @@
   "please_set_main_file": "Please choose the main file for this project in the project menu.  ",
   "please_try_again_in_a_few_moments": "Please try again in a few moments.",
   "please_wait": "Please wait",
+  "plus_additional_collaborators_and_more": "(plus additional collaborators, unlimited AI, track changes, and more).",
   "plus_additional_collaborators_document_history_track_changes_and_more": "(plus additional collaborators, document history, track changes, and more).",
   "plus_more": "plus more",
   "plus_x_additional_licenses_for_a_total_of_y_licenses": "Plus <0>__additionalLicenses__</0> additional license(s) for a total of <1>__count__ licenses</1>",
@@ -2274,7 +2279,7 @@
   "start_by_adding_your_email": "Start by adding your email address.",
   "start_by_fixing_the_first_error_in_your_document": "Start by fixing the first error in the document to avoid cascading problems later on.",
   "start_free_trial": "Start Free Trial!",
-  "start_free_trial_without_exclamation": "Start Free Trial",
+  "start_free_trial_without_exclamation": "Start free trial",
   "start_new_chat": "Start new chat",
   "start_the_conversation_by_saying_hello_or_sharing_an_update": "Start the conversation by saying hello or sharing an update",
   "start_time_utc": "Start time (UTC)",
@@ -2353,6 +2358,8 @@
   "sync_to_dropbox": "Sync to Dropbox",
   "sync_to_github": "Sync to GitHub",
   "sync_with_a_github_repository": "Sync with a GitHub repository.",
+  "sync_with_dropbox": "Sync with Dropbox",
+  "sync_with_github": "Sync with GitHub",
   "synctex_error_recompile_and_try_again": "That didn’t work. Recompile and try again.",
   "synctex_failed": "Couldn’t find the corresponding source file",
   "syntax_checks": "Syntax checks",
@@ -2618,6 +2625,7 @@
   "unknown": "Unknown",
   "unknown_group": "Unknown group",
   "unlimited": "Unlimited",
+  "unlimited_ai": "Unlimited AI",
   "unlimited_ai_use": "Unlimited AI use",
   "unlimited_collaborators_per_project": "Unlimited collaborators per project",
   "unlimited_collabs": "Unlimited collaborators",
@@ -2667,7 +2675,9 @@
   "upgrade_plan": "Upgrade plan",
   "upgrade_summary": "Upgrade summary",
   "upgrade_to_add_more_collaborators_and_access_collaboration_features": "Upgrade to add more collaborators and access collaboration features like track changes and full project history.",
+  "upgrade_to_add_more_collaborators_and_more": "Upgrade to add more collaborators and access features like Overleaf AI, track changes, and full project history.",
   "upgrade_to_get_feature": "Upgrade to get __feature__, plus:",
+  "upgrade_to_get_more_from_overleaf": "Upgrade to get more from Overleaf",
   "upgrade_to_review": "Upgrade to Review",
   "upgrade_your_subscription": "Upgrade your subscription",
   "upload": "Upload",
@@ -2799,6 +2809,7 @@
   "wide": "Wide",
   "will_lose_edit_access_on_date": "Will lose edit access on __date__",
   "will_need_to_log_out_from_and_in_with": "You will need to <b>log out</b> from your <b>__email1__</b> account and then log in with <b>__email2__</b>.",
+  "with_overleaf_subscription_you_also_get": "With an Overleaf subscription you also get",
   "with_premium_subscription_you_also_get": "With an Overleaf Premium subscription you also get",
   "word_count": "Word Count",
   "word_count_lower": "Word count",
@@ -2807,7 +2818,7 @@
   "work_offline": "Work offline",
   "work_offline_pull_to_overleaf": "Work offline, then pull to __appName__",
   "work_or_university_sso": "Work/university single sign-on",
-  "work_with_non_overleaf_users": "Work with non Overleaf users",
+  "work_with_non_overleaf_users": "Work with non-Overleaf users",
   "work_with_other_github_users": "Work with other GitHub users",
   "write_faster_smarter_with_research_ready_ai": "Write faster, smarter and with confidence with research-ready AI",
   "writefull": "Writefull",
@@ -2836,6 +2847,7 @@
   "you_are_on_a_paid_plan_contact_support_to_find_out_more": "You’re on an __appName__ Paid plan. <0>Contact Support</0> to find out more.",
   "you_are_on_x_plan_as_a_confirmed_member_of_institution_y": "You are on our <0>__planName__</0> plan as a <1>confirmed member</1> of <1>__institutionName__</1>",
   "you_are_on_x_plan_as_member_of_group_subscription_y_administered_by_z": "You are on our <0>__planName__</0> plan as a <1>member</1> of the group subscription <1>__groupName__</1> administered by <1>__adminEmail__</1>",
+  "you_are_using_our_free_plan": "You’re using our free plan. Upgrade to get the best Overleaf experience",
   "you_can_also_choose_to_view_anonymously_or_leave_the_project": "You can also choose to <0>view anonymously</0> (you will lose edit access) or <1>leave the project</1>.",
   "you_can_also_right_click_a_file_to_set_it_as_main": "You can also right-click a file to set it as main.",
   "you_can_buy_this_plan_but_not_as_a_trial": "You can buy this plan but not as a trial, as you’ve completed a trial before.",

+ 1 - 1
services/web/locales/nl.json

@@ -186,7 +186,7 @@
   "generic_something_went_wrong": "Sorry, er ging iets fout",
   "get_in_touch": "Contacteer ons",
   "github_commit_message_placeholder": "Bericht voor wijzigingen aangebracht in __appName__...",
-  "github_integration_lowercase": "Github integratie",
+  "github_integration_lowercase": "GitHub integratie",
   "github_is_premium": "GitHubsnychronisatie is een premium functie",
   "github_public_description": "Iedereen kan deze repository zien. Jij kiest wie eraan kan bijdragen.",
   "github_successfully_linked_description": "Bedankt, we hebben je GitHub-account kunnen koppelen aan __appName__. Je kunt nu je __appName__-projecten exporteren naar GitHub, of je projecten vanuit je GitHub repositories importeren.",

+ 1 - 1
services/web/locales/sv.json

@@ -311,7 +311,7 @@
   "github_private_description": "Du kan välja vem som kan se och checka in till detta kodförråd.",
   "github_public_description": "Alla kan se detta repo. Du bestämmer vem som kan commita.",
   "github_successfully_linked_description": "Tack, vi har länkat ditt GitHub konto till __appName__. Du kan du exportera dina __appName__ projekt till GitHub, eller importera projekt från dina GitHub repon.",
-  "github_symlink_error": "Ditt Github-arkiv innehåller symboliska länkfiler som för närvarande inte stöds av Overleaf. Vänligen ta bort dessa och försök igen.",
+  "github_symlink_error": "Ditt GitHub-arkiv innehåller symboliska länkfiler som för närvarande inte stöds av Overleaf. Vänligen ta bort dessa och försök igen.",
   "github_sync": "GitHub Synk",
   "github_sync_description": "Med GitHub synk kan du koppla dina __appName__ projekt till GitHub repon. Skapa nya commits från __appName__ och slå samman commits som har gjorts i offlineläge eller i GitHub.",
   "github_sync_error": "Ett fel uppstod vid kommunikationen med GitHub. Vänligen försök igen om en stund.",

+ 11 - 11
services/web/locales/zh-CN.json

@@ -776,7 +776,7 @@
   "from_enforcement_date": "自 __enforcementDate__ 起,该项目的任何其他编辑者都将成为查看者。",
   "from_external_url": "从外部 URL",
   "from_filename": "从文件 <0>__filename__</0>",
-  "from_github": "从 Github",
+  "from_github": "从 GitHub",
   "from_project_files": "从项目文件中",
   "from_provider": "来自__provider__",
   "from_url": "从 URL 上传",
@@ -823,28 +823,28 @@
   "git_integration_info": "通过Git集成,你可以用Git克隆你的Overleaf项目。有关完整教程, 请阅读 <0>我们的帮助页面</0>。",
   "github": "GitHub",
   "github_commit_message_placeholder": "为 __appName__ 中的更改提交信息",
-  "github_credentials_expired": "您的 Github 授权凭证已过期",
+  "github_credentials_expired": "您的 GitHub 授权凭证已过期",
   "github_empty_repository_error": "您的 GitHub 存储库似乎为空或尚不可用。 在 GitHub.com 上创建一个新文件,然后重试。",
   "github_file_name_error": "无法导入此存储库,因为它包含文件名无效的文件:",
   "github_file_sync_error": "我们无法同步以下文件:",
-  "github_git_and_dropbox_integrations": "<0>Github</0>, <0>Git</0> 与 <0>Dropbox</0> 集成",
-  "github_git_folder_error": "此项目在根目录中包含一个.git文件夹,这说明它已经是git存储库。Overleaf 的 Github 同步服务无法同步 git 历史记录。请删除.git文件夹,然后重试。",
+  "github_git_and_dropbox_integrations": "<0>GitHub</0>, <0>Git</0> 与 <0>Dropbox</0> 集成",
+  "github_git_folder_error": "此项目在根目录中包含一个.git文件夹,这说明它已经是git存储库。Overleaf 的 GitHub 同步服务无法同步 git 历史记录。请删除.git文件夹,然后重试。",
   "github_integration_lowercase": "Git 和 GitHub 支持",
   "github_is_no_longer_connected": "GitHub 已不再链接到此项目。",
   "github_is_premium": "与 GitHub 同步是一项付费功能",
-  "github_large_files_error": "合并失败:您的 Github 存储库包含超过 50mb 文件大小限制的文件 ",
+  "github_large_files_error": "合并失败:您的 GitHub 存储库包含超过 50mb 文件大小限制的文件 ",
   "github_merge_failed": "您对 __appName__ 和 GitHub 的更改无法自动合并。 请手动将<0>__sharelatex_branch__</0>分支合并到git中的默认分支中。 手动合并后,单击下面继续。",
   "github_no_master_branch_error": "无法导入此存储库,因为它缺少主分支。请确保项目有一个主分支",
   "github_private_description": "您可以选择谁可以查看并提交到此存储库。",
   "github_public_description": "任何人都可以看到该存储库。您可以选择谁有权提交。",
   "github_repository_diverged": "已强制推送到链接存储库的主分支。在强制推送之后拉取 GitHub 更改可能会导致 Overleaf 和 GitHub 不同步。您可能需要在拉取后推送更改以恢复同步。",
   "github_successfully_linked_description": "谢谢,您已成功建立了您的GitHub账户与 __appName__ 的关联。您现在可以导出您的 __appName__ 项目到GitHub,或者从您的GitHub存储困导入项目。",
-  "github_symlink_error": "您的Github存储库包含符号链接文件,Overleaf 暂时不支持这些文件。请删除这些文件并重试。",
+  "github_symlink_error": "您的GitHub存储库包含符号链接文件,Overleaf 暂时不支持这些文件。请删除这些文件并重试。",
   "github_sync": "GitHub 同步",
   "github_sync_description": "通过与 GitHub 同步,你可以将您的__appName__项目关联到GitHub的存储库,从 __appName__ 创建新的提交,并与线下或者GitHub中的提交合并。",
   "github_sync_error": "抱歉,与我们的 GitHub 服务连接出错。请稍后重试。",
-  "github_sync_repository_not_found_description": "链接的存储库已被删除,或者您不再有权访问它。通过克隆项目并使用“Github”菜单项,可以设置与新存储库的同步。您还可以取消存储库与此项目的链接。",
-  "github_timeout_error": "将 Overleaf 项目与 Github 同步时超时。这可能是由于项目的总体大小,或者要同步的文件/更改的数量太大。",
+  "github_sync_repository_not_found_description": "链接的存储库已被删除,或者您不再有权访问它。通过克隆项目并使用“GitHub”菜单项,可以设置与新存储库的同步。您还可以取消存储库与此项目的链接。",
+  "github_timeout_error": "将 Overleaf 项目与 GitHub 同步时超时。这可能是由于项目的总体大小,或者要同步的文件/更改的数量太大。",
   "github_too_many_files_error": "无法导入此存储库,因为它超过了允许的最大文件数",
   "github_validation_check": "请检查存储库的名字是否已被占用,且您有权限创建存储库。",
   "github_workflow_authorize": "授权 GitHub 工作流文件",
@@ -918,7 +918,7 @@
   "history_download_this_version": "下载此版本",
   "history_entry_origin_dropbox": "通过 Dropbox",
   "history_entry_origin_git": "通过 Git",
-  "history_entry_origin_github": "通过 Github",
+  "history_entry_origin_github": "通过 GitHub",
   "history_entry_origin_upload": "上传",
   "history_label_created_by": "创建人",
   "history_label_project_current_state": "当前状态",
@@ -2123,7 +2123,7 @@
   "symbol_palette_highlighted": "<0>符号</0> 面板",
   "symbol_palette_info_new": "单击按钮即可将数学符号插入到您的文档中。",
   "sync": "同步",
-  "sync_dropbox_github": "与dropbox或Github同步",
+  "sync_dropbox_github": "与dropbox或GitHub同步",
   "sync_project_to_github_explanation": "您在 __appName__ 中的所有更改将被提交并与 GitHub 中的所有更新合并。",
   "sync_to_dropbox": "同步到 Dropbox",
   "sync_to_github": "同步到 GitHub",
@@ -2380,7 +2380,7 @@
   "unlink_all_users_explanation": "您即将删除组中所有用户的 SSO 登录选项。 如果启用 SSO,这将强制用户使用您的 IdP 重新验证其 Overleaf 帐户。 他们会收到一封电子邮件,要求他们这样做。",
   "unlink_dropbox_folder": "取消 Dropbox 帐户链接",
   "unlink_dropbox_warning": "您与 Dropbox 同步的所有项目都将断开连接,并且不再与 Dropbox 保持同步。 您确定要取消 Dropbox 帐户的关联吗?",
-  "unlink_github_repository": "取消链接 Github 存储库",
+  "unlink_github_repository": "取消链接 GitHub 存储库",
   "unlink_github_warning": "任何您已经同步到GitHub的项目将被切断联系,并且不再保持与GitHub同步。您确定要取消与您的GitHub账户的关联吗?",
   "unlink_linked_accounts": "取消链接任何链接的帐户(例如 ORCID ID、IEEE)。 <0>在“帐户设置”(“关联帐户”下)中将其删除。</0>",
   "unlink_linked_google_account": "取消与您的 Google 帐户的关联。 <0>在“帐户设置”(“关联帐户”下)中将其删除。</0>",

+ 29 - 16
services/web/test/frontend/components/shared/start-free-trial-button.spec.tsx

@@ -1,5 +1,6 @@
 import StartFreeTrialButton from '../../../../frontend/js/shared/components/start-free-trial-button'
 import getMeta from '@/utils/meta'
+import { SplitTestProvider } from '@/shared/context/split-test-context'
 
 describe('start free trial button', function () {
   beforeEach(function () {
@@ -14,7 +15,11 @@ describe('start free trial button', function () {
   })
 
   it('renders the button with default text', function () {
-    cy.mount(<StartFreeTrialButton source="cypress-test" />)
+    cy.mount(
+      <SplitTestProvider>
+        <StartFreeTrialButton source="cypress-test" />
+      </SplitTestProvider>
+    )
 
     cy.wait('@event-paywall-prompt')
       .its('request.body.paywall-type')
@@ -25,9 +30,11 @@ describe('start free trial button', function () {
 
   it('renders the button with custom text', function () {
     cy.mount(
-      <StartFreeTrialButton source="cypress-test">
-        Some Custom Text
-      </StartFreeTrialButton>
+      <SplitTestProvider>
+        <StartFreeTrialButton source="cypress-test">
+          Some Custom Text
+        </StartFreeTrialButton>
+      </SplitTestProvider>
     )
 
     cy.wait('@event-paywall-prompt')
@@ -39,13 +46,15 @@ describe('start free trial button', function () {
 
   it('renders the button with styled button', function () {
     cy.mount(
-      <StartFreeTrialButton
-        source="cypress-test"
-        buttonProps={{
-          variant: 'danger',
-          size: 'lg',
-        }}
-      />
+      <SplitTestProvider>
+        <StartFreeTrialButton
+          source="cypress-test"
+          buttonProps={{
+            variant: 'danger',
+            size: 'lg',
+          }}
+        />
+      </SplitTestProvider>
     )
 
     cy.wait('@event-paywall-prompt')
@@ -55,10 +64,12 @@ describe('start free trial button', function () {
 
   it('renders the button with custom class', function () {
     cy.mount(
-      <StartFreeTrialButton
-        source="cypress-test"
-        buttonProps={{ className: 'ct-test-class' }}
-      />
+      <SplitTestProvider>
+        <StartFreeTrialButton
+          source="cypress-test"
+          buttonProps={{ className: 'ct-test-class' }}
+        />
+      </SplitTestProvider>
     )
 
     cy.wait('@event-paywall-prompt')
@@ -71,7 +82,9 @@ describe('start free trial button', function () {
   it('calls onClick callback and opens a new tab to the subscription page on click', function () {
     const onClickStub = cy.stub()
     cy.mount(
-      <StartFreeTrialButton source="cypress-test" handleClick={onClickStub} />
+      <SplitTestProvider>
+        <StartFreeTrialButton source="cypress-test" handleClick={onClickStub} />
+      </SplitTestProvider>
     )
 
     cy.wait('@event-paywall-prompt')

+ 6 - 1
services/web/test/frontend/features/subscription/components/dashboard/free-plan.test.tsx

@@ -1,9 +1,14 @@
 import { render, screen } from '@testing-library/react'
 import FreePlan from '../../../../../../frontend/js/features/subscription/components/dashboard/free-plan'
+import { SplitTestProvider } from '@/shared/context/split-test-context'
 
 describe('<FreePlan />', function () {
   it('renders free plan dash', function () {
-    render(<FreePlan />)
+    render(
+      <SplitTestProvider>
+        <FreePlan />
+      </SplitTestProvider>
+    )
 
     screen.getByText(
       'You are on the Overleaf Free plan. Upgrade to access these',