Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
f2f36de
feat: add custom plural for note relationship attribute
henrikmv Jul 23, 2026
18351e9
feat: update name assignment in TrackedEntityTypeFactory to use trans…
henrikmv Jul 23, 2026
5a895cd
feat: metadata loading support custom plural labels based on server v…
henrikmv Jul 23, 2026
8cedb68
feat: add customTerminologyPlurals feature support
henrikmv Jul 23, 2026
433aa56
Merge remote-tracking branch 'origin/master' into hv/feat/DHIS2-21878…
henrikmv Jul 25, 2026
ab2685d
Merge remote-tracking branch 'origin/master' into hv/feat/DHIS2-21878…
henrikmv Aug 6, 2026
c479953
fix: separate base and plural fields for improved readability
henrikmv Aug 6, 2026
e5b4d74
feat: temp change helper function and stop capitalize
henrikmv Aug 7, 2026
302cc2b
feat: implement custom terminology handling with bootstrap
henrikmv Aug 7, 2026
823f4e1
fix: revert changes belonging to child branch
henrikmv Aug 7, 2026
764e73b
fix: sonar qube
henrikmv Aug 7, 2026
df95c4d
Merge remote-tracking branch 'origin/master' into hv/feat/DHIS2-21635…
henrikmv Aug 7, 2026
2e19a93
feat: code clean up
henrikmv Aug 7, 2026
0a0d90a
fix: type change
henrikmv Aug 7, 2026
809aad6
feat: update terminology
henrikmv Aug 7, 2026
54d8332
feat: enhance API program fields with custom terminology support
henrikmv Aug 7, 2026
45eb553
feat: clean up
henrikmv Aug 7, 2026
de452bc
feat: temp devin review
henrikmv Aug 12, 2026
6a8cd9c
fix: revert single event infrastructure
henrikmv Aug 12, 2026
56ac556
feat: update terminology handling across components
henrikmv Aug 12, 2026
718ae46
feat: enhance custom terminology handling and optimize location query…
henrikmv Aug 12, 2026
b52ffd8
feat: custom terminology context handling
henrikmv Aug 12, 2026
f3b34dc
fix: change approach
henrikmv Aug 12, 2026
2b92b9a
fix: complete clean up after revert
henrikmv Aug 12, 2026
d66e422
feat: update custom label handling and refactor label exports
henrikmv Aug 12, 2026
762f6bd
fix: correct capitalization in widget header and improve label resolu…
henrikmv Aug 12, 2026
ee3d687
fix: simplify label resolution logic by removing fallback for plural …
henrikmv Aug 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 51 additions & 39 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"POT-Creation-Date: 2026-08-07T10:34:07.592Z\n"
"PO-Revision-Date: 2026-08-07T10:34:07.592Z\n"
"POT-Creation-Date: 2026-08-13T09:56:16.886Z\n"
"PO-Revision-Date: 2026-08-13T09:56:16.886Z\n"

msgid "The application could not be loaded."
msgstr "The application could not be loaded."
Expand Down Expand Up @@ -688,8 +688,8 @@ msgstr "before or equal to"
msgid "More filters"
msgstr "More filters"

msgid "Stage filters"
msgstr "Stage filters"
msgid "Program stage filters"
msgstr "Program stage filters"

msgid "Rows per page"
msgstr "Rows per page"
Expand Down Expand Up @@ -811,8 +811,8 @@ msgstr "There was an error loading the page"
msgid "Program stage is invalid"
msgstr "Program stage is invalid"

msgid "Stage not found"
msgstr "Stage not found"
msgid "Program stage not found"
msgstr "Program stage not found"

msgid "Report"
msgstr "Report"
Expand All @@ -832,14 +832,14 @@ msgstr "You can't add any more {{ programStageName }} events"
msgid "Cancel without saving"
msgstr "Cancel without saving"

msgid "Choose a stage for a new event"
msgstr "Choose a stage for a new event"
msgid "Choose a program stage for a new event"
msgstr "Choose a program stage for a new event"

msgid "Program Stages could not be loaded"
msgstr "Program Stages could not be loaded"

msgid "Stage"
msgstr "Stage"
msgid "Program stage"
msgstr "Program stage"

msgid "The category option is not valid for the selected organisation unit."
msgstr "The category option is not valid for the selected organisation unit."
Expand Down Expand Up @@ -1306,22 +1306,12 @@ msgstr "No one is assigned to this event"
msgid "Assign"
msgstr "Assign"

msgid "This program is protected"
msgstr "This program is protected"

msgid "Reason to check for enrollments"
msgstr "Reason to check for enrollments"

msgid ""
"Describe the reason you are checking for enrollments in this protected "
"program"
msgstr ""
"Describe the reason you are checking for enrollments in this protected "
"program"

msgid "Check for enrollments"
msgstr "Check for enrollments"

msgid "This program is protected"
msgstr "This program is protected"

msgid ""
"You must provide a reason to check for enrollments in this protected "
"program."
Expand All @@ -1332,6 +1322,16 @@ msgstr ""
msgid "All activity will be logged."
msgstr "All activity will be logged."

msgid "Reason to check for enrollments"
msgstr "Reason to check for enrollments"

msgid ""
"Describe the reason you are checking for enrollments in this protected "
"program"
msgstr ""
"Describe the reason you are checking for enrollments in this protected "
"program"

msgid "Unsaved changes"
msgstr "Unsaved changes"

Expand Down Expand Up @@ -1467,9 +1467,6 @@ msgstr "Add coordinates"
msgid "Add area"
msgstr "Add area"

msgid "Program stage not found"
msgstr "Program stage not found"

msgid "organisation unit could not be retrieved. Please try again later."
msgstr "organisation unit could not be retrieved. Please try again later."

Expand All @@ -1479,8 +1476,8 @@ msgstr "Saving to {{stageName}} for {{programName}} in {{orgUnitName}}"
msgid "Saving to {{stageName}} for {{programName}}"
msgstr "Saving to {{stageName}} for {{programName}}"

msgid "program or stage is invalid"
msgstr "program or stage is invalid"
msgid "Program or program stage is invalid"
msgstr "Program or program stage is invalid"

msgid "Notes about this enrollment"
msgstr "Notes about this enrollment"
Expand All @@ -1497,8 +1494,8 @@ msgstr "Error"
msgid "Warning"
msgstr "Warning"

msgid "stage not found in rules execution"
msgstr "stage not found in rules execution"
msgid "Program stage not found in rules execution"
msgstr "Program stage not found in rules execution"

msgid "Delete event"
msgstr "Delete event"
Expand Down Expand Up @@ -1593,9 +1590,6 @@ msgstr "Event notes"
msgid "Write a note about this scheduled event"
msgstr "Write a note about this scheduled event"

msgid "Program or stage is invalid"
msgstr "Program or stage is invalid"

msgid "Feedback"
msgstr "Feedback"

Expand Down Expand Up @@ -1754,8 +1748,8 @@ msgstr "Please enter a date"
msgid "Please select a valid event"
msgstr "Please select a valid event"

msgid "This stage can only have one event"
msgstr "This stage can only have one event"
msgid "This program stage can only have one event"
msgstr "This program stage can only have one event"

msgid "New {{ eventName }} event"
msgstr "New {{ eventName }} event"
Expand Down Expand Up @@ -1804,11 +1798,11 @@ msgstr "{{ overdueEvents }} overdue"
msgid "{{ scheduledEvents }} scheduled"
msgstr "{{ scheduledEvents }} scheduled"

msgid "No stages found in this program"
msgstr "No stages found in this program"
msgid "No program stages found in this program"
msgstr "No program stages found in this program"

msgid "Stages and Events"
msgstr "Stages and Events"
msgid "Program stages and events"
msgstr "Program stages and events"

msgid "An error occurred while unlinking and deleting the event."
msgstr "An error occurred while unlinking and deleting the event."
Expand Down Expand Up @@ -2248,6 +2242,24 @@ msgstr "Visited"
msgid "{{trackedEntityName}} in program{{escape}} {{programName}}"
msgstr "{{trackedEntityName}} in program{{escape}} {{programName}}"

msgid "program stage"
msgstr "program stage"

msgid "note"
msgstr "note"

msgid "relationship"
msgstr "relationship"

msgid "attribute"
msgstr "attribute"

msgid "organisation unit"
msgstr "organisation unit"

msgid "follow-up"
msgstr "follow-up"

msgid "Program not found"
msgstr "Program not found"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const FEATURES = Object.freeze({
orgUnitReplaceOuQueryParam: 'orgUnitReplaceOuQueryParam',
enrollmentStatusReplaceProgramStatusQueryParam: 'enrollmentStatusReplaceProgramStatusQueryParam',
emptyValueFilter: 'emptyValueFilter',
customTerminologyPlurals: 'customTerminologyPlurals',
});

const MINOR_VERSION_SUPPORT = Object.freeze({
Expand All @@ -40,6 +41,7 @@ const MINOR_VERSION_SUPPORT = Object.freeze({
[FEATURES.orgUnitReplaceOuQueryParam]: 42,
[FEATURES.enrollmentStatusReplaceProgramStatusQueryParam]: 42,
[FEATURES.emptyValueFilter]: 42,
[FEATURES.customTerminologyPlurals]: 43,
});

export const hasAPISupportForFeature = (minorVersion: string | number, featureName: string) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export const FiltersRowsPlain = ({
<>
<div className={classes.break} />
<div className={classes.additionalFiltersContainer}>
<div className={classes.additionalFiltersTitle}>{i18n.t('Stage filters').toUpperCase()}</div>
<div className={classes.additionalFiltersTitle}>{i18n.t('Program stage filters').toUpperCase()}</div>
<div className={classes.break} />
<Filters
columns={columns.filter(item => item.additionalColumn)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ const NewEventWorkspacePlain = ({

if (!stage) {
return renderWidget(
<div className={classes.errorWrapper}>{i18n.t('Stage not found')}</div>,
<div className={classes.errorWrapper}>{i18n.t('Program stage not found')}</div>,
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export const ProgramStageSelector = ({ programId, orgUnitId, teiId, enrollmentId
<>
{program ?
<Widget
header={i18n.t('Choose a stage for a new event')}
header={i18n.t('Choose a program stage for a new event')}
noncollapsible
>
<ProgramStageSelectorComponent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export const EnrollmentAddEventTopBar = ({
},
]}
selectedValue="alwaysPreselected"
title={i18n.t('Stage')}
title={i18n.t('Program stage')}
isUserInteractionInProgress={userInteractionInProgress}
/>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export const TopBar = ({
},
]}
selectedValue="alwaysPreselected"
title={i18n.t('Stage')}
title={i18n.t('Program stage')}
isUserInteractionInProgress={isUserInteractionInProgress}
/>
{programStage && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import type { PlainProps } from './NotesSection.types';

const LoadingNotes = withLoadingIndicator(null, props => ({ style: props.loadingIndicatorStyle }))(Notes);

const headerText = i18n.t('Notes');

const getStyles = (theme: any) => ({
badge: {
backgroundColor: theme.palette.grey.light,
Expand Down Expand Up @@ -42,7 +40,7 @@ class NotesSectionPlain extends React.Component<Props> {
return (
<ViewEventSectionHeader
icon={IconMessages24}
text={headerText}
text={i18n.t('Notes')}
badgeClass={classes.badge}
badgeCount={badgeCount}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ import type { PlainProps } from './RelationshipsSection.types';
const LoadingRelationships =
withLoadingIndicator(null, props => ({ style: props.loadingIndicatorStyle }))(Relationships);

const headerText = i18n.t('Relationships');

const getStyles = (theme: any) => ({
badge: {
backgroundColor: theme.palette.grey.light,
Expand Down Expand Up @@ -53,7 +51,7 @@ class RelationshipsSectionPlain extends React.Component<Props> {
return (
<ViewEventSectionHeader
icon={IconLink24}
text={headerText}
text={i18n.t('Relationships')}
badgeClass={classes.badge}
badgeCount={badgeCount}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import { getAttributesFromScopeId } from '../../../../metaData/helpers';
import type { DataElement } from '../../../../metaData/DataElement';
import { convertServerToClient, convertClientToView } from '../../../../converters';

const DEFAULT_NAME = i18n.t('tracked entity instance');

type Attribute = {
valueType: string;
attribute: string;
Expand Down Expand Up @@ -39,7 +37,7 @@ const getTetAttributes = (attributes: Array<Attribute>, tetAttributes: Array<Dat
export const deriveTeiName = (attributes: Array<Attribute>, trackedEntityType: string, teiId: string) => {
const tetAttributes = getAttributesFromScopeId(trackedEntityType);

if (!attributes || !tetAttributes) return teiId ?? DEFAULT_NAME;
if (!attributes || !tetAttributes) return teiId ?? i18n.t('tracked entity instance');

const teiNameDisplayInReports = getTetAttributesDisplayInReports(attributes, tetAttributes);
if (teiNameDisplayInReports) return teiNameDisplayInReports;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,9 @@ const styles: Readonly<any> = (theme: any) => ({
},
});

const fromNames = {
PROGRAM_STAGE_INSTANCE: i18n.t('This event'),
const getFromName = (entityType: string) => {
if (entityType === 'PROGRAM_STAGE_INSTANCE') return i18n.t('This event');
return undefined;
};

type PlainProps = {
Expand Down Expand Up @@ -105,7 +106,7 @@ class RelationshipsPlain extends React.Component<Props> {
const { onRenderConnectedEntity } = this.props;

if (entity.id === this.props.currentEntityId) {
return fromNames[entity.type];
return getFromName(entity.type);
}

return onRenderConnectedEntity ? onRenderConnectedEntity(entity) : entity.name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@ const styles: Readonly<any> = ({ typography }: any) => ({
},
});

const noticeBoxTitle = i18n.t('This program is protected');
const reasonHeader = i18n.t('Reason to check for enrollments');
const reasonPlaceholder = i18n.t('Describe the reason you are checking for enrollments in this protected program');

type Props = PlainProps & WithStyles<typeof styles>;

const WidgetBreakingTheGlassPlain = ({
Expand All @@ -52,15 +48,17 @@ const WidgetBreakingTheGlassPlain = ({
{i18n.t('Check for enrollments')}
</div>
<br />
<NoticeBox title={noticeBoxTitle} warning>
<NoticeBox title={i18n.t('This program is protected')} warning>
{i18n.t('You must provide a reason to check for enrollments in this protected program.')}
{' '}
{i18n.t('All activity will be logged.')}
</NoticeBox>
<br />
<TextAreaField
label={reasonHeader}
placeholder={reasonPlaceholder}
label={i18n.t('Reason to check for enrollments')}
placeholder={
i18n.t('Describe the reason you are checking for enrollments in this protected program')
}
onChange={reasonChangeHandler}
value={reason}
inputWidth="680px"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { withStyles, type WithStyles } from 'capture-core-utils/styles';
import { Tag, spacersNum } from '@dhis2/ui';
import { plainStatus, translatedStatus } from '../constants/status.const';
import { plainStatus, getTranslatedStatus } from '../constants/status.const';
import type { Props } from './status.types';

const styles = {
Expand All @@ -16,7 +16,7 @@ export const StatusPlain = ({ status = '', classes }: Props & WithStyles<typeof
positive={status === plainStatus.ACTIVE}
negative={status === plainStatus.CANCELLED}
>
{translatedStatus[status] ?? status}
{getTranslatedStatus()[status] ?? status}
</Tag>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const plainStatus = Object.freeze({
CANCELLED: 'CANCELLED',
});

export const translatedStatus = Object.freeze({
export const getTranslatedStatus = () => ({
[plainStatus.ACTIVE]: i18n.t('Active'),
[plainStatus.COMPLETED]: i18n.t('Completed'),
[plainStatus.CANCELLED]: i18n.t('Cancelled'),
Expand Down
Loading
Loading