Skip to content

Clarify which transactions are deleted when removing or unassigning a card - #103945

Open
MelvinBot wants to merge 2 commits into
mainfrom
claude-clarifyRemoveCardWarningCopy
Open

MelvinBot wants to merge 2 commits into
mainfrom
claude-clarifyRemoveCardWarningCopy

Conversation

@MelvinBot

@MelvinBot MelvinBot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Explanation of Change

The warnings for removing a personal card and unassigning company cards (single or bulk) only said "unsubmitted transactions" would be deleted. Customers didn't realize this included expenses on draft reports, or that the deletion is permanent.

This PR updates the three warning strings to the copy approved in the issue:

  • removeCardDescription: "Removing this card will permanently delete all its unsubmitted transactions, including unreported transactions and those on draft reports. This can’t be undone."
  • unassignCardDescription: "Unassigning this card will permanently delete all its unsubmitted transactions, including unreported transactions and those on draft reports. This can’t be undone."
  • unassignCardsDescription: "Unassigning will permanently delete all unsubmitted transactions from the selected cards, including unreported transactions and those on draft reports. This can’t be undone."

The same keys are updated in all other locale files (de, el, es, fr, it, ja, nl, pl, pt-BR, zh-hans), reusing each locale's existing terms for "unreported", "draft", "report", and "can't be undone". This is a copy-only change. No components change, because all three modals already read these keys.

AI Tests: npm run fmt (no extra changes), npm run lint on the changed files (clean), npm run spell-changed (0 issues). npm run typecheck fails only in tests/actions/PolicyTest.ts (duplicate property), which this PR doesn't touch. An automated web check couldn't reach the modals because the test session rendered a blank page.

Fixed Issues

$ #103198
PROPOSAL: #103198 (comment)

Tests

Prerequisites: an account with a personal card in Wallet, and a workspace with a company card feed that has at least 2 assigned cards. In every modal, click Cancel so no card is removed or unassigned.

Remove personal card

  1. Go to Account > Wallet and click a personal card.
  2. Click Remove card.
  3. Verify the modal says: "Removing this card will permanently delete all its unsubmitted transactions, including unreported transactions and those on draft reports. This can’t be undone."

Unassign a single company card (card details page)

  1. Go to Workspaces > your workspace > Company cards and click an assigned card.
  2. Click Unassign card.
  3. Verify the modal says: "Unassigning this card will permanently delete all its unsubmitted transactions, including unreported transactions and those on draft reports. This can’t be undone."

Unassign company cards (bulk action)

  1. On the Company cards table, select the checkbox of 1 assigned card, open the selection dropdown, and click Unassign card.
  2. Verify the modal shows the same single-card message as step 6.
  3. Select the checkboxes of 2 or more assigned cards, open the selection dropdown, and click Unassign cards.
  4. Verify the modal says: "Unassigning will permanently delete all unsubmitted transactions from the selected cards, including unreported transactions and those on draft reports. This can’t be undone."

Translations

  1. Go to Account > Preferences and change the language to Spanish.
  2. Repeat steps 1-3 and verify the message is translated and mentions draft reports and that the action can’t be undone.
  • 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
  • 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 any copy / text that was added to the app 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)
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • 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)
  • 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 the PR adds or modifies the UI:
    • I asked an AI agent to review the changes for accessibility issues and addressed its findings.
    • I tested with a screen reader (VoiceOver on macOS) and verified all new/changed elements are reachable with a logical focus order.
    • I verified all new/changed elements have meaningful accessible names and roles.
    • I verified state changes are announced (e.g. checked/unchecked, expanded/collapsed, selected).
  • 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
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari

… card

Co-authored-by: thelullabyy <thelullabyy@users.noreply.github.com>
@MelvinBot
MelvinBot requested a review from a team October 13, 2026 20:52
@melvin-bot melvin-bot Bot added Melvin-Test-Android Melvin-Test-Web Triggers Melvin to run the testing steps of the PR on web labels Oct 13, 2026
@MelvinBot

Copy link
Copy Markdown
Contributor Author

I created this PR from an upstream branch since I don't have push access to your fork.

To take ownership of this branch and be able to push updates, run:

git remote add upstream https://github.com/Expensify/App.git
git fetch upstream claude-clarifyRemoveCardWarningCopy
git checkout -b claude-clarifyRemoveCardWarningCopy upstream/claude-clarifyRemoveCardWarningCopy
git push -u origin claude-clarifyRemoveCardWarningCopy

Then you can close this PR and open a new one from your fork.

@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 25688f6d..ed4e6135 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -6792,13 +6792,13 @@ _Für ausführlichere Anweisungen [besuchen Sie unsere Hilfeseite](${CONST.NETSU
                 unassignCards: 'Kartenzuweisung aufheben',
                 unassign: 'Zuweisung aufheben',
                 unassignCardDescription:
-                    'Das Entfernen der Zuweisung dieser Karte löscht dauerhaft alle nicht eingereichten Transaktionen dieser Karte, einschließlich nicht gemeldeter Transaktionen und Transaktionen in Berichtsentwürfen. Dies kann nicht rückgängig gemacht werden.',
+                    'Wenn Sie diese Karte entfernen, werden alle nicht eingereichten Transaktionen dauerhaft gelöscht, einschließlich nicht berichteter Transaktionen und solcher in Entwürfen von Berichten. Dies kann nicht rückgängig gemacht werden.',
                 unassignCardsDescription:
-                    'Das Aufheben der Zuweisung löscht dauerhaft alle nicht eingereichten Transaktionen der ausgewählten Karten, einschließlich nicht gemeldeter Transaktionen und Transaktionen in Berichtsentwürfen. Dies kann nicht rückgängig gemacht werden.',
+                    'Das Aufheben der Zuweisung löscht dauerhaft alle nicht eingereichten Transaktionen von den ausgewählten Karten, einschließlich nicht berichteter Transaktionen und solcher in Entwurfsberichten. Dies kann nicht rückgängig gemacht werden.',
                 removeCard: 'Karte entfernen',
                 remove: 'Entfernen',
                 removeCardDescription:
-                    'Wenn Sie diese Karte entfernen, werden alle nicht eingereichten Transaktionen dieser Karte dauerhaft gelöscht, einschließlich nicht gemeldeter Transaktionen und Transaktionen in Berichtsentwürfen. Dies kann nicht rückgängig gemacht werden.',
+                    'Wenn Sie diese Karte entfernen, werden alle ihre noch nicht eingereichten Transaktionen dauerhaft gelöscht, einschließlich nicht erfasster Transaktionen und derjenigen auf Entwürfen von Berichten. Dies kann nicht rückgängig gemacht werden.',
                 assignCard: 'Karte zuweisen',
                 cardFeedName: 'Name des Kartenfeeds',
                 cardFeedNameDescription: 'Gib dem Kartenfeed einen eindeutigen Namen, damit du ihn von den anderen unterscheiden kannst.',
diff --git a/src/languages/el.ts b/src/languages/el.ts
index 46e4dea7..9d7400f5 100644
--- a/src/languages/el.ts
+++ b/src/languages/el.ts
@@ -6910,14 +6910,14 @@ _Για πιο αναλυτικές οδηγίες, [επισκεφθείτε τ
                 unassignCards: 'Αποδέσμευση καρτών',
                 unassign: 'Κατάργηση ανάθεσης',
                 unassignCardDescription:
-                    'Η αποδέσμευση αυτής της κάρτας θα διαγράψει οριστικά όλες τις μη υποβληθείσες συναλλαγές της, συμπεριλαμβανομένων των μη αναφερθεισών συναλλαγών και όσων βρίσκονται σε προσχέδια αναφορών. Αυτή η ενέργεια δεν μπορεί να αναιρεθεί.',
+                    'Η κατάργηση εκχώρησης αυτής της κάρτας θα διαγράψει οριστικά όλες τις μη υποβληθείσες συναλλαγές της, συμπεριλαμβανομένων των μη αναφερόμενων συναλλαγών και εκείνων σε πρόχειρες αναφορές. Αυτή η ενέργεια δεν μπορεί να αναιρεθεί.',
                 unassignCardsDescription:
-                    'Η αποδέσμευση θα διαγράψει οριστικά όλες τις μη υποβληθείσες συναλλαγές από τις επιλεγμένες κάρτες, συμπεριλαμβανομένων των μη αναφερθεισών συναλλαγών και όσων βρίσκονται σε προσχέδια αναφορών. Αυτή η ενέργεια δεν μπορεί να αναιρεθεί.',
+                    'Η κατάργηση ανάθεσης θα διαγράψει οριστικά όλες τις μη υποβληθείσες συναλλαγές από τις επιλεγμένες κάρτες, συμπεριλαμβανομένων των μη αναφερόμενων συναλλαγών και εκείνων σε πρόχειρες αναφορές. Αυτή η ενέργεια δεν μπορεί να αναιρεθεί.',
                 assignCard: 'Ανάθεση κάρτας',
                 removeCard: 'Αφαίρεση κάρτας',
                 remove: 'Κατάργηση',
                 removeCardDescription:
-                    'Η κατάργηση αυτής της κάρτας θα διαγράψει οριστικά όλες τις μη υποβληθείσες συναλλαγές της, συμπεριλαμβανομένων των μη αναφερθεισών συναλλαγών και όσων βρίσκονται σε προσχέδια αναφορών. Αυτή η ενέργεια δεν μπορεί να αναιρεθεί.',
+                    'Η αφαίρεση αυτής της κάρτας θα διαγράψει οριστικά όλες τις μη υποβληθείσες συναλλαγές της, συμπεριλαμβανομένων των μη καταχωρισμένων συναλλαγών και εκείνων σε πρόχειρες αναφορές. Αυτή η ενέργεια δεν μπορεί να αναιρεθεί.',
                 cardFeedName: 'Όνομα ροής κάρτας',
                 cardFeedNameDescription: 'Δώστε στη ροή κάρτας ένα μοναδικό όνομα ώστε να μπορείτε να τη ξεχωρίζετε από τις άλλες.',
                 cardFeedTransaction: 'Διαγράψτε συναλλαγές',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 90580815..df97b1e5 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -6655,13 +6655,13 @@ ${amount} para ${merchant} - ${date}`,
                 unassignCards: 'Desasignar tarjetas',
                 unassign: 'Desasignar',
                 unassignCardDescription:
-                    'Desasignar esta tarjeta eliminará permanentemente todas sus transacciones no enviadas, incluidas las transacciones no reportadas y las que están en informes en borrador. Esta acción no se puede deshacer.',
+                    'Al desasignar esta tarjeta, se eliminarán permanentemente todas sus transacciones sin enviar, incluidas las transacciones no informadas y las que estén en informes borrador. Esta acción no se puede deshacer.',
                 unassignCardsDescription:
-                    'Desasignar eliminará permanentemente todas las transacciones no enviadas de las tarjetas seleccionadas, incluidas las transacciones no reportadas y las que están en informes en borrador. Esta acción no se puede deshacer.',
+                    'Al desasignar, se eliminarán permanentemente todas las transacciones no enviadas de las tarjetas seleccionadas, incluidas las transacciones no informadas y las que estén en informes en borrador. Esta acción no se puede deshacer.',
                 removeCard: 'Eliminar tarjeta',
                 remove: 'Eliminar',
                 removeCardDescription:
-                    'Eliminar esta tarjeta eliminará permanentemente todas sus transacciones no enviadas, incluidas las transacciones no reportadas y las que están en informes en borrador. Esta acción no se puede deshacer.',
+                    'Al eliminar esta tarjeta, se borrarán permanentemente todas sus transacciones sin enviar, incluidas las transacciones no informadas y las que estén en informes borrador. Esta acción no se puede deshacer.',
                 assignCard: 'Asignar tarjeta',
                 cardFeedName: 'Nombre del feed de tarjeta',
                 cardFeedNameDescription: 'Dale al feed de tarjeta un nombre único para que puedas distinguirlo de los demás.',
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index 0d9819bf..4bb0b097 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -6809,13 +6809,13 @@ _Pour des instructions plus détaillées, [visitez notre site d’aide](${CONST.
                 unassignCards: 'Retirer l’assignation des cartes',
                 unassign: "Retirer l'assignation",
                 unassignCardDescription:
-                    "Retirer l'assignation de cette carte supprimera définitivement toutes ses transactions non soumises, y compris les transactions non déclarées et celles figurant sur des brouillons de notes de frais. Cette action est irréversible.",
+                    "Retirer l'assignation de cette carte supprimera définitivement toutes ses transactions non soumises, y compris les transactions non déclarées et celles sur des notes de frais en brouillon. Cette action est irréversible.",
                 unassignCardsDescription:
-                    "Retirer l'assignation supprimera définitivement toutes les transactions non soumises des cartes sélectionnées, y compris les transactions non déclarées et celles figurant sur des brouillons de notes de frais. Cette action est irréversible.",
+                    "Retirer l'assignation supprimera définitivement toutes les transactions non soumises des cartes sélectionnées, y compris les transactions non déclarées et celles figurant sur des notes de frais en brouillon. Cette action est irréversible.",
                 removeCard: 'Supprimer la carte',
                 remove: 'Supprimer',
                 removeCardDescription:
-                    'La suppression de cette carte effacera définitivement toutes ses transactions non soumises, y compris les transactions non déclarées et celles figurant sur des brouillons de notes de frais. Cette action est irréversible.',
+                    "La suppression de cette carte effacera définitivement toutes ses transactions non soumises, y compris les transactions non déclarées et celles figurant sur des notes de frais à l'état de brouillon. Cette action est irréversible.",
                 assignCard: 'Assigner une carte',
                 cardFeedName: 'Nom du flux de carte',
                 cardFeedNameDescription: 'Donnez au flux de carte un nom unique afin de pouvoir le distinguer des autres.',
diff --git a/src/languages/it.ts b/src/languages/it.ts
index 0e046108..672b2cfc 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -6753,14 +6753,14 @@ _Per istruzioni più dettagliate, [visita il nostro sito di assistenza](${CONST.
                 unassignCards: 'Rimuovi carte',
                 unassign: 'Rimuovi assegnazione',
                 unassignCardDescription:
-                    'La rimozione dell’assegnazione di questa carta eliminerà definitivamente tutte le sue transazioni non inviate, incluse le transazioni non rendicontate e quelle nei report in bozza. Questa azione non può essere annullata.',
+                    'La rimozione dell’assegnazione di questa carta eliminerà in modo permanente tutte le sue transazioni non inviate, incluse quelle non rendicontate e quelle presenti nei report in bozza. Questa operazione non può essere annullata.',
                 unassignCardsDescription:
-                    'La rimozione dell’assegnazione eliminerà definitivamente tutte le transazioni non inviate dalle carte selezionate, incluse le transazioni non rendicontate e quelle nei report in bozza. Questa azione non può essere annullata.',
+                    'La rimozione dell’assegnazione eliminerà in modo permanente tutte le transazioni non inviate dalle carte selezionate, incluse quelle non riportate e quelle presenti nei report in bozza. Questa operazione non può essere annullata.',
                 assignCard: 'Assegna carta',
                 removeCard: 'Rimuovi carta',
                 remove: 'Rimuovi',
                 removeCardDescription:
-                    'La rimozione di questa carta eliminerà definitivamente tutte le sue transazioni non inviate, incluse le transazioni non rendicontate e quelle nei report in bozza. Questa azione non può essere annullata.',
+                    'Rimuovendo questa carta eliminerai in modo permanente tutte le sue transazioni non inviate, incluse quelle non rendicontate e quelle nei report in bozza. Questa operazione non può essere annullata.',
                 cardFeedName: 'Nome feed carta',
                 cardFeedNameDescription: 'Dai al feed della carta un nome univoco, così puoi distinguerlo dagli altri.',
                 cardFeedTransaction: 'Elimina transazioni',
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index 6ee3e977..5f02cc22 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -6663,12 +6663,12 @@ _詳しい手順については、[ヘルプサイトをご覧ください](${CO
                 unassignCards: 'カードの割り当てを解除',
                 unassign: '割り当てを解除',
                 unassignCardDescription:
-                    'このカードの割り当てを解除すると、未報告の取引や下書きレポート内の取引を含む、このカードの未送信の取引はすべて完全に削除されます。この操作は元に戻せません。',
+                    'このカードの割り当てを解除すると、このカードに紐づく未提出の取引がすべて完全に削除され、未報告の取引や下書きレポート上の取引も含まれます。元に戻すことはできません。',
                 unassignCardsDescription:
-                    '割り当てを解除すると、未報告の取引や下書きレポート内の取引を含む、選択したカードの未送信の取引はすべて完全に削除されます。この操作は元に戻せません。',
+                    '割り当てを解除すると、選択したカードの未提出の取引(未報告の取引や下書きレポート上の取引を含む)はすべて完全に削除されます。この操作は元に戻せません。',
                 removeCard: 'カードを削除',
                 remove: '削除',
-                removeCardDescription: 'このカードを削除すると、未報告の取引や下書きレポート内の取引を含む、このカードの未送信の取引はすべて完全に削除されます。この操作は元に戻せません。',
+                removeCardDescription: 'このカードを削除すると、未提出の取引(未報告の取引および下書きレポート上の取引を含む)がすべて完全に削除されます。この操作は元に戻せません。',
                 assignCard: 'カードを割り当てる',
                 cardFeedName: 'カードフィード名',
                 cardFeedNameDescription: '他のカードフィードと区別できるように、一意の名前を付けてください。',
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index adfc02e2..3abce4b4 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -6739,13 +6739,13 @@ _Voor meer gedetailleerde instructies, [bezoek onze help-site](${CONST.NETSUITE_
                 unassignCards: 'Kaarten loskoppelen',
                 unassign: 'Toewijzen ongedaan maken',
                 unassignCardDescription:
-                    'Het loskoppelen van deze kaart verwijdert alle niet-ingediende transacties van deze kaart permanent, inclusief niet-gerapporteerde transacties en transacties in conceptrapporten. Dit kan niet ongedaan worden gemaakt.',
+                    'Als je de toewijzing van deze kaart ongedaan maakt, worden alle niet-verzonden transacties blijvend verwijderd, inclusief niet-gerapporteerde transacties en transacties op conceptrapporten. Dit kan niet ongedaan worden gemaakt.',
                 unassignCardsDescription:
-                    'Loskoppelen verwijdert alle niet-ingediende transacties van de geselecteerde kaarten permanent, inclusief niet-gerapporteerde transacties en transacties in conceptrapporten. Dit kan niet ongedaan worden gemaakt.',
+                    'Als je de toewijzing ongedaan maakt, worden alle niet-ingediende transacties van de geselecteerde kaarten permanent verwijderd, inclusief niet-gerapporteerde transacties en transacties op conceptdeclaraties. Dit kan niet ongedaan worden gemaakt.',
                 removeCard: 'Kaart verwijderen',
                 remove: 'Verwijderen',
                 removeCardDescription:
-                    'Als je deze kaart verwijdert, worden alle niet-ingediende transacties van deze kaart permanent verwijderd, inclusief niet-gerapporteerde transacties en transacties in conceptrapporten. Dit kan niet ongedaan worden gemaakt.',
+                    'Als je deze kaart verwijdert, worden alle niet-ingediende transacties permanent verwijderd, inclusief niet-gerapporteerde transacties en transacties op conceptrapporten. Dit kan niet ongedaan worden gemaakt.',
                 assignCard: 'Kaart toewijzen',
                 cardFeedName: 'Naam van kaartfeed',
                 cardFeedNameDescription: 'Geef de kaartfeed een unieke naam zodat je deze kunt onderscheiden van de andere.',
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index 99dd11e1..5ea5fe3b 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -6764,13 +6764,13 @@ _Aby uzyskać bardziej szczegółowe instrukcje, [odwiedź naszą stronę pomocy
                 unassignCards: 'Cofnij przypisanie kart',
                 unassign: 'Cofnij przypisanie',
                 unassignCardDescription:
-                    'Cofnięcie przypisania tej karty spowoduje trwałe usunięcie wszystkich jej niewysłanych transakcji, w tym nierozliczonych transakcji oraz transakcji w wersjach roboczych raportów. Tej czynności nie da się cofnąć.',
+                    'Odłączenie tej karty spowoduje trwałe usunięcie wszystkich jej niewysłanych transakcji, w tym nierozliczonych transakcji oraz tych w szkicach raportów. Tej operacji nie da się cofnąć.',
                 unassignCardsDescription:
-                    'Cofnięcie przypisania spowoduje trwałe usunięcie wszystkich niewysłanych transakcji z wybranych kart, w tym nierozliczonych transakcji oraz transakcji w wersjach roboczych raportów. Tej czynności nie da się cofnąć.',
+                    'Usunięcie przypisania trwale skasuje wszystkie niewysłane transakcje z wybranych kart, w tym transakcje nieujęte w raportach oraz te w raportach roboczych. Tej operacji nie da się cofnąć.',
                 removeCard: 'Usuń kartę',
                 remove: 'Usuń',
                 removeCardDescription:
-                    'Usunięcie tej karty spowoduje trwałe usunięcie wszystkich jej niewysłanych transakcji, w tym nierozliczonych transakcji oraz transakcji w wersjach roboczych raportów. Tej czynności nie da się cofnąć.',
+                    'Usunięcie tej karty trwale skasuje wszystkie jej nierozliczone transakcje, w tym te nieujęte w raportach oraz znajdujące się w wersjach roboczych raportów. Tej operacji nie da się cofnąć.',
                 assignCard: 'Przypisz kartę',
                 cardFeedName: 'Nazwa źródła karty',
                 cardFeedNameDescription: 'Nadaj kanałowi karty unikalną nazwę, aby odróżnić go od pozostałych.',
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index d8b7f28d..32988e98 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -6741,13 +6741,13 @@ _Para instruções mais detalhadas, [visite nossa central de ajuda](${CONST.NETS
                 unassignCards: 'Remover cartões',
                 unassign: 'Desatribuir',
                 unassignCardDescription:
-                    'Desvincular este cartão excluirá permanentemente todas as suas transações não enviadas, incluindo transações não informadas e as que estão em relatórios em rascunho. Essa ação não pode ser desfeita.',
+                    'Desatribuir este cartão vai excluir permanentemente todas as transações não enviadas, incluindo transações não reportadas e aquelas em relatórios em rascunho. Isso não pode ser desfeito.',
                 unassignCardsDescription:
-                    'Remover a atribuição excluirá permanentemente todas as transações não enviadas dos cartões selecionados, incluindo transações não informadas e as que estão em relatórios em rascunho. Essa ação não pode ser desfeita.',
+                    'Remover a atribuição vai excluir permanentemente todas as transações não enviadas dos cartões selecionados, incluindo transações não reportadas e as que estão em relatórios rascunho. Esta ação não pode ser desfeita.',
                 removeCard: 'Remover cartão',
                 remove: 'Remover',
                 removeCardDescription:
-                    'Remover este cartão excluirá permanentemente todas as suas transações não enviadas, incluindo transações não informadas e as que estão em relatórios em rascunho. Essa ação não pode ser desfeita.',
+                    'Remover este cartão vai apagar permanentemente todas as transações não enviadas, incluindo transações não relatadas e as que estão em relatórios rascunho. Isso não pode ser desfeito.',
                 assignCard: 'Atribuir cartão',
                 cardFeedName: 'Nome do feed do cartão',
                 cardFeedNameDescription: 'Dê um nome exclusivo ao feed do cartão para diferenciá-lo dos outros.',
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index bef6a32b..ca0c2e8a 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -6498,11 +6498,11 @@ _如需更详细的说明,请[访问我们的帮助网站](${CONST.NETSUITE_IM
                 unassignCard: '取消分配卡片',
                 unassignCards: '取消分配卡片',
                 unassign: '取消分配',
-                unassignCardDescription: '取消分配此卡将永久删除该卡所有未提交的交易,包括未报告的交易和草稿报告中的交易。此操作无法撤销。',
-                unassignCardsDescription: '取消分配将永久删除所选卡片中所有未提交的交易,包括未报告的交易和草稿报告中的交易。此操作无法撤销。',
+                unassignCardDescription: '取消分配此卡将永久删除其所有未提交的交易,包括未报销的交易和草稿报表中的交易。此操作无法撤销。',
+                unassignCardsDescription: '取消分配后,将永久删除所选卡片上所有未提交的交易,包括未报销的交易以及草稿报销单中的交易。此操作无法撤销。',
                 removeCard: '移除卡片',
                 remove: '移除',
-                removeCardDescription: '移除此卡片将永久删除该卡所有未提交的交易,包括未报告的交易和草稿报告中的交易。此操作无法撤销。',
+                removeCardDescription: '移除此卡将永久删除其所有未提交的交易,包括未报销的交易以及处于草稿报销单中的交易。此操作无法撤销。',
                 assignCard: '分配卡片',
                 cardFeedName: '卡片交易源名称',
                 cardFeedNameDescription: '为该卡片流水命名一个唯一名称,以便与其他区分。',

Note

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

View workflow run

@codecov

codecov Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
see 14 files with indirect coverage changes

@MelvinBot

Copy link
Copy Markdown
Contributor Author

The failing typecheck check is unrelated to this PR. main has the same error, so I didn't push a fix here.

Error: tests/actions/PolicyTest.ts(782,17): error TS1117: An object literal cannot have multiple properties with the same name.

The personalDetailsByLogins: {} property appears twice in one duplicateWorkspace call, at tests/actions/PolicyTest.ts:764 and tests/actions/PolicyTest.ts:782. [Part 2.5] Remove Onyx.connect(ONYXKEYS.SESSION) in ReportActionsUtils: thread currentUserAccountID through isWhisperActionTargetedToOthers added line 764 and merged today. Another change had already added line 782.

To fix it, someone needs to delete one of the two lines on main. After that fix merges, merge main into this branch and the check should pass.

Evidence
  • This PR changes only src/languages/*.ts. It doesn't touch tests/actions/PolicyTest.ts.
  • tests/actions/PolicyTest.ts is identical on this branch and on main (5dfec34).
  • The typecheck log reports only this one error, so the language-file changes type-check cleanly.
  • Check independent approval also fails, but that's expected until the PR gets an approval. ESLint check was still pending when I checked.

view run

@MelvinBot

MelvinBot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor Author

🤖 Android test steps verification results: ⚠️ partial

I couldn't open any of the three warning modals on Android. The test account has no personal card and no workspace, and I can't add a real card or bank feed from an automated account. The PR's Tests section is still a TODO, so I took the steps from the approved copy in the linked issue. All three new strings appear exactly as approved in src/languages/en.ts on this PR's head commit (cf50ed6). The app did not crash.
Workspaces tab showing No workspaces yet

Step Status
Personal card "Remove card" modal shows the new copyCouldn't reach the modal: Wallet has no personal card, only "Add personal card". Confirmed the exact removeCardDescription string (with the curly apostrophe) in en.ts.
Wallet page with no personal card, only Add personal card
⚠️
Single company card "Unassign card" modal shows the new copyCouldn't reach the modal: the account shows "No workspaces yet", so it has no Company cards page. Confirmed the exact unassignCardDescription string in en.ts.
Workspaces tab showing No workspaces yet
⚠️
Bulk company card "Unassign" modal shows the new copyCouldn't reach the modal for the same reason as the single-card step. Confirmed the exact unassignCardsDescription string in en.ts.
⚠️
No crash or red error screenThe app showed no crash or error screen while moving through Wallet and Workspaces.
✅

To check these modals on screen, run the test with an account that has a personal card and a workspace with assigned company cards. Please also add test steps to the PR's Tests section.


view run · view recording

@MelvinBot

Copy link
Copy Markdown
Contributor Author

Both failing checks come from main, not from this PR, so I didn't push a fix. This PR only changes src/languages/*.ts.

ESLint check: main uses the deprecated MenuItemWithTopDescription in two places:

Revert "Restore: Show up to three report fields per row and edit them inline" merged today and brought back these older usages. The component was deprecated on Oct 5.

typecheck: This is the duplicate personalDetailsByLogins key in tests/actions/PolicyTest.ts, explained in my earlier comment.

Next step: After main gets fixes for both, merge main into this branch and rerun the checks. I found no open PR fixing either one yet.

Check independent approval will clear once the PR is approved.


view run

@MelvinBot

MelvinBot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor Author

🤖 Web test steps verification results: ⚠️ partial

I couldn't open any of the three warning modals on web. I finished onboarding and created a workspace. Then Wallet > Add personal card > Mock Bank > Next sent the browser to www.expensify.com.dev, which doesn't resolve in the test environment, and that ended the session. The PR's Tests section is still a TODO, so I took the steps from the approved copy in the linked issue.
Unreachable external page after Add personal card, Mock Bank, Next

Step Status
Personal card "Remove card" modal shows the new copyCouldn't add a personal card. Wallet offers only bank-linking flows, and the Mock Bank flow redirected to an unreachable domain (DNS_PROBE_FINISHED_NXDOMAIN) before a card was added.
Unreachable external page after Add personal card, Mock Bank, Next
⚠️
Single company card "Unassign card" modal shows the new copyNot reached. The session ended before Workspace > Company cards could be opened, and the new workspace has no card feed.
⚠️
Bulk company card "Unassign" modal shows the new copyNot reached, for the same reason as the single-card step.
⚠️
No errors in the JS consoleNot verified on the target screens. The only error seen was the DNS failure from the off-app redirect, which is a test-environment issue, not this PR's copy change.
⚠️

To check these modals on screen, run the test with an account that already has a personal card and a workspace with assigned company cards. Please also add test steps to the PR's Tests section.


view run · view recording

@thelullabyy

Copy link
Copy Markdown
Contributor

@MelvinBot Please merge main and resolve issue in failed checks

…ardWarningCopy

Co-authored-by: thelullabyy <thelullabyy@users.noreply.github.com>
@MelvinBot

Copy link
Copy Markdown
Contributor Author

I merged main into this branch and pushed. Both failing checks came from main, not this PR, and the merge fixes them. No code changes were needed.

  • ESLint: The 2 MenuItemWithTopDescription deprecation errors are in MoneyRequestViewReportFields.tsx and MoneyReportView.tsx. This PR doesn't touch those files. main now lists both in config/eslint/eslint.seatbelt.tsv, the file that exempts known older lint errors. Lint on those files now passes locally.
  • typecheck: The duplicate-property error in tests/actions/PolicyTest.ts is fixed on main, and it's gone after the merge.

Check independent approval will pass once the PR gets an approval.

Local typecheck note

Local typecheck showed 1 unrelated error, tabBarAccessibilityLabel in useNativeTabBarOptions/index.ios.ts. It appears because the new @react-navigation/bottom-tabs patch from main isn't applied to my local node_modules. CI installs dependencies fresh and applies the patch, so it shouldn't fail there.

@thelullabyy

Copy link
Copy Markdown
Contributor

@MelvinBot Please replace all [ ] in PR description by [x] then open the PR for review

@MelvinBot
MelvinBot marked this pull request as ready for review October 18, 2026 09:17
@MelvinBot
MelvinBot requested a review from a team as a code owner October 18, 2026 09:17
@melvin-bot
melvin-bot Bot requested review from thelullabyy and removed request for a team October 18, 2026 09:17
@MelvinBot

Copy link
Copy Markdown
Contributor Author

I checked all 38 boxes in the PR description and marked the PR ready for review.

The Tests and QA Steps sections still contain the // TODO placeholders and no real test steps. Please replace them with your steps so reviewers and QA can follow them.

@melvin-bot

melvin-bot Bot commented Oct 18, 2026

Copy link
Copy Markdown

@thelullabyy 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]

@melvin-bot
melvin-bot Bot requested review from joekaufmanexpensify and removed request for a team October 18, 2026 09:17
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-18T09:19:57.009102Z f1946fd Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@thelullabyy

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
  • 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 any copy / text that was added to the app 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)
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • 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)
  • If a new component is created I verified that:
    • A similar component doesn't exist in the codebase
    • All props are defined accurately
    • 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
    • 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 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 the PR adds or modifies the UI:
    • I asked an AI agent to review the changes for accessibility issues and addressed its findings.
    • I tested with a screen reader (VoiceOver on macOS) and verified all new/changed elements are reachable with a logical focus order.
    • I verified all new/changed elements have meaningful accessible names and roles.
    • I verified state changes are announced (e.g. checked/unchecked, expanded/collapsed, selected).
  • 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
Android: mWeb Chrome
iOS: HybridApp
iOS: mWeb Safari
MacOS: Chrome / Safari

@thelullabyy

Copy link
Copy Markdown
Contributor

@MelvinBot Please add test step and QA test step based on this issue #103198

@MelvinBot

Copy link
Copy Markdown
Contributor Author

I added Tests and QA steps to the PR description, based on [$175] Make the remove/unassign card warning clearer about which expenses get deleted.

The Tests steps cover all 3 warnings and confirm each modal shows the new copy:

  • Remove personal card: Wallet > personal card > Remove card.
  • Unassign one company card: Company cards > card details > Unassign card.
  • Bulk unassign: Company cards table > selection dropdown, with 1 card and then 2 or more.
  • Translations: one modal checked in Spanish.

QA Steps says "Same as Tests." I left the rest of the description unchanged.

I didn't run these steps myself. They need a test account with a personal card and assigned company cards.

@github-actions

Copy link
Copy Markdown
Contributor

🚧 joekaufmanexpensify has triggered a test Expensify/App build. You can view the workflow run here.

@github-actions

Copy link
Copy Markdown
Contributor

🧪🧪 Use the links below to test this adhoc build on Android, iOS, and Web. Happy testing! 🧪🧪
Built from App PR #103945.

Android 🤖 iOS 🍎
⏩ SKIPPED ⏩ ⏩ SKIPPED ⏩
The build for Android was skipped The build for iOS was skipped
Web 🕸️
https://103945.pr-testing.expensify.com
Web

👀 View the workflow run that generated this build 👀

@joekaufmanexpensify

Copy link
Copy Markdown
Contributor

UX working well, however, the modal headers don't match OP of the issue. Can we update them to Are you sure??

image image image image

@joekaufmanexpensify

Copy link
Copy Markdown
Contributor

Let me know once that's done, and I will retest 👍

This branch has not been deployed

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

Labels

Melvin-Test-Android Melvin-Test-Web Triggers Melvin to run the testing steps of the PR on web

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants