Contribution Number: 1
Student: Jia Dodeja
Issue: openedx/frontend-app-learner-record#457
Status: Phase IV Complete
I chose this issue because it is well-defined and directly tied to a real user experience problem. Non-English speakers using the app still see "Completed" and "Partially Completed" in English even when the rest of the interface is translated, which is the kind of inconsistency that quietly affects usability. The fix involves extracting hardcoded strings into i18n messages in a React component, which aligns with my JavaScript background and gives me a chance to learn how internationalization patterns work in a production codebase.
The maintainer also linked the exact file and line number, which gave me enough context to feel confident this was a contribution I could meaningfully complete.
In ProgramRecordsList.jsx, the strings 'Completed' and 'Partially Completed' are hardcoded directly in JavaScript. This means they are always displayed in English regardless of the user's language setting.
The strings should be wrapped in the project's translation function so they can be translated into the user's language.
Even when the app is displayed in another language, the program status still shows as "Completed" or "Partially Completed" in English.
src/components/ProgramRecordsList/ProgramRecordsList.jsx(lines 30 and 32)
Cloned the fork locally, ran npm install (instead of npm ci due to a lock file sync error), and started the dev server with npm start. The app compiled successfully and ran at http://localhost:1990/. The page renders blank locally since it requires a real OpenEdX backend for data, but the hardcoded strings are visible directly in the source code at the referenced file and lines.
- Open
src/components/ProgramRecordsList/ProgramRecordsList.jsx - Navigate to lines 29 to 32
- Observe that
program.status = 'Completed'andprogram.status = 'Partially Completed'are hardcoded English strings with no translation wrapper - Expected: strings should use the project's
intl.formatMessage()pattern with defined message descriptors - Actual: strings are hardcoded and will always render in English regardless of user locale
Understand: The program status strings "Completed" and "Partially Completed" are hardcoded in ProgramRecordsList.jsx. They need to be extracted into i18n message descriptors so the app can translate them for non-English users.
Match: Other components in this codebase use defineMessages from @edx/frontend-platform/i18n and useIntl to define and format translatable strings. The surrounding components use FormattedMessage for JSX rendering, and intl.formatMessage() for string assignment outside of JSX.
Plan:
- Import
defineMessagesanduseIntlfrom@edx/frontend-platform/i18n - Define message descriptors for
'Completed'and'Partially Completed'usingdefineMessages - Replace the hardcoded strings on lines 30 and 32 with
intl.formatMessage(messages.completed)andintl.formatMessage(messages.partiallyCompleted) - Run existing tests with
npm testto confirm nothing is broken
Implement: https://github.com/jia-dodeja/frontend-app-learner-record/tree/fix-issue-457
Review: Followed the project's existing i18n patterns and commit message conventions before opening a PR.
Evaluate: Ran npm test to verify existing tests pass and added a new test to explicitly verify the translated status strings render correctly.
Added one new test case to src/components/ProgramRecordsList/test/ProgramRecordsList.test.jsx that explicitly verifies the translated status strings "Completed" and "Partially Completed" are rendered correctly when program data is present.
- 76 tests passing, 2 failing
- The 2 failing tests are in
SendLearnerRecordModaland are pre-existing failures unrelated to this change (ReactdefaultPropsdeprecation warnings in the Paragon component library) ProgramRecordsList.jsxcoverage: 95% statements, 100% branch
Confirmed the hardcoded strings on lines 30 and 32 of ProgramRecordsList.jsx have been replaced with intl.formatMessage() calls referencing properly defined message descriptors.
What I built:
- Updated the import on line 7 of
ProgramRecordsList.jsxto includedefineMessagesanduseIntlfrom@edx/frontend-platform/i18n - Added
const messages = defineMessages(...)block above the component with descriptors forcompletedandpartiallyCompleted - Added
const intl = useIntl()inside the component function - Replaced hardcoded
'Completed'and'Partially Completed'strings withintl.formatMessage()calls - Added a new test case verifying the translated strings render correctly
Challenges faced:
npm cifailed due to a lock file sync issue; resolved by usingnpm installinstead- Git credential conflict between two Windows accounts (
jiadodejavsjia-dodeja); resolved by clearing Windows Credential Manager and embedding a Personal Access Token in the remote URL - Initially considered using
<FormattedMessage>JSX component, but since the strings are assigned to a variable outside JSX,intl.formatMessage()was the correct approach
Key commits:
feat: extract hardcoded i18n strings in ProgramRecordsListtest: add test for i18n status strings in ProgramRecordsList
- Files modified:
src/components/ProgramRecordsList/ProgramRecordsList.jsx,src/components/ProgramRecordsList/test/ProgramRecordsList.test.jsx - Active branch: https://github.com/jia-dodeja/frontend-app-learner-record/tree/fix-issue-457
PR Link: openedx/frontend-app-learner-record#685
PR Description: Extracted the hardcoded 'Completed' and 'Partially Completed' status strings in ProgramRecordsList.jsx into i18n message descriptors using defineMessages and useIntl, replacing them with intl.formatMessage() calls so they can be translated into the user's language.
Maintainer Feedback: Awaiting review. CLA submitted; waiting for DocuSign confirmation within 1 business day.
Status: Awaiting review
The most important thing I learned was the difference between intl.formatMessage() and <FormattedMessage>. The JSX component works for rendering strings directly in markup, but when you are assigning a string to a variable in logic, you need the function form. Reading the existing components before writing anything was what made that clear.
The credential conflict between two GitHub accounts on Windows was the most frustrating blocker. Clearing Windows Credential Manager and embedding the PAT directly in the remote URL fixed it. I would set that up correctly from the start next time.