feat: add lingui/no-unlocalized-strings ESLint rule and fix translations (#16610)
## Summary
This PR adds the `lingui/no-unlocalized-strings` ESLint rule to detect
untranslated strings and fixes translation issues across multiple
components.
## Changes
### ESLint Configuration (`eslint.config.react.mjs`)
- Added comprehensive `ignore` patterns for non-translatable strings
(CSS values, HTML attributes, technical identifiers)
- Added `ignoreNames` for props that don't need translation (className,
data-*, aria-*, etc.)
- Added `ignoreFunctions` for console methods, URL APIs, and other
non-user-facing functions
- Disabled rule for debug files, storybook, and test files
### Components Fixed (~19 files)
- Object record components (field inputs, pickers, merge dialogs)
- Settings components (accounts, admin panel)
- Serverless function components
- Record table and title cell components
## Status
🚧 **Work in Progress** - ~124 files remaining to fix
This PR is being submitted as draft to allow progressive fixing of
remaining translation issues.
## Testing
- Run `npx eslint "src/**/*.tsx"` in `packages/twenty-front` to check
remaining issues
This commit is contained in:
+2
-1
@@ -7,6 +7,7 @@ import { Select } from '@/ui/input/components/Select';
|
||||
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||
|
||||
import styled from '@emotion/styled';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useContext } from 'react';
|
||||
import { capitalize } from 'twenty-shared/utils';
|
||||
|
||||
@@ -38,7 +39,7 @@ export const AdvancedFilterCommandMenuLogicalOperatorCell = ({
|
||||
return (
|
||||
<StyledContainer>
|
||||
{index === 0 ? (
|
||||
<StyledText>Where</StyledText>
|
||||
<StyledText>{t`Where`}</StyledText>
|
||||
) : index === 1 ? (
|
||||
readonly ? (
|
||||
<Select
|
||||
|
||||
+2
-1
@@ -5,6 +5,7 @@ import { currentRecordFiltersComponentState } from '@/object-record/record-filte
|
||||
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
||||
import { SelectControl } from '@/ui/input/components/SelectControl';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useContext } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
@@ -41,7 +42,7 @@ export const AdvancedFilterCommandMenuRecordFilterOperandSelect = ({
|
||||
selectedOption={{
|
||||
label: filter?.operand
|
||||
? getOperandLabel(filter.operand)
|
||||
: 'Select operand',
|
||||
: t`Select operand`,
|
||||
value: null,
|
||||
}}
|
||||
isDisabled
|
||||
|
||||
+7
-6
@@ -17,6 +17,7 @@ import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||
import { useContext } from 'react';
|
||||
import { RecordFilterGroupLogicalOperator } from 'twenty-shared/types';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { getFilterTypeFromFieldType, isDefined } from 'twenty-shared/utils';
|
||||
import { IconLibraryPlus, IconPlus } from 'twenty-ui/display';
|
||||
import { MenuItem } from 'twenty-ui/navigation';
|
||||
@@ -149,8 +150,8 @@ export const AdvancedFilterAddFilterRuleSelect = ({
|
||||
<ActionButton
|
||||
action={{
|
||||
Icon: IconPlus,
|
||||
label: 'Add rule',
|
||||
shortLabel: 'Add rule',
|
||||
label: t`Add rule`,
|
||||
shortLabel: t`Add rule`,
|
||||
key: 'add-rule',
|
||||
}}
|
||||
onClick={handleAddFilter}
|
||||
@@ -165,8 +166,8 @@ export const AdvancedFilterAddFilterRuleSelect = ({
|
||||
<ActionButton
|
||||
action={{
|
||||
Icon: IconPlus,
|
||||
label: 'Add filter rule',
|
||||
shortLabel: 'Add filter rule',
|
||||
label: t`Add filter rule`,
|
||||
shortLabel: t`Add filter rule`,
|
||||
key: 'add-filter-rule',
|
||||
}}
|
||||
/>
|
||||
@@ -176,13 +177,13 @@ export const AdvancedFilterAddFilterRuleSelect = ({
|
||||
<DropdownMenuItemsContainer>
|
||||
<MenuItem
|
||||
LeftIcon={IconPlus}
|
||||
text="Add rule"
|
||||
text={t`Add rule`}
|
||||
onClick={handleAddFilter}
|
||||
/>
|
||||
{isFilterRuleGroupOptionVisible && (
|
||||
<MenuItem
|
||||
LeftIcon={IconLibraryPlus}
|
||||
text="Add rule group"
|
||||
text={t`Add rule group`}
|
||||
onClick={handleAddFilterGroup}
|
||||
/>
|
||||
)}
|
||||
|
||||
+2
-1
@@ -4,6 +4,7 @@ import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-recor
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { TextInput } from '@/ui/input/components/TextInput';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { t } from '@lingui/core/macro';
|
||||
|
||||
export const AdvancedFilterDropdownNumberInput = () => {
|
||||
const selectedOperandInDropdown = useRecoilComponentValue(
|
||||
@@ -32,7 +33,7 @@ export const AdvancedFilterDropdownNumberInput = () => {
|
||||
<TextInput
|
||||
value={objectFilterDropdownFilterValue}
|
||||
onChange={handleChange}
|
||||
placeholder="Enter value"
|
||||
placeholder={t`Enter value`}
|
||||
fullWidth
|
||||
type="number"
|
||||
/>
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
import { useApplyObjectFilterDropdownFilterValue } from '@/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownFilterValue';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { TextInput } from '@/ui/input/components/TextInput';
|
||||
import { t } from '@lingui/core/macro';
|
||||
|
||||
type AdvancedFilterDropdownTextInputProps = {
|
||||
recordFilter: RecordFilter;
|
||||
@@ -20,7 +21,7 @@ export const AdvancedFilterDropdownTextInput = ({
|
||||
<TextInput
|
||||
value={recordFilter.value}
|
||||
onChange={handleChange}
|
||||
placeholder="Enter value"
|
||||
placeholder={t`Enter value`}
|
||||
fullWidth
|
||||
/>
|
||||
);
|
||||
|
||||
+2
-1
@@ -2,6 +2,7 @@ import { AdvancedFilterLogicalOperatorDropdown } from '@/object-record/advanced-
|
||||
import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup';
|
||||
|
||||
import styled from '@emotion/styled';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { capitalize } from 'twenty-shared/utils';
|
||||
|
||||
const StyledText = styled.div`
|
||||
@@ -31,7 +32,7 @@ export const AdvancedFilterLogicalOperatorCell = ({
|
||||
return (
|
||||
<StyledContainer>
|
||||
{index === 0 ? (
|
||||
<StyledText>Where</StyledText>
|
||||
<StyledText>{t`Where`}</StyledText>
|
||||
) : index === 1 ? (
|
||||
<AdvancedFilterLogicalOperatorDropdown
|
||||
recordFilterGroup={recordFilterGroup}
|
||||
|
||||
+3
-2
@@ -7,6 +7,7 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { IconDotsVertical, IconTrash } from 'twenty-ui/display';
|
||||
import { IconButton } from 'twenty-ui/input';
|
||||
import { MenuItem } from 'twenty-ui/navigation';
|
||||
@@ -48,7 +49,7 @@ export const AdvancedFilterRecordFilterGroupOptionsDropdown = ({
|
||||
dropdownId={dropdownId}
|
||||
clickableComponent={
|
||||
<IconButton
|
||||
aria-label="Filter group rule options"
|
||||
aria-label={t`Filter group rule options`}
|
||||
variant="tertiary"
|
||||
Icon={IconDotsVertical}
|
||||
/>
|
||||
@@ -57,7 +58,7 @@ export const AdvancedFilterRecordFilterGroupOptionsDropdown = ({
|
||||
<DropdownContent>
|
||||
<DropdownMenuItemsContainer>
|
||||
<MenuItem
|
||||
text="Remove rule group"
|
||||
text={t`Remove rule group`}
|
||||
onClick={handleRemove}
|
||||
LeftIcon={IconTrash}
|
||||
accent="danger"
|
||||
|
||||
+2
-1
@@ -5,6 +5,7 @@ import { getRecordFilterOperands } from '@/object-record/record-filter/utils/get
|
||||
import { SelectControl } from '@/ui/input/components/SelectControl';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import styled from '@emotion/styled';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
@@ -43,7 +44,7 @@ export const AdvancedFilterRecordFilterOperandSelect = ({
|
||||
selectedOption={{
|
||||
label: filter?.operand
|
||||
? getOperandLabel(filter.operand)
|
||||
: 'Select operand',
|
||||
: t`Select operand`,
|
||||
value: null,
|
||||
}}
|
||||
isDisabled
|
||||
|
||||
+2
-1
@@ -14,6 +14,7 @@ import { SelectableList } from '@/ui/layout/selectable-list/components/Selectabl
|
||||
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
|
||||
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { type ViewFilterOperand } from 'twenty-shared/types';
|
||||
import { MenuItem } from 'twenty-ui/navigation';
|
||||
|
||||
@@ -54,7 +55,7 @@ export const AdvancedFilterRecordFilterOperandSelectContent = ({
|
||||
selectedOption={{
|
||||
label: filter?.operand
|
||||
? getOperandLabel(filter.operand)
|
||||
: 'Select operand',
|
||||
: t`Select operand`,
|
||||
value: null,
|
||||
}}
|
||||
/>
|
||||
|
||||
+3
-2
@@ -11,6 +11,7 @@ import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { IconDotsVertical, IconTrash } from 'twenty-ui/display';
|
||||
import { IconButton } from 'twenty-ui/input';
|
||||
@@ -68,7 +69,7 @@ export const AdvancedFilterRecordFilterOptionsDropdown = ({
|
||||
dropdownId={dropdownId}
|
||||
clickableComponent={
|
||||
<IconButton
|
||||
aria-label="Record filter rule options"
|
||||
aria-label={t`Record filter rule options`}
|
||||
variant="tertiary"
|
||||
Icon={IconDotsVertical}
|
||||
/>
|
||||
@@ -77,7 +78,7 @@ export const AdvancedFilterRecordFilterOptionsDropdown = ({
|
||||
<DropdownContent>
|
||||
<DropdownMenuItemsContainer>
|
||||
<MenuItem
|
||||
text="Remove rule"
|
||||
text={t`Remove rule`}
|
||||
onClick={handleRemove}
|
||||
LeftIcon={IconTrash}
|
||||
accent="danger"
|
||||
|
||||
+4
-1
@@ -23,6 +23,7 @@ import { SelectableList } from '@/ui/layout/selectable-list/components/Selectabl
|
||||
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
|
||||
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
|
||||
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { IconChevronLeft, useIcons } from 'twenty-ui/display';
|
||||
import { MenuItem } from 'twenty-ui/navigation';
|
||||
|
||||
@@ -112,6 +113,8 @@ export const AdvancedFilterSubFieldSelectMenu = ({
|
||||
...subFieldNames.map((subFieldName) => subFieldName),
|
||||
];
|
||||
|
||||
const fieldLabel = fieldMetadataItemUsedInDropdown?.label;
|
||||
|
||||
return (
|
||||
<DropdownContent widthInPixels={GenericDropdownContentWidth.ExtraLarge}>
|
||||
<DropdownMenuHeader
|
||||
@@ -146,7 +149,7 @@ export const AdvancedFilterSubFieldSelectMenu = ({
|
||||
handleSelectFilter(fieldMetadataItemUsedInDropdown);
|
||||
}}
|
||||
LeftIcon={getIcon(fieldMetadataItemUsedInDropdown.icon)}
|
||||
text={`Any ${fieldMetadataItemUsedInDropdown.label} field`}
|
||||
text={t`Any ${fieldLabel} field`}
|
||||
/>
|
||||
</SelectableListItem>
|
||||
)}
|
||||
|
||||
+2
-1
@@ -9,6 +9,7 @@ import styled from '@emotion/styled';
|
||||
|
||||
import { useFieldMetadataItemById } from '@/object-metadata/hooks/useFieldMetadataItemById';
|
||||
import { useGetRecordFilterDisplayValue } from '@/object-record/record-filter/hooks/useGetRecordFilterDisplayValue';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
// TODO: factorize this with https://github.com/twentyhq/core-team-issues/issues/752
|
||||
@@ -57,7 +58,7 @@ export const AdvancedFilterValueInputDropdownButtonClickableSelect = ({
|
||||
|
||||
const placeholderText = isDefined(fieldMetadataItem)
|
||||
? getAdvancedFilterInputPlaceholderText(fieldMetadataItem)
|
||||
: 'Enter filter';
|
||||
: t`Enter filter`;
|
||||
|
||||
const recordFilterDisplayValue = getRecordFilterDisplayValue(recordFilter);
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import { recordIndexOpenRecordInState } from '@/object-record/record-index/state
|
||||
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { canOpenObjectInSidePanel } from '@/object-record/utils/canOpenObjectInSidePanel';
|
||||
import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { type MouseEvent } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
@@ -81,6 +82,7 @@ export const RecordChip = ({
|
||||
return (
|
||||
<Chip
|
||||
label={recordChipData.name}
|
||||
emptyLabel={t`Untitled`}
|
||||
size={size}
|
||||
maxWidth={maxWidth}
|
||||
className={className}
|
||||
@@ -104,6 +106,7 @@ export const RecordChip = ({
|
||||
size={size}
|
||||
maxWidth={maxWidth}
|
||||
label={recordChipData.name}
|
||||
emptyLabel={t`Untitled`}
|
||||
isLabelHidden={isLabelHidden}
|
||||
leftComponent={
|
||||
isIconHidden ? null : (
|
||||
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { t } from '@lingui/core/macro';
|
||||
|
||||
import { useApplyObjectFilterDropdownFilterValue } from '@/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownFilterValue';
|
||||
import { useObjectFilterDropdownFilterValue } from '@/object-record/object-filter-dropdown/hooks/useObjectFilterDropdownFilterValue';
|
||||
@@ -45,7 +46,7 @@ export const ObjectFilterDropdownBooleanSelect = () => {
|
||||
const handleOptionSelect = (newValue: boolean) => {
|
||||
applyObjectFilterDropdownFilterValue(
|
||||
newValue.toString(),
|
||||
newValue ? 'True' : 'False',
|
||||
newValue ? t`True` : t`False`,
|
||||
);
|
||||
|
||||
closeDropdown();
|
||||
|
||||
+3
-1
@@ -8,6 +8,7 @@ import { type SelectableItem } from '@/object-record/select/types/SelectableItem
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
@@ -64,9 +65,10 @@ export const ObjectFilterDropdownSourceSelect = ({
|
||||
.filter((option) => newSelectedItemIds.includes(option.id))
|
||||
.map((option) => option.name);
|
||||
|
||||
const selectedCount = selectedItemNames.length;
|
||||
const filterDisplayValue =
|
||||
selectedItemNames.length > MAX_ITEMS_TO_DISPLAY
|
||||
? `${selectedItemNames.length} source types`
|
||||
? t`${selectedCount} source types`
|
||||
: selectedItemNames.join(', ');
|
||||
|
||||
const newFilterValue =
|
||||
|
||||
+4
-2
@@ -50,7 +50,7 @@ export const ObjectOptionsDropdownCustomView = ({
|
||||
? {
|
||||
...currentView,
|
||||
key: ViewKey.Custom,
|
||||
name: currentView.name || 'Custom View',
|
||||
name: currentView.name || t`Custom View`,
|
||||
}
|
||||
: null;
|
||||
|
||||
@@ -76,6 +76,8 @@ export const ObjectOptionsDropdownCustomView = ({
|
||||
viewBarId: recordIndexId,
|
||||
});
|
||||
|
||||
const visibleFieldsCount = visibleBoardFields.length;
|
||||
|
||||
const { deleteViewFromCurrentState } = useDeleteViewFromCurrentState();
|
||||
const setViewPickerReferenceViewId = useSetRecoilComponentState(
|
||||
viewPickerReferenceViewIdComponentState,
|
||||
@@ -211,7 +213,7 @@ export const ObjectOptionsDropdownCustomView = ({
|
||||
onClick={() => onContentChange('fields')}
|
||||
LeftIcon={IconListDetails}
|
||||
text={t`Fields`}
|
||||
contextualText={`${visibleBoardFields.length} shown`}
|
||||
contextualText={t`${visibleFieldsCount} shown`}
|
||||
contextualTextPosition="right"
|
||||
hasSubMenu
|
||||
/>
|
||||
|
||||
+3
-1
@@ -35,6 +35,8 @@ export const ObjectOptionsDropdownDefaultView = () => {
|
||||
viewBarId: recordIndexId,
|
||||
});
|
||||
|
||||
const visibleFieldsCount = visibleBoardFields.length;
|
||||
|
||||
const selectableItemIdArray = [
|
||||
'Fields',
|
||||
'Copy link to view',
|
||||
@@ -86,7 +88,7 @@ export const ObjectOptionsDropdownDefaultView = () => {
|
||||
onClick={() => onContentChange('fields')}
|
||||
LeftIcon={IconListDetails}
|
||||
text={t`Fields`}
|
||||
contextualText={`${visibleBoardFields.length} shown`}
|
||||
contextualText={t`${visibleFieldsCount} shown`}
|
||||
contextualTextPosition="right"
|
||||
hasSubMenu
|
||||
/>
|
||||
|
||||
+2
-2
@@ -75,10 +75,10 @@ export const ObjectOptionsDropdownHiddenRecordGroupsContent = () => {
|
||||
/>
|
||||
}
|
||||
>
|
||||
Hidden {recordGroupFieldMetadata?.label}
|
||||
{t`Hidden`} {recordGroupFieldMetadata?.label}
|
||||
</DropdownMenuHeader>
|
||||
<RecordGroupsVisibilityDropdownSection
|
||||
title={`Hidden ${recordGroupFieldMetadata?.label}`}
|
||||
title={`${t`Hidden`} ${recordGroupFieldMetadata?.label}`}
|
||||
recordGroupIds={hiddenRecordGroupIds}
|
||||
onVisibilityChange={handleRecordGroupVisibilityChange}
|
||||
isDraggable={false}
|
||||
|
||||
+2
-1
@@ -14,6 +14,7 @@ import { SelectableListItem } from '@/ui/layout/selectable-list/components/Selec
|
||||
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
|
||||
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import {
|
||||
IconChevronLeft,
|
||||
IconHandMove,
|
||||
@@ -67,7 +68,7 @@ export const ObjectOptionsDropdownRecordGroupSortContent = () => {
|
||||
/>
|
||||
}
|
||||
>
|
||||
Sort
|
||||
{t`Sort`}
|
||||
</DropdownMenuHeader>
|
||||
<DropdownMenuItemsContainer>
|
||||
<SelectableList
|
||||
|
||||
+2
-2
@@ -106,7 +106,7 @@ export const ObjectOptionsDropdownRecordGroupsContent = () => {
|
||||
/>
|
||||
}
|
||||
>
|
||||
Group
|
||||
{t`Group`}
|
||||
</DropdownMenuHeader>
|
||||
<DropdownMenuItemsContainer>
|
||||
<SelectableList
|
||||
@@ -187,7 +187,7 @@ export const ObjectOptionsDropdownRecordGroupsContent = () => {
|
||||
<MenuItemNavigate
|
||||
onClick={() => onContentChange('hiddenRecordGroups')}
|
||||
LeftIcon={IconEyeOff}
|
||||
text={`Hidden ${recordGroupFieldMetadata?.label ?? ''}`}
|
||||
text={`${t`Hidden`} ${recordGroupFieldMetadata?.label ?? ''}`}
|
||||
/>
|
||||
</SelectableListItem>
|
||||
</SelectableList>
|
||||
|
||||
+2
-1
@@ -6,6 +6,7 @@ import { useCreateNewIndexRecord } from '@/object-record/record-table/hooks/useC
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useContext } from 'react';
|
||||
import { IconPlus } from 'twenty-ui/display';
|
||||
|
||||
@@ -66,7 +67,7 @@ export const RecordBoardColumnNewRecordButton = () => {
|
||||
}}
|
||||
>
|
||||
<IconPlus size={theme.icon.size.md} />
|
||||
New
|
||||
{t`New`}
|
||||
</StyledNewButton>
|
||||
);
|
||||
};
|
||||
|
||||
+3
-3
@@ -91,15 +91,15 @@ export const RecordCalendarTopBar = () => {
|
||||
selectSizeVariant="small"
|
||||
options={[
|
||||
{
|
||||
label: 'Month',
|
||||
label: t`Month`,
|
||||
value: ViewCalendarLayout.MONTH,
|
||||
},
|
||||
{
|
||||
label: 'Week',
|
||||
label: t`Week`,
|
||||
value: ViewCalendarLayout.WEEK,
|
||||
},
|
||||
{
|
||||
label: 'Timeline',
|
||||
label: t`Timeline`,
|
||||
value: ViewCalendarLayout.DAY,
|
||||
},
|
||||
]}
|
||||
|
||||
+3
-2
@@ -7,6 +7,7 @@ import { currentRecordFiltersComponentState } from '@/object-record/record-filte
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||
import {
|
||||
combineFilters,
|
||||
@@ -56,7 +57,7 @@ export const useRecordCalendarQueryDateRangeFilter = (selectedDate: Date) => {
|
||||
value: `${firstDayOfFirstWeek.toISOString()}`,
|
||||
operand: RecordFilterOperand.IS_AFTER,
|
||||
type: 'DATE',
|
||||
label: 'After',
|
||||
label: t`After`,
|
||||
displayValue: `${firstDayOfFirstWeek.toISOString()}`,
|
||||
};
|
||||
|
||||
@@ -66,7 +67,7 @@ export const useRecordCalendarQueryDateRangeFilter = (selectedDate: Date) => {
|
||||
value: `${lastDayOfLastWeek.toISOString()}`,
|
||||
operand: RecordFilterOperand.IS_BEFORE,
|
||||
type: 'DATE',
|
||||
label: 'Before',
|
||||
label: t`Before`,
|
||||
displayValue: `${lastDayOfLastWeek.toISOString()}`,
|
||||
};
|
||||
|
||||
|
||||
+8
-6
@@ -35,6 +35,8 @@ import {
|
||||
computeMorphRelationFieldName,
|
||||
CustomError,
|
||||
} from 'twenty-shared/utils';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import {
|
||||
IconChevronDown,
|
||||
IconDotsVertical,
|
||||
@@ -263,14 +265,14 @@ export const RecordDetailRelationRecordsListItem = ({
|
||||
<DropdownMenuItemsContainer>
|
||||
<MenuItem
|
||||
LeftIcon={IconUnlink}
|
||||
text="Detach"
|
||||
text={t`Detach`}
|
||||
onClick={handleDetach}
|
||||
/>
|
||||
{!isAccountOwnerRelation &&
|
||||
relationObjectPermissions.canSoftDeleteObjectRecords && (
|
||||
<MenuItem
|
||||
LeftIcon={IconTrash}
|
||||
text="Delete"
|
||||
text={t`Delete`}
|
||||
accent="danger"
|
||||
onClick={handleDelete}
|
||||
/>
|
||||
@@ -295,17 +297,17 @@ export const RecordDetailRelationRecordsListItem = ({
|
||||
{createPortal(
|
||||
<ConfirmationModal
|
||||
modalId={getDeleteRelationModalId(relationRecord.id)}
|
||||
title={`Delete Related ${relationObjectTypeName}`}
|
||||
title={t`Delete Related ${relationObjectTypeName}`}
|
||||
subtitle={
|
||||
<>
|
||||
<Trans>
|
||||
Are you sure you want to delete this related{' '}
|
||||
{relationObjectMetadataNameSingular}?
|
||||
<br />
|
||||
This action will break all its relationships with other objects.
|
||||
</>
|
||||
</Trans>
|
||||
}
|
||||
onConfirmClick={handleConfirmDelete}
|
||||
confirmButtonText={`Delete ${relationObjectTypeName}`}
|
||||
confirmButtonText={t`Delete ${relationObjectTypeName}`}
|
||||
/>,
|
||||
document.body,
|
||||
)}
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ export const LightCopyIconButton = ({ copyText }: LightCopyIconButtonProps) => {
|
||||
onClick={() => {
|
||||
copyToClipboard(copyText, t`Text copied to clipboard`);
|
||||
}}
|
||||
aria-label="Copy to Clipboard"
|
||||
aria-label={t`Copy to Clipboard`}
|
||||
/>
|
||||
</StyledButtonContainer>
|
||||
);
|
||||
|
||||
+12
-11
@@ -6,6 +6,7 @@ import { type VariablePickerComponent } from '@/object-record/record-field/ui/fo
|
||||
import { type FieldAddressDraftValue } from '@/object-record/record-field/ui/types/FieldInputDraftValue';
|
||||
import { type FieldAddressValue } from '@/object-record/record-field/ui/types/FieldMetadata';
|
||||
import { InputLabel } from '@/ui/input/components/InputLabel';
|
||||
import { t } from '@lingui/core/macro';
|
||||
|
||||
type FormAddressFieldInputProps = {
|
||||
label?: string;
|
||||
@@ -43,47 +44,47 @@ export const FormAddressFieldInput = ({
|
||||
{label ? <InputLabel>{label}</InputLabel> : null}
|
||||
<FormNestedFieldInputContainer>
|
||||
<FormTextFieldInput
|
||||
label="Address 1"
|
||||
label={t`Address 1`}
|
||||
defaultValue={defaultValue?.addressStreet1 ?? ''}
|
||||
onChange={handleChange('addressStreet1')}
|
||||
readonly={readonly}
|
||||
VariablePicker={VariablePicker}
|
||||
placeholder="Street address"
|
||||
placeholder={t`Street address`}
|
||||
/>
|
||||
<FormTextFieldInput
|
||||
label="Address 2"
|
||||
label={t`Address 2`}
|
||||
defaultValue={defaultValue?.addressStreet2 ?? ''}
|
||||
onChange={handleChange('addressStreet2')}
|
||||
readonly={readonly}
|
||||
VariablePicker={VariablePicker}
|
||||
placeholder="Street address 2"
|
||||
placeholder={t`Street address 2`}
|
||||
/>
|
||||
<FormTextFieldInput
|
||||
label="City"
|
||||
label={t`City`}
|
||||
defaultValue={defaultValue?.addressCity ?? ''}
|
||||
onChange={handleChange('addressCity')}
|
||||
readonly={readonly}
|
||||
VariablePicker={VariablePicker}
|
||||
placeholder="City"
|
||||
placeholder={t`City`}
|
||||
/>
|
||||
<FormTextFieldInput
|
||||
label="State"
|
||||
label={t`State`}
|
||||
defaultValue={defaultValue?.addressState ?? ''}
|
||||
onChange={handleChange('addressState')}
|
||||
readonly={readonly}
|
||||
VariablePicker={VariablePicker}
|
||||
placeholder="State"
|
||||
placeholder={t`State`}
|
||||
/>
|
||||
<FormTextFieldInput
|
||||
label="Post Code"
|
||||
label={t`Post Code`}
|
||||
defaultValue={defaultValue?.addressPostcode ?? ''}
|
||||
onChange={handleChange('addressPostcode')}
|
||||
readonly={readonly}
|
||||
VariablePicker={VariablePicker}
|
||||
placeholder="Post Code"
|
||||
placeholder={t`Post Code`}
|
||||
/>
|
||||
<FormCountrySelectInput
|
||||
label="Country"
|
||||
label={t`Country`}
|
||||
selectedCountryName={defaultValue?.addressCountry ?? ''}
|
||||
onChange={handleChange('addressCountry')}
|
||||
readonly={readonly}
|
||||
|
||||
+2
-1
@@ -3,6 +3,7 @@ import { useMemo } from 'react';
|
||||
import { FormSelectFieldInput } from '@/object-record/record-field/ui/form-types/components/FormSelectFieldInput';
|
||||
import { type VariablePickerComponent } from '@/object-record/record-field/ui/form-types/types/VariablePickerComponent';
|
||||
import { useCountries } from '@/ui/input/components/internal/hooks/useCountries';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import type { CountryCode } from 'libphonenumber-js';
|
||||
import { IconCircleOff, type IconComponentProps } from 'twenty-ui/display';
|
||||
import { type SelectOption } from 'twenty-ui/input';
|
||||
@@ -35,7 +36,7 @@ export const FormCountryCodeSelectInput = ({
|
||||
);
|
||||
return [
|
||||
{
|
||||
label: 'No country',
|
||||
label: t`No country`,
|
||||
value: '',
|
||||
Icon: IconCircleOff,
|
||||
},
|
||||
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { FormSelectFieldInput } from '@/object-record/record-field/ui/form-types/components/FormSelectFieldInput';
|
||||
@@ -32,7 +33,7 @@ export const FormCountrySelectInput = ({
|
||||
);
|
||||
return [
|
||||
{
|
||||
label: 'No country',
|
||||
label: t`No country`,
|
||||
value: '',
|
||||
Icon: IconCircleOff,
|
||||
},
|
||||
|
||||
+5
-4
@@ -1,3 +1,4 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { FormFieldInputContainer } from '@/object-record/record-field/ui/form-types/components/FormFieldInputContainer';
|
||||
import { FormNestedFieldInputContainer } from '@/object-record/record-field/ui/form-types/components/FormNestedFieldInputContainer';
|
||||
import { FormNumberFieldInput } from '@/object-record/record-field/ui/form-types/components/FormNumberFieldInput';
|
||||
@@ -56,7 +57,7 @@ export const FormCurrencyFieldInput = ({
|
||||
const currencies = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
label: 'No currency',
|
||||
label: t`No currency`,
|
||||
value: '',
|
||||
Icon: IconCircleOff,
|
||||
},
|
||||
@@ -85,7 +86,7 @@ export const FormCurrencyFieldInput = ({
|
||||
{label ? <InputLabel>{label}</InputLabel> : null}
|
||||
<FormNestedFieldInputContainer>
|
||||
<FormSelectFieldInput
|
||||
label="Currency Code"
|
||||
label={t`Currency Code`}
|
||||
defaultValue={defaultValue?.currencyCode ?? ''}
|
||||
onChange={handleCurrencyCodeChange}
|
||||
options={currencies}
|
||||
@@ -93,11 +94,11 @@ export const FormCurrencyFieldInput = ({
|
||||
readonly={readonly}
|
||||
/>
|
||||
<FormNumberFieldInput
|
||||
label="Amount"
|
||||
label={t`Amount`}
|
||||
defaultValue={formatMicrosToDisplayAmount(defaultValue?.amountMicros)}
|
||||
onChange={handleAmountMicrosChange}
|
||||
VariablePicker={VariablePicker}
|
||||
placeholder="Set 3.21 for $3.21"
|
||||
placeholder={t`Set 3.21 for $3.21`}
|
||||
readonly={readonly}
|
||||
/>
|
||||
</FormNestedFieldInputContainer>
|
||||
|
||||
+3
-2
@@ -1,3 +1,4 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { FormFieldInputContainer } from '@/object-record/record-field/ui/form-types/components/FormFieldInputContainer';
|
||||
import { FormNestedFieldInputContainer } from '@/object-record/record-field/ui/form-types/components/FormNestedFieldInputContainer';
|
||||
import { FormTextFieldInput } from '@/object-record/record-field/ui/form-types/components/FormTextFieldInput';
|
||||
@@ -41,7 +42,7 @@ export const FormFullNameFieldInput = ({
|
||||
{label ? <InputLabel>{label}</InputLabel> : null}
|
||||
<FormNestedFieldInputContainer>
|
||||
<FormTextFieldInput
|
||||
label="First Name"
|
||||
label={t`First Name`}
|
||||
defaultValue={defaultValue?.firstName}
|
||||
onChange={handleFirstNameChange}
|
||||
placeholder={
|
||||
@@ -51,7 +52,7 @@ export const FormFullNameFieldInput = ({
|
||||
VariablePicker={VariablePicker}
|
||||
/>
|
||||
<FormTextFieldInput
|
||||
label="Last Name"
|
||||
label={t`Last Name`}
|
||||
defaultValue={defaultValue?.lastName}
|
||||
onChange={handleLastNameChange}
|
||||
placeholder={
|
||||
|
||||
+5
-4
@@ -1,3 +1,4 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { FormFieldInputContainer } from '@/object-record/record-field/ui/form-types/components/FormFieldInputContainer';
|
||||
import { FormNestedFieldInputContainer } from '@/object-record/record-field/ui/form-types/components/FormNestedFieldInputContainer';
|
||||
import { FormTextFieldInput } from '@/object-record/record-field/ui/form-types/components/FormTextFieldInput';
|
||||
@@ -39,18 +40,18 @@ export const FormLinksFieldInput = ({
|
||||
{label ? <InputLabel>{label}</InputLabel> : null}
|
||||
<FormNestedFieldInputContainer>
|
||||
<FormTextFieldInput
|
||||
label="Primary Link Label"
|
||||
label={t`Primary Link Label`}
|
||||
defaultValue={defaultValue?.primaryLinkLabel}
|
||||
onChange={handleChange('primaryLinkLabel')}
|
||||
placeholder={placeholder ?? 'Primary Link Label'}
|
||||
placeholder={placeholder ?? t`Primary Link Label`}
|
||||
readonly={readonly}
|
||||
VariablePicker={VariablePicker}
|
||||
/>
|
||||
<FormTextFieldInput
|
||||
label="Primary Link URL"
|
||||
label={t`Primary Link URL`}
|
||||
defaultValue={defaultValue?.primaryLinkUrl}
|
||||
onChange={handleChange('primaryLinkUrl')}
|
||||
placeholder={placeholder ?? 'Primary Link URL'}
|
||||
placeholder={placeholder ?? t`Primary Link URL`}
|
||||
readonly={readonly}
|
||||
VariablePicker={VariablePicker}
|
||||
/>
|
||||
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { FormFieldInputContainer } from '@/object-record/record-field/ui/form-types/components/FormFieldInputContainer';
|
||||
@@ -232,7 +233,7 @@ export const FormMultiSelectFieldInput = ({
|
||||
data-open={draftValue.editingMode === 'edit'}
|
||||
onClick={handleDisplayModeClick}
|
||||
>
|
||||
<VisibilityHidden>Edit</VisibilityHidden>
|
||||
<VisibilityHidden>{t`Edit`}</VisibilityHidden>
|
||||
|
||||
{isDefined(selectedOptions) && selectedOptions.length > 0 ? (
|
||||
<MultiSelectDisplay
|
||||
|
||||
+4
-3
@@ -1,3 +1,4 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { FormFieldInputContainer } from '@/object-record/record-field/ui/form-types/components/FormFieldInputContainer';
|
||||
import { FormFieldInputInnerContainer } from '@/object-record/record-field/ui/form-types/components/FormFieldInputInnerContainer';
|
||||
import { FormFieldInputRowContainer } from '@/object-record/record-field/ui/form-types/components/FormFieldInputRowContainer';
|
||||
@@ -74,8 +75,8 @@ export const FormNumberFieldInput = ({
|
||||
|
||||
const persistNumber = (newValue: string) => {
|
||||
if (!canBeCastAsNumberOrNull(newValue)) {
|
||||
setErrorMessage('Invalid number');
|
||||
onError?.('Invalid number');
|
||||
setErrorMessage(t`Invalid number`);
|
||||
onError?.(t`Invalid number`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -117,7 +118,7 @@ export const FormNumberFieldInput = ({
|
||||
placeholder={
|
||||
isDefined(placeholder) && !isEmpty(placeholder)
|
||||
? placeholder
|
||||
: 'Enter a number'
|
||||
: t`Enter a number`
|
||||
}
|
||||
value={draftValue.value}
|
||||
copyButton={false}
|
||||
|
||||
+5
-4
@@ -1,3 +1,4 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import {
|
||||
FormCountryCodeSelectInput,
|
||||
type FormCountryCodeSelectInputUpdatedValue,
|
||||
@@ -55,18 +56,18 @@ export const FormPhoneFieldInput = ({
|
||||
{label && <InputLabel>{label}</InputLabel>}
|
||||
<FormNestedFieldInputContainer>
|
||||
<FormCountryCodeSelectInput
|
||||
label="Country Code"
|
||||
label={t`Country Code`}
|
||||
selectedCountryCode={defaultValue?.primaryPhoneCountryCode ?? ''}
|
||||
onChange={handleCountryChange}
|
||||
readonly={readonly}
|
||||
/>
|
||||
<FormNumberFieldInput
|
||||
label="Phone Number"
|
||||
label={t`Phone Number`}
|
||||
defaultValue={defaultValue?.primaryPhoneNumber ?? ''}
|
||||
onChange={handleNumberChange}
|
||||
VariablePicker={VariablePicker}
|
||||
placeholder="Enter phone number"
|
||||
hint="Without calling code"
|
||||
placeholder={t`Enter phone number`}
|
||||
hint={t`Without calling code`}
|
||||
readonly={readonly}
|
||||
/>
|
||||
</FormNestedFieldInputContainer>
|
||||
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { FormFieldInputContainer } from '@/object-record/record-field/ui/form-types/components/FormFieldInputContainer';
|
||||
import { FormFieldInputInnerContainer } from '@/object-record/record-field/ui/form-types/components/FormFieldInputInnerContainer';
|
||||
import { FormFieldInputRowContainer } from '@/object-record/record-field/ui/form-types/components/FormFieldInputRowContainer';
|
||||
@@ -34,7 +35,7 @@ export const FormRawJsonFieldInput = ({
|
||||
const instanceId = useId();
|
||||
|
||||
const editor = useTextVariableEditor({
|
||||
placeholder: placeholder ?? 'Enter a JSON object',
|
||||
placeholder: placeholder ?? t`Enter a JSON object`,
|
||||
multiline: true,
|
||||
readonly,
|
||||
defaultValue: defaultValue ?? undefined,
|
||||
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { FormFieldInputContainer } from '@/object-record/record-field/ui/form-types/components/FormFieldInputContainer';
|
||||
import { FormFieldInputInnerContainer } from '@/object-record/record-field/ui/form-types/components/FormFieldInputInnerContainer';
|
||||
import { FormFieldInputRowContainer } from '@/object-record/record-field/ui/form-types/components/FormFieldInputRowContainer';
|
||||
@@ -96,7 +97,7 @@ export const FormSelectFieldInput = ({
|
||||
);
|
||||
|
||||
const defaultEmptyOption = {
|
||||
label: `No ${label ?? 'value'}`,
|
||||
label: label ? t`No ${label}` : t`No value`,
|
||||
value: '',
|
||||
icon: IconCircleOff,
|
||||
};
|
||||
|
||||
+4
-1
@@ -1,3 +1,4 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { RecordChip } from '@/object-record/components/RecordChip';
|
||||
import { FormFieldPlaceholder } from '@/object-record/record-field/ui/form-types/components/FormFieldPlaceholder';
|
||||
import {
|
||||
@@ -63,5 +64,7 @@ export const FormSingleRecordFieldChip = ({
|
||||
);
|
||||
}
|
||||
|
||||
return <StyledPlaceholder>Select a {objectNameSingular}</StyledPlaceholder>;
|
||||
return (
|
||||
<StyledPlaceholder>{t`Select a ${objectNameSingular}`}</StyledPlaceholder>
|
||||
);
|
||||
};
|
||||
|
||||
+4
-1
@@ -1,3 +1,4 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
|
||||
import { FormFieldInputContainer } from '@/object-record/record-field/ui/form-types/components/FormFieldInputContainer';
|
||||
import { FormFieldInputInnerContainer } from '@/object-record/record-field/ui/form-types/components/FormFieldInputInnerContainer';
|
||||
@@ -159,6 +160,8 @@ export const FormSingleRecordPicker = ({
|
||||
}
|
||||
};
|
||||
|
||||
const objectNames = objectNameSingulars.join(' or ');
|
||||
|
||||
return (
|
||||
<FormFieldInputContainer data-testid={testId}>
|
||||
{label ? <InputLabel>{label}</InputLabel> : null}
|
||||
@@ -211,7 +214,7 @@ export const FormSingleRecordPicker = ({
|
||||
focusId={dropdownId}
|
||||
componentInstanceId={dropdownId}
|
||||
EmptyIcon={IconForbid}
|
||||
emptyLabel={'No ' + objectNameSingulars.join(' or ')}
|
||||
emptyLabel={t`No ${objectNames}`}
|
||||
onCancel={() => closeDropdown(dropdownId)}
|
||||
onMorphItemSelected={handleMorphItemSelected}
|
||||
objectNameSingulars={objectNameSingulars}
|
||||
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { FormFieldInputContainer } from '@/object-record/record-field/ui/form-types/components/FormFieldInputContainer';
|
||||
import { FormFieldInputInnerContainer } from '@/object-record/record-field/ui/form-types/components/FormFieldInputInnerContainer';
|
||||
import { FormFieldInputRowContainer } from '@/object-record/record-field/ui/form-types/components/FormFieldInputRowContainer';
|
||||
@@ -39,7 +40,7 @@ export const FormTextFieldInput = ({
|
||||
const instanceId = useId();
|
||||
|
||||
const editor = useTextVariableEditor({
|
||||
placeholder: placeholder ?? 'Enter text',
|
||||
placeholder: placeholder ?? t`Enter text`,
|
||||
multiline,
|
||||
readonly,
|
||||
defaultValue,
|
||||
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { FormFieldInputContainer } from '@/object-record/record-field/ui/form-types/components/FormFieldInputContainer';
|
||||
import { FormFieldInputInnerContainer } from '@/object-record/record-field/ui/form-types/components/FormFieldInputInnerContainer';
|
||||
import { FormFieldInputRowContainer } from '@/object-record/record-field/ui/form-types/components/FormFieldInputRowContainer';
|
||||
@@ -101,7 +102,7 @@ export const FormUuidFieldInput = ({
|
||||
{draftValue.type === 'static' ? (
|
||||
<StyledInput
|
||||
instanceId={instanceId}
|
||||
placeholder={placeholder ?? 'Enter a UUID'}
|
||||
placeholder={placeholder ?? t`Enter a UUID`}
|
||||
value={draftValue.value}
|
||||
copyButton={false}
|
||||
disabled={readonly}
|
||||
|
||||
+1
-1
@@ -109,7 +109,7 @@ export const VariableChip = ({
|
||||
{onRemove ? (
|
||||
<StyledDelete
|
||||
onClick={onRemove}
|
||||
aria-label="Remove variable"
|
||||
aria-label={t`Remove variable`}
|
||||
danger={isVariableNotFound}
|
||||
>
|
||||
<IconX size={theme.icon.size.sm} stroke={theme.icon.stroke.sm} />
|
||||
|
||||
+3
-2
@@ -1,3 +1,4 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { FieldInputEventContext } from '@/object-record/record-field/ui/contexts/FieldInputEventContext';
|
||||
import { useArrayField } from '@/object-record/record-field/ui/meta-types/hooks/useArrayField';
|
||||
import { ArrayFieldMenuItem } from '@/object-record/record-field/ui/meta-types/input/components/ArrayFieldMenuItem';
|
||||
@@ -62,13 +63,13 @@ export const ArrayFieldInput = () => {
|
||||
|
||||
return (
|
||||
<MultiItemFieldInput
|
||||
newItemLabel="Add Item"
|
||||
newItemLabel={t`Add Item`}
|
||||
items={arrayItems}
|
||||
onChange={handleChange}
|
||||
onEnter={handleEnter}
|
||||
onEscape={handleEscape}
|
||||
onClickOutside={handleClickOutside}
|
||||
placeholder="Enter value"
|
||||
placeholder={t`Enter value`}
|
||||
fieldMetadataType={FieldMetadataType.ARRAY}
|
||||
renderItem={({ value, index, handleEdit, handleDelete }) => (
|
||||
<ArrayFieldMenuItem
|
||||
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
|
||||
import { type FieldCurrencyValue } from '@/object-record/record-field/ui/types/FieldMetadata';
|
||||
@@ -137,7 +138,7 @@ export const CurrencyFieldInput = () => {
|
||||
value={draftValue?.amount?.toString() ?? ''}
|
||||
currencyCode={currencyCode}
|
||||
autoFocus
|
||||
placeholder="Currency"
|
||||
placeholder={t`Currency`}
|
||||
onClickOutside={handleClickOutside}
|
||||
onEnter={handleEnter}
|
||||
onEscape={handleEscape}
|
||||
|
||||
+1
-1
@@ -109,7 +109,7 @@ export const EmailsFieldInput = () => {
|
||||
onEnter={handleEnter}
|
||||
onEscape={handleEscape}
|
||||
onClickOutside={handleClickOutside}
|
||||
placeholder="Email"
|
||||
placeholder={t`Email`}
|
||||
fieldMetadataType={FieldMetadataType.EMAILS}
|
||||
validateInput={validateInput}
|
||||
renderItem={({
|
||||
|
||||
+4
-1
@@ -1,3 +1,4 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { FieldInputEventContext } from '@/object-record/record-field/ui/contexts/FieldInputEventContext';
|
||||
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
@@ -76,12 +77,14 @@ export const MorphRelationManyToOneFieldInput = () => {
|
||||
(morphRelation) => morphRelation.targetObjectMetadata.nameSingular,
|
||||
);
|
||||
|
||||
const fieldLabel = fieldDefinition.label;
|
||||
|
||||
return (
|
||||
<SingleRecordPicker
|
||||
focusId={instanceId}
|
||||
componentInstanceId={instanceId}
|
||||
EmptyIcon={IconForbid}
|
||||
emptyLabel={'No ' + fieldDefinition.label}
|
||||
emptyLabel={t`No ${fieldLabel}`}
|
||||
onCancel={onCancel}
|
||||
onMorphItemSelected={handleMorphItemSelected}
|
||||
objectNameSingulars={objectNameSingulars}
|
||||
|
||||
+5
-4
@@ -1,3 +1,4 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
||||
@@ -86,25 +87,25 @@ export const MultiItemFieldMenuItem = <T,>({
|
||||
{showSetAsPrimaryButton && (
|
||||
<MenuItem
|
||||
LeftIcon={IconBookmarkPlus}
|
||||
text="Set as Primary"
|
||||
text={t`Set as Primary`}
|
||||
onClick={handleSetAsPrimaryClick}
|
||||
/>
|
||||
)}
|
||||
<MenuItem
|
||||
LeftIcon={IconPencil}
|
||||
text="Edit"
|
||||
text={t`Edit`}
|
||||
onClick={handleEditClick}
|
||||
/>
|
||||
<MenuItem
|
||||
accent="danger"
|
||||
LeftIcon={IconTrash}
|
||||
text="Delete"
|
||||
text={t`Delete`}
|
||||
onClick={handleDeleteClick}
|
||||
/>
|
||||
{showCopyButton && (
|
||||
<MenuItem
|
||||
LeftIcon={IconCopy}
|
||||
text="Copy"
|
||||
text={t`Copy`}
|
||||
onClick={handleCopyClick}
|
||||
/>
|
||||
)}
|
||||
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { usePhonesField } from '@/object-record/record-field/ui/meta-types/hooks/usePhonesField';
|
||||
import { PhonesFieldMenuItem } from '@/object-record/record-field/ui/meta-types/input/components/PhonesFieldMenuItem';
|
||||
import { recordFieldInputIsFieldInErrorComponentState } from '@/object-record/record-field/ui/states/recordFieldInputIsFieldInErrorComponentState';
|
||||
@@ -160,7 +161,7 @@ export const PhonesFieldInput = () => {
|
||||
onClickOutside={handleClickOutside}
|
||||
onEscape={handleEscape}
|
||||
onEnter={handleEnter}
|
||||
placeholder="Phone"
|
||||
placeholder={t`Phone`}
|
||||
fieldMetadataType={FieldMetadataType.PHONES}
|
||||
validateInput={validateInput}
|
||||
formatInput={(input) => {
|
||||
|
||||
+3
-1
@@ -1,3 +1,4 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { FieldInputEventContext } from '@/object-record/record-field/ui/contexts/FieldInputEventContext';
|
||||
import { useClearField } from '@/object-record/record-field/ui/hooks/useClearField';
|
||||
import { useAddSelectOption } from '@/object-record/record-field/ui/meta-types/hooks/useAddSelectOption';
|
||||
@@ -68,8 +69,9 @@ export const SelectFieldInput = () => {
|
||||
dependencies: [onCancel, resetSelectedItem],
|
||||
});
|
||||
|
||||
const fieldLabel = fieldDefinition.label;
|
||||
const optionIds = [
|
||||
`No ${fieldDefinition.label}`,
|
||||
t`No ${fieldLabel}`,
|
||||
...filteredOptions.map((option) => option.value),
|
||||
];
|
||||
|
||||
|
||||
+3
@@ -10,7 +10,9 @@ import { RECORD_TABLE_CELL_INPUT_ID_PREFIX } from '@/object-record/record-table/
|
||||
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
||||
import { ArrayFieldInput } from '../ArrayFieldInput';
|
||||
|
||||
const { FieldInputEventContextProviderWithJestMocks } =
|
||||
@@ -100,6 +102,7 @@ const ArrayInputWithContext = ({
|
||||
const meta: Meta<typeof ArrayInputWithContext> = {
|
||||
title: 'UI/Input/ArrayFieldInput',
|
||||
component: ArrayInputWithContext,
|
||||
decorators: [I18nFrontDecorator],
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
+2
@@ -7,6 +7,7 @@ import { recordStoreFamilyState } from '@/object-record/record-store/states/reco
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
|
||||
import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext';
|
||||
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
||||
import { getFieldInputEventContextProviderWithJestMocks } from '@/object-record/record-field/ui/meta-types/input/components/__stories__/utils/getFieldInputEventContextProviderWithJestMocks';
|
||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/ui/states/contexts/RecordFieldComponentInstanceContext';
|
||||
import { RECORD_TABLE_CELL_INPUT_ID_PREFIX } from '@/object-record/record-table/constants/RecordTableCellInputIdPrefix';
|
||||
@@ -84,6 +85,7 @@ const BooleanFieldInputWithContext = ({
|
||||
const meta: Meta = {
|
||||
title: 'UI/Data/Field/Input/BooleanFieldInput',
|
||||
component: BooleanFieldInputWithContext,
|
||||
decorators: [I18nFrontDecorator],
|
||||
args: {
|
||||
value: true,
|
||||
recordId: 'id-1',
|
||||
|
||||
+2
@@ -11,6 +11,7 @@ import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFi
|
||||
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||
import { getCanvasElementForDropdownTesting } from 'twenty-ui/testing';
|
||||
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import { LinksFieldInput } from '../LinksFieldInput';
|
||||
|
||||
@@ -121,6 +122,7 @@ const getPrimaryLinkBookmarkIcon = (canvasElement: HTMLElement) =>
|
||||
const meta: Meta = {
|
||||
title: 'UI/Data/Field/Input/LinksFieldInput',
|
||||
component: LinksInputWithContext,
|
||||
decorators: [I18nFrontDecorator],
|
||||
args: {
|
||||
value: {
|
||||
primaryLinkUrl: null,
|
||||
|
||||
+2
@@ -4,6 +4,7 @@ import { useEffect } from 'react';
|
||||
import { getCanvasElementForDropdownTesting } from 'twenty-ui/testing';
|
||||
|
||||
import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext';
|
||||
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
||||
import { usePhonesField } from '@/object-record/record-field/ui/meta-types/hooks/usePhonesField';
|
||||
import { getFieldInputEventContextProviderWithJestMocks } from '@/object-record/record-field/ui/meta-types/input/components/__stories__/utils/getFieldInputEventContextProviderWithJestMocks';
|
||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/ui/states/contexts/RecordFieldComponentInstanceContext';
|
||||
@@ -98,6 +99,7 @@ const PhoneInputWithContext = ({
|
||||
const meta: Meta<typeof PhoneInputWithContext> = {
|
||||
title: 'UI/Input/PhonesFieldInput',
|
||||
component: PhoneInputWithContext,
|
||||
decorators: [I18nFrontDecorator],
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
+2
-1
@@ -5,6 +5,7 @@ import { useEffect } from 'react';
|
||||
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||
|
||||
import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext';
|
||||
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
||||
import { getFieldInputEventContextProviderWithJestMocks } from '@/object-record/record-field/ui/meta-types/input/components/__stories__/utils/getFieldInputEventContextProviderWithJestMocks';
|
||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/ui/states/contexts/RecordFieldComponentInstanceContext';
|
||||
import { RECORD_TABLE_CELL_INPUT_ID_PREFIX } from '@/object-record/record-table/constants/RecordTableCellInputIdPrefix';
|
||||
@@ -107,7 +108,7 @@ const meta: Meta = {
|
||||
argTypes: {
|
||||
onSubmit: { control: false },
|
||||
},
|
||||
decorators: [clearMocksDecorator],
|
||||
decorators: [I18nFrontDecorator, clearMocksDecorator],
|
||||
parameters: {
|
||||
clearMocks: true,
|
||||
},
|
||||
|
||||
+4
-2
@@ -4,6 +4,7 @@ import {
|
||||
RecordGroupDefinitionType,
|
||||
} from '@/object-record/record-group/types/RecordGroupDefinition';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { Tag } from 'twenty-ui/components';
|
||||
import { IconEye, IconEyeOff } from 'twenty-ui/display';
|
||||
@@ -33,12 +34,13 @@ export const RecordGroupMenuItemDraggable = ({
|
||||
const isNoValue = recordGroup.type === RecordGroupDefinitionType.NoValue;
|
||||
|
||||
const getIconButtons = (recordGroup: RecordGroupDefinition) => {
|
||||
const groupValue = recordGroup.value;
|
||||
const iconButtons = [
|
||||
{
|
||||
Icon: recordGroup.isVisible ? IconEyeOff : IconEye,
|
||||
ariaLabel: recordGroup.isVisible
|
||||
? `Hide group ${recordGroup.value}`
|
||||
: `Show group ${recordGroup.value}`,
|
||||
? t`Hide group ${groupValue}`
|
||||
: t`Show group ${groupValue}`,
|
||||
dataTestId: recordGroup.isVisible
|
||||
? `hide-group-${recordGroup.value?.toLowerCase().replace(' ', '-') ?? ''}`
|
||||
: `show-group-${recordGroup.value?.toLowerCase().replace(' ', '-') ?? ''}`,
|
||||
|
||||
+5
-3
@@ -132,13 +132,15 @@ export const displayedExportProgress = (progress?: ExportProgress): string => {
|
||||
progress.displayType === 'percentage' &&
|
||||
isDefined(progress?.totalRecordCount)
|
||||
) {
|
||||
return `Export (${percentage(
|
||||
const percentageValue = percentage(
|
||||
progress.exportedRecordCount,
|
||||
progress.totalRecordCount,
|
||||
)}%)`;
|
||||
);
|
||||
return t`Export (${percentageValue}%)`;
|
||||
}
|
||||
|
||||
return `Export (${progress.exportedRecordCount})`;
|
||||
const exportedCount = progress.exportedRecordCount;
|
||||
return t`Export (${exportedCount})`;
|
||||
};
|
||||
|
||||
const downloader = (mimeType: string, generator: GenerateExport) => {
|
||||
|
||||
+2
-1
@@ -7,6 +7,7 @@ import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUp
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { isSoftDeleteFilterActiveComponentState } from '@/object-record/record-table/states/isSoftDeleteFilterActiveComponentState';
|
||||
import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { getFilterTypeFromFieldType, isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
@@ -60,7 +61,7 @@ export const useHandleToggleTrashColumnFilter = ({
|
||||
operand: ViewFilterOperand.IS_NOT_EMPTY,
|
||||
displayValue: '',
|
||||
type: filterType,
|
||||
label: `Deleted`,
|
||||
label: t`Deleted`,
|
||||
value: '',
|
||||
};
|
||||
|
||||
|
||||
+2
-1
@@ -3,6 +3,7 @@ import { useMergeRecordsActions } from '@/object-record/record-merge/hooks/useMe
|
||||
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||
import styled from '@emotion/styled';
|
||||
import { Key } from 'ts-key-enum';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { IconArrowMerge } from 'twenty-ui/display';
|
||||
import { Button } from 'twenty-ui/input';
|
||||
|
||||
@@ -48,7 +49,7 @@ export const MergeRecordsFooter = ({
|
||||
<StyledFooterContainer>
|
||||
<StyledFooterActions>
|
||||
<Button
|
||||
title={isMerging ? 'Merging...' : 'Merge'}
|
||||
title={isMerging ? t`Merging...` : t`Merge`}
|
||||
variant="primary"
|
||||
accent="blue"
|
||||
size="medium"
|
||||
|
||||
+11
-7
@@ -1,3 +1,4 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useMergeRecordsSelectedRecords } from '@/object-record/record-merge/hooks/useMergeRecordsSelectedRecords';
|
||||
import { useMergeRecordsSettings } from '@/object-record/record-merge/hooks/useMergeRecordsSettings';
|
||||
import { Select } from '@/ui/input/components/Select';
|
||||
@@ -16,12 +17,15 @@ export const MergeSettingsTab = () => {
|
||||
useMergeRecordsSettings();
|
||||
const { selectedRecords } = useMergeRecordsSelectedRecords();
|
||||
|
||||
const priorityOptions = selectedRecords.map((_, index) => ({
|
||||
value: index,
|
||||
label: `${getPositionWordLabel(index)} record holds priority`,
|
||||
Icon: getPositionNumberIcon(index),
|
||||
recordIndex: index,
|
||||
}));
|
||||
const priorityOptions = selectedRecords.map((_, index) => {
|
||||
const positionLabel = getPositionWordLabel(index);
|
||||
return {
|
||||
value: index,
|
||||
label: t`${positionLabel} record holds priority`,
|
||||
Icon: getPositionNumberIcon(index),
|
||||
recordIndex: index,
|
||||
};
|
||||
});
|
||||
|
||||
const handleSelectionChange = (index: number) => {
|
||||
updatePriorityRecordIndex(index);
|
||||
@@ -38,7 +42,7 @@ export const MergeSettingsTab = () => {
|
||||
options={priorityOptions}
|
||||
value={mergeSettings.conflictPriorityIndex}
|
||||
onChange={handleSelectionChange}
|
||||
label="Fields conflicts"
|
||||
label={t`Fields conflicts`}
|
||||
/>
|
||||
</StyledSection>
|
||||
);
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ export const useMergeRecordsActions = ({
|
||||
message:
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: 'Failed to merge records. Please try again.',
|
||||
: t`Failed to merge records. Please try again.`,
|
||||
});
|
||||
} finally {
|
||||
setMergeInProgress(false);
|
||||
|
||||
+2
-1
@@ -18,6 +18,7 @@ import { useRef } from 'react';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { Key } from 'ts-key-enum';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { IconPlus } from 'twenty-ui/display';
|
||||
|
||||
type MultipleRecordPickerProps = {
|
||||
@@ -118,7 +119,7 @@ export const MultipleRecordPicker = ({
|
||||
<CreateNewButton
|
||||
onClick={handleCreateNewButtonClick}
|
||||
LeftIcon={IconPlus}
|
||||
text="Add New"
|
||||
text={t`Add New`}
|
||||
/>
|
||||
</DropdownMenuItemsContainer>
|
||||
) : null;
|
||||
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useMultipleRecordPickerPerformSearch } from '@/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerPerformSearch';
|
||||
import { MultipleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/multiple-record-picker/states/contexts/MultipleRecordPickerComponentInstanceContext';
|
||||
|
||||
@@ -118,7 +119,7 @@ export const MultipleRecordPickerFetchMoreLoader = () => {
|
||||
<>
|
||||
<StyledIntersectionObserver ref={ref} />
|
||||
{multipleRecordPickerIsFetchingMore && (
|
||||
<StyledText>Loading more...</StyledText>
|
||||
<StyledText>{t`Loading more...`}</StyledText>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
+3
-2
@@ -1,3 +1,4 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
@@ -62,9 +63,9 @@ export const MultipleRecordPickerMenuItemContent = ({
|
||||
});
|
||||
};
|
||||
|
||||
const labelSingular = objectMetadataItem.labelSingular;
|
||||
const displayText =
|
||||
searchRecord.label?.trim() ||
|
||||
`Untitled ${objectMetadataItem.labelSingular}`;
|
||||
searchRecord.label?.trim() || t`Untitled ${labelSingular}`;
|
||||
|
||||
const searchableObjectMetadataItems = useRecoilComponentValue(
|
||||
multipleRecordPickerSearchableObjectMetadataItemsComponentState,
|
||||
|
||||
+3
-2
@@ -17,6 +17,7 @@ import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownM
|
||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { IconPlus } from 'twenty-ui/display';
|
||||
|
||||
export type SingleRecordPickerMenuItemsWithSearchProps = {
|
||||
@@ -88,7 +89,7 @@ export const SingleRecordPickerMenuItemsWithSearch = ({
|
||||
<CreateNewButton
|
||||
onClick={handleCreateNew}
|
||||
LeftIcon={IconPlus}
|
||||
text="Add New"
|
||||
text={t`Add New`}
|
||||
/>
|
||||
</DropdownMenuItemsContainer>
|
||||
<DropdownMenuSeparator />
|
||||
@@ -137,7 +138,7 @@ export const SingleRecordPickerMenuItemsWithSearch = ({
|
||||
<CreateNewButton
|
||||
onClick={handleCreateNew}
|
||||
LeftIcon={IconPlus}
|
||||
text="Add New"
|
||||
text={t`Add New`}
|
||||
/>
|
||||
</DropdownMenuItemsContainer>
|
||||
</>
|
||||
|
||||
+3
-1
@@ -17,6 +17,7 @@ import { evaluateTabVisibility } from '@/object-record/record-show/utils/evaluat
|
||||
import { type RecordLayoutTab } from '@/ui/layout/tab-list/types/RecordLayoutTab';
|
||||
import { type SingleTabProps } from '@/ui/layout/tab-list/types/SingleTabProps';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { useMemo } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { IconHome, useIcons } from 'twenty-ui/display';
|
||||
@@ -40,6 +41,7 @@ export const useRecordShowContainerTabs = (
|
||||
isInRightDrawer: boolean,
|
||||
objectMetadataItem: ObjectMetadataItem,
|
||||
): { layout: RecordLayout; tabs: SingleTabProps[] } => {
|
||||
const { t } = useLingui();
|
||||
const isMobile = useIsMobile();
|
||||
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
||||
|
||||
@@ -109,7 +111,7 @@ export const useRecordShowContainerTabs = (
|
||||
...acc,
|
||||
{
|
||||
id: 'home',
|
||||
title: 'Home',
|
||||
title: t`Home`,
|
||||
Icon: IconHome,
|
||||
cards: [
|
||||
...(tab.hide ? [] : tab.cards),
|
||||
|
||||
+5
-2
@@ -1,4 +1,5 @@
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { useState } from 'react';
|
||||
import { useParams, useSearchParams } from 'react-router-dom';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
@@ -16,6 +17,7 @@ export const useRecordShowPagePagination = (
|
||||
propsObjectNameSingular: string,
|
||||
propsObjectRecordId: string,
|
||||
) => {
|
||||
const { t } = useLingui();
|
||||
const {
|
||||
objectNameSingular: paramObjectNameSingular,
|
||||
objectRecordId: paramObjectRecordId,
|
||||
@@ -220,9 +222,10 @@ export const useRecordShowPagePagination = (
|
||||
|
||||
const totalCount = 1 + Math.max(totalCountBefore, totalCountAfter);
|
||||
|
||||
const currentRank = rankInView + 1;
|
||||
const viewNameWithCount = rankFoundInView
|
||||
? `${rankInView + 1} of ${totalCount} in ${objectLabelPlural}`
|
||||
: `${objectLabelPlural} (${totalCount})`;
|
||||
? t`${currentRank} of ${totalCount} in ${objectLabelPlural}`
|
||||
: t`${objectLabelPlural} (${totalCount})`;
|
||||
|
||||
return {
|
||||
viewName: viewNameWithCount,
|
||||
|
||||
+4
-3
@@ -2,6 +2,7 @@ import { useObjectLabel } from '@/object-metadata/hooks/useObjectLabel';
|
||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { RecordTableEmptyStateDisplay } from '@/object-record/record-table/empty-state/components/RecordTableEmptyStateDisplay';
|
||||
import { useCreateNewIndexRecord } from '@/object-record/record-table/hooks/useCreateNewIndexRecord';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { IconPlus } from 'twenty-ui/display';
|
||||
|
||||
export const RecordTableEmptyStateNoRecordFoundForFilter = () => {
|
||||
@@ -17,11 +18,11 @@ export const RecordTableEmptyStateNoRecordFoundForFilter = () => {
|
||||
|
||||
const objectLabelSingular = useObjectLabel(objectMetadataItem);
|
||||
|
||||
const buttonTitle = `Add a ${objectLabelSingular}`;
|
||||
const buttonTitle = t`Add a ${objectLabelSingular}`;
|
||||
|
||||
const title = `No ${objectLabelSingular} found`;
|
||||
const title = t`No ${objectLabelSingular} found`;
|
||||
|
||||
const subTitle = 'No records matching the filter criteria were found.';
|
||||
const subTitle = t`No records matching the filter criteria were found.`;
|
||||
|
||||
return (
|
||||
<RecordTableEmptyStateDisplay
|
||||
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { type Theme, withTheme } from '@emotion/react';
|
||||
import { styled } from '@linaria/react';
|
||||
import { type Ref } from 'react';
|
||||
@@ -52,7 +53,7 @@ export const RecordTableCellDisplayContainer = ({
|
||||
>
|
||||
{placeholderForEmptyCell ? (
|
||||
<StyledEmptyPlaceholderField>
|
||||
{'Set ' + placeholderForEmptyCell}
|
||||
{t`Set ${placeholderForEmptyCell}`}
|
||||
</StyledEmptyPlaceholderField>
|
||||
) : (
|
||||
<StyledInnerContainer>{children}</StyledInnerContainer>
|
||||
|
||||
+2
-1
@@ -4,6 +4,7 @@ import { recordIndexHasFetchedAllRecordsByGroupComponentState } from '@/object-r
|
||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { RecordTableActionRow } from '@/object-record/record-table/record-table-row/components/RecordTableActionRow';
|
||||
import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { IconArrowDown } from 'twenty-ui/display';
|
||||
|
||||
export const RecordTableRecordGroupSectionLoadMore = () => {
|
||||
@@ -30,7 +31,7 @@ export const RecordTableRecordGroupSectionLoadMore = () => {
|
||||
return (
|
||||
<RecordTableActionRow
|
||||
LeftIcon={IconArrowDown}
|
||||
text="Load more"
|
||||
text={t`Load more`}
|
||||
onClick={handleLoadMore}
|
||||
/>
|
||||
);
|
||||
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { useRecordTitleCell } from '@/object-record/record-title-cell/hooks/useRecordTitleCell';
|
||||
@@ -60,7 +61,7 @@ export const RecordTitleCellSingleTextDisplayMode = ({
|
||||
}}
|
||||
>
|
||||
{isEmpty ? (
|
||||
<StyledEmptyText>Untitled</StyledEmptyText>
|
||||
<StyledEmptyText>{t`Untitled`}</StyledEmptyText>
|
||||
) : (
|
||||
<OverflowingTextWithTooltip
|
||||
text={
|
||||
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext';
|
||||
import { useFullNameFieldDisplay } from '@/object-record/record-field/ui/meta-types/hooks/useFullNameFieldDisplay';
|
||||
import { useRecordTitleCell } from '@/object-record/record-title-cell/hooks/useRecordTitleCell';
|
||||
@@ -82,7 +83,7 @@ export const RecordTitleFullNameFieldDisplay = ({
|
||||
}}
|
||||
>
|
||||
{!content ? (
|
||||
<StyledEmptyText>Untitled</StyledEmptyText>
|
||||
<StyledEmptyText>{t`Untitled`}</StyledEmptyText>
|
||||
) : (
|
||||
<OverflowingTextWithTooltip
|
||||
text={isNonEmptyString(content) ? content : fieldDefinition.label}
|
||||
|
||||
+2
-1
@@ -10,6 +10,7 @@ import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectab
|
||||
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
|
||||
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { Avatar } from 'twenty-ui/display';
|
||||
import { MenuItem, MenuItemMultiSelectAvatar } from 'twenty-ui/navigation';
|
||||
|
||||
@@ -117,7 +118,7 @@ export const MultipleSelectDropdown = ({
|
||||
</SelectableListItem>
|
||||
);
|
||||
})}
|
||||
{showNoResult && <MenuItem text="No results" />}
|
||||
{showNoResult && <MenuItem text={t`No results`} />}
|
||||
{loadingItems && <DropdownMenuSkeletonItem />}
|
||||
</DropdownMenuItemsContainer>
|
||||
</SelectableList>
|
||||
|
||||
Reference in New Issue
Block a user