Skip to content

Commit 37e3901

Browse files
feat: add translations: CLI commands and update runtime i18n integration (#205)
Adds two new CLI commands for managing translations, plus the runtime wiring to feed pulled translations into the app. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 28377f4 commit 37e3901

45 files changed

Lines changed: 1168 additions & 715 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/how_tos/migrate-frontend-app.md

Lines changed: 35 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,8 @@ packages/
269269
270270
### i18n ###
271271
src/i18n/transifex_input.json
272+
src/i18n/messages.ts
273+
src/i18n/messages/
272274
273275
### Editors ###
274276
.DS_Store
@@ -538,51 +540,45 @@ i18n
538540

539541
Description fields are now required on all i18n messages in the repository. This is because of a change to the ESLint config.
540542

541-
Also, replace the contents of `src/i18n/index.js` with:
542-
543-
```
544-
// Placeholder be overridden by `make pull_translations`
545-
export default {
546-
ar: {},
547-
'zh-hk': {},
548-
'zh-cn': {},
549-
uk: {},
550-
'tr-tr': {},
551-
th: {},
552-
te: {},
553-
ru: {},
554-
'pt-pt': {},
555-
'pt-br': {},
556-
'it-it': {},
557-
id: {},
558-
hi: {},
559-
he: {},
560-
'fr-ca': {},
561-
fa: {},
562-
'es-es': {},
563-
'es-419': {},
564-
el: {},
565-
'de-de': {},
566-
da: {},
567-
bo: {},
568-
};
543+
Translations are now pulled and prepared using the `openedx translations:pull` CLI command. Add an `atlasTranslations` field to your `package.json` so the command knows where to find your app's translations and which dependencies to resolve transitively:
544+
545+
```json
546+
"atlasTranslations": {
547+
"path": "translations/frontend-app-[YOUR_APP]/src/i18n/messages",
548+
"dependencies": ["@openedx/frontend-base"]
549+
}
569550
```
570551

571-
Finally, edit the `Makefile` so that no strings are being pulled from `frontend-component-(header|footer)`, and rename `frontend-platform` to `frontend-base`. Such as:
552+
Also add a `translations:pull` script to your `package.json`:
572553

573-
```Makefile
574-
# Pulls translations using atlas.
575-
pull_translations:
576-
mkdir src/i18n/messages
577-
cd src/i18n/messages \
578-
&& atlas pull $(ATLAS_OPTIONS) \
579-
translations/frontend-base/src/i18n/messages:frontend-base \
580-
translations/paragon/src/i18n/messages:paragon \
581-
translations/frontend-app-[YOUR_APP]/src/i18n/messages:frontend-app-[YOUR_APP]
554+
```json
555+
"scripts": {
556+
"translations:pull": "openedx translations:pull"
557+
}
558+
```
559+
560+
And update your `pull_translations` Makefile target to use it:
582561

583-
$(intl_imports) frontend-base paragon frontend-app-[YOUR_APP]
562+
```Makefile
563+
pull_translations: | requirements
564+
npm run translations:pull
584565
```
566+
567+
Running `npm run translations:pull` will pull translations from `openedx-translations` and generate `src/i18n/messages.ts`.
568+
569+
Add a `src/i18n/index.ts` file that re-exports the generated messages:
570+
571+
```ts
572+
export { default } from './messages';
585573
```
574+
575+
Also add a `src/i18n/messages.d.ts` type declaration file so TypeScript knows the shape of the generated module even before `translations:pull` has been run:
576+
577+
```ts
578+
import type { SiteMessages } from '@openedx/frontend-base';
579+
580+
declare const messages: SiteMessages;
581+
export default messages;
586582
```
587583

588584
SVGR "ReactComponent" imports have been removed

frontend-base.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ declare module 'site.config' {
22
export default SiteConfig;
33
}
44

5+
declare module 'site.i18n' {
6+
export default SiteMessages;
7+
}
8+
59
declare module '*.svg' {
610
const content: string;
711
export default content;

package-lock.json

Lines changed: 15 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,23 @@
1616
"/dist"
1717
],
1818
"bin": {
19-
"intl-imports.js": "./dist/tools/cli/intl-imports.js",
20-
"openedx": "./dist/tools/cli/openedx.js",
21-
"transifex-utils.js": "./dist/tools/cli/transifex-utils.js"
19+
"openedx": "./dist/tools/cli/openedx.js"
20+
},
21+
"atlasTranslations": {
22+
"path": "translations/frontend-base/src/i18n/messages",
23+
"dependencies": [
24+
"@openedx/paragon"
25+
]
2226
},
2327
"scripts": {
2428
"build": "make build",
2529
"clean": "make clean",
2630
"dev": "npm run build && node ./dist/tools/cli/openedx.js dev:shell",
2731
"docs": "jsdoc -c jsdoc.json",
2832
"lint": "eslint .; npm run lint:tools; npm --prefix ./test-site run lint",
33+
"lint:fix": "eslint . --fix; npm run lint:fix:tools",
2934
"lint:tools": "cd ./tools && eslint . && cd ..",
35+
"lint:fix:tools": "cd ./tools && eslint . --fix && cd ..",
3036
"pack": "mkdir -p pack && npm pack --silent --pack-destination pack >/dev/null && mv \"$(ls -t pack/*.tgz | head -n 1)\" pack/openedx-frontend-base.tgz",
3137
"prepack": "npm run build",
3238
"test": "jest",
@@ -143,12 +149,12 @@
143149
"@testing-library/jest-dom": "^6.6.3",
144150
"@testing-library/react": "^16.3.0",
145151
"@testing-library/user-event": "^14.6.1",
146-
"@tsconfig/node20": "^20.1.5",
152+
"@tsconfig/node24": "^24.0.4",
147153
"@types/compression": "^1.7.5",
148154
"@types/jest": "^29.5.14",
149155
"@types/lodash.camelcase": "^4.3.9",
150156
"@types/lodash.merge": "^4.6.9",
151-
"@types/node": "^18.19.43",
157+
"@types/node": "^24.12.0",
152158
"@types/react": "^18.3.20",
153159
"@types/react-dom": "^18.3.6",
154160
"axios-mock-adapter": "^1.22.0",
@@ -157,7 +163,7 @@
157163
"nodemon": "^3.1.4"
158164
},
159165
"peerDependencies": {
160-
"@openedx/paragon": "^23.4.5",
166+
"@openedx/paragon": "^23.20.0",
161167
"@tanstack/react-query": "^5.81.2",
162168
"react": "^18.3.1",
163169
"react-dom": "^18.3.1",

runtime/i18n/index.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ export {
9797
} from 'react-intl';
9898

9999
export {
100-
addAppMessages,
101100
configureI18n,
102101
getLocale,
103102
getLocalizedLanguageName,

runtime/i18n/lib.ts

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -237,20 +237,6 @@ export function mergeMessages(newMessages = {}) {
237237
return messages;
238238
}
239239

240-
/**
241-
* Adds all the messages found in the loaded apps.
242-
*
243-
* @memberof module:Internationalization
244-
*/
245-
export function addAppMessages() {
246-
const { apps } = getSiteConfig();
247-
if (apps) {
248-
apps.forEach((app) => {
249-
mergeMessages(app.messages);
250-
});
251-
}
252-
}
253-
254240
interface ConfigureI18nOptions {
255241
messages: LocalizedMessages[] | LocalizedMessages,
256242
}

shell/dev/devHome/app.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { App } from '../../../types';
22
import HomePage from './HomePage';
3-
import messages from './i18n';
43

54
const app: App = {
65
appId: 'org.openedx.frontend.app.dev.home',
@@ -12,7 +11,6 @@ const app: App = {
1211
role: 'org.openedx.frontend.role.devHome'
1312
}
1413
}],
15-
messages,
1614
};
1715

1816
export default app;

shell/dev/devHome/i18n/index.ts

Lines changed: 0 additions & 27 deletions
This file was deleted.

shell/i18n/index.ts

Lines changed: 0 additions & 25 deletions
This file was deleted.

shell/site.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,14 @@ import {
1010
subscribe
1111
} from '../runtime';
1212
import { addAppConfigs } from '../runtime/config';
13-
import { addAppMessages } from '../runtime/i18n';
14-
import messages from './i18n';
13+
import messages from 'site.i18n';
1514
import createRouter from './router/createRouter';
1615

1716
subscribe(SITE_READY, async () => {
1817
const queryClient = new QueryClient();
1918
const router = createRouter();
2019

2120
addAppConfigs();
22-
addAppMessages();
2321

2422
const root = createRoot(document.getElementById('root') as HTMLElement);
2523
root.render(

0 commit comments

Comments
 (0)