Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
6ef31b6
add initial types
JS00001 Jan 26, 2026
619b400
add more types
JS00001 Jan 26, 2026
360776d
add helper method
JS00001 Jan 26, 2026
8f5b9dc
add translation
JS00001 Jan 26, 2026
34f1548
add translations for routes
JS00001 Jan 27, 2026
b7ca2bf
cleanup using map
JS00001 Jan 27, 2026
23cfe6f
add tests from php
JS00001 Jan 27, 2026
381cd6c
add to not deprecated action
JS00001 Jan 27, 2026
8022c05
add tests, fix lowercasing/links
JS00001 Jan 27, 2026
2016541
update spacing, update test names
JS00001 Jan 27, 2026
43c1701
fix spellchec
JS00001 Jan 27, 2026
f453812
translations
JS00001 Jan 27, 2026
af203c4
Merge branch 'main' of github.com:Expensify/App into jsenyitko-applie…
JS00001 Jan 27, 2026
8e79c3b
fix lint and types
JS00001 Jan 27, 2026
5565821
add tax rate support
JS00001 Jan 27, 2026
f72fdf8
fix policy ID fields
JS00001 Jan 27, 2026
81c6a67
add tax rate name
JS00001 Jan 27, 2026
5b070c6
add another test for tax rate
JS00001 Jan 27, 2026
5f51cb1
update translation
JS00001 Jan 27, 2026
75f32c2
Merge branch 'main' of github.com:Expensify/App into jsenyitko-applie…
JS00001 Jan 27, 2026
bc954ec
update how we translate
JS00001 Jan 27, 2026
b72bd6c
update translations
JS00001 Jan 27, 2026
ba1ce20
update es
JS00001 Jan 27, 2026
7a6fdd7
update translation logic to match
JS00001 Jan 27, 2026
cbc325e
Merge branch 'main' of github.com:Expensify/App into jsenyitko-applie…
JS00001 Jan 27, 2026
6b3d349
update spanish translation
JS00001 Jan 27, 2026
85c2e94
Merge branch 'main' of github.com:Expensify/App into jsenyitko-applie…
JS00001 Jan 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/languages/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import dedent from '@libs/StringUtils/dedent';
import CONST from '@src/CONST';
import type {Country} from '@src/CONST';
import type OriginalMessage from '@src/types/onyx/OriginalMessage';
import {PolicyRulesModifiedFields} from '@src/types/onyx/OriginalMessage';
import ObjectUtils from '@src/types/utils/ObjectUtils';
import type en from './en';
import type {
ChangeFieldParams,
Expand Down Expand Up @@ -1487,6 +1489,32 @@ const translations: TranslationDeepObject<typeof en> = {
},
correctDistanceRateError: 'Beheben Sie den Fehler beim Entfernungssatz und versuchen Sie es erneut.',
AskToExplain: `. <a href="${CONST.CONCIERGE_EXPLAIN_LINK_PATH}"><strong>Erklären</strong></a> &#x2728;`,
policyRulesModifiedFields: (policyRulesModifiedFields: PolicyRulesModifiedFields, policyRulesRoute: string, formatList: (list: string[]) => string) => {
const entries = ObjectUtils.typedEntries(policyRulesModifiedFields);
const fragments = entries.map(([key, value], i) => {
const isFirst = i === 0;
if (key === 'reimbursable') {
return value ? 'hat die Ausgabe als „erstattungsfähig“ markiert' : 'hat die Ausgabe als „nicht erstattungsfähig“ markiert';
}
if (key === 'billable') {
return value ? 'hat die Ausgabe als „verrechenbar“ markiert' : 'hat die Ausgabe als „nicht abrechenbar“ markiert';
}
if (key === 'tax') {
const taxEntry = value as PolicyRulesModifiedFields['tax'];
const taxRateName = taxEntry?.field_id_TAX.name ?? '';
if (isFirst) {
return `Steuersatz auf „${taxRateName}“ festlegen`;
}
return `Steuersatz zu „${taxRateName}“`;
}
const updatedValue = value as string | boolean;
if (isFirst) {
return `Setzen Sie ${translations.common[key].toLowerCase()} auf „${updatedValue}“`;
}
return `${translations.common[key].toLowerCase()} zu "${updatedValue}"`;
});
return `${formatList(fragments)} über <a href="${policyRulesRoute}">Workspace-Regeln</a>`;
},
},
transactionMerge: {
listPage: {
Expand Down
35 changes: 35 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import dedent from '@libs/StringUtils/dedent';
import CONST from '@src/CONST';
import type {Country} from '@src/CONST';
import type OriginalMessage from '@src/types/onyx/OriginalMessage';
import type {PolicyRulesModifiedFields} from '@src/types/onyx/OriginalMessage';
import ObjectUtils from '@src/types/utils/ObjectUtils';
import type {
ChangeFieldParams,
ConnectionNameParams,
Expand Down Expand Up @@ -1471,6 +1473,39 @@ const translations = {
},
correctDistanceRateError: 'Fix the distance rate error and try again.',
AskToExplain: `. <a href="${CONST.CONCIERGE_EXPLAIN_LINK_PATH}"><strong>Explain</strong></a> &#x2728;`,
policyRulesModifiedFields: (policyRulesModifiedFields: PolicyRulesModifiedFields, policyRulesRoute: string, formatList: (list: string[]) => string) => {
const entries = ObjectUtils.typedEntries(policyRulesModifiedFields);

const fragments = entries.map(([key, value], i) => {
const isFirst = i === 0;

if (key === 'reimbursable') {
return value ? 'marked the expense as "reimbursable"' : 'marked the expense as "non-reimbursable"';
}

if (key === 'billable') {
return value ? 'marked the expense as "billable"' : 'marked the expense as "non-billable"';
}

if (key === 'tax') {
const taxEntry = value as PolicyRulesModifiedFields['tax'];
const taxRateName = taxEntry?.field_id_TAX.name ?? '';
if (isFirst) {
return `set the tax rate to "${taxRateName}"`;
}
return `tax rate to "${taxRateName}"`;
}

const updatedValue = value as string | boolean;
if (isFirst) {
return `set the ${translations.common[key].toLowerCase()} to "${updatedValue}"`;
}

return `${translations.common[key].toLowerCase()} to "${updatedValue}"`;
});

return `${formatList(fragments)} via <a href="${policyRulesRoute}">workspace rules</a>`;
},
},
transactionMerge: {
listPage: {
Expand Down
35 changes: 35 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import {CONST as COMMON_CONST} from 'expensify-common';
import dedent from '@libs/StringUtils/dedent';
import CONST from '@src/CONST';
import type {PolicyRulesModifiedFields} from '@src/types/onyx/OriginalMessage';
import ObjectUtils from '@src/types/utils/ObjectUtils';
import type en from './en';
import type {CreatedReportForUnapprovedTransactionsParams, PaidElsewhereParams, RoutedDueToDEWParams, SplitDateRangeParams, ViolationsRterParams} from './params';
import type {TranslationDeepObject} from './types';
Expand Down Expand Up @@ -1216,6 +1218,39 @@ const translations: TranslationDeepObject<typeof en> = {
},
correctDistanceRateError: 'Corrige el error de la tasa de distancia y vuelve a intentarlo.',
AskToExplain: `. <a href="${CONST.CONCIERGE_EXPLAIN_LINK_PATH}"><strong>Explicar</strong></a> &#x2728;`,
policyRulesModifiedFields: (policyRulesModifiedFields: PolicyRulesModifiedFields, policyRulesRoute: string, formatList: (list: string[]) => string) => {
const entries = ObjectUtils.typedEntries(policyRulesModifiedFields);

const fragments = entries.map(([key, value], i) => {
const isFirst = i === 0;

if (key === 'reimbursable') {
return value ? 'marcó el gasto como "reembolsable"' : 'marcó el gasto como "no reembolsable"';
}

if (key === 'billable') {
return value ? 'marcó el gasto como "facturable"' : 'marcó el gasto como "no facturable"';
}

if (key === 'tax') {
const taxEntry = value as PolicyRulesModifiedFields['tax'];
const taxRateName = taxEntry?.field_id_TAX.name ?? '';
if (isFirst) {
return `estableció la tasa de impuesto a "${taxRateName}"`;
}
return `tasa de impuesto a "${taxRateName}"`;
}

const updatedValue = value as string | boolean;
if (isFirst) {
return `estableció el ${translations.common[key].toLowerCase()} a "${updatedValue}"`;
}

return `${translations.common[key].toLowerCase()} a "${updatedValue}"`;
});

return `${formatList(fragments)} a través de <a href="${policyRulesRoute}">reglas del espacio de trabajo</a>`;
},
},
transactionMerge: {
listPage: {
Expand Down
28 changes: 28 additions & 0 deletions src/languages/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import dedent from '@libs/StringUtils/dedent';
import CONST from '@src/CONST';
import type {Country} from '@src/CONST';
import type OriginalMessage from '@src/types/onyx/OriginalMessage';
import {PolicyRulesModifiedFields} from '@src/types/onyx/OriginalMessage';
import ObjectUtils from '@src/types/utils/ObjectUtils';
import type en from './en';
import type {
ChangeFieldParams,
Expand Down Expand Up @@ -1490,6 +1492,32 @@ const translations: TranslationDeepObject<typeof en> = {
},
correctDistanceRateError: 'Corrigez l’erreur de taux de distance et réessayez.',
AskToExplain: `. <a href="${CONST.CONCIERGE_EXPLAIN_LINK_PATH}"><strong>Expliquer</strong></a> &#x2728;`,
policyRulesModifiedFields: (policyRulesModifiedFields: PolicyRulesModifiedFields, policyRulesRoute: string, formatList: (list: string[]) => string) => {
const entries = ObjectUtils.typedEntries(policyRulesModifiedFields);
const fragments = entries.map(([key, value], i) => {
const isFirst = i === 0;
if (key === 'reimbursable') {
return value ? 'a marqué la dépense comme « remboursable »' : 'a marqué la dépense comme « non remboursable »';
}
if (key === 'billable') {
return value ? 'a marqué la dépense comme « facturable »' : 'a marqué la dépense comme « non refacturable »';
}
if (key === 'tax') {
const taxEntry = value as PolicyRulesModifiedFields['tax'];
const taxRateName = taxEntry?.field_id_TAX.name ?? '';
if (isFirst) {
return `définir le taux de taxe sur « ${taxRateName} »`;
}
return `taux de taxe vers « ${taxRateName} »`;
}
const updatedValue = value as string | boolean;
if (isFirst) {
return `définir ${translations.common[key].toLowerCase()} sur « ${updatedValue} »`;
}
return `${translations.common[key].toLowerCase()} à « ${updatedValue} »`;
});
return `${formatList(fragments)} via les <a href="${policyRulesRoute}">règles de l’espace de travail</a>`;
},
},
transactionMerge: {
listPage: {
Expand Down
28 changes: 28 additions & 0 deletions src/languages/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import dedent from '@libs/StringUtils/dedent';
import CONST from '@src/CONST';
import type {Country} from '@src/CONST';
import type OriginalMessage from '@src/types/onyx/OriginalMessage';
import {PolicyRulesModifiedFields} from '@src/types/onyx/OriginalMessage';
import ObjectUtils from '@src/types/utils/ObjectUtils';
import type en from './en';
import type {
ChangeFieldParams,
Expand Down Expand Up @@ -1484,6 +1486,32 @@ const translations: TranslationDeepObject<typeof en> = {
},
correctDistanceRateError: "Correggi l'errore nella tariffa della distanza e riprova.",
AskToExplain: `. <a href="${CONST.CONCIERGE_EXPLAIN_LINK_PATH}"><strong>Spiega</strong></a> &#x2728;`,
policyRulesModifiedFields: (policyRulesModifiedFields: PolicyRulesModifiedFields, policyRulesRoute: string, formatList: (list: string[]) => string) => {
const entries = ObjectUtils.typedEntries(policyRulesModifiedFields);
const fragments = entries.map(([key, value], i) => {
const isFirst = i === 0;
if (key === 'reimbursable') {
return value ? 'ha contrassegnato la spesa come "rimborsabile"' : 'ha contrassegnato la spesa come "non rimborsabile"';
}
if (key === 'billable') {
return value ? 'ha contrassegnato la spesa come "fatturabile"' : 'ha contrassegnato la spesa come "non addebitabile"';
}
if (key === 'tax') {
const taxEntry = value as PolicyRulesModifiedFields['tax'];
const taxRateName = taxEntry?.field_id_TAX.name ?? '';
if (isFirst) {
return `imposta l'aliquota fiscale su "${taxRateName}"`;
}
return `aliquota fiscale in "${taxRateName}"`;
}
const updatedValue = value as string | boolean;
if (isFirst) {
return `imposta ${translations.common[key].toLowerCase()} su "${updatedValue}"`;
}
return `${translations.common[key].toLowerCase()} a "${updatedValue}"`;
});
return `${formatList(fragments)} tramite <a href="${policyRulesRoute}">regole dello spazio di lavoro</a>`;
},
},
transactionMerge: {
listPage: {
Expand Down
28 changes: 28 additions & 0 deletions src/languages/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import dedent from '@libs/StringUtils/dedent';
import CONST from '@src/CONST';
import type {Country} from '@src/CONST';
import type OriginalMessage from '@src/types/onyx/OriginalMessage';
import {PolicyRulesModifiedFields} from '@src/types/onyx/OriginalMessage';
import ObjectUtils from '@src/types/utils/ObjectUtils';
import type en from './en';
import type {
ChangeFieldParams,
Expand Down Expand Up @@ -1482,6 +1484,32 @@ const translations: TranslationDeepObject<typeof en> = {
},
correctDistanceRateError: '距離レートのエラーを修正して、もう一度お試しください。',
AskToExplain: `. <a href="${CONST.CONCIERGE_EXPLAIN_LINK_PATH}"><strong>説明する</strong></a> &#x2728;`,
policyRulesModifiedFields: (policyRulesModifiedFields: PolicyRulesModifiedFields, policyRulesRoute: string, formatList: (list: string[]) => string) => {
const entries = ObjectUtils.typedEntries(policyRulesModifiedFields);
const fragments = entries.map(([key, value], i) => {
const isFirst = i === 0;
if (key === 'reimbursable') {
return value ? '経費を「立替精算対象」にマークしました' : '経費を「非精算」としてマークしました';
}
if (key === 'billable') {
return value ? '経費を「請求可能」とマークしました' : '経費を「請求対象外」としてマークしました';
}
if (key === 'tax') {
const taxEntry = value as PolicyRulesModifiedFields['tax'];
const taxRateName = taxEntry?.field_id_TAX.name ?? '';
if (isFirst) {
return `税率を「${taxRateName}」に設定`;
}
return `税率を「${taxRateName}」に`;
}
const updatedValue = value as string | boolean;
if (isFirst) {
return `${translations.common[key].toLowerCase()} を「${updatedValue}」に設定`;
}
return `${translations.common[key].toLowerCase()} を「${updatedValue}」に`;
});
return `${formatList(fragments)}(<a href="${policyRulesRoute}">ワークスペースルール</a>経由)`;
},
},
transactionMerge: {
listPage: {
Expand Down
28 changes: 28 additions & 0 deletions src/languages/nl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import dedent from '@libs/StringUtils/dedent';
import CONST from '@src/CONST';
import type {Country} from '@src/CONST';
import type OriginalMessage from '@src/types/onyx/OriginalMessage';
import {PolicyRulesModifiedFields} from '@src/types/onyx/OriginalMessage';
import ObjectUtils from '@src/types/utils/ObjectUtils';
import type en from './en';
import type {
ChangeFieldParams,
Expand Down Expand Up @@ -1483,6 +1485,32 @@ const translations: TranslationDeepObject<typeof en> = {
},
correctDistanceRateError: 'Los het foutieve kilometertarief op en probeer het opnieuw.',
AskToExplain: `. <a href="${CONST.CONCIERGE_EXPLAIN_LINK_PATH}"><strong>Uitleggen</strong></a> &#x2728;`,
policyRulesModifiedFields: (policyRulesModifiedFields: PolicyRulesModifiedFields, policyRulesRoute: string, formatList: (list: string[]) => string) => {
const entries = ObjectUtils.typedEntries(policyRulesModifiedFields);
const fragments = entries.map(([key, value], i) => {
const isFirst = i === 0;
if (key === 'reimbursable') {
return value ? 'heeft de uitgave als „vergoedbaar” gemarkeerd' : 'markeerde de uitgave als ‘niet-terugbetaalbaar’';
}
if (key === 'billable') {
return value ? 'heeft de uitgave gemarkeerd als ‘factureerbaar’' : 'heeft de uitgave als ‘niet-declarabel’ gemarkeerd';
}
if (key === 'tax') {
const taxEntry = value as PolicyRulesModifiedFields['tax'];
const taxRateName = taxEntry?.field_id_TAX.name ?? '';
if (isFirst) {
return `stel het belastingtarief in op "${taxRateName}"`;
}
return `belastingtarief naar "${taxRateName}"`;
}
const updatedValue = value as string | boolean;
if (isFirst) {
return `stel de ${translations.common[key].toLowerCase()} in op "${updatedValue}"`;
}
return `${translations.common[key].toLowerCase()} naar "${updatedValue}"`;
});
return `${formatList(fragments)} via <a href="${policyRulesRoute}">werkruimteregels</a>`;
},
},
transactionMerge: {
listPage: {
Expand Down
28 changes: 28 additions & 0 deletions src/languages/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import dedent from '@libs/StringUtils/dedent';
import CONST from '@src/CONST';
import type {Country} from '@src/CONST';
import type OriginalMessage from '@src/types/onyx/OriginalMessage';
import {PolicyRulesModifiedFields} from '@src/types/onyx/OriginalMessage';
import ObjectUtils from '@src/types/utils/ObjectUtils';
import type en from './en';
import type {
ChangeFieldParams,
Expand Down Expand Up @@ -1482,6 +1484,32 @@ const translations: TranslationDeepObject<typeof en> = {
},
correctDistanceRateError: 'Napraw błąd stawki za dystans i spróbuj ponownie.',
AskToExplain: `. <a href="${CONST.CONCIERGE_EXPLAIN_LINK_PATH}"><strong>Wyjaśnij</strong></a> &#x2728;`,
policyRulesModifiedFields: (policyRulesModifiedFields: PolicyRulesModifiedFields, policyRulesRoute: string, formatList: (list: string[]) => string) => {
const entries = ObjectUtils.typedEntries(policyRulesModifiedFields);
const fragments = entries.map(([key, value], i) => {
const isFirst = i === 0;
if (key === 'reimbursable') {
return value ? 'oznaczył wydatek jako „podlegający zwrotowi”' : 'oznaczył wydatek jako „niepodlegający zwrotowi”';
}
if (key === 'billable') {
return value ? 'oznaczył wydatek jako „refakturowalny”' : 'oznaczył wydatek jako „niepodlegający refakturowaniu”';
}
if (key === 'tax') {
const taxEntry = value as PolicyRulesModifiedFields['tax'];
const taxRateName = taxEntry?.field_id_TAX.name ?? '';
if (isFirst) {
return `ustaw stawkę podatku na „${taxRateName}”`;
}
return `stawka podatku na „${taxRateName}”`;
}
const updatedValue = value as string | boolean;
if (isFirst) {
return `ustaw ${translations.common[key].toLowerCase()} na „${updatedValue}”`;
}
return `${translations.common[key].toLowerCase()} na „${updatedValue}”`;
});
return `${formatList(fragments)} przez <a href="${policyRulesRoute}">zasady przestrzeni roboczej</a>`;
},
},
transactionMerge: {
listPage: {
Expand Down
Loading
Loading