Skip to content

Handle OpenApp failure using alert modal#72850

Merged
Valforte merged 9 commits into
Expensify:mainfrom
software-mansion-labs:@GCyganek/handle-open-app-failure
Oct 23, 2025
Merged

Handle OpenApp failure using alert modal#72850
Valforte merged 9 commits into
Expensify:mainfrom
software-mansion-labs:@GCyganek/handle-open-app-failure

Conversation

@GCyganek

@GCyganek GCyganek commented Oct 17, 2025

Copy link
Copy Markdown
Contributor

Explanation of Change

Adding OpenApp request failure handling by:

  1. limiting number of retries for OpenApp to 2 (3 tries in total)
  2. opening an alert modal on OpenApp failure - Refresh and try again button reloads the page on the web, on mobile it closes the modal and tries to connect to OpenApp 3 times again

BUG_BOT alert is also supposed to be triggered, but it is already implemented in src/libs/Middleware/Logging.ts, line 150:

Log.alert(`${CONST.ERROR.ENSURE_BUG_BOT} unknown API request error caught while processing request`, logParams, false);

Currently all OpenApp failures should trigger the alert modal and BUG_BOT alert (if error is not logged differently by logger in src/libs/Middleware/Logging.ts before line 150), not only 404

Fixed Issues

$ #64652
PROPOSAL: N/A

Tests

It's hard to simulate the 404 error other than by changing the OPEN_APP: 'OpenApp' entry in src/libs/API/types.ts (WRITE_COMMANDS object) to an invalid one like OPEN_APP: 'OpenAppx'
Then, you have to open the app and log in to trigger the OpenApp request (if you're logged in, log out and log in again)
After a while it should show the alert modal with error message.

  • Verify that no errors appear in the JS console

Offline tests

QA Steps

Same as tests.

  • Verify that no errors appear in the JS console

PR Author Checklist

  • I linked the correct issue in the ### Fixed Issues section above
  • I wrote clear testing steps that cover the changes made in this PR
    • I added steps for local testing in the Tests section
    • I added steps for the expected offline behavior in the Offline steps section
    • I added steps for Staging and/or Production testing in the QA steps section
    • I added steps to cover failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
    • I tested this PR with a High Traffic account against the staging or production API to ensure there are no regressions (e.g. long loading states that impact usability).
  • I included screenshots or videos for tests on all platforms
  • I ran the tests on all platforms & verified they passed on:
    • Android: Native
    • Android: mWeb Chrome
    • iOS: Native
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
    • MacOS: Desktop
  • I verified there are no console errors (if there's a console error not related to the PR, report it or open an issue for it to be fixed)
  • I verified there are no new alerts related to the canBeMissing param for useOnyx
  • I followed proper code patterns (see Reviewing the code)
    • I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. toggleReport and not onIconClick)
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
    • I verified any copy / text shown in the product is localized by adding it to src/languages/* files and using the translation method
      • If any non-english text was added/modified, I used JaimeGPT to get English > Spanish translation. I then posted it in #expensify-open-source and it was approved by an internal Expensify engineer. Link to Slack message:
    • I verified all numbers, amounts, dates and phone numbers shown in the product are using the localization methods
    • I verified any copy / text that was added to the app is grammatically correct in English. It adheres to proper capitalization guidelines (note: only the first word of header/labels should be capitalized), and is either coming verbatim from figma or has been approved by marketing (in order to get marketing approval, ask the Bug Zero team member to add the Waiting for copy label to the issue)
    • I verified proper file naming conventions were followed for any new files or renamed files. All non-platform specific files are named after what they export and are not named "index.js". All platform-specific files are named for the platform the code supports as outlined in the README.
    • I verified the JSDocs style guidelines (in STYLE.md) were followed
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I followed the guidelines as stated in the Review Guidelines
  • I tested other components that can be impacted by my changes (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar are working as expected)
  • I verified all code is DRY (the PR doesn't include any logic written more than once, with the exception of tests)
  • I verified any variables that can be defined as constants (ie. in CONST.ts or at the top of the file that uses the constant) are defined as such
  • I verified that if a function's arguments changed that all usages have also been updated correctly
  • If any new file was added I verified that:
    • The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory
  • If a new CSS style is added I verified that:
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))
  • If new assets were added or existing ones were modified, I verified that:
    • The assets are optimized and compressed (for SVG files, run npm run compress-svg)
    • The assets load correctly across all supported platforms.
  • If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
  • If the PR modifies the UI (e.g. new buttons, new UI components, changing the padding/spacing/sizing, moving components, etc) or modifies the form input styles:
    • I verified that all the inputs inside a form are aligned with each other.
    • I added Design label and/or tagged @Expensify/design so the design team can review the changes.
  • If a new page is added, I verified it's using the ScrollView component to make it scrollable when more elements are added to the page.
  • I added unit tests for any new feature or bug fix in this PR to help automatically prevent regressions in this user flow.
  • If the main branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the Test steps.

Screenshots/Videos

Android: Native
Screen.Recording.2025-10-17.at.10.41.06.mov
Android: mWeb Chrome
Screen.Recording.2025-10-17.at.10.43.23.mov
iOS: Native
Screen.Recording.2025-10-17.at.10.32.48.mov
iOS: mWeb Safari
Screen.Recording.2025-10-17.at.10.33.42.mov
MacOS: Chrome / Safari
Screen.Recording.2025-10-17.at.09.50.50.mov
MacOS: Desktop
Screen.Recording.2025-10-17.at.09.56.27.mov

@GCyganek GCyganek marked this pull request as ready for review October 20, 2025 07:39
@GCyganek GCyganek requested a review from a team as a code owner October 20, 2025 07:39
@melvin-bot melvin-bot Bot requested review from Ollyws and removed request for a team October 20, 2025 07:39
@melvin-bot

melvin-bot Bot commented Oct 20, 2025

Copy link
Copy Markdown

@Ollyws Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button]

@GCyganek GCyganek marked this pull request as draft October 20, 2025 07:39
@OSBotify

Copy link
Copy Markdown
Contributor

🦜 Polyglot Parrot! 🦜

Squawk! Looks like you added some shiny new English strings. Allow me to parrot them back to you in other tongues:

View the translation diff
diff --git a/src/languages/de.ts b/src/languages/de.ts
index 35ae0c66..b186a792 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -2559,13 +2559,15 @@ ${amount} für ${merchant} - ${date}`,
             splitExpenseTask: {
                 title: 'Teile eine Ausgabe',
                 description:
-                    '*Teile Ausgaben* mit einer oder mehreren Personen.\n\n' +
-                    `1. Klicke auf den ${CONST.CUSTOM_EMOJIS.GLOBAL_CREATE}-Button.\n` +
-                    '2. Wähle *Chat starten*.\n' +
-                    '3. Gib E-Mail-Adressen oder Telefonnummern ein.\n' +
-                    '4. Klicke im Chat auf den grauen *+*-Button > *Ausgabe teilen*.\n' +
-                    '5. Wähle *Manuell*, *Scan* oder *Entfernung*.\n\n' +
-                    'Du kannst Details hinzufügen oder es direkt abschicken. Zeit, dein Geld zurückzubekommen!',
+                    '*Ausgaben aufteilen* mit einer oder mehreren Personen.' +
+                    '\n' +
+                    `1. Klicken Sie auf die Schaltfläche ${CONST.CUSTOM_EMOJIS.GLOBAL_CREATE}.` +
+                    '2. Wählen Sie *Chat starten*.' +
+                    '3. E-Mail-Adressen oder Telefonnummern eingeben..' +
+                    '4. Klicken Sie im Chat auf die graue *+*-Schaltfläche > *Ausgabe aufteilen*.' +
+                    '5. Erstellen Sie die Ausgabe, indem Sie *Manuell*, *Scan* oder *Entfernung* auswählen.' +
+                    '\n' +
+                    'Du kannst bei Bedarf noch weitere Details hinzufügen oder es einfach abschicken. Lass uns dafür sorgen, dass du dein Geld zurückbekommst!',
             },
             reviewWorkspaceSettingsTask: {
                 title: ({workspaceSettingsLink}) => `Überprüfe deine [Workspace-Einstellungen](${workspaceSettingsLink})`,
@@ -4610,7 +4612,7 @@ ${amount} für ${merchant} - ${date}`,
             addShippingDetails: 'Versanddetails hinzufügen',
             issuedCard: ({assignee}: AssigneeParams) => `hat ${assignee} eine Expensify-Karte ausgestellt! Die Karte wird in 2-3 Werktagen ankommen.`,
             issuedCardNoShippingDetails: ({assignee}: AssigneeParams) =>
-                `hat ${assignee} eine Expensify-Karte ausgestellt! Die Karte wird versendet, sobald die Versanddetails hinzugefügt wurden.`,
+                `hat ${assignee} eine Expensify Card ausgestellt! Die Karte wird versandt, sobald die Versanddetails hinzugefügt wurden.`,
             issuedCardVirtual: ({assignee, link}: IssueVirtualCardParams) => `hat ${assignee} eine virtuelle ${link} ausgestellt! Die Karte kann sofort verwendet werden.`,
             addedShippingDetails: ({assignee}: AssigneeParams) => `${assignee} hat Versanddetails hinzugefügt. Die Expensify Card wird in 2-3 Werktagen ankommen.`,
             verifyingHeader: 'Überprüfen',
@@ -5383,12 +5385,12 @@ ${amount} für ${merchant} - ${date}`,
             chooseReconciliationAccount: {
                 chooseBankAccount: 'Wählen Sie das Bankkonto, gegen das Ihre Expensify Card-Zahlungen abgeglichen werden sollen.',
                 accountMatches: 'Stellen Sie sicher, dass dieses Konto mit Ihrem übereinstimmt',
-                settlementAccount: 'Expensify-Kartenabrechnungskonto',
-                reconciliationWorks: ({lastFourPAN}: ReconciliationWorksParams) => `(endend mit ${lastFourPAN}), damit die kontinuierliche Abstimmung ordnungsgemäß funktioniert.`,
+                settlementAccount: 'Abrechnungskonto der Expensify Card',
+                reconciliationWorks: ({lastFourPAN}: ReconciliationWorksParams) => `(endet auf ${lastFourPAN}), damit die kontinuierliche Abstimmung ordnungsgemäß funktioniert.`,
             },
         },
         export: {
-            notReadyHeading: 'Nicht bereit zum Exportieren',
+            notReadyHeading: 'Nicht bereit für den Export',
             notReadyDescription:
                 'Entwürfe oder ausstehende Spesenabrechnungen können nicht in das Buchhaltungssystem exportiert werden. Bitte genehmigen oder begleichen Sie diese Ausgaben, bevor Sie sie exportieren.',
         },
@@ -7328,6 +7330,11 @@ ${amount} für ${merchant} - ${date}`,
         conciergeWillSend: 'Concierge sendet dir die Datei in Kürze.',
     },
     avatarPage: {title: 'Profilbild bearbeiten', uploadPhoto: 'Foto hochladen'},
+    openAppFailureModal: {
+        title: 'Etwas ist schiefgelaufen...',
+        subtitle: `Wir konnten nicht alle Ihre Daten laden. Wir wurden benachrichtigt und untersuchen das Problem. Wenn das weiterhin besteht, wenden Sie sich bitte an`,
+        refreshAndTryAgain: 'Aktualisieren und erneut versuchen',
+    },
 };
 // IMPORTANT: This line is manually replaced in generate translation files by scripts/generateTranslations.ts,
 // so if you change it here, please update it there as well.
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index b2d64347..7c8a5842 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -2555,13 +2555,15 @@ ${amount} pour ${merchant} - ${date}`,
             splitExpenseTask: {
                 title: 'Partager une dépense',
                 description:
-                    '*Partagez une dépense* avec une ou plusieurs personnes.\n\n' +
-                    `1. Cliquez sur le bouton ${CONST.CUSTOM_EMOJIS.GLOBAL_CREATE}.\n` +
-                    '2. Choisissez *Démarrer un chat*.\n' +
-                    '3. Entrez des emails ou numéros de téléphone.\n' +
-                    '4. Cliquez sur le bouton gris *+* > *Partager une dépense*.\n' +
-                    '5. Créez la dépense : *Manuelle*, *Scan*, ou *Distance*.\n\n' +
-                    'Ajoutez plus de détails si vous le souhaitez, ou envoyez simplement. On vous rembourse vite !',
+                    '*Divisez les dépenses* avec une ou plusieurs personnes.' +
+                    '\n' +
+                    `Cliquez sur le bouton ${CONST.CUSTOM_EMOJIS.GLOBAL_CREATE}.` +
+                    '2. Choisissez *Démarrer la discussion*.' +
+                    '3. Saisissez des adresses e-mail ou des numéros de téléphone..' +
+                    '4. Cliquez sur le bouton *+* gris dans la discussion > *Fractionner la dépense*.' +
+                    '5. Créez la dépense en sélectionnant *Manuel*, *Scan* ou *Distance*.' +
+                    '\n' +
+                    'N’hésitez pas à ajouter plus de détails si vous le souhaitez, ou envoyez-le tel quel. Nous allons vous rembourser !',
             },
             reviewWorkspaceSettingsTask: {
                 title: ({workspaceSettingsLink}) => `Vérifiez les [paramètres de l’espace](${workspaceSettingsLink})`,
@@ -4617,7 +4619,7 @@ ${amount} pour ${merchant} - ${date}`,
             addShippingDetails: "Ajouter les détails d'expédition",
             issuedCard: ({assignee}: AssigneeParams) => `a émis une carte Expensify à ${assignee} ! La carte arrivera dans 2-3 jours ouvrables.`,
             issuedCardNoShippingDetails: ({assignee}: AssigneeParams) =>
-                `a émis une carte Expensify à ${assignee} ! La carte sera expédiée une fois que les détails d'expédition seront ajoutés.`,
+                `a attribué une Expensify Card à ${assignee} ! La carte sera expédiée une fois les informations d'expédition ajoutées.`,
             issuedCardVirtual: ({assignee, link}: IssueVirtualCardParams) => `a émis une ${link} virtuelle à ${assignee} ! La carte peut être utilisée immédiatement.`,
             addedShippingDetails: ({assignee}: AssigneeParams) => `${assignee} a ajouté les détails d'expédition. La carte Expensify arrivera dans 2-3 jours ouvrables.`,
             verifyingHeader: 'Vérification en cours',
@@ -5393,7 +5395,7 @@ ${amount} pour ${merchant} - ${date}`,
                 chooseBankAccount: 'Choisissez le compte bancaire sur lequel les paiements de votre carte Expensify seront rapprochés.',
                 accountMatches: 'Assurez-vous que ce compte correspond à votre',
                 settlementAccount: 'Compte de règlement de la carte Expensify',
-                reconciliationWorks: ({lastFourPAN}: ReconciliationWorksParams) => `(terminant par ${lastFourPAN}) afin que la Réconciliation Continue fonctionne correctement.`,
+                reconciliationWorks: ({lastFourPAN}: ReconciliationWorksParams) => `(se terminant par ${lastFourPAN}) afin que la réconciliation continue fonctionne correctement.`,
             },
         },
         export: {
@@ -7331,6 +7333,11 @@ ${amount} pour ${merchant} - ${date}`,
         conciergeWillSend: 'Concierge vous enverra le fichier sous peu.',
     },
     avatarPage: {title: 'Modifier la photo de profil', uploadPhoto: 'Télécharger une photo'},
+    openAppFailureModal: {
+        title: "Quelque chose s'est mal passé...",
+        subtitle: `Nous n'avons pas pu charger toutes vos données. Nous avons été informés et examinons le problème. Si cela persiste, veuillez contacter`,
+        refreshAndTryAgain: 'Actualisez puis réessayez',
+    },
 };
 // IMPORTANT: This line is manually replaced in generate translation files by scripts/generateTranslations.ts,
 // so if you change it here, please update it there as well.
diff --git a/src/languages/it.ts b/src/languages/it.ts
index 86b4fac5..507fb0e9 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -2566,15 +2566,15 @@ ${amount} per ${merchant} - ${date}`,
             splitExpenseTask: {
                 title: 'Dividi una spesa',
                 description:
-                    '*Dividi le spese* con una o più persone.\n' +
+                    '*Dividi le spese* con una o più persone.' +
                     '\n' +
-                    `1. Clicca sul pulsante ${CONST.CUSTOM_EMOJIS.GLOBAL_CREATE}.\n` +
-                    '2. Scegli *Avvia chat*.\n' +
-                    '3. Inserisci email o numeri di telefono.\n' +
-                    '4. Clicca sul pulsante grigio *+* nella chat > *Dividi spesa*.\n' +
-                    '5. Crea la spesa selezionando *Manuale*, *Scansione* o *Distanza*.\n' +
+                    `Fai clic sul pulsante ${CONST.CUSTOM_EMOJIS.GLOBAL_CREATE}.` +
+                    '2. Seleziona *Avvia chat*.' +
+                    '3. Inserisci email o numeri di telefono..' +
+                    '4. Fai clic sul pulsante *+* grigio nella chat > *Dividi spesa*.' +
+                    '5. Crea la spesa selezionando *Manuale*, *Scansione* o *Distanza*.' +
                     '\n' +
-                    'Puoi aggiungere altri dettagli se vuoi, oppure inviarla subito. Recuperiamo i tuoi soldi!',
+                    'Aggiungi pure altri dettagli se vuoi, oppure invialo subito. Facciamo in modo che il rimborso ti arrivi!',
             },
             reviewWorkspaceSettingsTask: {
                 title: ({workspaceSettingsLink}) => `Rivedi le [impostazioni dello spazio di lavoro](${workspaceSettingsLink})`,
@@ -4621,7 +4621,8 @@ ${amount} per ${merchant} - ${date}`,
                 `Se cambi il tipo di limite di questa carta a Mensile, le nuove transazioni verranno rifiutate perché il limite mensile di ${limit} è già stato raggiunto.`,
             addShippingDetails: 'Aggiungi dettagli di spedizione',
             issuedCard: ({assignee}: AssigneeParams) => `ha emesso a ${assignee} una Expensify Card! La carta arriverà in 2-3 giorni lavorativi.`,
-            issuedCardNoShippingDetails: ({assignee}: AssigneeParams) => `ha emesso una Expensify Card per ${assignee}! La carta verrà spedita una volta aggiunti i dettagli di spedizione.`,
+            issuedCardNoShippingDetails: ({assignee}: AssigneeParams) =>
+                `È stata emessa una Expensify Card per ${assignee}! La carta verrà spedita una volta aggiunti i dettagli di spedizione.`,
             issuedCardVirtual: ({assignee, link}: IssueVirtualCardParams) => `ha emesso ${assignee} una ${link} virtuale! La carta può essere utilizzata immediatamente.`,
             addedShippingDetails: ({assignee}: AssigneeParams) => `${assignee} ha aggiunto i dettagli di spedizione. La carta Expensify arriverà in 2-3 giorni lavorativi.`,
             verifyingHeader: 'Verifica in corso',
@@ -5392,8 +5393,8 @@ ${amount} per ${merchant} - ${date}`,
             chooseReconciliationAccount: {
                 chooseBankAccount: 'Scegli il conto bancario su cui verranno riconciliati i pagamenti della tua carta Expensify.',
                 accountMatches: 'Assicurati che questo account corrisponda al tuo',
-                settlementAccount: 'Conto di regolamento della carta Expensify',
-                reconciliationWorks: ({lastFourPAN}: ReconciliationWorksParams) => `(termine con ${lastFourPAN}) affinché la Riconciliazione Continua funzioni correttamente.`,
+                settlementAccount: 'Conto di regolamento per Expensify Card',
+                reconciliationWorks: ({lastFourPAN}: ReconciliationWorksParams) => `(che termina con ${lastFourPAN}) affinché la riconciliazione continua funzioni correttamente.`,
             },
         },
         export: {
@@ -6272,10 +6273,10 @@ ${amount} per ${merchant} - ${date}`,
             reimbursable: 'Rimborsabile',
             purchaseCurrency: 'Valuta di acquisto',
             groupBy: {
-                [CONST.SEARCH.GROUP_BY.REPORTS]: 'Rapporto',
+                [CONST.SEARCH.GROUP_BY.REPORTS]: 'Rendiconto',
                 [CONST.SEARCH.GROUP_BY.FROM]: 'Da',
                 [CONST.SEARCH.GROUP_BY.CARD]: 'Carta',
-                [CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID]: 'ID di prelievo',
+                [CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID]: 'ID prelievo',
             },
             feed: 'Feed',
             withdrawalType: {
@@ -7334,6 +7335,11 @@ ${amount} per ${merchant} - ${date}`,
         conciergeWillSend: 'Concierge ti invierà il file a breve.',
     },
     avatarPage: {title: 'Modifica immagine del profilo', uploadPhoto: 'Carica foto'},
+    openAppFailureModal: {
+        title: 'Qualcosa è andato storto...',
+        subtitle: `Non siamo riusciti a caricare tutti i tuoi dati. Siamo stati avvisati e stiamo esaminando il problema. Se il problema persiste, contatta`,
+        refreshAndTryAgain: 'Aggiorna e riprova',
+    },
 };
 // IMPORTANT: This line is manually replaced in generate translation files by scripts/generateTranslations.ts,
 // so if you change it here, please update it there as well.
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index dd613894..ef50d3e5 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -2555,15 +2555,15 @@ ${date} - ${merchant}に${amount}`,
             splitExpenseTask: {
                 title: '経費を分割する',
                 description:
-                    '*経費を分割する* には、1人または複数の人と共有します。\n' +
+                    '1人以上の相手と*経費を分割*。' +
                     '\n' +
-                    '1. 緑色の*+*ボタンをクリックします。\n' +
-                    '2. *チャットを開始*を選択します。\n' +
-                    '3. メールアドレスまたは電話番号を入力します。\n' +
-                    '4. チャット内の灰色の*+*ボタンをクリック > *経費を分割*。\n' +
-                    '5. *手動* 、*スキャン* 、または*距離*を選択して経費を作成します。\n' +
+                    `1. ${CONST.CUSTOM_EMOJIS.GLOBAL_CREATE} ボタンをクリックします。` +
+                    '2. *チャットを開始* を選択します。' +
+                    '3. メールアドレスまたは電話番号を入力します。' +
+                    '4. チャット内のグレーの*+*ボタンをクリック > *経費を分割*。' +
+                    '5. *手動*、*スキャン*、または*距離*を選択して経費を作成します。' +
                     '\n' +
-                    '必要ならば詳細を追加するか、単に送信します。払い戻しをありましょう!',
+                    '必要なら詳細を追加しても、すぐに送信してもかまいません。精算してもらいましょう!',
             },
             reviewWorkspaceSettingsTask: {
                 title: ({workspaceSettingsLink}) => `[ワークスペース設定](${workspaceSettingsLink})を確認する`,
@@ -4581,11 +4581,11 @@ ${date} - ${merchant}に${amount}`,
                 `このカードの限度額タイプを月次に変更すると、${limit} の月次限度額にすでに達しているため、新しい取引は拒否されます。`,
             addShippingDetails: '配送詳細を追加',
             issuedCard: ({assignee}: AssigneeParams) => `${assignee}にExpensifyカードを発行しました!カードは2~3営業日で到着します。`,
-            issuedCardNoShippingDetails: ({assignee}: AssigneeParams) => `${assignee}にExpensifyカードを発行しました!カードは発送情報が追加され次第、発送されます。`,
+            issuedCardNoShippingDetails: ({assignee}: AssigneeParams) => `${assignee} に Expensify Card を発行しました!配送情報が追加され次第、カードが発送されます。`,
             issuedCardVirtual: ({assignee, link}: IssueVirtualCardParams) => `${assignee}にバーチャル${link}を発行しました!カードはすぐに使用できます。`,
             addedShippingDetails: ({assignee}: AssigneeParams) => `${assignee}が配送情報を追加しました。Expensify Cardは2~3営業日で到着します。`,
             verifyingHeader: '確認中',
-            bankAccountVerifiedHeader: '銀行口座が確認されました',
+            bankAccountVerifiedHeader: '銀行口座は確認済み',
             verifyingBankAccount: '銀行口座を確認しています...',
             verifyingBankAccountDescription: 'このアカウントがExpensifyカードを発行できることを確認するまでお待ちください。',
             bankAccountVerified: '銀行口座が確認されました!',
@@ -5347,8 +5347,8 @@ ${date} - ${merchant}に${amount}`,
             chooseReconciliationAccount: {
                 chooseBankAccount: 'Expensifyカードの支払いを照合する銀行口座を選択してください。',
                 accountMatches: 'このアカウントがあなたのものと一致していることを確認してください',
-                settlementAccount: 'Expensifyカード決済口座',
-                reconciliationWorks: ({lastFourPAN}: ReconciliationWorksParams) => `(${lastFourPAN}で終わる)ため、継続的な調整が正しく機能します。`,
+                settlementAccount: 'Expensify Card の決済口座',
+                reconciliationWorks: ({lastFourPAN}: ReconciliationWorksParams) => `(末尾が${lastFourPAN})にすることで、継続的な照合が正しく機能します。`,
             },
         },
         export: {
@@ -6208,8 +6208,8 @@ ${date} - ${merchant}に${amount}`,
             reimbursable: '払い戻し可能',
             purchaseCurrency: '購入通貨',
             groupBy: {
-                [CONST.SEARCH.GROUP_BY.REPORTS]: '報告',
-                [CONST.SEARCH.GROUP_BY.FROM]: 'から',
+                [CONST.SEARCH.GROUP_BY.REPORTS]: 'レポート',
+                [CONST.SEARCH.GROUP_BY.FROM]: '差出人',
                 [CONST.SEARCH.GROUP_BY.CARD]: 'カード',
                 [CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID]: '出金ID',
             },
@@ -7261,6 +7261,11 @@ ${date} - ${merchant}に${amount}`,
         conciergeWillSend: 'コンシェルジュがまもなくファイルを送信します。',
     },
     avatarPage: {title: 'プロフィール写真を編集', uploadPhoto: '写真をアップロード'},
+    openAppFailureModal: {
+        title: '問題が発生しました...',
+        subtitle: `すべてのデータを読み込むことができませんでした。通知を受けており、問題を調査しています。この状態が続く場合は、お問い合わせください。`,
+        refreshAndTryAgain: '再読み込みして、もう一度お試しください',
+    },
 };
 // IMPORTANT: This line is manually replaced in generate translation files by scripts/generateTranslations.ts,
 // so if you change it here, please update it there as well.
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index 7ef50bec..0575861d 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -2567,15 +2567,15 @@ ${amount} voor ${merchant} - ${date}`,
             splitExpenseTask: {
                 title: 'Splits een uitgave',
                 description:
-                    '*Splits uitgaven* met één of meer personen.\n' +
+                    '*Splits uitgaven* met één of meer personen.' +
                     '\n' +
-                    `1. Klik op de ${CONST.CUSTOM_EMOJIS.GLOBAL_CREATE}-knop.\n` +
-                    '2. Kies *Start chat*.\n' +
-                    '3. Voer e-mailadressen of telefoonnummers in.\n' +
-                    '4. Klik op de grijze *+*-knop in de chat > *Splits uitgave*.\n' +
-                    '5. Maak de uitgave aan door *Handmatig*, *Scannen* of *Afstand* te selecteren.\n' +
+                    `1. Klik op de knop ${CONST.CUSTOM_EMOJIS.GLOBAL_CREATE}.` +
+                    '2. Selecteer *Chat starten*.' +
+                    '3. Voer e-mailadressen of telefoonnummers in..' +
+                    '4. Klik op de grijze *+*-knop in de chat > *Uitgave splitsen*.' +
+                    '5. Maak de uitgave aan door *Handmatig*, *Scan* of *Afstand* te selecteren.' +
                     '\n' +
-                    'Voeg gerust meer details toe als u wilt, of stuur het gewoon op. Laten we ervoor zorgen dat u wordt terugbetaald!',
+                    'Voel je vrij om meer details toe te voegen als je wilt, of stuur het gewoon in. Laten we ervoor zorgen dat je je geld terugkrijgt!',
             },
             reviewWorkspaceSettingsTask: {
                 title: ({workspaceSettingsLink}) => `Bekijk uw [werkruimte-instellingen](${workspaceSettingsLink})`,
@@ -4619,8 +4619,7 @@ ${amount} voor ${merchant} - ${date}`,
                 `Als je het limiettype van deze kaart wijzigt naar Maandelijks, worden nieuwe transacties geweigerd omdat de maandelijkse limiet van ${limit} al is bereikt.`,
             addShippingDetails: 'Verzendgegevens toevoegen',
             issuedCard: ({assignee}: AssigneeParams) => `heeft ${assignee} een Expensify Card uitgegeven! De kaart zal binnen 2-3 werkdagen arriveren.`,
-            issuedCardNoShippingDetails: ({assignee}: AssigneeParams) =>
-                `heeft ${assignee} een Expensify Card uitgegeven! De kaart wordt verzonden zodra de verzendgegevens zijn toegevoegd.`,
+            issuedCardNoShippingDetails: ({assignee}: AssigneeParams) => `heeft ${assignee} een Expensify Card verstrekt! De kaart wordt verzonden zodra de verzendgegevens zijn toegevoegd.`,
             issuedCardVirtual: ({assignee, link}: IssueVirtualCardParams) => `heeft ${assignee} een virtuele ${link} uitgegeven! De kaart kan direct worden gebruikt.`,
             addedShippingDetails: ({assignee}: AssigneeParams) => `${assignee} heeft verzendgegevens toegevoegd. Expensify Card zal binnen 2-3 werkdagen arriveren.`,
             verifyingHeader: 'Verifiëren',
@@ -5386,13 +5385,13 @@ ${amount} voor ${merchant} - ${date}`,
                 `<muted-text-label>Om continue afstemming mogelijk te maken, moet u <a href="${accountingAdvancedSettingsLink}">automatische synchronisatie</a> voor ${connectionName} inschakelen.</muted-text-label>`,
             chooseReconciliationAccount: {
                 chooseBankAccount: 'Kies de bankrekening waarmee uw Expensify Card-betalingen worden verrekend.',
-                accountMatches: 'Zorg ervoor dat dit account overeenkomt met uw',
-                settlementAccount: 'Expensify Card afwikkelingsrekening',
-                reconciliationWorks: ({lastFourPAN}: ReconciliationWorksParams) => `(eindigend op ${lastFourPAN}) zodat Continue Reconciliation goed werkt.`,
+                accountMatches: 'Zorg ervoor dat deze account overeenkomt met je',
+                settlementAccount: 'Expensify Card-afwikkelingsrekening',
+                reconciliationWorks: ({lastFourPAN}: ReconciliationWorksParams) => `(eindigend op ${lastFourPAN}) zodat Doorlopende Afstemming naar behoren werkt.`,
             },
         },
         export: {
-            notReadyHeading: 'Niet klaar om te exporteren',
+            notReadyHeading: 'Nog niet klaar om te exporteren',
             notReadyDescription:
                 'Concept- of in behandeling zijnde onkostendeclaraties kunnen niet naar het boekhoudsysteem worden geëxporteerd. Keur deze onkosten goed of betaal ze voordat u ze exporteert.',
         },
@@ -6258,7 +6257,7 @@ ${amount} voor ${merchant} - ${date}`,
             reimbursable: 'Vergoedbaar',
             purchaseCurrency: 'Aankoopvaluta',
             groupBy: {
-                [CONST.SEARCH.GROUP_BY.REPORTS]: 'Verslag',
+                [CONST.SEARCH.GROUP_BY.REPORTS]: 'Rapport',
                 [CONST.SEARCH.GROUP_BY.FROM]: 'Van',
                 [CONST.SEARCH.GROUP_BY.CARD]: 'Kaart',
                 [CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID]: 'Opname-ID',
@@ -7317,6 +7316,11 @@ ${amount} voor ${merchant} - ${date}`,
         conciergeWillSend: 'Concierge stuurt je het bestand binnenkort.',
     },
     avatarPage: {title: 'Profielfoto bewerken', uploadPhoto: 'Foto uploaden'},
+    openAppFailureModal: {
+        title: 'Er is iets misgegaan...',
+        subtitle: `We hebben niet al uw gegevens kunnen laden. We zijn op de hoogte gesteld en onderzoeken het probleem. Als dit aanhoudt, neem dan contact op met`,
+        refreshAndTryAgain: 'Vernieuw en probeer het opnieuw',
+    },
 };
 // IMPORTANT: This line is manually replaced in generate translation files by scripts/generateTranslations.ts,
 // so if you change it here, please update it there as well.
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index 687f503b..484a1717 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -2561,15 +2561,15 @@ ${amount} dla ${merchant} - ${date}`,
             splitExpenseTask: {
                 title: 'Splits een uitgave',
                 description:
-                    '*Splits uitgaven* met één of meer personen.\n' +
+                    '*Podziel wydatki* z jedną lub kilkoma osobami.' +
                     '\n' +
-                    `1. Klik op de ${CONST.CUSTOM_EMOJIS.GLOBAL_CREATE}-knop.\n` +
-                    '2. Kies *Start chat*.\n' +
-                    '3. Voer e-mailadressen of telefoonnummers in.\n' +
-                    '4. Klik op de grijze *+*-knop in de chat > *Splits uitgave*.\n' +
-                    '5. Maak de uitgave aan door *Handmatig*, *Scannen* of *Afstand* te selecteren.\n' +
+                    `1. Kliknij przycisk ${CONST.CUSTOM_EMOJIS.GLOBAL_CREATE}.` +
+                    '2. Wybierz *Rozpocznij czat*.' +
+                    '3. Wprowadź adresy e-mail lub numery telefonów..' +
+                    '4. Kliknij szary przycisk *+* na czacie > *Podziel wydatek*.' +
+                    '5. Utwórz wydatek, wybierając *Manual*, *Scan* lub *Distance*.' +
                     '\n' +
-                    'Voeg gerust meer details toe als u wilt, of stuur het gewoon op. Laten we ervoor zorgen dat u wordt terugbetaald!',
+                    'Jeśli chcesz, dodaj więcej szczegółów albo po prostu wyślij. Zadbajmy o to, żebyś otrzymał(a) zwrot!',
             },
             reviewWorkspaceSettingsTask: {
                 title: ({workspaceSettingsLink}) => `Bekijk uw [werkruimte-instellingen](${workspaceSettingsLink})`,
@@ -4606,11 +4606,11 @@ ${amount} dla ${merchant} - ${date}`,
                 `Jeśli zmienisz typ limitu tej karty na Miesięczny, nowe transakcje zostaną odrzucone, ponieważ miesięczny limit ${limit} został już osiągnięty.`,
             addShippingDetails: 'Dodaj szczegóły wysyłki',
             issuedCard: ({assignee}: AssigneeParams) => `wydano ${assignee} kartę Expensify! Karta dotrze w ciągu 2-3 dni roboczych.`,
-            issuedCardNoShippingDetails: ({assignee}: AssigneeParams) => `wydano ${assignee} kartę Expensify! Karta zostanie wysłana, gdy zostaną dodane szczegóły wysyłki.`,
+            issuedCardNoShippingDetails: ({assignee}: AssigneeParams) => `Wydano ${assignee} kartę Expensify! Karta zostanie wysłana po dodaniu szczegółów wysyłki.`,
             issuedCardVirtual: ({assignee, link}: IssueVirtualCardParams) => `wydano ${assignee} wirtualną ${link}! Karta może być używana od razu.`,
             addedShippingDetails: ({assignee}: AssigneeParams) => `${assignee} dodał szczegóły wysyłki. Karta Expensify dotrze w ciągu 2-3 dni roboczych.`,
             verifyingHeader: 'Weryfikacja',
-            bankAccountVerifiedHeader: 'Zweryfikowano konto bankowe',
+            bankAccountVerifiedHeader: 'Konto bankowe zweryfikowane',
             verifyingBankAccount: 'Weryfikacja konta bankowego...',
             verifyingBankAccountDescription: 'Proszę czekać, podczas gdy potwierdzamy, że to konto może być używane do wydawania kart Expensify.',
             bankAccountVerified: 'Konto bankowe zweryfikowane!',
@@ -5374,13 +5374,13 @@ ${amount} dla ${merchant} - ${date}`,
                 `<muted-text-label>Aby włączyć funkcję ciągłego uzgadniania, włącz <a href="${accountingAdvancedSettingsLink}">automatyczną synchronizację</a> dla ${connectionName}.</muted-text-label>`,
             chooseReconciliationAccount: {
                 chooseBankAccount: 'Wybierz konto bankowe, z którym będą uzgadniane płatności kartą Expensify.',
-                accountMatches: 'Upewnij się, że to konto pasuje do Twojego',
+                accountMatches: 'Upewnij się, że to konto odpowiada Twojemu',
                 settlementAccount: 'Konto rozliczeniowe karty Expensify',
-                reconciliationWorks: ({lastFourPAN}: ReconciliationWorksParams) => `(kończący się na ${lastFourPAN}), aby Ciągła Rekonsyliacja działała poprawnie.`,
+                reconciliationWorks: ({lastFourPAN}: ReconciliationWorksParams) => `(kończący się na ${lastFourPAN}), aby Ciągłe uzgadnianie działało poprawnie.`,
             },
         },
         export: {
-            notReadyHeading: 'Nie gotowy do eksportu',
+            notReadyHeading: 'Nie gotowe do eksportu',
             notReadyDescription: 'Robocze lub oczekujące raporty wydatków nie mogą być eksportowane do systemu księgowego. Proszę zatwierdzić lub opłacić te wydatki przed ich eksportem.',
         },
         invoices: {
@@ -6246,7 +6246,7 @@ ${amount} dla ${merchant} - ${date}`,
                 [CONST.SEARCH.GROUP_BY.REPORTS]: 'Raport',
                 [CONST.SEARCH.GROUP_BY.FROM]: 'Od',
                 [CONST.SEARCH.GROUP_BY.CARD]: 'Karta',
-                [CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID]: 'Identyfikator wypłaty',
+                [CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID]: 'ID wypłaty', //_/\__/_/  \_,_/\__/\__/\_,_/
             },
             feed: 'Kanal',
             withdrawalType: {
@@ -7303,6 +7303,11 @@ ${amount} dla ${merchant} - ${date}`,
         conciergeWillSend: 'Concierge wkrótce prześle plik.',
     },
     avatarPage: {title: 'Edytuj zdjęcie profilowe', uploadPhoto: 'Prześlij zdjęcie'},
+    openAppFailureModal: {
+        title: 'Coś poszło nie tak...',
+        subtitle: `Nie udało nam się wczytać wszystkich Twoich danych. Zostaliśmy o tym powiadomieni i badamy problem. Jeśli problem będzie się utrzymywał, skontaktuj się z`,
+        refreshAndTryAgain: 'Odśwież i spróbuj ponownie',
+    },
 };
 // IMPORTANT: This line is manually replaced in generate translation files by scripts/generateTranslations.ts,
 // so if you change it here, please update it there as well.
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index 40396c93..c98c17c4 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -2559,15 +2559,15 @@ ${amount} para ${merchant} - ${date}`,
             splitExpenseTask: {
                 title: 'Dividir uma despesa',
                 description:
-                    '*Divida despesas* com uma ou mais pessoas.\n' +
+                    '*Divida despesas* com uma ou mais pessoas.' +
                     '\n' +
-                    `1. Clique no botão ${CONST.CUSTOM_EMOJIS.GLOBAL_CREATE}.\n` +
-                    '2. Escolha *Iniciar bate-papo*.\n' +
-                    '3. Insira e-mails ou números de telefone.\n' +
-                    '4. Clique no botão cinza *+* no bate-papo > *Dividir despesa*.\n' +
-                    '5. Crie a despesa selecionando *Manual*, *Digitalizar* ou *Distância*.\n' +
+                    `Clique no botão ${CONST.CUSTOM_EMOJIS.GLOBAL_CREATE}.` +
+                    '2. Selecione *Iniciar chat*.' +
+                    '3. Insira e-mails ou números de telefone..' +
+                    '4. Clique no botão cinza *+* no chat > *Dividir despesa*.' +
+                    '5. Crie a despesa selecionando *Manual*, *Digitalizar* ou *Distância*.' +
                     '\n' +
-                    'Sinta-se à vontade para adicionar mais detalhes, se quiser, ou apenas envie. Vamos te reembolsar!',
+                    'Sinta-se à vontade para adicionar mais detalhes, se quiser, ou apenas enviar. Vamos garantir o seu reembolso!',
             },
             reviewWorkspaceSettingsTask: {
                 title: ({workspaceSettingsLink}) => `Revise suas [configurações de espaço de trabalho](${workspaceSettingsLink})`,
@@ -4607,7 +4607,7 @@ ${amount} para ${merchant} - ${date}`,
             addShippingDetails: 'Adicionar detalhes de envio',
             issuedCard: ({assignee}: AssigneeParams) => `emitiu um Cartão Expensify para ${assignee}! O cartão chegará em 2-3 dias úteis.`,
             issuedCardNoShippingDetails: ({assignee}: AssigneeParams) =>
-                `emitiu um Cartão Expensify para ${assignee}! O cartão será enviado assim que os detalhes de envio forem adicionados.`,
+                `Emitimos um Expensify Card para ${assignee}! O cartão será enviado assim que as informações de envio forem adicionadas.`,
             issuedCardVirtual: ({assignee, link}: IssueVirtualCardParams) => `emitiu ${assignee} um ${link} virtual! O cartão pode ser usado imediatamente.`,
             addedShippingDetails: ({assignee}: AssigneeParams) => `${assignee} adicionou os detalhes de envio. O Cartão Expensify chegará em 2-3 dias úteis.`,
             verifyingHeader: 'Verificando',
@@ -5376,9 +5376,9 @@ ${amount} para ${merchant} - ${date}`,
                 `<muted-text-label>Para ativar a reconciliação contínua, habilite a <a href="${accountingAdvancedSettingsLink}">sincronização automática</a> para o ${connectionName}.</muted-text-label>`,
             chooseReconciliationAccount: {
                 chooseBankAccount: 'Escolha a conta bancária na qual os pagamentos do seu Expensify Card serão reconciliados.',
-                accountMatches: 'Certifique-se de que esta conta corresponde à sua',
+                accountMatches: 'Certifique-se de que esta conta corresponda à sua',
                 settlementAccount: 'Conta de liquidação do Cartão Expensify',
-                reconciliationWorks: ({lastFourPAN}: ReconciliationWorksParams) => `(terminando em ${lastFourPAN}) para que a Reconciliação Contínua funcione corretamente.`,
+                reconciliationWorks: ({lastFourPAN}: ReconciliationWorksParams) => `(terminando em ${lastFourPAN}) para que a Conciliação Contínua funcione corretamente.`,
             },
         },
         export: {
@@ -6255,7 +6255,7 @@ ${amount} para ${merchant} - ${date}`,
                 [CONST.SEARCH.GROUP_BY.REPORTS]: 'Relatório',
                 [CONST.SEARCH.GROUP_BY.FROM]: 'De',
                 [CONST.SEARCH.GROUP_BY.CARD]: 'Cartão',
-                [CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID]: 'ID de retirada',
+                [CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID]: 'ID do saque',
             },
             feed: 'Feed',
             withdrawalType: {
@@ -7311,6 +7311,11 @@ ${amount} para ${merchant} - ${date}`,
         conciergeWillSend: 'Concierge enviará o arquivo em breve.',
     },
     avatarPage: {title: 'Editar foto de perfil', uploadPhoto: 'Carregar foto'},
+    openAppFailureModal: {
+        title: 'Algo deu errado...',
+        subtitle: `Não conseguimos carregar todos os seus dados. Fomos notificados e estamos investigando o problema. Se isso persistir, entre em contato com`,
+        refreshAndTryAgain: 'Atualize e tente novamente',
+    },
 };
 // IMPORTANT: This line is manually replaced in generate translation files by scripts/generateTranslations.ts,
 // so if you change it here, please update it there as well.
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index c3af5934..a2b26ebe 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -2532,15 +2532,15 @@ ${merchant}的${amount} - ${date}`,
             splitExpenseTask: {
                 title: '拆分支出',
                 description:
-                    '*与一个或多个人拆分支出*。\n' +
+                    '与一人或多人*分摊费用*。' +
                     '\n' +
-                    '1. 点击绿色的 *+* 按钮。\n' +
-                    '2. 选择 *开始聊天*。\n' +
-                    '3. 输入电子邮件或电话号码。\n' +
-                    '4. 点击聊天中的灰色 *+* 按钮 > *拆分支出*。\n' +
-                    '5. 通过选择 *手动*、*扫描*或 *距离*创建支出。\n' +
+                    `1. 点击${CONST.CUSTOM_EMOJIS.GLOBAL_CREATE}按钮。` +
+                    '2. 选择*开始聊天*。' +
+                    '3. 输入电子邮件地址或电话号码..' +
+                    '4. 在聊天中点击灰色的*+*按钮 > *拆分费用*。' +
+                    '5. 通过选择*手动*、*扫描*或*距离*来创建该费用。' +
                     '\n' +
-                    '如有需要,随意添加更多详情,或直接发送。让我们让您获得报销!',
+                    '如果你愿意,可以随意添加更多细节,或者直接发送。让我们尽快让你拿到报销款!',
             },
             reviewWorkspaceSettingsTask: {
                 title: ({workspaceSettingsLink}) => `查看您的[工作区设置](${workspaceSettingsLink})`,
@@ -4525,7 +4525,7 @@ ${merchant}的${amount} - ${date}`,
             changeCardMonthlyLimitTypeWarning: ({limit}: CharacterLimitParams) => `如果您将此卡的限额类型更改为每月,由于已达到${limit}的每月限额,新交易将被拒绝。`,
             addShippingDetails: '添加运输详情',
             issuedCard: ({assignee}: AssigneeParams) => `已为${assignee}发放了一张Expensify卡!该卡将在2-3个工作日内送达。`,
-            issuedCardNoShippingDetails: ({assignee}: AssigneeParams) => `已为${assignee}发放了一张Expensify卡!一旦添加了运送详情,卡片将被寄出。`,
+            issuedCardNoShippingDetails: ({assignee}: AssigneeParams) => `已为${assignee}发放了一张 Expensify Card!添加邮寄信息后,该卡将会寄出。`,
             issuedCardVirtual: ({assignee, link}: IssueVirtualCardParams) => `已向${assignee}发放了一张虚拟${link}!该卡可以立即使用。`,
             addedShippingDetails: ({assignee}: AssigneeParams) => `${assignee} 添加了送货详情。Expensify Card 将在2-3个工作日内送达。`,
             verifyingHeader: '验证中',
@@ -5285,15 +5285,12 @@ ${merchant}的${amount} - ${date}`,
                 `<muted-text-label>要启用持续对账,请启用 ${connectionName} 的<a href="${accountingAdvancedSettingsLink}">自动同步</a>功能。</muted-text-label>`,
             chooseReconciliationAccount: {
                 chooseBankAccount: '选择用于对账您的 Expensify Card 支付的银行账户。',
-                accountMatches: '确保此账户与您的账户匹配',
+                accountMatches: '请确保此账户与您的相匹配',
                 settlementAccount: 'Expensify Card 结算账户',
-                reconciliationWorks: ({lastFourPAN}: ReconciliationWorksParams) => `(以 ${lastFourPAN} 结尾)以便持续对账正常工作。`,
+                reconciliationWorks: ({lastFourPAN}: ReconciliationWorksParams) => `(以${lastFourPAN}结尾),以便持续对账正常工作。`,
             },
         },
-        export: {
-            notReadyHeading: '尚未准备好导出',
-            notReadyDescription: '草稿或待处理的费用报告无法导出到会计系统。请在导出之前批准或支付这些费用。',
-        },
+        export: {notReadyHeading: '尚未准备好导出', notReadyDescription: '草稿或待处理的费用报告无法导出到会计系统。请在导出之前批准或支付这些费用。'},
         invoices: {
             sendInvoice: '发送发票',
             sendFrom: '发送自',
@@ -6130,10 +6127,11 @@ ${merchant}的${amount} - ${date}`,
             reimbursable: '可报销的',
             purchaseCurrency: '购买货币',
             groupBy: {
-                [CONST.SEARCH.GROUP_BY.REPORTS]: '报告',
-                [CONST.SEARCH.GROUP_BY.FROM]: '从',
-                [CONST.SEARCH.GROUP_BY.CARD]: '卡片',
-                [CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID]: '提现ID',
+                [CONST.SEARCH.GROUP_BY.REPORTS]: '报销单',
+                [CONST.SEARCH.GROUP_BY.FROM]: '来自',
+                //_/\__/_/  \_,_/\__/\__/\_,_/
+                [CONST.SEARCH.GROUP_BY.CARD]: '卡',
+                [CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID]: '提现 ID',
             },
             feed: '通道',
             withdrawalType: {
@@ -7166,6 +7164,7 @@ ${merchant}的${amount} - ${date}`,
         conciergeWillSend: 'Concierge 很快会将文件发送给您。',
     },
     avatarPage: {title: '编辑个人资料图片', uploadPhoto: '上传照片'},
+    openAppFailureModal: {title: '出了点问题...', subtitle: `我们未能加载您的所有数据。我们已收到通知,正在调查此问题。如果问题仍然存在,请联系`, refreshAndTryAgain: '刷新并重试'},
 };
 // IMPORTANT: This line is manually replaced in generate translation files by scripts/generateTranslations.ts,
 // so if you change it here, please update it there as well.

Note

You can apply these changes to your branch by copying the patch to your clipboard, then running pbpaste | git apply 😉

@codecov

codecov Bot commented Oct 20, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 66.66667% with 11 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/components/OpenAppFailureModal/index.tsx 0.00% 4 Missing ⚠️
...rc/components/OpenAppFailureModal/index.native.tsx 57.14% 3 Missing ⚠️
src/libs/Network/SequentialQueue.ts 0.00% 2 Missing ⚠️
src/libs/actions/isOpenAppFailureModalOpen.ts 0.00% 2 Missing ⚠️
Files with missing lines Coverage Δ
src/CONST/index.ts 85.84% <ø> (ø)
src/ONYXKEYS.ts 100.00% <ø> (ø)
...ts/OpenAppFailureModal/BaseOpenAppFailureModal.tsx 100.00% <100.00%> (ø)
src/libs/Navigation/AppNavigator/AuthScreens.tsx 53.58% <ø> (ø)
src/libs/RequestThrottle.ts 93.33% <100.00%> (+0.22%) ⬆️
src/setup/index.ts 100.00% <ø> (ø)
src/libs/Network/SequentialQueue.ts 84.86% <0.00%> (-0.93%) ⬇️
src/libs/actions/isOpenAppFailureModalOpen.ts 0.00% <0.00%> (ø)
...rc/components/OpenAppFailureModal/index.native.tsx 57.14% <57.14%> (ø)
src/components/OpenAppFailureModal/index.tsx 0.00% <0.00%> (ø)

... and 16 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@jnowakow jnowakow left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 💯

@GCyganek GCyganek marked this pull request as ready for review October 21, 2025 15:30
@Ollyws

Ollyws commented Oct 23, 2025

Copy link
Copy Markdown
Contributor

Reviewer Checklist

  • I have verified the author checklist is complete (all boxes are checked off).
  • I verified the correct issue is linked in the ### Fixed Issues section above
  • I verified testing steps are clear and they cover the changes made in this PR
    • I verified the steps for local testing are in the Tests section
    • I verified the steps for Staging and/or Production testing are in the QA steps section
    • I verified the steps cover any possible failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
  • I checked that screenshots or videos are included for tests on all platforms
  • I included screenshots or videos for tests on all platforms
  • I verified that the composer does not automatically focus or open the keyboard on mobile unless explicitly intended. This includes checking that returning the app from the background does not unexpectedly open the keyboard.
  • I verified tests pass on all platforms & I tested again on:
    • Android: HybridApp
    • Android: mWeb Chrome
    • iOS: HybridApp
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
    • MacOS: Desktop
  • If there are any errors in the console that are unrelated to this PR, I either fixed them (preferred) or linked to where I reported them in Slack
  • I verified there are no new alerts related to the canBeMissing param for useOnyx
  • I verified proper code patterns were followed (see Reviewing the code)
    • I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. toggleReport and not onIconClick).
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
    • I verified any copy / text shown in the product is localized by adding it to src/languages/* files and using the translation method
    • I verified all numbers, amounts, dates and phone numbers shown in the product are using the localization methods
    • I verified any copy / text that was added to the app is grammatically correct in English. It adheres to proper capitalization guidelines (note: only the first word of header/labels should be capitalized), and is either coming verbatim from figma or has been approved by marketing (in order to get marketing approval, ask the Bug Zero team member to add the Waiting for copy label to the issue)
    • I verified proper file naming conventions were followed for any new files or renamed files. All non-platform specific files are named after what they export and are not named "index.js". All platform-specific files are named for the platform the code supports as outlined in the README.
    • I verified the JSDocs style guidelines (in STYLE.md) were followed
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I verified that this PR follows the guidelines as stated in the Review Guidelines
  • I verified other components that can be impacted by these changes have been tested, and I retested again (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar have been tested & I retested again)
  • I verified all code is DRY (the PR doesn't include any logic written more than once, with the exception of tests)
  • I verified any variables that can be defined as constants (ie. in CONST.ts or at the top of the file that uses the constant) are defined as such
  • If a new component is created I verified that:
    • A similar component doesn't exist in the codebase
    • All props are defined accurately and each prop has a /** comment above it */
    • The file is named correctly
    • The component has a clear name that is non-ambiguous and the purpose of the component can be inferred from the name alone
    • The only data being stored in the state is data necessary for rendering and nothing else
    • For Class Components, any internal methods passed to components event handlers are bound to this properly so there are no scoping issues (i.e. for onClick={this.submit} the method this.submit should be bound to this in the constructor)
    • Any internal methods bound to this are necessary to be bound (i.e. avoid this.submit = this.submit.bind(this); if this.submit is never passed to a component event handler like onClick)
    • All JSX used for rendering exists in the render method
    • The component has the minimum amount of code necessary for its purpose, and it is broken down into smaller components in order to separate concerns and functions
  • If any new file was added I verified that:
    • The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory
  • If a new CSS style is added I verified that:
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(theme.componentBG)
  • If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
  • If the PR modifies the UI (e.g. new buttons, new UI components, changing the padding/spacing/sizing, moving components, etc) or modifies the form input styles:
    • I verified that all the inputs inside a form are aligned with each other.
    • I added Design label and/or tagged @Expensify/design so the design team can review the changes.
  • If a new page is added, I verified it's using the ScrollView component to make it scrollable when more elements are added to the page.
  • For any bug fix or new feature in this PR, I verified that sufficient unit tests are included to prevent regressions in this flow.
  • If the main branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the Test steps.
  • I have checked off every checkbox in the PR reviewer checklist, including those that don't apply to this PR.

Screenshots/Videos

Android: HybridApp
01_Android_Native.mp4
Android: mWeb Chrome
02_Android_Chrome.mp4
iOS: HybridApp
03_iOS_Native.mp4
iOS: mWeb Safari
04_iOS_Safari.mp4
MacOS: Chrome / Safari
05_MacOS_Chrome.mp4
MacOS: Desktop
06_MacOS_Desktop.mp4

@Ollyws Ollyws left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's hard to simulate the 404 error other than by changing the OPEN_APP: 'OpenApp' entry in src/libs/API/types.ts (WRITE_COMMANDS object) to an invalid one like OPEN_APP: 'OpenAppx'

I could only test like this but LGTM.

@melvin-bot

melvin-bot Bot commented Oct 23, 2025

Copy link
Copy Markdown

We did not find an internal engineer to review this PR, trying to assign a random engineer to #64652 as well as to this PR... Please reach out for help on Slack if no one gets assigned!

@melvin-bot melvin-bot Bot requested a review from Valforte October 23, 2025 10:40
@Valforte Valforte merged commit 0b9723f into Expensify:main Oct 23, 2025
27 checks passed
@OSBotify

Copy link
Copy Markdown
Contributor

✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release.

@kavimuru

Copy link
Copy Markdown

@GCyganek can you help with QA steps how to test this PR?

@OSBotify

Copy link
Copy Markdown
Contributor

🚀 Deployed to staging by https://github.com/Valforte in version: 9.2.38-0 🚀

platform result
🖥 desktop 🖥 success ✅
🕸 web 🕸 success ✅
🤖 android 🤖 success ✅
🍎 iOS 🍎 success ✅

@kavimuru

Copy link
Copy Markdown

@GCyganek #72850 (comment)

@Ollyws @Valforte @Could you help with QA steps?

@GCyganek

Copy link
Copy Markdown
Contributor Author

@Valforte do you have any idea for testing this without changing the code to have OpenApp request failing?

@kavimuru the only possible way I've just found is opening DevTools and in the Network tab, searching for the OpenApp request, right-click on it and click on Block request URL. Remember to log out and log in, because OpenApp request is triggered after logging in.

Screenshot 2025-10-27 at 13 07 46

After blocking the request URL log out and log in again to trigger OpenApp request, now it should fail and you will see the alert modal with error message and Refresh and Close buttons.

@OSBotify

Copy link
Copy Markdown
Contributor

🚀 Deployed to production by https://github.com/puneetlath in version: 9.2.38-5 🚀

platform result
🖥 desktop 🖥 success ✅
🕸 web 🕸 success ✅
🤖 android 🤖 success ✅
🍎 iOS 🍎 success ✅

@Valforte

Copy link
Copy Markdown
Contributor

I believe @GCyganek approach here is the easiest. I couldnt think of anything else so I ask ChatGPT how to test a request failing and it gave the exact solution @GCyganek commented above, along with two other way more convoluted that I would stray away from. LMK if further help is needed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants