diff --git a/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/Default.tsx b/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/Default.tsx index 60ff99e4..605b058d 100644 --- a/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/Default.tsx +++ b/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/Default.tsx @@ -54,7 +54,7 @@ export function Default({ validationStatus, type, }: DefaultProps) { - const { t } = useTranslation(['scenarios']); + const { t } = useTranslation(['common', 'scenarios']); const customLists = useCustomLists(); const dataModel = useDataModel(); diff --git a/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/Operand/Operand.tsx b/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/Operand/Operand.tsx index f8f597fd..8760429a 100644 --- a/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/Operand/Operand.tsx +++ b/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/Operand/Operand.tsx @@ -1,5 +1,6 @@ import { type AstNode } from '@app-builder/models'; import { useAdaptEditableAstNode } from '@app-builder/services/ast-node/options'; +import { formatReturnValue } from '@app-builder/services/ast-node/return-value'; import { type EditorNodeViewModel, getValidationStatus, @@ -39,7 +40,7 @@ export function Operand({ editableAstNode={editableAstNode} validationStatus={getValidationStatus(operandViewModel)} type="viewer" - returnValue={operandViewModel.returnValue} + returnValue={formatReturnValue(operandViewModel.returnValue)} /> ); } diff --git a/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/Operand/OperandEditor/OperandEditor.tsx b/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/Operand/OperandEditor/OperandEditor.tsx index e15dc537..6cf08441 100644 --- a/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/Operand/OperandEditor/OperandEditor.tsx +++ b/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/Operand/OperandEditor/OperandEditor.tsx @@ -288,8 +288,13 @@ function useMatchOptions({ }) { const { t } = useTranslation(['common']); const constantOptions = useMemo(() => { - return coerceToConstantEditableAstNode(searchValue, { - booleans: { true: [t('common:true')], false: [t('common:false')] }, + return coerceToConstantEditableAstNode(t, searchValue, { + // Accept english and localized values for booleans + // They will be coerced to the localized value + booleans: { + true: ['true', t('common:true')], + false: ['false', t('common:false')], + }, }); }, [searchValue, t]); const matchOptions = useMemo(() => { diff --git a/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/Operand/OperandInfos.tsx b/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/Operand/OperandInfos.tsx index 05fb5787..70b02db8 100644 --- a/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/Operand/OperandInfos.tsx +++ b/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/Operand/OperandInfos.tsx @@ -208,7 +208,7 @@ function AggregatorDescription({ }: { editableAstNode: AggregatorEditableAstNode; }) { - const { t } = useTranslation(['scenarios']); + const { t } = useTranslation(['common', 'scenarios']); const { aggregator, tableName, fieldName, filters } = editableAstNode.astNode.namedChildren; if ( diff --git a/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/Operator.tsx b/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/Operator.tsx index a7e06be7..6356ab8c 100644 --- a/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/Operator.tsx +++ b/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/Operator.tsx @@ -68,7 +68,7 @@ export function Operator({ errors?: EvaluationError[]; viewOnly?: boolean; }) { - const { t } = useTranslation(['scenarios']); + const { t } = useTranslation(['common', 'scenarios']); // We treat undefinedAstNodeName as "no value" const _value = value !== undefinedAstNodeName ? value : undefined; diff --git a/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/TimeAddEdit/TimestampField.tsx b/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/TimeAddEdit/TimestampField.tsx index bb02e1f7..429947f5 100644 --- a/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/TimeAddEdit/TimestampField.tsx +++ b/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/TimeAddEdit/TimestampField.tsx @@ -37,7 +37,7 @@ export const TimestampField = ({ errors: EvaluationError[]; value: EditorNodeViewModel | null; }) => { - const { t } = useTranslation(['scenarios']); + const { t } = useTranslation(['common', 'scenarios']); const dataModel = useDataModel(); const triggerObjectTable = useTriggerObjectTable(); const options = useTimestampFieldOptions(); diff --git a/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/TwoOperandsLine.tsx b/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/TwoOperandsLine.tsx index 0b5eba14..3a8fa823 100644 --- a/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/TwoOperandsLine.tsx +++ b/packages/app-builder/src/components/Scenario/AstBuilder/AstBuilderNode/TwoOperandsLine.tsx @@ -84,7 +84,7 @@ export function TwoOperandsLine({ /> { + setValue={(operator: (typeof operators)[number]) => { setOperator(twoOperandsViewModel.operator.nodeId, operator); }} errors={twoOperandsViewModel.operator.errors} diff --git a/packages/app-builder/src/components/Scenario/AstBuilder/RootAstBuilderNode/RootOrWithAnd.tsx b/packages/app-builder/src/components/Scenario/AstBuilder/RootAstBuilderNode/RootOrWithAnd.tsx index c318c7e8..c62c5f63 100644 --- a/packages/app-builder/src/components/Scenario/AstBuilder/RootAstBuilderNode/RootOrWithAnd.tsx +++ b/packages/app-builder/src/components/Scenario/AstBuilder/RootAstBuilderNode/RootOrWithAnd.tsx @@ -8,6 +8,10 @@ import { type EvaluationError, separateChildrenErrors, } from '@app-builder/models/node-evaluation'; +import { + adaptBooleanReturnValue, + useDisplayReturnValues, +} from '@app-builder/services/ast-node/return-value'; import { type EditorNodeViewModel, findArgumentIndexErrorsFromParent, @@ -20,6 +24,8 @@ import { } from '@app-builder/services/validation'; import clsx from 'clsx'; import { Fragment } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Tag } from 'ui-design-system'; import { EvaluationErrors } from '../../ScenarioValidationError'; import { AstBuilderNode } from '../AstBuilderNode/AstBuilderNode'; @@ -48,6 +54,7 @@ export function adaptRootOrWithAndViewModel( return null; } } + return { orNodeId: viewModel.nodeId, orErrors: viewModel.errors, @@ -87,6 +94,7 @@ export function RootOrWithAnd({ rootOrWithAndViewModel: RootOrWithAndViewModel; viewOnly?: boolean; }) { + const { t } = useTranslation(['common']); const getOrAndNodeEvaluationErrorMessage = useGetOrAndNodeEvaluationErrorMessage(); const getNodeEvaluationErrorMessage = useGetNodeEvaluationErrorMessage(); @@ -102,8 +110,10 @@ export function RootOrWithAnd({ getOrAndNodeEvaluationErrorMessage, ); + const [displayReturnValues] = useDisplayReturnValues(); + return ( -
+
{rootOrWithAndViewModel.ands.map((andChild, childIndex) => { const isFirstChild = childIndex === 0; const { nodeErrors: andNodeErrors } = separateChildrenErrors( @@ -145,6 +155,35 @@ export function RootOrWithAnd({ ...findArgumentIndexErrorsFromParent(child), ]).map(getNodeEvaluationErrorMessage); + const childBooleanReturnValue = adaptBooleanReturnValue( + child.returnValue, + ); + + let rightComponent = null; + if (!viewOnly) { + rightComponent = ( +
+ { + removeAndChild(child.nodeId); + }} + /> +
+ ); + } else if (displayReturnValues && childBooleanReturnValue) { + rightComponent = ( +
+ + {t(`common:${childBooleanReturnValue.value}`)} + +
+ ); + } + return ( // AND operand row @@ -160,7 +199,7 @@ export function RootOrWithAnd({
- {!viewOnly ? ( -
- { - removeAndChild(child.nodeId); - }} - /> -
- ) : null} + {rightComponent}
); })} diff --git a/packages/app-builder/src/models/editable-ast-node.ts b/packages/app-builder/src/models/editable-ast-node.ts index ef8164e9..f59f3fbb 100644 --- a/packages/app-builder/src/models/editable-ast-node.ts +++ b/packages/app-builder/src/models/editable-ast-node.ts @@ -88,13 +88,19 @@ interface EditableAstNodeBase { displayName: string; } +type TFunctionDisplayName = TFunction<['common', 'scenarios'], undefined>; + export class ConstantEditableAstNode implements EditableAstNodeBase { astNode: ConstantAstNode; operandType: OperandType; dataType: DataType; displayName: string; - constructor(astNode: ConstantAstNode, enumOptions: EnumValue[]) { + constructor( + t: TFunctionDisplayName, + astNode: ConstantAstNode, + enumOptions: EnumValue[], + ) { this.astNode = astNode; this.operandType = ConstantEditableAstNode.getOperandType( astNode.constant, @@ -102,6 +108,7 @@ export class ConstantEditableAstNode implements EditableAstNodeBase { ); this.dataType = ConstantEditableAstNode.getDataType(astNode.constant); this.displayName = ConstantEditableAstNode.getConstantDisplayName( + t, astNode.constant, ); } @@ -147,12 +154,13 @@ export class ConstantEditableAstNode implements EditableAstNodeBase { private static getConstantDisplayName( this: void, + t: TFunctionDisplayName, constant: ConstantType, ): string { if (R.isNil(constant)) return ''; if (R.isArray(constant)) { - return `[${constant.map(ConstantEditableAstNode.getConstantDisplayName).join(', ')}]`; + return `[${constant.map((constant) => ConstantEditableAstNode.getConstantDisplayName(t, constant)).join(', ')}]`; } if (R.isString(constant)) { @@ -160,13 +168,19 @@ export class ConstantEditableAstNode implements EditableAstNodeBase { return `"${constant.toString()}"`; } - if (R.isNumber(constant) || R.isBoolean(constant)) { + if (R.isNumber(constant)) { return constant.toString(); } + if (R.isBoolean(constant)) { + return t(`common:${constant}`); + } + // Handle other cases when needed return JSON.stringify( - R.mapValues(constant, ConstantEditableAstNode.getConstantDisplayName), + R.mapValues(constant, (constant) => + ConstantEditableAstNode.getConstantDisplayName(t, constant), + ), ); } } @@ -182,7 +196,7 @@ export class AggregatorEditableAstNode implements EditableAstNodeBase { triggerObjectTable: TableModel; constructor( - t: TFunction<['scenarios'], undefined>, + t: TFunctionDisplayName, astNode: AggregationAstNode, dataModel: TableModel[], customLists: CustomList[], @@ -200,7 +214,7 @@ export class AggregatorEditableAstNode implements EditableAstNodeBase { static getAggregatorDisplayName( this: void, - t: TFunction<['scenarios'], undefined>, + t: TFunctionDisplayName, astNode: AggregationAstNode, ) { const { aggregator, label } = astNode.namedChildren; @@ -312,7 +326,7 @@ export class TimeAddEditableAstNode implements EditableAstNodeBase { displayName: string; constructor( - t: TFunction<['scenarios'], undefined>, + t: TFunctionDisplayName, astNode: TimeAddAstNode = NewTimeAddAstNode(), ) { this.astNode = astNode; @@ -320,7 +334,7 @@ export class TimeAddEditableAstNode implements EditableAstNodeBase { } private static getTimeAddName( - t: TFunction<['scenarios'], undefined>, + t: TFunctionDisplayName, astNode: TimeAddAstNode, ) { const sign = astNode.namedChildren['sign']?.constant ?? ''; @@ -405,7 +419,7 @@ export class TimeNowEditableAstNode implements EditableAstNodeBase { displayName: string; constructor( - t: TFunction<['scenarios'], undefined>, + t: TFunctionDisplayName, astNode: TimeNowAstNode = NewTimeNowAstNode(), ) { this.astNode = astNode; @@ -435,7 +449,7 @@ export type EditableAstNode = | UndefinedEditableAstNode; export function adaptEditableAstNode( - t: TFunction<['scenarios'], undefined>, + t: TFunctionDisplayName, node: AstNode, { triggerObjectTable, @@ -450,7 +464,7 @@ export function adaptEditableAstNode( }, ): EditableAstNode | undefined { if (isConstant(node)) { - return new ConstantEditableAstNode(node, enumOptions); + return new ConstantEditableAstNode(t, node, enumOptions); } if (isCustomListAccess(node)) { @@ -499,7 +513,7 @@ export function adaptEditableAstNode( * - Else, return a default string representation */ export function stringifyAstNode( - t: TFunction<['scenarios'], undefined>, + t: TFunctionDisplayName, astNode: AstNode, config: { triggerObjectTable: TableModel; diff --git a/packages/app-builder/src/models/editable-operators.ts b/packages/app-builder/src/models/editable-operators.ts index 06ab9f81..451aa695 100644 --- a/packages/app-builder/src/models/editable-operators.ts +++ b/packages/app-builder/src/models/editable-operators.ts @@ -87,7 +87,7 @@ export function isOperatorFunction(value: string): value is OperatorFunction { } export function getOperatorName( - t: TFunction<['scenarios'], undefined>, + t: TFunction<['common', 'scenarios'], undefined>, operatorName: string, ) { if (isOperatorFunction(operatorName)) { diff --git a/packages/app-builder/src/services/ast-node/options.tsx b/packages/app-builder/src/services/ast-node/options.tsx index 60af219c..182e3156 100644 --- a/packages/app-builder/src/services/ast-node/options.tsx +++ b/packages/app-builder/src/services/ast-node/options.tsx @@ -103,7 +103,7 @@ export function OptionsProvider({ } export function useTimestampFieldOptions() { - const { t } = useTranslation(['scenarios']); + const { t } = useTranslation(['common', 'scenarios']); const databaseAccessors = useDatabaseAccessors(); const payloadAccessors = usePayloadAccessors(); @@ -131,7 +131,7 @@ export function useOperandOptions({ }: { operandViewModel: OperandViewModel; }) { - const { t } = useTranslation(['scenarios']); + const { t } = useTranslation(['common', 'scenarios']); const databaseAccessors = useDatabaseAccessors(); const payloadAccessors = usePayloadAccessors(); @@ -173,6 +173,7 @@ export function useOperandOptions({ const enumOptions = enumOptionValues.map( (enumValue) => new ConstantEditableAstNode( + t, NewConstantAstNode({ constant: enumValue, }), @@ -244,7 +245,7 @@ function getEnumOptionsFromNeighbour({ } export function useAdaptEditableAstNode() { - const { t } = useTranslation(['scenarios']); + const { t } = useTranslation(['common', 'scenarios']); const customLists = useCustomLists(); const dataModel = useDataModel(); diff --git a/packages/app-builder/src/services/ast-node/return-value.tsx b/packages/app-builder/src/services/ast-node/return-value.tsx index 3171688b..172a5ddc 100644 --- a/packages/app-builder/src/services/ast-node/return-value.tsx +++ b/packages/app-builder/src/services/ast-node/return-value.tsx @@ -3,7 +3,7 @@ import { createContext, useContext, useState } from 'react'; import * as R from 'remeda'; import { noop } from 'typescript-utils'; -type ReturnValue = +export type ReturnValue = | { value: ConstantType; isOmitted: false; @@ -65,3 +65,14 @@ export function DisplayReturnValuesProvider({ export function useDisplayReturnValues() { return useContext(DisplayReturnValues); } + +export function adaptBooleanReturnValue(returnValue?: ReturnValue) { + if ( + returnValue !== undefined && + returnValue.isOmitted === false && + typeof returnValue.value === 'boolean' + ) { + return { value: returnValue.value }; + } + return undefined; +} diff --git a/packages/app-builder/src/services/editor/ast-editor.ts b/packages/app-builder/src/services/editor/ast-editor.ts index 321706a6..15c5ec3d 100644 --- a/packages/app-builder/src/services/editor/ast-editor.ts +++ b/packages/app-builder/src/services/editor/ast-editor.ts @@ -13,7 +13,7 @@ import { nanoid } from 'nanoid'; import { useCallback, useEffect, useState } from 'react'; import * as R from 'remeda'; -import { formatReturnValue } from '../ast-node/return-value'; +import { type ReturnValue } from '../ast-node/return-value'; import { findAndReplaceNode } from './FindAndReplaceNode'; export interface EditorNodeViewModel { @@ -24,7 +24,7 @@ export interface EditorNodeViewModel { children: EditorNodeViewModel[]; namedChildren: Record; parent: EditorNodeViewModel | null; - returnValue?: string; + returnValue?: ReturnValue; } export function adaptEditorNodeViewModel({ @@ -44,7 +44,7 @@ export function adaptEditorNodeViewModel({ errors: computeEvaluationErrors(ast.name, evaluation), children: [], namedChildren: {}, - returnValue: formatReturnValue(evaluation.returnValue), + returnValue: evaluation.returnValue, }; currentNode.children = ast.children.map((child, i) => diff --git a/packages/app-builder/src/services/editor/coerceToConstantEditableAstNode.spec.ts b/packages/app-builder/src/services/editor/coerceToConstantEditableAstNode.spec.ts index 2cc33c96..d1abf4d0 100644 --- a/packages/app-builder/src/services/editor/coerceToConstantEditableAstNode.spec.ts +++ b/packages/app-builder/src/services/editor/coerceToConstantEditableAstNode.spec.ts @@ -1,4 +1,6 @@ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ import { NewAstNode, NewConstantAstNode } from '@app-builder/models'; +import { i18nextTest as t } from '@app-builder/tests/setup/i18next'; import { coerceToConstantEditableAstNode, @@ -14,8 +16,9 @@ const options: CoerceToConstantEditableAstNodeOptions = { describe('coerceToConstantEditableAstNode', () => { it('returns nothing given empty string', () => { - expect(coerceToConstantEditableAstNode('', options)).toHaveLength(0); - expect(coerceToConstantEditableAstNode(' ', options)).toHaveLength(0); + expect(coerceToConstantEditableAstNode(t, '', options)).toHaveLength(0); + expect(coerceToConstantEditableAstNode(t, ' ', options)).toHaveLength(0); + t('common:true'); }); it('return a constant string given a random string', () => { @@ -24,7 +27,7 @@ describe('coerceToConstantEditableAstNode', () => { helperConstantOperandOption({ valueToCoerce, dataType: 'String' }), ]; expect( - coerceToConstantEditableAstNode(valueToCoerce, options), + coerceToConstantEditableAstNode(t, valueToCoerce, options), ).toMatchObject(expected); }); @@ -35,7 +38,7 @@ describe('coerceToConstantEditableAstNode', () => { helperConstantOperandOption({ valueToCoerce, dataType: 'String' }), ]; expect( - coerceToConstantEditableAstNode(valueToCoerce, options), + coerceToConstantEditableAstNode(t, valueToCoerce, options), ).toMatchObject(expected); }); @@ -46,7 +49,7 @@ describe('coerceToConstantEditableAstNode', () => { helperConstantOperandOption({ valueToCoerce, dataType: 'String' }), ]; expect( - coerceToConstantEditableAstNode(valueToCoerce, options), + coerceToConstantEditableAstNode(t, valueToCoerce, options), ).toMatchObject(expected); }); @@ -57,7 +60,7 @@ describe('coerceToConstantEditableAstNode', () => { helperConstantOperandOption({ valueToCoerce, dataType: 'String' }), ]; expect( - coerceToConstantEditableAstNode(valueToCoerce, options), + coerceToConstantEditableAstNode(t, valueToCoerce, options), ).toMatchObject(expected); }); @@ -72,7 +75,7 @@ describe('coerceToConstantEditableAstNode', () => { helperConstantOperandOption({ valueToCoerce, dataType: 'String' }), ]; expect( - coerceToConstantEditableAstNode(valueToCoerce, options), + coerceToConstantEditableAstNode(t, valueToCoerce, options), ).toMatchObject(expected); }); @@ -86,7 +89,7 @@ describe('coerceToConstantEditableAstNode', () => { helperConstantOperandOption({ valueToCoerce, dataType: 'String' }), ]; expect( - coerceToConstantEditableAstNode(valueToCoerce, options), + coerceToConstantEditableAstNode(t, valueToCoerce, options), ).toMatchObject(expected); }); @@ -100,7 +103,7 @@ describe('coerceToConstantEditableAstNode', () => { helperConstantOperandOption({ valueToCoerce, dataType: 'String' }), ]; expect( - coerceToConstantEditableAstNode(valueToCoerce, options), + coerceToConstantEditableAstNode(t, valueToCoerce, options), ).toMatchObject(expected); }); }); @@ -141,15 +144,17 @@ function helperConstantOperandOption({ constant: parseFloat(valueToCoerce), }), }; - case 'Bool': + case 'Bool': { + const constant = valueToCoerce.toLowerCase() === 'true'; return { - displayName: valueToCoerce.toLowerCase(), + displayName: t(`common:${constant}`), operandType: 'Constant', dataType: dataType, astNode: NewAstNode({ - constant: valueToCoerce.toLowerCase() === 'true', + constant, }), }; + } } } diff --git a/packages/app-builder/src/services/editor/coerceToConstantEditableAstNode.ts b/packages/app-builder/src/services/editor/coerceToConstantEditableAstNode.ts index 902db5d4..a91346dc 100644 --- a/packages/app-builder/src/services/editor/coerceToConstantEditableAstNode.ts +++ b/packages/app-builder/src/services/editor/coerceToConstantEditableAstNode.ts @@ -1,5 +1,6 @@ import { NewConstantAstNode } from '@app-builder/models'; import { ConstantEditableAstNode } from '@app-builder/models/editable-ast-node'; +import { type TFunction } from 'i18next'; import * as R from 'remeda'; export interface CoerceToConstantEditableAstNodeOptions { @@ -7,6 +8,7 @@ export interface CoerceToConstantEditableAstNodeOptions { } export function coerceToConstantEditableAstNode( + t: TFunction<['common']>, search: string, options: CoerceToConstantEditableAstNodeOptions, ): ConstantEditableAstNode[] { @@ -26,22 +28,22 @@ export function coerceToConstantEditableAstNode( const astNode = NewConstantAstNode({ constant: parsedNumber, }); - results.push(new ConstantEditableAstNode(astNode, [])); + results.push(new ConstantEditableAstNode(t, astNode, [])); } if (isCoerceableToBoolean(searchLowerCase)) { const astNode = NewConstantAstNode({ constant: coerceToBoolean(searchLowerCase), }); - results.push(new ConstantEditableAstNode(astNode, [])); + results.push(new ConstantEditableAstNode(t, astNode, [])); } - results.push(...coerceToConstantArray(search)); + results.push(...coerceToConstantArray(t, search)); const astNode = NewConstantAstNode({ constant: search, }); - results.push(new ConstantEditableAstNode(astNode, [])); + results.push(new ConstantEditableAstNode(t, astNode, [])); return results; } @@ -52,7 +54,10 @@ const isStringArray = /^\[(\s*"?(\w+)"?\s*,?)*(\s*|\])$/; const captureNumbers = /(?:\s*(?\d+(\.\d+)?)\s*,?)/g; const captureStrings = /(?:\s*"?(?\w(\w|\s)*\w)"?\s*,?)/g; -function coerceToConstantArray(search: string): ConstantEditableAstNode[] { +function coerceToConstantArray( + t: TFunction<['common']>, + search: string, +): ConstantEditableAstNode[] { const trimSearch = search.trim(); if (isNumberArray.test(trimSearch)) { @@ -66,7 +71,7 @@ function coerceToConstantArray(search: string): ConstantEditableAstNode[] { constant, }), ); - return [new ConstantEditableAstNode(astNode, [])]; + return [new ConstantEditableAstNode(t, astNode, [])]; } if (isStringArray.test(trimSearch)) { @@ -79,7 +84,7 @@ function coerceToConstantArray(search: string): ConstantEditableAstNode[] { constant, }), ); - return [new ConstantEditableAstNode(astNode, [])]; + return [new ConstantEditableAstNode(t, astNode, [])]; } return []; diff --git a/packages/app-builder/src/services/i18n/i18n-config.ts b/packages/app-builder/src/services/i18n/i18n-config.ts index aae44e2d..8a961fcd 100644 --- a/packages/app-builder/src/services/i18n/i18n-config.ts +++ b/packages/app-builder/src/services/i18n/i18n-config.ts @@ -11,6 +11,9 @@ export const supportedLngs = ['en'] as const; const fallbackLng = 'en'; export const i18nConfig = { + interpolation: { + escapeValue: false, // not needed for react + }, defaultNS, // This is the list of languages your application supports supportedLngs: [...supportedLngs], diff --git a/packages/app-builder/src/tests/setup/i18next.ts b/packages/app-builder/src/tests/setup/i18next.ts new file mode 100644 index 00000000..c31514b9 --- /dev/null +++ b/packages/app-builder/src/tests/setup/i18next.ts @@ -0,0 +1,46 @@ +import { i18nConfig } from '@app-builder/services/i18n/i18n-config'; +import i18next, { type TFunction } from 'i18next'; +import { initReactI18next } from 'react-i18next'; + +import api from '../../../public/locales/en/api.json'; +import auth from '../../../public/locales/en/auth.json'; +import cases from '../../../public/locales/en/cases.json'; +import common from '../../../public/locales/en/common.json'; +import data from '../../../public/locales/en/data.json'; +import decisions from '../../../public/locales/en/decisions.json'; +import filters from '../../../public/locales/en/filters.json'; +import lists from '../../../public/locales/en/lists.json'; +import navigation from '../../../public/locales/en/navigation.json'; +import scenarios from '../../../public/locales/en/scenarios.json'; +import scheduledExecution from '../../../public/locales/en/scheduledExecution.json'; +import settings from '../../../public/locales/en/settings.json'; +import upload from '../../../public/locales/en/upload.json'; + +const resources = { + en: { + api, + auth, + cases, + common, + data, + decisions, + filters, + lists, + navigation, + scenarios, + scheduledExecution, + settings, + upload, + }, +}; + +// eslint-disable-next-line import/no-named-as-default-member +export const i18nextTest = (await i18next.use(initReactI18next).init({ + ...i18nConfig, + lng: 'en', + fallbackLng: 'en', + debug: true, + resources, + // cf https://github.com/i18next/react-i18next/issues/1699 + // eslint-disable-next-line @typescript-eslint/no-explicit-any +})) as TFunction;