Skip to content

[Payment due @huult] Add setting to prevent manual/odometer distance requests for a given policy - #99433

Merged
lakchote merged 15 commits into
mainfrom
alberto-disableManual
Aug 28, 2026
Merged

[Payment due @huult] Add setting to prevent manual/odometer distance requests for a given policy#99433
lakchote merged 15 commits into
mainfrom
alberto-disableManual

Conversation

@Gonals

@Gonals Gonals commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

HELD ON https://github.com/Expensify/Web-Expensify/pull/55619

Explanation of Change

Fixed Issues

$ https://github.com/Expensify/Expensify/issues/674995
PROPOSAL:

Tests

In an account in a single workspace:

  1. Go to the workspace -> Distance Rates -> Settings and enable "Require GPS or map entry"
  2. Go to the admins chat for the workspace and confirm the change was logged as a comment.
  3. Click on + -> Track distance and confirm only Map and GPS tabs are visible

In an account with 2 workspaces:

  1. Go to one of the workspaces -> Distance Rates -> Settings and enable "Require GPS or map entry"
  2. Click on + -> Track distance and confirm all options are available
  3. Select manual and enter a distance.
  4. On the next step, confirm that when the workspace with the setting enabled is selected, you are blocked by:
Screenshot 2026-08-25 at 15 45 37
  1. Enable the setting for the other workspace. Only Map/GPS tabs should be visible now.

In an account in the commuter exclusions beta:

  1. Go to one of the workspaces -> Distance Rates -> Settings and enable Commuter exclusions
  2. Confirm "Require GPS or map entry" is enabled automatically and locked. Trying to unset it displays:
Screenshot 2026-08-25 at 15 47 23
  • Verify that no errors appear in the JS console

Offline tests

Same as 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 followed proper code patterns (see Reviewing the code)
    • 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 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)
  • 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)
  • 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.
  • 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

@OSBotify

This comment has been minimized.

@codecov

codecov Bot commented Aug 25, 2026

Copy link
Copy Markdown

Codecov Report

❌ Looks like you've decreased code coverage for some files. Please write tests to increase, or at least maintain, the existing level of code coverage. See our documentation here for how to interpret this table.

Files with missing lines Coverage Δ
src/components/MoneyRequestConfirmationList.tsx 94.24% <100.00%> (ø)
...neyRequestReportPreview/AddExpenseActionButton.tsx 100.00% <100.00%> (ø)
src/hooks/useBlockDistanceRequest.ts 100.00% <100.00%> (ø)
src/hooks/useExpenseActions.ts 66.19% <100.00%> (-0.16%) ⬇️
src/hooks/useParticipantSubmission.ts 71.66% <100.00%> (ø)
src/libs/API/types.ts 100.00% <ø> (ø)
src/libs/PolicyDistanceRatesUtils.ts 40.65% <100.00%> (+6.51%) ⬆️
src/libs/actions/Report/index.ts 71.89% <100.00%> (+0.50%) ⬆️
...iou/request/step/DynamicIOURequestStepDistance.tsx 85.32% <100.00%> (ø)
...es/iou/request/step/IOURequestEditReportCommon.tsx 80.59% <100.00%> (ø)
... and 14 more
... and 103 files with indirect coverage changes

@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 cb45e164..b104ae1a 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -7231,9 +7231,9 @@ Der Control-Tarif beginnt bei 9 $ pro aktivem Mitglied und Monat.`,
         distanceRates: {
             oopsNotSoFast: 'Ups! Nicht so schnell ...',
             workspaceNeeds: 'Ein Arbeitsbereich benötigt mindestens einen aktivierten Entfernungssatz.',
-            requireMapOrGPSDescription: 'Manuelle Eingabe und Kilometerstand-Eingabe werden deaktiviert.',
+            requireMapOrGPSDescription: 'Manuelle Eingabe und Kilometerzähler-Eingabe werden deaktiviert.',
             requireMapOrGPSLockedByCommuterExclusions:
-                'Das Ausschließen von Arbeitswegen erfordert eine kartierte Route, daher wird GPS- oder Karteneingabe bereits verlangt. Beenden Sie den Ausschluss von Arbeitswegen, um diese Einstellung zu ändern.',
+                'Das Ausschließen von Arbeitswegen benötigt Routendaten, daher ist bei eingeschalteter Option immer eine Karten- oder GPS-Distanz erforderlich. Um diese Einstellung zu ändern, setzen Sie „Arbeitswege ausschließen“ auf „Arbeitswege nicht ausschließen“.',
             commuterExclusions: {
                 title: 'Arbeitswege ausschließen',
                 summaryDisabled: 'Kein Ausschluss von Pendelstrecken',
@@ -8612,7 +8612,7 @@ Fügen Sie weitere Ausgabelimits hinzu, um den Cashflow Ihres Unternehmens zu sc
                 case 'tags':
                     return `${enabled ? 'aktiviert' : 'deaktiviert'} Tags`;
                 case 'workflows':
-                    return `${enabled ? 'aktiviert' : 'deaktiviert'} Workflows`;
+                    return `${enabled ? 'aktiviert' : 'deaktiviert'}-Workflows`;
                 case 'distance rates':
                     return `${enabled ? 'aktiviert' : 'deaktiviert'} Entfernungssätze`;
                 case 'accounting':
@@ -8630,11 +8630,11 @@ Fügen Sie weitere Ausgabelimits hinzu, um den Cashflow Ihres Unternehmens zu sc
                 case 'receipt partners':
                     return `${enabled ? 'aktiviert' : 'deaktiviert'} Belegpartner`;
                 case 'rules':
-                    return `${enabled ? 'aktiviert' : 'deaktiviert'}-Regeln`;
+                    return `${enabled ? 'aktiviert' : 'deaktiviert'} Regeln`;
                 case 'tax tracking':
                     return `${enabled ? 'aktiviert' : 'deaktiviert'} Steuerverfolgung`;
                 case 'require GPS or map entry for distance rates':
-                    return `${enabled ? 'aktiviert' : 'deaktiviert'} die Pflicht zur GPS- oder Karteneingabe für Entfernungssätze`;
+                    return `${enabled ? 'eingeschaltet' : 'deaktiviert'} erfordern GPS oder Karteneingabe für Entfernungsraten`;
                 default:
                     return `${enabled ? 'aktiviert' : 'deaktiviert'} ${featureName}`;
             }
@@ -9725,7 +9725,7 @@ Fügen Sie weitere Ausgabelimits hinzu, um den Cashflow Ihres Unternehmens zu sc
         error: {
             selectSuggestedAddress: 'Bitte wählen Sie eine vorgeschlagene Adresse aus oder verwenden Sie den aktuellen Standort',
             mapOrGpsDistanceRequired: {
-                title: 'GPS- oder Karteneingabe verlangen',
+                title: 'GPS- oder Karteneingabe erforderlich',
                 description: 'Dieser Workspace erfordert entweder kartenbasierte oder GPS-verfolgte Entfernungskosten.',
             },
         },
diff --git a/src/languages/el.ts b/src/languages/el.ts
index 16e73540..2f1be300 100644
--- a/src/languages/el.ts
+++ b/src/languages/el.ts
@@ -1258,7 +1258,6 @@ const translations: TranslationDeepObject<typeof en> = {
             if (count === 0) {
                 return duplicates > 0 ? 'Δεν προστέθηκαν κανόνες εμπόρων, καθώς υπάρχουν ήδη όλοι.' : 'Δεν έχουν προστεθεί κανόνες εμπόρου.';
             }
-
             return {
                 one: 'Προστέθηκε 1 κανόνας εμπόρου.',
                 other: `Έχουν προστεθεί ${count} κανόνες εμπόρων.`,
@@ -7474,9 +7473,9 @@ _Για πιο αναλυτικές οδηγίες, [επισκεφθείτε τ
         distanceRates: {
             oopsNotSoFast: 'Ουπς! Όχι τόσο γρήγορα...',
             workspaceNeeds: 'Ένας χώρος εργασίας χρειάζεται τουλάχιστον έναν ενεργοποιημένο συντελεστή απόστασης.',
-            requireMapOrGPSDescription: 'Η μη αυτόματη καταχώριση και η καταχώριση μέσω οδομέτρου θα απενεργοποιηθούν.',
+            requireMapOrGPSDescription: 'Η χειροκίνητη καταχώριση και η καταχώριση χιλιομετρητή θα απενεργοποιηθούν.',
             requireMapOrGPSLockedByCommuterExclusions:
-                'Η εξαίρεση των μετακινήσεων προς την εργασία απαιτεί χαρτογραφημένη διαδρομή, οπότε η καταχώριση μέσω GPS ή χάρτη απαιτείται ήδη. Σταματήστε να εξαιρείτε τις μετακινήσεις προς την εργασία για να αλλάξετε αυτή τη ρύθμιση.',
+                'Η εξαίρεση μετακινήσεων από και προς την εργασία απαιτεί δεδομένα διαδρομής, επομένως η απόσταση από χάρτη ή GPS είναι πάντα απαραίτητη όταν είναι ενεργή. Για να αλλάξετε αυτήν τη ρύθμιση, ορίστε το «Εξαίρεση μετακινήσεων από και προς την εργασία» σε «Να μην εξαιρούνται οι μετακινήσεις από και προς την εργασία».',
             commuterExclusions: {
                 title: 'Εξαίρεση μετακινήσεων από και προς την εργασία',
                 summaryDisabled: 'Χωρίς εξαίρεση μετακίνησης',
@@ -9020,35 +9019,35 @@ ${reportName}`,
         updatedFeatureEnabled: ({enabled, featureName}: {enabled: boolean; featureName: string}) => {
             switch (featureName) {
                 case 'categories':
-                    return `${enabled ? 'ενεργοποιημένο' : 'απενεργοποιημένο'} κατηγορίες`;
+                    return `${enabled ? 'ενεργοποιημένο' : 'ανενεργό'} κατηγορίες`;
                 case 'tags':
-                    return `ετικέτες ${enabled ? 'ενεργοποιημένο' : 'απενεργοποιημένο'}`;
+                    return `${enabled ? 'ενεργοποιημένο' : 'ανενεργό'} ετικέτες`;
                 case 'workflows':
-                    return `ροές εργασίας ${enabled ? 'ενεργοποιημένο' : 'απενεργοποιημένο'}`;
+                    return `ροές εργασιών ${enabled ? 'ενεργοποιημένο' : 'ανενεργό'}`;
                 case 'distance rates':
-                    return `${enabled ? 'ενεργοποιημένο' : 'απενεργοποιημένο'} χρεώσεις απόστασης`;
+                    return `τιμές χρέωσης απόστασης ${enabled ? 'ενεργοποιημένο' : 'ανενεργό'}`;
                 case 'accounting':
-                    return `λογιστική ${enabled ? 'ενεργοποιημένο' : 'απενεργοποιημένο'}`;
+                    return `${enabled ? 'ενεργοποιημένο' : 'ανενεργό'} λογιστική`;
                 case 'Expensify Cards':
-                    return `${enabled ? 'ενεργοποιημένο' : 'απενεργοποιημένο'} Κάρτες Expensify`;
+                    return `${enabled ? 'ενεργοποιημένο' : 'ανενεργό'} κάρτες Expensify`;
                 case 'travel invoicing':
-                    return `${enabled ? 'ενεργοποιημένο' : 'απενεργοποιημένο'} ενοποιημένη χρέωση ταξιδιών`;
+                    return `${enabled ? 'ενεργοποιημένο' : 'ανενεργό'} ενοποιημένη χρέωση ταξιδιών`;
                 case 'company cards':
-                    return `${enabled ? 'ενεργοποιημένο' : 'απενεργοποιημένο'} εταιρικές κάρτες`;
+                    return `${enabled ? 'ενεργοποιημένο' : 'ανενεργό'} εταιρικές κάρτες`;
                 case 'invoicing':
-                    return `τιμολόγηση ${enabled ? 'ενεργοποιημένο' : 'απενεργοποιημένο'}`;
+                    return `τιμολόγηση ${enabled ? 'ενεργοποιημένο' : 'ανενεργό'}`;
                 case 'per diem':
-                    return `${enabled ? 'ενεργοποιημένο' : 'απενεργοποιημένο'} ημερήσια αποζημίωση`;
+                    return `${enabled ? 'ενεργοποιημένο' : 'ανενεργό'} ημερήσιο επίδομα`;
                 case 'receipt partners':
-                    return `${enabled ? 'ενεργοποιημένο' : 'απενεργοποιημένο'} συνεργάτες αποδείξεων`;
+                    return `συνεργάτες αποδείξεων ${enabled ? 'ενεργοποιημένο' : 'ανενεργό'}`;
                 case 'rules':
-                    return `κανόνες ${enabled ? 'ενεργοποιημένο' : 'απενεργοποιημένο'}`;
+                    return `κανόνες ${enabled ? 'ενεργοποιημένο' : 'ανενεργό'}`;
                 case 'tax tracking':
-                    return `παρακολούθηση φόρου ${enabled ? 'ενεργοποιημένο' : 'απενεργοποιημένο'}`;
+                    return `παρακολούθηση φόρων ${enabled ? 'ενεργοποιημένο' : 'ανενεργό'}`;
                 case 'require GPS or map entry for distance rates':
-                    return `${enabled ? 'ενεργοποιήθηκε' : 'απενεργοποιήθηκε'} η απαίτηση καταχώρισης μέσω GPS ή χάρτη για τους συντελεστές απόστασης`;
+                    return `${enabled ? 'ενεργοποιήθηκε' : 'απενεργοποιήθηκε'} απαιτούν GPS ή καταχώριση σε χάρτη για χρεώσεις απόστασης`;
                 default:
-                    return `${enabled ? 'ενεργοποιημένο' : 'απενεργοποιημένο'} ${featureName}`;
+                    return `${enabled ? 'ενεργοποιημένο' : 'ανενεργό'} ${featureName}`;
             }
         },
         updatedAttendeeTracking: ({enabled}: {enabled: boolean}) => `παρακολούθηση συμμετεχόντων ${enabled ? 'ενεργοποιημένο' : 'απενεργοποιημένο'}`,
@@ -9938,7 +9937,7 @@ ${reportName}`,
         error: {
             selectSuggestedAddress: 'Παρακαλείστε να επιλέξετε μια προτεινόμενη διεύθυνση ή να χρησιμοποιήσετε την τρέχουσα τοποθεσία',
             mapOrGpsDistanceRequired: {
-                title: 'Απαίτηση καταχώρισης μέσω GPS ή χάρτη',
+                title: 'Απαίτηση GPS ή καταχώρισης χάρτη',
                 description: 'Αυτός ο χώρος εργασίας απαιτεί έξοδα απόστασης είτε με βάση χάρτη είτε με παρακολούθηση GPS.',
             },
         },
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 7c22b651..2c449e89 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -1182,7 +1182,6 @@ const translations: TranslationDeepObject<typeof en> = {
             if (count === 0) {
                 return duplicates > 0 ? 'No se han añadido reglas de comerciante, ya que todas ya existen.' : 'No se han añadido reglas de comerciante.';
             }
-
             return {
                 one: 'Se ha añadido 1 regla de comerciante.',
                 other: `Se han añadido ${count} reglas de comerciante.`,
@@ -7201,9 +7200,9 @@ El plan Controlar empieza en 9 $ por miembro activo al mes.`,
         distanceRates: {
             oopsNotSoFast: 'Ups! No tan rápido...',
             workspaceNeeds: 'Un espacio de trabajo necesita al menos una tasa de distancia activa.',
-            requireMapOrGPSDescription: 'La entrada manual y por odómetro se desactivará.',
+            requireMapOrGPSDescription: 'Se deshabilitará la introducción manual y del cuentakilómetros.',
             requireMapOrGPSLockedByCommuterExclusions:
-                'Excluir los desplazamientos al trabajo requiere una ruta cartografiada, así que ya se exige la entrada por GPS o mapa. Deja de excluir los desplazamientos al trabajo para cambiar este ajuste.',
+                'Excluir desplazamientos necesita datos de ruta, por lo que la distancia del mapa o del GPS siempre es obligatoria mientras esté activado. Para cambiar esta configuración, establece Excluir desplazamientos en «No excluir desplazamientos».',
             commuterExclusions: {
                 title: 'Excluir desplazamientos al trabajo',
                 summaryDisabled: 'Sin exclusión por desplazamiento al trabajo',
@@ -8673,29 +8672,29 @@ ${reportName}`,
                 case 'tags':
                     return `${enabled ? 'habilitado' : 'desactivado'} etiquetas`;
                 case 'workflows':
-                    return `Flujos de trabajo ${enabled ? 'habilitado' : 'desactivado'}`;
+                    return `Flujos de trabajo de ${enabled ? 'habilitado' : 'desactivado'}`;
                 case 'distance rates':
-                    return `${enabled ? 'habilitado' : 'desactivado'} tarifas por distancia`;
+                    return `Tarifas de distancia ${enabled ? 'habilitado' : 'desactivado'}`;
                 case 'accounting':
-                    return `${enabled ? 'habilitado' : 'desactivado'} contabilidad`;
+                    return `contabilidad ${enabled ? 'habilitado' : 'desactivado'}`;
                 case 'Expensify Cards':
                     return `${enabled ? 'habilitado' : 'desactivado'} Tarjetas Expensify`;
                 case 'travel invoicing':
                     return `${enabled ? 'habilitado' : 'desactivado'} Facturación consolidada de viajes`;
                 case 'company cards':
-                    return `${enabled ? 'habilitado' : 'desactivado'} tarjetas de la empresa`;
+                    return `tarjetas de empresa ${enabled ? 'habilitado' : 'desactivado'}`;
                 case 'invoicing':
-                    return `Facturación ${enabled ? 'habilitado' : 'desactivado'}`;
+                    return `${enabled ? 'habilitado' : 'desactivado'} facturación`;
                 case 'per diem':
-                    return `${enabled ? 'habilitado' : 'desactivado'} Per diem`;
+                    return `${enabled ? 'habilitado' : 'desactivado'} per diem`;
                 case 'receipt partners':
                     return `${enabled ? 'habilitado' : 'desactivado'} socios de recibos`;
                 case 'rules':
-                    return `${enabled ? 'habilitado' : 'desactivado'} reglas`;
+                    return `Reglas de ${enabled ? 'habilitado' : 'desactivado'}`;
                 case 'tax tracking':
-                    return `seguimiento de impuestos ${enabled ? 'habilitado' : 'desactivado'}`;
+                    return `Seguimiento de impuestos ${enabled ? 'habilitado' : 'desactivado'}`;
                 case 'require GPS or map entry for distance rates':
-                    return `${enabled ? 'activado' : 'desactivado'} el requisito de entrada por GPS o mapa para las tasas de distancia`;
+                    return `${enabled ? 'activado' : 'desactivado'} requiere GPS o introducción en el mapa para las tasas de distancia`;
                 default:
                     return `${enabled ? 'habilitado' : 'desactivado'} ${featureName}`;
             }
@@ -10016,7 +10015,7 @@ ${reportName}`,
         error: {
             selectSuggestedAddress: 'Por favor, selecciona una dirección sugerida o usa la ubicación actual',
             mapOrGpsDistanceRequired: {
-                title: 'Requerir entrada por GPS o mapa',
+                title: 'Requerir GPS o introducción en el mapa',
                 description: 'Este espacio de trabajo requiere gastos de distancia basados en mapa o con seguimiento por GPS.',
             },
         },
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index e0cd0df9..2cfecf2c 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -7253,9 +7253,9 @@ Le forfait Control commence à 9 $ par Membre actif et par mois.`,
         distanceRates: {
             oopsNotSoFast: 'Oups ! Pas si vite...',
             workspaceNeeds: 'Un espace de travail doit avoir au moins un taux de distance activé.',
-            requireMapOrGPSDescription: 'La saisie manuelle et par odomètre sera désactivée.',
+            requireMapOrGPSDescription: 'La saisie manuelle et la saisie du compteur kilométrique seront désactivées.',
             requireMapOrGPSLockedByCommuterExclusions:
-                'Exclure les trajets domicile-travail nécessite un itinéraire cartographié, la saisie GPS ou cartographique est donc déjà exigée. Cessez d’exclure les trajets domicile-travail pour modifier ce paramètre.',
+                'L’exclusion des trajets domicile‑travail nécessite des données d’itinéraire, donc la distance issue de la carte ou du GPS est toujours requise lorsqu’elle est activée. Pour modifier ce paramètre, définissez Exclure les trajets domicile‑travail sur « Ne pas exclure les trajets domicile‑travail ».',
             commuterExclusions: {
                 title: 'Exclure les trajets domicile-travail',
                 summaryDisabled: 'Pas d’exclusion du trajet domicile-travail',
@@ -8643,27 +8643,27 @@ Ajoutez davantage de règles de dépenses pour protéger la trésorerie de l’e
                 case 'workflows':
                     return `Workflows ${enabled ? 'activé' : 'Désactivé'}`;
                 case 'distance rates':
-                    return `${enabled ? 'activé' : 'Désactivé'} barèmes kilométriques`;
+                    return `Taux de distance ${enabled ? 'activé' : 'Désactivé'}`;
                 case 'accounting':
                     return `Comptabilité ${enabled ? 'activé' : 'Désactivé'}`;
                 case 'Expensify Cards':
-                    return `Cartes Expensify ${enabled ? 'activé' : 'Désactivé'}`;
+                    return `${enabled ? 'activé' : 'Désactivé'} Cartes Expensify`;
                 case 'travel invoicing':
-                    return `${enabled ? 'activé' : 'Désactivé'} Facturation de voyages consolidée`;
+                    return `${enabled ? 'activé' : 'Désactivé'} Facturation de voyage consolidée`;
                 case 'company cards':
                     return `${enabled ? 'activé' : 'Désactivé'} cartes d’entreprise`;
                 case 'invoicing':
                     return `Facturation ${enabled ? 'activé' : 'Désactivé'}`;
                 case 'per diem':
-                    return `${enabled ? 'activé' : 'Désactivé'} par diem`;
+                    return `${enabled ? 'activé' : 'Désactivé'} par jour`;
                 case 'receipt partners':
                     return `Partenaires de reçus ${enabled ? 'activé' : 'Désactivé'}`;
                 case 'rules':
-                    return `Règles de ${enabled ? 'activé' : 'Désactivé'}`;
+                    return `Règles ${enabled ? 'activé' : 'Désactivé'}`;
                 case 'tax tracking':
-                    return `Suivi fiscal ${enabled ? 'activé' : 'Désactivé'}`;
+                    return `Suivi des taxes ${enabled ? 'activé' : 'Désactivé'}`;
                 case 'require GPS or map entry for distance rates':
-                    return `${enabled ? 'activé' : 'désactivé'} l’obligation de saisie GPS ou cartographique pour les taux de distance`;
+                    return `${enabled ? 'activé' : 'désactivé'} exigent un GPS ou une saisie sur la carte pour les taux de distance`;
                 default:
                     return `${enabled ? 'activé' : 'Désactivé'} ${featureName}`;
             }
@@ -9755,7 +9755,7 @@ Ajoutez davantage de règles de dépenses pour protéger la trésorerie de l’e
         error: {
             selectSuggestedAddress: 'Veuillez sélectionner une adresse suggérée ou utiliser la position actuelle',
             mapOrGpsDistanceRequired: {
-                title: 'Exiger une saisie GPS ou cartographique',
+                title: 'Exiger un GPS ou une saisie sur la carte',
                 description: 'Cet espace de travail requiert des dépenses kilométriques calculées soit sur la base d’une carte, soit suivies par GPS.',
             },
         },
diff --git a/src/languages/it.ts b/src/languages/it.ts
index f8c0eead..cad03d47 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -7199,9 +7199,9 @@ Il piano Control parte da 9 $ al mese per ogni membro attivo.`,
         distanceRates: {
             oopsNotSoFast: 'Ops! Non così in fretta...',
             workspaceNeeds: 'Uno spazio di lavoro necessita di almeno una tariffa distanza abilitata.',
-            requireMapOrGPSDescription: 'L’inserimento manuale e tramite contachilometri sarà disattivato.',
+            requireMapOrGPSDescription: 'L’inserimento manuale e tramite contachilometri sarà disabilitato.',
             requireMapOrGPSLockedByCommuterExclusions:
-                'Escludere i tragitti casa-lavoro richiede un percorso mappato, quindi l’inserimento tramite GPS o mappa è già richiesto. Smetti di escludere i tragitti casa-lavoro per modificare questa impostazione.',
+                'La funzione Escludi spostamenti casa-lavoro richiede i dati del percorso, quindi mentre è attiva è sempre necessaria la distanza dalla mappa o dal GPS. Per modificare questa impostazione, imposta Escludi spostamenti casa-lavoro su "Non escludere spostamenti casa-lavoro".',
             commuterExclusions: {
                 title: 'Escludi spostamenti casa-lavoro',
                 summaryDisabled: 'Nessuna esclusione per il tragitto',
@@ -8575,15 +8575,15 @@ Aggiungi altre regole di spesa per proteggere il flusso di cassa aziendale.`,
                 case 'tags':
                     return `${enabled ? 'abilitato' : 'disattivato'} tag`;
                 case 'workflows':
-                    return `${enabled ? 'abilitato' : 'disattivato'} flussi di lavoro`;
+                    return `workflow ${enabled ? 'abilitato' : 'disattivato'}`;
                 case 'distance rates':
-                    return `${enabled ? 'abilitato' : 'disattivato'} tariffe chilometriche`;
+                    return `tariffe chilometriche ${enabled ? 'abilitato' : 'disattivato'}`;
                 case 'accounting':
                     return `${enabled ? 'abilitato' : 'disattivato'} contabilità`;
                 case 'Expensify Cards':
                     return `${enabled ? 'abilitato' : 'disattivato'} Carte Expensify`;
                 case 'travel invoicing':
-                    return `${enabled ? 'abilitato' : 'disattivato'} fatturazione di viaggio consolidata`;
+                    return `${enabled ? 'abilitato' : 'disattivato'} fatturazione viaggi consolidata`;
                 case 'company cards':
                     return `${enabled ? 'abilitato' : 'disattivato'} carte aziendali`;
                 case 'invoicing':
@@ -8595,9 +8595,9 @@ Aggiungi altre regole di spesa per proteggere il flusso di cassa aziendale.`,
                 case 'rules':
                     return `${enabled ? 'abilitato' : 'disattivato'} regole`;
                 case 'tax tracking':
-                    return `monitoraggio imposte ${enabled ? 'abilitato' : 'disattivato'}`;
+                    return `Monitoraggio tasse ${enabled ? 'abilitato' : 'disattivato'}`;
                 case 'require GPS or map entry for distance rates':
-                    return `${enabled ? 'attivato' : 'disattivato'} l’obbligo di inserimento tramite GPS o mappa per le tariffe distanza`;
+                    return `${enabled ? 'attivato' : 'disattivato'} richiede il GPS o l’inserimento sulla mappa per le tariffe chilometriche`;
                 default:
                     return `${enabled ? 'abilitato' : 'disattivato'} ${featureName}`;
             }
@@ -9694,7 +9694,7 @@ Aggiungi altre regole di spesa per proteggere il flusso di cassa aziendale.`,
         error: {
             selectSuggestedAddress: 'Seleziona un indirizzo suggerito o usa la posizione attuale',
             mapOrGpsDistanceRequired: {
-                title: 'Richiedi inserimento tramite GPS o mappa',
+                title: 'Richiedi GPS o inserimento su mappa',
                 description: 'Questo spazio di lavoro richiede spese chilometriche basate su mappa o tracciate tramite GPS.',
             },
         },
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index 8515cef4..d08753ce 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -7109,7 +7109,7 @@ Control プランは、アクティブメンバー1人あたり月額 $9 から
             workspaceNeeds: 'ワークスペースには、少なくとも 1 つの有効な距離レートが必要です。',
             requireMapOrGPSDescription: '手動入力とオドメーター入力は無効になります。',
             requireMapOrGPSLockedByCommuterExclusions:
-                '通勤を除外するにはマップ上のルートが必要なため、GPS またはマップでの入力はすでに必須です。この設定を変更するには、通勤の除外を停止してください。',
+                '通勤を除外するにはルートデータが必要なため、この設定がオンの間は、常にマップまたは GPS による距離情報が必要です。この設定を変更するには、「通勤を除外」を「通勤を除外しない」に設定してください。',
             commuterExclusions: {
                 title: '通勤を除外',
                 summaryDisabled: '通勤除外なし',
@@ -8458,33 +8458,33 @@ ${reportName}`,
         updatedFeatureEnabled: ({enabled, featureName}: {enabled: boolean; featureName: string}) => {
             switch (featureName) {
                 case 'categories':
-                    return `${enabled ? '有効' : '無効'} 件のカテゴリ`;
+                    return `${enabled ? '有効' : '無効'} 個のカテゴリ`;
                 case 'tags':
                     return `${enabled ? '有効' : '無効'} 個のタグ`;
                 case 'workflows':
                     return `${enabled ? '有効' : '無効'} 個のワークフロー`;
                 case 'distance rates':
-                    return `${enabled ? '有効' : '無効'} 件の距離レート`;
+                    return `${enabled ? '有効' : '無効'} 距離レート`;
                 case 'accounting':
                     return `${enabled ? '有効' : '無効'} 会計`;
                 case 'Expensify Cards':
                     return `${enabled ? '有効' : '無効'} Expensify カード`;
                 case 'travel invoicing':
-                    return `${enabled ? '有効' : '無効'} 統合旅行請求`;
+                    return `${enabled ? '有効' : '無効'} 統合トラベル請求`;
                 case 'company cards':
-                    return `${enabled ? '有効' : '無効'} 件の会社カード`;
+                    return `${enabled ? '有効' : '無効'} 件の法人カード`;
                 case 'invoicing':
-                    return `${enabled ? '有効' : '無効'} 請求書作成`;
+                    return `${enabled ? '有効' : '無効'} の請求書作成`;
                 case 'per diem':
-                    return `${enabled ? '有効' : '無効'} 日当`;
+                    return `${enabled ? '有効' : '無効'} の日当`;
                 case 'receipt partners':
                     return `${enabled ? '有効' : '無効'} 件のレシートパートナー`;
                 case 'rules':
-                    return `${enabled ? '有効' : '無効'} 件のルール`;
+                    return `${enabled ? '有効' : '無効'} 個のルール`;
                 case 'tax tracking':
                     return `${enabled ? '有効' : '無効'} 税金の追跡`;
                 case 'require GPS or map entry for distance rates':
-                    return `距離レートで GPS またはマップでの入力の必須設定を${enabled ? 'オンにしました' : 'オフにしました'}`;
+                    return `${enabled ? 'オンになりました' : 'オフにしました'} は距離レートに GPS もしくは地図での入力が必要です`;
                 default:
                     return `${enabled ? '有効' : '無効'} ${featureName}`;
             }
@@ -9012,9 +9012,6 @@ ${reportName}`,
             reject: '却下',
             duplicateExpense: () => ({
                 one: '経費を複製',
-                // Japanese has no grammatical plural, so `Intl.PluralRules` selects `other` for every count,
-                // including 1. The single/bulk distinction here is semantic rather than grammatical, so `other`
-                // branches on the count itself to keep 一括 (bulk) on the multi-expense action only.
                 other: (count: number) => (count === 1 ? '経費を複製' : '経費を一括複製'),
             }),
             noOptionsAvailable: '選択した経費グループには利用できるオプションがありません。',
@@ -9562,7 +9559,7 @@ ${reportName}`,
         error: {
             selectSuggestedAddress: '候補の住所を選択するか、現在地を使用してください',
             mapOrGpsDistanceRequired: {
-                title: 'GPS またはマップでの入力を必須にする',
+                title: 'GPS または地図での入力が必須です',
                 description: 'このワークスペースでは、地図に基づく距離精算または GPS で追跡された距離精算のいずれかが必要です。',
             },
         },
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index d9ef6a5f..0110ed59 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -7184,9 +7184,9 @@ Het Control-abonnement begint bij $9 per actieve deelnemer per maand.`,
         distanceRates: {
             oopsNotSoFast: 'Oeps! Niet zo snel...',
             workspaceNeeds: 'Een workspace heeft minstens één ingeschakelde afstandstarief nodig.',
-            requireMapOrGPSDescription: 'Handmatige invoer en kilometerstandinvoer worden uitgeschakeld.',
+            requireMapOrGPSDescription: 'Handmatige invoer en kilometertellerinvoer worden uitgeschakeld.',
             requireMapOrGPSLockedByCommuterExclusions:
-                'Het uitsluiten van woon-werkverkeer vereist een route op de kaart, dus invoer via gps of kaart is al vereist. Stop met het uitsluiten van woon-werkverkeer om deze instelling te wijzigen.',
+                'Woon-werkverkeer uitsluiten heeft routedata nodig, dus een kaart- of GPS-afstand is altijd vereist zolang deze optie aanstaat. Om deze instelling te wijzigen, zet Woon-werkverkeer uitsluiten op ‘Woon-werkverkeer niet uitsluiten’.',
             commuterExclusions: {
                 title: 'Woon-werkverkeer uitsluiten',
                 summaryDisabled: 'Geen woon-werkuitzondering',
@@ -8550,7 +8550,7 @@ er bestedingsregels toe om de kasstroom van het bedrijf te beschermen.`,
                 case 'tags':
                     return `${enabled ? 'ingeschakeld' : 'uitgeschakeld'} labels`;
                 case 'workflows':
-                    return `${enabled ? 'ingeschakeld' : 'uitgeschakeld'}-workflows`;
+                    return `${enabled ? 'ingeschakeld' : 'uitgeschakeld'} workflows`;
                 case 'distance rates':
                     return `${enabled ? 'ingeschakeld' : 'uitgeschakeld'} afstandstarieven`;
                 case 'accounting':
@@ -8558,11 +8558,11 @@ er bestedingsregels toe om de kasstroom van het bedrijf te beschermen.`,
                 case 'Expensify Cards':
                     return `${enabled ? 'ingeschakeld' : 'uitgeschakeld'} Expensify Kaarten`;
                 case 'travel invoicing':
-                    return `${enabled ? 'ingeschakeld' : 'uitgeschakeld'} Geconsolideerde reiskostenfacturatie`;
+                    return `${enabled ? 'ingeschakeld' : 'uitgeschakeld'} Geconsolideerde reisfacturatie`;
                 case 'company cards':
                     return `${enabled ? 'ingeschakeld' : 'uitgeschakeld'} bedrijfskaarten`;
                 case 'invoicing':
-                    return `${enabled ? 'ingeschakeld' : 'uitgeschakeld'} facturering`;
+                    return `${enabled ? 'ingeschakeld' : 'uitgeschakeld'} facturatie`;
                 case 'per diem':
                     return `${enabled ? 'ingeschakeld' : 'uitgeschakeld'} dagvergoeding`;
                 case 'receipt partners':
@@ -8572,7 +8572,7 @@ er bestedingsregels toe om de kasstroom van het bedrijf te beschermen.`,
                 case 'tax tracking':
                     return `${enabled ? 'ingeschakeld' : 'uitgeschakeld'} belastingregistratie`;
                 case 'require GPS or map entry for distance rates':
-                    return `${enabled ? 'ingeschakeld' : 'uitgeschakeld'} de verplichte invoer via gps of kaart voor afstandstarieven`;
+                    return `${enabled ? 'ingeschakeld' : 'uitgeschakeld'} vereisen GPS of kaartinvoer voor afstandstarieven`;
                 default:
                     return `${enabled ? 'ingeschakeld' : 'uitgeschakeld'} ${featureName}`;
             }
@@ -9662,7 +9662,7 @@ er bestedingsregels toe om de kasstroom van het bedrijf te beschermen.`,
         error: {
             selectSuggestedAddress: 'Selecteer een voorgesteld adres of gebruik de huidige locatie',
             mapOrGpsDistanceRequired: {
-                title: 'Invoer via gps of kaart vereisen',
+                title: 'GPS of kaartinvoer verplicht',
                 description: 'Deze workspace vereist afstandsdeclaraties die zijn gebaseerd op een kaart of via GPS worden bijgehouden.',
             },
         },
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index a5176786..31ea929c 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -7205,9 +7205,9 @@ Plan Control zaczyna się od 9 USD za aktywnego członka miesięcznie.`,
         distanceRates: {
             oopsNotSoFast: 'Ups! Nie tak szybko...',
             workspaceNeeds: 'Miejsce pracy musi mieć włączoną co najmniej jedną stawkę za dystans.',
-            requireMapOrGPSDescription: 'Wpis ręczny i z licznika zostanie wyłączony.',
+            requireMapOrGPSDescription: 'Ręczne wpisy i wprowadzanie stanu licznika przebiegu zostaną wyłączone.',
             requireMapOrGPSLockedByCommuterExclusions:
-                'Wykluczanie dojazdów do pracy wymaga trasy z mapy, więc wpis z GPS lub mapy jest już wymagany. Przestań wykluczać dojazdy do pracy, aby zmienić to ustawienie.',
+                'Wykluczanie dojazdów wymaga danych o trasie, więc gdy ta opcja jest włączona, zawsze jest potrzebny dystans z mapy lub GPS. Żeby zmienić to ustawienie, ustaw Wykluczaj dojazdy na „Nie wykluczaj dojazdów”.',
             commuterExclusions: {
                 title: 'Wyklucz dojazdy',
                 summaryDisabled: 'Bez wykluczenia dojazdów',
@@ -8573,29 +8573,29 @@ Dodaj więcej zasad wydatków, żeby chronić płynność finansową firmy.`,
                 case 'tags':
                     return `${enabled ? 'włączone' : 'wyłączone'} tagi`;
                 case 'workflows':
-                    return `${enabled ? 'włączone' : 'wyłączone'} przepływy pracy`;
+                    return `${enabled ? 'włączone' : 'wyłączone'} procesy pracy`;
                 case 'distance rates':
-                    return `stawki za przejazdy ${enabled ? 'włączone' : 'wyłączone'}`;
+                    return `Stawki za przejazdy ${enabled ? 'włączone' : 'wyłączone'}`;
                 case 'accounting':
                     return `${enabled ? 'włączone' : 'wyłączone'} księgowość`;
                 case 'Expensify Cards':
                     return `${enabled ? 'włączone' : 'wyłączone'} Karty Expensify`;
                 case 'travel invoicing':
-                    return `${enabled ? 'włączone' : 'wyłączone'} Zbiorcze rozliczenie podróży`;
+                    return `${enabled ? 'włączone' : 'wyłączone'} Zbiorcze rozliczanie podróży`;
                 case 'company cards':
                     return `${enabled ? 'włączone' : 'wyłączone'} karty firmowe`;
                 case 'invoicing':
-                    return `Fakturowanie ${enabled ? 'włączone' : 'wyłączone'}`;
+                    return `Wystawianie faktur ${enabled ? 'włączone' : 'wyłączone'}`;
                 case 'per diem':
-                    return `${enabled ? 'włączone' : 'wyłączone'} diety`;
+                    return `${enabled ? 'włączone' : 'wyłączone'} diety dzienne`;
                 case 'receipt partners':
-                    return `${enabled ? 'włączone' : 'wyłączone'} paragonów od partnerów`;
+                    return `${enabled ? 'włączone' : 'wyłączone'} paragonów partnerów`;
                 case 'rules':
                     return `${enabled ? 'włączone' : 'wyłączone'} reguły`;
                 case 'tax tracking':
-                    return `Śledzenie podatku ${enabled ? 'włączone' : 'wyłączone'}`;
+                    return `śledzenie podatków ${enabled ? 'włączone' : 'wyłączone'}`;
                 case 'require GPS or map entry for distance rates':
-                    return `${enabled ? 'włączono' : 'wyłączono'} wymóg wpisu z GPS lub mapy dla stawek za dystans`;
+                    return `${enabled ? 'włączono' : 'wyłączone'} wymagają GPS lub wprowadzenia na mapie dla stawek za przejazd`;
                 default:
                     return `${enabled ? 'włączone' : 'wyłączone'} ${featureName}`;
             }
@@ -9689,7 +9689,7 @@ Dodaj więcej zasad wydatków, żeby chronić płynność finansową firmy.`,
         error: {
             selectSuggestedAddress: 'Wybierz sugerowany adres lub użyj bieżącej lokalizacji',
             mapOrGpsDistanceRequired: {
-                title: 'Wymagaj wpisu z GPS lub mapy',
+                title: 'Wymagaj GPS lub wpisania na mapie',
                 description: 'W tym obszarze roboczym wymagane są wydatki za przejazdy oparte na mapie lub śledzone za pomocą GPS.',
             },
         },
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index 59c14c63..2ac77665 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -7185,9 +7185,9 @@ O plano Control começa em US$ 9 por membro ativo por mês.`,
         distanceRates: {
             oopsNotSoFast: 'Opa! Não tão rápido...',
             workspaceNeeds: 'Um workspace precisa de pelo menos uma taxa de distância ativada.',
-            requireMapOrGPSDescription: 'A entrada manual e por odômetro será desativada.',
+            requireMapOrGPSDescription: 'A entrada manual e do hodômetro será desativada.',
             requireMapOrGPSLockedByCommuterExclusions:
-                'Excluir deslocamentos para o trabalho exige uma rota mapeada, então a entrada por GPS ou mapa já é exigida. Pare de excluir deslocamentos para o trabalho para alterar esta configuração.',
+                'A opção Excluir deslocamentos exige dados de rota, portanto a distância do mapa ou do GPS sempre será obrigatória enquanto ela estiver ativada. Para alterar essa configuração, defina Excluir deslocamentos como “Não excluir deslocamentos”.',
             commuterExclusions: {
                 title: 'Excluir deslocamentos para o trabalho',
                 summaryDisabled: 'Sem exclusão de deslocamento',
@@ -8550,29 +8550,29 @@ Adicione mais regras de gasto para proteger o fluxo de caixa da empresa.`,
                 case 'tags':
                     return `${enabled ? 'ativado' : 'desativado'} tags`;
                 case 'workflows':
-                    return `Fluxos de trabalho ${enabled ? 'ativado' : 'desativado'}`;
+                    return `${enabled ? 'ativado' : 'desativado'} fluxos de trabalho`;
                 case 'distance rates':
-                    return `${enabled ? 'ativado' : 'desativado'} taxas de distância`;
+                    return `${enabled ? 'ativado' : 'desativado'} tarifas de distância`;
                 case 'accounting':
                     return `${enabled ? 'ativado' : 'desativado'} contabilidade`;
                 case 'Expensify Cards':
                     return `${enabled ? 'ativado' : 'desativado'} Cartões Expensify`;
                 case 'travel invoicing':
-                    return `${enabled ? 'ativado' : 'desativado'} Faturamento Consolidado de Viagens`;
+                    return `${enabled ? 'ativado' : 'desativado'} Faturamento Consolidado de Viagem`;
                 case 'company cards':
                     return `${enabled ? 'ativado' : 'desativado'} cartões corporativos`;
                 case 'invoicing':
-                    return `Faturamento de ${enabled ? 'ativado' : 'desativado'}`;
+                    return `Faturamento ${enabled ? 'ativado' : 'desativado'}`;
                 case 'per diem':
                     return `${enabled ? 'ativado' : 'desativado'} por dia`;
                 case 'receipt partners':
-                    return `${enabled ? 'ativado' : 'desativado'} parceiros de recibos`;
+                    return `Parceiros de recibos ${enabled ? 'ativado' : 'desativado'}`;
                 case 'rules':
                     return `Regras de ${enabled ? 'ativado' : 'desativado'}`;
                 case 'tax tracking':
-                    return `${enabled ? 'ativado' : 'desativado'} rastreamento de impostos`;
+                    return `rastreamento de impostos ${enabled ? 'ativado' : 'desativado'}`;
                 case 'require GPS or map entry for distance rates':
-                    return `${enabled ? 'ativado' : 'desativado'} a exigência de entrada por GPS ou mapa para as taxas de distância`;
+                    return `${enabled ? 'ativado' : 'desativado'} exige GPS ou entrada no mapa para taxas de distância`;
                 default:
                     return `${enabled ? 'ativado' : 'desativado'} ${featureName}`;
             }
@@ -9659,10 +9659,7 @@ Adicione mais regras de gasto para proteger o fluxo de caixa da empresa.`,
         },
         error: {
             selectSuggestedAddress: 'Selecione um endereço sugerido ou use a localização atual',
-            mapOrGpsDistanceRequired: {
-                title: 'Exigir entrada por GPS ou mapa',
-                description: 'Este espaço de trabalho exige despesas de distância baseadas em mapa ou rastreadas por GPS.',
-            },
+            mapOrGpsDistanceRequired: {title: 'Exigir GPS ou inserção no mapa', description: 'Este espaço de trabalho exige despesas de distância baseadas em mapa ou rastreadas por GPS.'},
         },
         odometer: {
             startReading: 'Começar a ler',
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index 12c6735f..9cdca69e 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -6936,8 +6936,8 @@ _如需更详细的说明,请[访问我们的帮助网站](${CONST.NETSUITE_IM
         distanceRates: {
             oopsNotSoFast: '哎呀!先别急……',
             workspaceNeeds: '一个工作区至少需要一个已启用的距离费率。',
-            requireMapOrGPSDescription: '手动录入和里程表录入将被停用。',
-            requireMapOrGPSLockedByCommuterExclusions: '排除通勤需要地图规划的路线,因此已要求使用 GPS 或地图录入。若要更改此设置,请停止排除通勤。',
+            requireMapOrGPSDescription: '将禁用手动输入和里程表输入。',
+            requireMapOrGPSLockedByCommuterExclusions: '排除通勤需要路线数据,因此在其开启时始终需要地图或 GPS 距离。要更改此设置,请将“排除通勤”设为“不要排除通勤”。',
             commuterExclusions: {
                 title: '排除通勤',
                 summaryDisabled: '不排除通勤',
@@ -8248,7 +8248,7 @@ ${reportName}`,
                 case 'tags':
                     return `${enabled ? '已启用' : '已禁用'} 个标签`;
                 case 'workflows':
-                    return `${enabled ? '已启用' : '已禁用'} 个工作流程`;
+                    return `${enabled ? '已启用' : '已禁用'} 个工作流`;
                 case 'distance rates':
                     return `${enabled ? '已启用' : '已禁用'} 距离费率`;
                 case 'accounting':
@@ -8256,13 +8256,13 @@ ${reportName}`,
                 case 'Expensify Cards':
                     return `${enabled ? '已启用' : '已禁用'} Expensify 卡`;
                 case 'travel invoicing':
-                    return `${enabled ? '已启用' : '已禁用'} 合并差旅账单`;
+                    return `${enabled ? '已启用' : '已禁用'} 差旅费用汇总账单`;
                 case 'company cards':
                     return `${enabled ? '已启用' : '已禁用'} 张公司卡`;
                 case 'invoicing':
-                    return `${enabled ? '已启用' : '已禁用'} 开票`;
+                    return `${enabled ? '已启用' : '已禁用'} 开具发票`;
                 case 'per diem':
-                    return `每日津贴 ${enabled ? '已启用' : '已禁用'}`;
+                    return `${enabled ? '已启用' : '已禁用'} 每日津贴`;
                 case 'receipt partners':
                     return `${enabled ? '已启用' : '已禁用'} 个收据合作伙伴`;
                 case 'rules':
@@ -8270,7 +8270,7 @@ ${reportName}`,
                 case 'tax tracking':
                     return `${enabled ? '已启用' : '已禁用'} 税务跟踪`;
                 case 'require GPS or map entry for distance rates':
-                    return `${enabled ? '开启' : '关闭'}了距离费率的 GPS 或地图录入要求`;
+                    return `${enabled ? '已开启' : '已关闭'} 需要使用 GPS 或地图输入来计算距离费率`;
                 default:
                     return `${enabled ? '已启用' : '已禁用'} ${featureName}`;
             }
@@ -9315,10 +9315,7 @@ ${reportName}`,
         },
         error: {
             selectSuggestedAddress: '请选择一个推荐地址或使用当前位置',
-            mapOrGpsDistanceRequired: {
-                title: '要求使用 GPS 或地图录入',
-                description: '此工作区要求里程报销必须基于地图或通过 GPS 进行轨迹跟踪。',
-            },
+            mapOrGpsDistanceRequired: {title: '需要 GPS 或地图输入', description: '此工作区要求里程报销必须基于地图或通过 GPS 进行轨迹跟踪。'},
         },
         odometer: {
             startReading: '开始阅读',

Note

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

View workflow run

@Gonals
Gonals marked this pull request as ready for review August 25, 2026 16:07
@Gonals
Gonals requested review from a team as code owners August 25, 2026 16:07
@melvin-bot
melvin-bot Bot requested review from huult and removed request for a team August 25, 2026 16:07
@melvin-bot

melvin-bot Bot commented Aug 25, 2026

Copy link
Copy Markdown

@huult 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 August 25, 2026 16:07

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b553c96a36

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/libs/actions/Policy/DistanceRate.ts Outdated
onyxMethod: Onyx.METHOD.MERGE,
key: policyKey,
value: {
requireMapOrGPS: !requireMapOrGPS,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Restore the actual prior requirement value

When multiple toggles are queued before responses arrive—particularly while offline—and both requests fail, restoring !requireMapOrGPS can leave Onyx opposite to the server. For example, starting off, toggling on and then off, and having both writes rejected applies failure values false and then true, although the server remains off; the client then incorrectly blocks manual and odometer requests until policy data is refreshed. Pass the pre-toggle stored value into this action and use it for rollback, as the other policy-setting actions do.

Useful? React with 👍 / 👎.

This comment was marked as resolved.

@huult

huult commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

tag me when it's ready for review 🙏

@Gonals

Gonals commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

@huult, code is ready for review. If you don't have backend access, it can't be tested until Auth/Web deploy, though

@Gonals
Gonals requested a review from lakchote August 25, 2026 16:21
@huult

huult commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

@huult, code is ready for review. If you don't have backend access, it can't be tested until Auth/Web deploy, though

@Gonals Yes, I can't access the backend. Once the backend is ready, please tag me to review it. Thank you!

@Gonals Gonals changed the title [HOLD] Add setting to prevent manual/odometer distance requests for a given policy Add setting to prevent manual/odometer distance requests for a given policy Aug 27, 2026
@joekaufmanexpensify
joekaufmanexpensify requested review from JmillsExpensify and removed request for joekaufmanexpensify August 27, 2026 14:57
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Breezy!

Reviewed commit: 6672cd2674

ℹ️ 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@huult

huult commented Aug 27, 2026

Copy link
Copy Markdown
Contributor
Screen.Recording.2026-08-27.at.22.06.06.mov

BUG: Manual distance can't be created in Self-DM when the default workspace has “Require GPS or map entry” enabled.

@huult

huult commented Aug 27, 2026

Copy link
Copy Markdown
Contributor
Screen.Recording.2026-08-27.at.22.16.26.mov
  1. Turn off “Require GPS or map entry” in the workspace settings.
  2. Go to the workspace and create a distance using Manual.
  3. Go back to the workspace settings and enable “Require GPS or map entry”.
  4. Go to the workspace and tap Track distance.

BUG: A “Require GPS or map entry” modal appears instead of opening the Map and GPS tabs.

@Gonals

Gonals commented Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

Screen.Recording.2026-08-27.at.22.06.06.mov
BUG: Manual distance can't be created in Self-DM when the default workspace has “Require GPS or map entry” enabled.

Pre-existing from commute exclusions and getting fixed in its own PR 👍

@huult

huult commented Aug 27, 2026

Copy link
Copy Markdown
Contributor
Screen.Recording.2026-08-28.at.00.32.12.mov

This is still not fixed.

@huult huult 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.

Screen.Recording.2026-08-28.at.01.06.15.mp4

@melvin-bot melvin-bot Bot changed the title Add setting to prevent manual/odometer distance requests for a given policy [Payment due @huult] Add setting to prevent manual/odometer distance requests for a given policy Aug 27, 2026
@melvin-bot

melvin-bot Bot commented Aug 27, 2026

Copy link
Copy Markdown

🎯 @huult, thanks for reviewing and testing this PR! 🎉

A payment issue will be created for your review once this PR is deployed to production.
E/E issue linked to the PR - https://www.github.com/Expensify/Expensify/issues/674995.

If payment is not needed (e.g., regression PR review fix etc), react with 👎 to this comment to prevent the payment issue from being created.

@github-actions

Copy link
Copy Markdown
Contributor

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

@github-actions

This comment has been minimized.

@JmillsExpensify

Copy link
Copy Markdown
Contributor

@Gonals The only thing I noticed was that in this case:

  • Employee is on a workspace restricted to GPS or maps
  • This is the employee's only workspace

We are still showing all creation options.

CleanShot 2026-08-28 at 12 05 54@2x

The logic we're going for is:

  • We show the options permitted by all workspaces the user is a member of
  • If none permit odometer or manual, we don't show them in the segmented control

@JmillsExpensify JmillsExpensify 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.

My bad. I was testing the wrong adhoc for that last comment. Disregard all LGTM!

@lakchote lakchote 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

@lakchote
lakchote merged commit 13c9c4d into main Aug 28, 2026
46 of 48 checks passed
@lakchote
lakchote deleted the alberto-disableManual branch August 28, 2026 12:32
@github-actions

Copy link
Copy Markdown
Contributor

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

@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.

@OSBotify

Copy link
Copy Markdown
Contributor

🚀 Deployed to staging by https://github.com/lakchote in version: 9.4.64-0 🚀

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

@MelvinBot

Copy link
Copy Markdown
Contributor

Yes — help site changes were required. Draft PR: #99801

This PR adds Require GPS or map entry to Distance rates > Settings, and nothing in docs/articles covered it. Two articles are updated:

Article What changed
docs/articles/new-expensify/workspaces/Set-distance-rates.md Admin: how to enable the toggle, what happens after (hidden Manual / Odometer tabs, the block on selecting a restricted workspace, multi-workspace behavior, Your space exemption), plus 2 FAQs
docs/articles/new-expensify/reports-and-expenses/Distance-Expenses.md Member: notes under the Manual and Odometer steps explaining why those tabs may be missing, plus 2 FAQs on the hidden tabs and the block message

One thing to confirm: the FAQ "Why can't I turn off Require GPS or map entry?" references Exclude commutes, which is still beta-gated and isn't documented on the help site yet. It's the only reason the toggle locks, so omitting it leaves the locked state unexplainable — say the word and I'll drop that FAQ until commute exclusions ships publicly.

UI verification

I drove dev NewDot web on alberto-disableManual and confirmed every label used in the docs:

Step Status Observation
Toggle label pass Require GPS or map entry
Toggle subtitle pass Manual and odometer entry will be disabled.
Distance rates Settings rows pass Unit, Default category, Require GPS or map entry, Track tax (no Exclude commutes row — beta off on the test account)
Track distance tabs pass Map, Manual, GPS, Odometer

Block message comes from distance.error.mapOrGpsDistanceRequired.description: "This workspace requires either map-based or GPS-tracked distance expenses."

Distance rates Settings tab with Require GPS or map entry toggle

Distance rates Settings tab with Require GPS or map entry toggle

Track distance panel with Map, Manual, GPS, Odometer tabs

Track distance panel with Map, Manual, GPS, Odometer tabs

@Gonals, please review the linked help site PR and confirm it reflects the current behavior. Then mark the linked help site PR Ready for review


view run

@mitarachim

Copy link
Copy Markdown

Deploy Blocker #99806 was identified to be related to this PR.

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.

8 participants