@micha.bigler/ui-core-micha 3.14.4 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (341) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +7 -0
  3. package/dist/chat/kitSxRegistry.js +9 -0
  4. package/dist/components/charts/kitSxRegistry.js +6 -0
  5. package/dist/entries/charts.js +6 -0
  6. package/dist/entries/chat.js +8 -0
  7. package/dist/entries/markdown.js +1 -0
  8. package/dist/index.js +0 -14
  9. package/dist/pages/AccountPage.js +1 -2
  10. package/dist/pages/LoginPage.js +1 -2
  11. package/dist/pages/PasswordChangePage.js +1 -2
  12. package/dist/pages/PasswordInvitePage.js +1 -2
  13. package/dist/pages/PasswordResetRequestPage.js +1 -2
  14. package/dist/pages/SignUpPage.js +1 -2
  15. package/dist/pages/SignupConfirmPage.js +1 -2
  16. package/dist/theme/kitSxEntry.js +11 -0
  17. package/dist/theme/kitSxRegistry.js +2 -15
  18. package/package.json +31 -7
  19. package/.github/workflows/ci.yml +0 -35
  20. package/.github/workflows/publish.yml +0 -126
  21. package/DESIGN.md +0 -60
  22. package/WORK_ORDERS.md +0 -150
  23. package/dev/entries.jsx +0 -721
  24. package/dev/fixtures.js +0 -26
  25. package/dev/main.jsx +0 -75
  26. package/dev/mockTransport.jsx +0 -128
  27. package/docs/CHART-LAYOUT.md +0 -157
  28. package/docs/DARK-TOKENS.md +0 -140
  29. package/docs/TYPE-SCALE.md +0 -111
  30. package/docs/messaging-deviations.md +0 -118
  31. package/index.html +0 -12
  32. package/renovate.json +0 -10
  33. package/scripts/chart-api-census.mjs +0 -415
  34. package/src/auth/AuthContext.jsx +0 -158
  35. package/src/auth/ReauthModal.jsx +0 -82
  36. package/src/auth/UserMenu.jsx +0 -121
  37. package/src/auth/apiClient.jsx +0 -232
  38. package/src/auth/authApi.jsx +0 -539
  39. package/src/auth/authConfig.jsx +0 -34
  40. package/src/auth/reauth.js +0 -47
  41. package/src/chat/ChatComposer.jsx +0 -36
  42. package/src/chat/ChatList.jsx +0 -87
  43. package/src/chat/ChatThread.jsx +0 -128
  44. package/src/chat/ChatWorkspace.jsx +0 -244
  45. package/src/chat/MarkdownReply.jsx +0 -22
  46. package/src/chat/ModelPicker.jsx +0 -85
  47. package/src/chat/api.js +0 -18
  48. package/src/chat/useChatSocket.js +0 -32
  49. package/src/chat/wire.js +0 -7
  50. package/src/components/AccessCodeManager.jsx +0 -288
  51. package/src/components/AccessCodeSingleUseToggle.jsx +0 -92
  52. package/src/components/AllowedEmailDomainsManager.jsx +0 -92
  53. package/src/components/AuthFactorRequirementCard.jsx +0 -95
  54. package/src/components/BulkInviteCsvTab.jsx +0 -198
  55. package/src/components/EmptyState.jsx +0 -38
  56. package/src/components/LoginForm.jsx +0 -159
  57. package/src/components/MFAComponent.jsx +0 -350
  58. package/src/components/MfaLoginComponent.jsx +0 -252
  59. package/src/components/MobileBottomNav.jsx +0 -82
  60. package/src/components/PasskeysComponent.jsx +0 -252
  61. package/src/components/PasswordChangeForm.jsx +0 -87
  62. package/src/components/PasswordResetRequestForm.jsx +0 -43
  63. package/src/components/PasswordSetForm.jsx +0 -97
  64. package/src/components/ProfileComponent.jsx +0 -348
  65. package/src/components/QrSignupManager.jsx +0 -404
  66. package/src/components/QrSignupValidityManager.jsx +0 -106
  67. package/src/components/RegistrationMethodsManager.jsx +0 -150
  68. package/src/components/SecurityComponent.jsx +0 -141
  69. package/src/components/SocialLoginButtons.jsx +0 -83
  70. package/src/components/SoftChip.jsx +0 -93
  71. package/src/components/StatTile.jsx +0 -39
  72. package/src/components/SupportRecoveryRequestsTab.jsx +0 -482
  73. package/src/components/TurnstileWidget.jsx +0 -99
  74. package/src/components/UserInviteComponent.jsx +0 -76
  75. package/src/components/UserListComponent.jsx +0 -618
  76. package/src/components/charts/BarChart.jsx +0 -102
  77. package/src/components/charts/ChartFrame.jsx +0 -214
  78. package/src/components/charts/LineChart.jsx +0 -126
  79. package/src/components/charts/ScatterChart.jsx +0 -299
  80. package/src/components/charts/TimeSeriesChart.jsx +0 -300
  81. package/src/components/charts/chartDefaults.js +0 -644
  82. package/src/components/charts/chartLabels.js +0 -36
  83. package/src/components/charts/exportChart.js +0 -258
  84. package/src/components/charts/formatters.js +0 -39
  85. package/src/components/charts/palette.js +0 -33
  86. package/src/components/charts/yearTickInterval.js +0 -7
  87. package/src/i18n/authTranslations.ts +0 -2651
  88. package/src/i18n/chartsTranslations.ts +0 -91
  89. package/src/i18n/chatTranslations.ts +0 -55
  90. package/src/i18n/messagingTranslations.ts +0 -120
  91. package/src/i18n/notificationsTranslations.ts +0 -32
  92. package/src/i18n/onboardingTranslations.ts +0 -29
  93. package/src/i18n/sectionNavTranslations.ts +0 -20
  94. package/src/i18n/uiCoreTranslations.js +0 -29
  95. package/src/i18n/userMenuTranslations.ts +0 -5
  96. package/src/index.js +0 -158
  97. package/src/layout/PageLayout.jsx +0 -36
  98. package/src/layout/SectionNav.jsx +0 -320
  99. package/src/messaging/AttachmentList.jsx +0 -145
  100. package/src/messaging/Composer.jsx +0 -197
  101. package/src/messaging/ConversationLaunchers.jsx +0 -51
  102. package/src/messaging/ConversationList.jsx +0 -109
  103. package/src/messaging/DirectMessageLauncher.jsx +0 -112
  104. package/src/messaging/MessageBubble.jsx +0 -183
  105. package/src/messaging/MessagingProvider.jsx +0 -0
  106. package/src/messaging/MessagingScopeConfig.jsx +0 -24
  107. package/src/messaging/PollCard.jsx +0 -163
  108. package/src/messaging/ReactionBar.jsx +0 -43
  109. package/src/messaging/ReadTicks.jsx +0 -82
  110. package/src/messaging/Thread.jsx +0 -195
  111. package/src/messaging/api.js +0 -48
  112. package/src/messaging/composerImageCompression.js +0 -35
  113. package/src/messaging/linkifyText.jsx +0 -37
  114. package/src/notifications/NotificationBell.jsx +0 -84
  115. package/src/notifications/NotificationSettings.jsx +0 -330
  116. package/src/notifications/NotificationsProvider.jsx +0 -224
  117. package/src/notifications/PopupSurface.jsx +0 -105
  118. package/src/notifications/api.js +0 -55
  119. package/src/notifications/feedApi.js +0 -18
  120. package/src/notifications/realtime.jsx +0 -138
  121. package/src/notifications/serviceWorker/sw.js +0 -50
  122. package/src/onboarding/OnboardingProvider.jsx +0 -326
  123. package/src/onboarding/OnboardingWizard.jsx +0 -61
  124. package/src/onboarding/WizardDialogShell.jsx +0 -51
  125. package/src/onboarding/api.js +0 -13
  126. package/src/onboarding/stepSelection.js +0 -16
  127. package/src/onboarding/steps/BrowserPushStep.jsx +0 -121
  128. package/src/onboarding/steps/CompleteNameStep.jsx +0 -46
  129. package/src/onboarding/steps/CookieConsentStep.jsx +0 -133
  130. package/src/onboarding/steps/PwaInstallStep.jsx +0 -47
  131. package/src/pages/AccountPage.jsx +0 -394
  132. package/src/pages/LoginPage.jsx +0 -343
  133. package/src/pages/PasswordChangePage.jsx +0 -62
  134. package/src/pages/PasswordInvitePage.jsx +0 -177
  135. package/src/pages/PasswordResetRequestPage.jsx +0 -68
  136. package/src/pages/SignUpPage.jsx +0 -268
  137. package/src/pages/SignupConfirmPage.jsx +0 -155
  138. package/src/testing/checkKitIntegration.js +0 -233
  139. package/src/theme/createAppTheme.js +0 -423
  140. package/src/theme/fonts.js +0 -3
  141. package/src/theme/index.js +0 -21
  142. package/src/theme/kitSxRegistry.js +0 -285
  143. package/src/theme/themeCompleteness.js +0 -1045
  144. package/src/theme/tokens.js +0 -478
  145. package/src/utils/auth-errors.js +0 -76
  146. package/src/utils/authService.js +0 -223
  147. package/src/utils/resolveErrorText.js +0 -28
  148. package/src/utils/webauthn.js +0 -51
  149. package/tests/AccountPage.profileStatements.test.jsx +0 -162
  150. package/tests/AccountPage.test.jsx +0 -200
  151. package/tests/AuthContext.test.jsx +0 -129
  152. package/tests/BarChart.test.jsx +0 -112
  153. package/tests/BrowserPushStep.test.jsx +0 -110
  154. package/tests/ChartFrame.test.jsx +0 -336
  155. package/tests/ConversationList.test.jsx +0 -144
  156. package/tests/CookieConsentStep.test.jsx +0 -69
  157. package/tests/EmptyState.test.jsx +0 -62
  158. package/tests/LineChart.test.jsx +0 -80
  159. package/tests/MessagingProvider.test.jsx +0 -50
  160. package/tests/MobileBottomNav.test.jsx +0 -319
  161. package/tests/NotificationBell.test.jsx +0 -60
  162. package/tests/NotificationSettings.test.jsx +0 -276
  163. package/tests/NotificationsProvider.test.jsx +0 -240
  164. package/tests/OnboardingProvider.test.jsx +0 -294
  165. package/tests/OnboardingWizard.test.jsx +0 -143
  166. package/tests/PasswordChangeForm.test.jsx +0 -70
  167. package/tests/PasswordInvitePage.test.jsx +0 -142
  168. package/tests/PasswordSetForm.test.jsx +0 -70
  169. package/tests/PopupSurface.test.jsx +0 -142
  170. package/tests/ProfileComponent.refresh.test.jsx +0 -194
  171. package/tests/QrSignupManager.registrationContext.test.jsx +0 -106
  172. package/tests/QrSignupManagerInfoBox.test.jsx +0 -49
  173. package/tests/ScatterChart.test.jsx +0 -270
  174. package/tests/SectionNav.test.jsx +0 -363
  175. package/tests/SignUpPage.test.jsx +0 -208
  176. package/tests/SoftChip.test.jsx +0 -105
  177. package/tests/StatTile.test.jsx +0 -57
  178. package/tests/Thread.test.jsx +0 -151
  179. package/tests/TimeSeriesChart.test.jsx +0 -367
  180. package/tests/UserListComponent.test.jsx +0 -192
  181. package/tests/UserMenu.test.jsx +0 -171
  182. package/tests/apiClientLanguage.test.js +0 -33
  183. package/tests/apiClientPublicPaths.test.js +0 -178
  184. package/tests/authApiLogin.test.js +0 -42
  185. package/tests/authApiRegistration.test.js +0 -31
  186. package/tests/authErrorCodeRendering.test.jsx +0 -77
  187. package/tests/authErrors.test.js +0 -74
  188. package/tests/authTranslations.test.js +0 -74
  189. package/tests/chart-api-census.test.js +0 -366
  190. package/tests/chartAxisTickBand.test.jsx +0 -95
  191. package/tests/chartDefaults.test.js +0 -902
  192. package/tests/chartLabels.test.js +0 -50
  193. package/tests/chartsPalette.test.js +0 -99
  194. package/tests/chatApi.test.js +0 -48
  195. package/tests/chatDriverNames.test.jsx +0 -71
  196. package/tests/chatExports.test.js +0 -3
  197. package/tests/chatList.test.jsx +0 -84
  198. package/tests/chatPicker.test.jsx +0 -82
  199. package/tests/chatSocket.test.jsx +0 -26
  200. package/tests/chatThread.test.jsx +0 -116
  201. package/tests/chatTranslations.test.js +0 -47
  202. package/tests/chatWorkspace.test.jsx +0 -234
  203. package/tests/checkKitIntegration.test.jsx +0 -219
  204. package/tests/createAppTheme.test.js +0 -132
  205. package/tests/createAppThemeDark.test.js +0 -127
  206. package/tests/createAppThemeLightGuard.test.js +0 -40
  207. package/tests/createAppThemePageContrast.test.js +0 -108
  208. package/tests/createAppThemeTypography.test.js +0 -53
  209. package/tests/errorCallSiteGuard.test.js +0 -32
  210. package/tests/exportChart.test.js +0 -313
  211. package/tests/feedApi.test.js +0 -46
  212. package/tests/fixtures/light-theme-baseline.json +0 -2234
  213. package/tests/i18nAggregate.test.js +0 -120
  214. package/tests/i18nGermanVariant.test.js +0 -65
  215. package/tests/loginPageErrorResolution.test.jsx +0 -102
  216. package/tests/messagingApi.test.js +0 -32
  217. package/tests/messagingChunk6.test.jsx +0 -116
  218. package/tests/messagingCompactBubble.test.jsx +0 -64
  219. package/tests/messagingComposer.test.jsx +0 -136
  220. package/tests/messagingComposerChunk5.test.jsx +0 -113
  221. package/tests/messagingContractConformance.test.js +0 -69
  222. package/tests/messagingDirectMessageLauncher.test.jsx +0 -151
  223. package/tests/messagingExports.test.js +0 -21
  224. package/tests/messagingInteractions.test.jsx +0 -136
  225. package/tests/messagingLastMessagePreview.test.jsx +0 -93
  226. package/tests/messagingLinkify.test.jsx +0 -51
  227. package/tests/messagingMessageActions.test.jsx +0 -163
  228. package/tests/messagingMsg6.test.jsx +0 -105
  229. package/tests/messagingMsg6f.test.jsx +0 -155
  230. package/tests/messagingMsg6g.test.jsx +0 -166
  231. package/tests/messagingMsg6h.test.jsx +0 -136
  232. package/tests/messagingMsg6i.test.jsx +0 -129
  233. package/tests/messagingPollRendering.test.jsx +0 -142
  234. package/tests/messagingReactionMerge.test.jsx +0 -77
  235. package/tests/messagingReadTicksTooltip.test.jsx +0 -36
  236. package/tests/messagingThreadReceipts.test.jsx +0 -178
  237. package/tests/messagingThreadingQuoting.test.jsx +0 -87
  238. package/tests/messagingUnreadLifecycle.test.jsx +0 -78
  239. package/tests/notificationsApi.test.js +0 -41
  240. package/tests/notificationsExports.test.js +0 -34
  241. package/tests/onboardingDescriptors.test.js +0 -132
  242. package/tests/packageTreeShaking.test.js +0 -126
  243. package/tests/realtime.test.jsx +0 -219
  244. package/tests/resolveErrorText.test.js +0 -72
  245. package/tests/stepSelection.test.js +0 -53
  246. package/tests/themeCompleteness.test.js +0 -626
  247. package/tests/timeSeriesLegend.test.js +0 -99
  248. package/tests/userScreenTranslations.test.jsx +0 -218
  249. package/tsconfig.build.json +0 -18
  250. package/vite.config.mjs +0 -6
  251. package/work-orders/AUTH-1.md +0 -74
  252. package/work-orders/AUTH-2.md +0 -74
  253. package/work-orders/AUTH-4.md +0 -183
  254. package/work-orders/AUTH-5.md +0 -154
  255. package/work-orders/AUTH-7.md +0 -181
  256. package/work-orders/AUTH-8.md +0 -184
  257. package/work-orders/CHART-1.md +0 -285
  258. package/work-orders/CHART-2.md +0 -222
  259. package/work-orders/CHART-3.md +0 -163
  260. package/work-orders/CHART-4.md +0 -203
  261. package/work-orders/CHART-5.md +0 -226
  262. package/work-orders/CHART-6.md +0 -428
  263. package/work-orders/CHART-7.md +0 -175
  264. package/work-orders/DX-1.md +0 -169
  265. package/work-orders/DX-2.md +0 -188
  266. package/work-orders/DX-3.md +0 -195
  267. package/work-orders/I18N-1.md +0 -254
  268. package/work-orders/I18N-3.md +0 -207
  269. package/work-orders/MSG-3.md +0 -375
  270. package/work-orders/MSG-3b.md +0 -1002
  271. package/work-orders/MSG-3c.md +0 -378
  272. package/work-orders/MSG-3d.md +0 -268
  273. package/work-orders/MSG-3e.md +0 -164
  274. package/work-orders/MSG-3f.md +0 -391
  275. package/work-orders/MSG-6e.md +0 -308
  276. package/work-orders/MSG-6f.md +0 -214
  277. package/work-orders/MSG-6g.md +0 -244
  278. package/work-orders/MSG-6h.md +0 -238
  279. package/work-orders/MSG-6i.md +0 -271
  280. package/work-orders/MSG-6j.md +0 -117
  281. package/work-orders/NOTIF-12.md +0 -214
  282. package/work-orders/NOTIF-13.md +0 -142
  283. package/work-orders/NOTIF-14.md +0 -151
  284. package/work-orders/PRIM-1.md +0 -177
  285. package/work-orders/SHELL-1.md +0 -255
  286. package/work-orders/SHELL-2.md +0 -197
  287. package/work-orders/SHELL-3.md +0 -359
  288. package/work-orders/SHELL-4.md +0 -351
  289. package/work-orders/SHELL-5.md +0 -345
  290. package/work-orders/SHELL-6.md +0 -210
  291. package/work-orders/THEME-1.md +0 -587
  292. package/work-orders/THEME-10.md +0 -303
  293. package/work-orders/THEME-11.md +0 -208
  294. package/work-orders/THEME-2.md +0 -339
  295. package/work-orders/THEME-3.md +0 -210
  296. package/work-orders/THEME-4.md +0 -271
  297. package/work-orders/THEME-5.md +0 -341
  298. package/work-orders/THEME-6.md +0 -247
  299. package/work-orders/THEME-7.md +0 -82
  300. package/work-orders/THEME-8.md +0 -211
  301. package/work-orders/THEME-9.md +0 -194
  302. package/work-orders/UCM-AUTH-10.md +0 -490
  303. package/work-orders/UCM-AUTH-11.md +0 -185
  304. package/work-orders/UCM-AUTH-12.md +0 -98
  305. package/work-orders/UCM-AUTH-13.md +0 -47
  306. package/work-orders/UCM-AUTH-9.md +0 -207
  307. package/work-orders/UCM-CHART-10.md +0 -150
  308. package/work-orders/UCM-CHART-11.md +0 -132
  309. package/work-orders/UCM-CHART-12.md +0 -348
  310. package/work-orders/UCM-CHART-13.md +0 -122
  311. package/work-orders/UCM-CHART-14.md +0 -198
  312. package/work-orders/UCM-CHART-15.md +0 -187
  313. package/work-orders/UCM-CHART-16.md +0 -169
  314. package/work-orders/UCM-CHART-17.md +0 -195
  315. package/work-orders/UCM-CHART-18.md +0 -200
  316. package/work-orders/UCM-CHART-8.md +0 -147
  317. package/work-orders/UCM-CHART-9.md +0 -265
  318. package/work-orders/UCM-CHAT-1.md +0 -190
  319. package/work-orders/UCM-CHAT-2.md +0 -75
  320. package/work-orders/UCM-CI-1.md +0 -65
  321. package/work-orders/UCM-DEP-1.md +0 -63
  322. package/work-orders/UCM-I18N-4.md +0 -226
  323. package/work-orders/UCM-I18N-5.md +0 -211
  324. package/work-orders/UCM-MSG-20.md +0 -192
  325. package/work-orders/UCM-PRIM-2.md +0 -114
  326. package/work-orders/UCM-SHELL-7.md +0 -134
  327. package/work-orders/UCM-SHELL-8.md +0 -125
  328. package/work-orders/UCM-TEST-1.md +0 -304
  329. package/work-orders/UCM-THEME-13.md +0 -69
  330. package/work-orders/UCM-THEME-14.md +0 -312
  331. package/work-orders/UCM-THEME-15.md +0 -356
  332. package/work-orders/UCM-THEME-16.md +0 -80
  333. package/work-orders/UCM-THEME-17.md +0 -111
  334. package/work-orders/UCM-THEME-18.md +0 -184
  335. package/work-orders/assets/AUTH-4-user-list-card.html +0 -407
  336. package/work-orders/assets/PRIM-1-dashboard-primitives.html +0 -624
  337. package/work-orders/assets/SHELL-2-account-navigation.html +0 -1159
  338. package/work-orders/assets/THEME-1-baseline-reference-sheet.html +0 -1352
  339. package/work-orders/assets/UCM-CHAT-1-ai-chat.html +0 -447
  340. package/work-orders/assets/UCM-THEME-13-dark-prototype.html +0 -390
  341. package/work-orders/assets/UCM-THEME-17-type-scale.html +0 -391
@@ -1,254 +0,0 @@
1
- # I18N-1 — One export, so a consumer cannot half-register the kit's strings
2
-
3
- **Target repo:** `ui-core-micha` (branch `main`)
4
- **Tier:** 3 — shared-core, and it adds a public export every consumer will depend on
5
- **Target version:** `2.36.0` — minor. A new capability, fully backwards compatible.
6
- **Prototype:** none. Nothing visual changes.
7
-
8
- ---
9
-
10
- ## A. Envelope
11
-
12
- ### Goal
13
-
14
- `ui-core-micha` exports its UI strings as **six separate bundles** that each consuming app must
15
- spread into its own i18n resources by hand. Adopting a component without also adding its bundle
16
- produces **a raw key rendered as visible UI text** — silently, with no type error and no runtime
17
- error. Ship one aggregate export so that cannot happen, and so a *future* ucm feature is carried
18
- automatically instead of requiring twelve apps to notice.
19
-
20
- ### The evidence
21
-
22
- **Two apps hit by the same mechanism, one of them still live.**
23
-
24
- - **cockpit, 2026-08-11 (`UI-3`).** Adopted `UserMenu`; the matching `userMenuTranslations` was not
25
- spread, and the header button rendered the literal string `UserMenu.TITLE`. **Both independent
26
- static reviews were clean** — the defect is structurally invisible to `Read`/`Grep` review. It
27
- was caught by the rendered click-through, and only by DOM inspection at that, because screenshot
28
- capture was unavailable in that session. Fixed there.
29
- - **fitness-monitor, live now.** Imports `ChartFrame` (`frontend/src/pages/BodyHistoryPage.jsx:7`,
30
- used at `:295` and `:445`) but registers **only** `authTranslations`
31
- (`frontend/i18n/index.js`), and carries no `ChartFrame.*` key of its own. So
32
- `ChartFrame.jsx:74`'s `t('ChartFrame.LOADING')` and its sibling empty/error states render their
33
- raw keys. Nobody noticed because those are transient edge states — which is exactly the class
34
- `DESIGN.md` #7 says must be designed rather than left to chance.
35
-
36
- **The estate survey, measured 2026-08-11.** Twelve apps register ucm bundles:
37
-
38
- | App | Bundles registered | ucm components used beyond auth | Verdict |
39
- |---|---|---|---|
40
- | jg-ferien | all six + surveyRenderer | Bell, Settings, Wizard, UserMenu | correct |
41
- | cockpit | auth, notifications, onboarding, userMenu | Bell, Settings, Wizard, UserMenu | correct (since `UI-3`) |
42
- | hram | auth, charts, userMenu | ChartFrame, UserMenu | correct |
43
- | **fitness-monitor** | **auth only** | **ChartFrame** | **defective** |
44
- | spesix, survey_app, kerzenziehen, webshop-guenter, webapp-template, hpc-bridge, bigler-consult, survey_contact_app | auth only | none | correct today, exposed the moment they adopt anything |
45
-
46
- Eight of the twelve are correct only because they have not yet adopted a second component. That is
47
- not a safety property; it is a coincidence with an expiry date.
48
-
49
- **The merge is safe.** All six bundles together hold **504 keys with zero collisions**, verified by
50
- enumerating them; every key is namespace-prefixed (`Auth.*`, `ChartFrame.*`, `Messaging*.*`,
51
- `NotificationBell.*`, `Onboarding.*`, `UserMenu.*`, plus the bare allauth error codes
52
- `AUTH-2` deals with). A flat aggregate therefore changes no resolution today.
53
-
54
- ### Scope
55
-
56
- 1. **Export `uiCoreTranslations`** from the package root — the flat merge of all six bundles.
57
- Consumers spread one thing instead of six.
58
- 2. **Keep the six per-feature exports.** Removing them would break twelve apps for no gain; this
59
- work order is additive. An app may spread both during migration — harmless, because the values
60
- are identical and there are no collisions.
61
- 3. **A ratchet test, and this is the part that makes the fix permanent.** Assert that the aggregate
62
- contains every key of every bundle in `src/i18n/`, **enumerated from the directory rather than
63
- from a hand-written list**. A new bundle added later that is not folded into the aggregate must
64
- fail this test. Without that, the aggregate is correct today and rots the same way the six
65
- exports did.
66
- 4. **A collision test.** Assert the union has no duplicate key across bundles. It holds today at
67
- 504 keys; the test is what stops a future bundle from silently shadowing an existing string.
68
- 5. **Document the contract** where a consumer will actually meet it: one line in the README's i18n
69
- section saying that spreading `uiCoreTranslations` is the supported way, and that the
70
- per-feature exports remain for apps that want to be selective and accept the pairing burden.
71
-
72
- ### Non-goals / do not touch
73
-
74
- - **Self-registering components.** Feasible — ucm components use `useTranslation()` against the
75
- consumer's own instance, so a component could call `addResourceBundle` itself — but it is a
76
- separate question and a separate work order (`I18N-2`), deliberately: all twelve consumers flatten
77
- everything into the **default namespace** with dotted keys, so the registration shape has to match
78
- exactly, and registering at render time risks a first-paint flash of the raw key. That would
79
- replace an invisible defect with a visible one. Framed as a bundle-size optimisation, not a
80
- correctness fix, because this work order already closes the correctness hole.
81
- - **Namespaces**, and the flat dotted-key shape generally. Twelve apps depend on it.
82
- - **The bare allauth error codes** in `authTranslations` — `AUTH-2` owns those.
83
- - **Any consumer repository.** See the rollout note below.
84
- - Removing or renaming any existing export.
85
-
86
- ### Risks
87
-
88
- - **Bundle size for the eight auth-only apps.** `authTranslations` is 316 keys on its own; the other
89
- five add 188, of which `messagingTranslations` is 116. An auth-only app that switches to the
90
- aggregate ships roughly 30 KB of source strings it never renders. Judged acceptable against a
91
- defect class that has already fired twice — but **measure the built delta and report it**, because
92
- that number is the whole input to `I18N-2`, and a guess there would make that decision
93
- unfalsifiable.
94
- - **The ratchet test can be faked.** A test that enumerates the directory but compares against a
95
- re-export (`export * from './i18n'`) would pass while proving nothing. It must compare *keys of
96
- the aggregate value* against *keys read from each bundle module*.
97
- - **Consumers spreading both during migration.** Safe today because of the zero-collision property
98
- — which is precisely why item 4 is a test and not a comment.
99
- - A parallel session is active in this repo (`THEME-*` work landed today up to `2.35.0`). Check
100
- `git status` at start and sequence.
101
-
102
- ### Rollout — and the constraint that shapes it
103
-
104
- **A work order implements in one repository.** The twelve consumers cannot be migrated from here,
105
- so this work order ships the export and the rollout lands as named rows in the consuming repos.
106
-
107
- - **`fitness-monitor/FM-14` is mandatory and is the reason this is not merely hygiene** — it is the
108
- app with a live defect. It is written and blocked on this work order's release.
109
- **State the exposure plainly: fitness-monitor renders raw keys until `FM-14` lands.** The operator
110
- chose to route the fix through this rollout rather than patch it separately, so that it cannot be
111
- lost between two work orders; the cost of that choice is the delay, and it is recorded here rather
112
- than left implicit.
113
- - The other eleven apps are **correct today**. Migrating them to the aggregate is prevention, not
114
- repair, and it can ride along the next time each is touched. Do not open eleven rows now.
115
-
116
- ### Required tests to WRITE
117
-
118
- 1. `uiCoreTranslations` contains every key of every module in `src/i18n/`, with the module list read
119
- from the directory, not hand-written.
120
- 2. The union has no duplicate key across bundles (504 today; assert the property, not the number).
121
- 3. Every value keeps its `{ de, fr, en, sw }` shape through the merge — no bundle is flattened or
122
- partially spread.
123
- 4. The six per-feature exports still exist and are unchanged, so no consumer breaks.
124
-
125
- Run ucm's own affected set, not the full suite: the i18n tests plus whatever imports from
126
- `src/index.js`.
127
-
128
- ### Parity guardrail
129
-
130
- Purely additive. No existing export changes, no key changes, no rendered output changes in any app
131
- that is correct today.
132
-
133
- ---
134
-
135
- ## B. Implementation map
136
-
137
- *Filled by the Orchestrator on `git pull` — see `AGENTS.md` → "Work Order".*
138
-
139
- ### Context package
140
-
141
- **Bundle files** (all in `src/i18n/`, each `export const <name>Translations = { 'Key.NAME': { de, fr,
142
- en, sw }, ... }`, flat object, no nesting):
143
-
144
- - `src/i18n/authTranslations.ts` → `authTranslations` (316 keys, includes bare allauth codes like
145
- `email_password_mismatch` alongside `Auth.*` keys — still a flat top-level key, no special casing
146
- needed for the merge)
147
- - `src/i18n/chartsTranslations.ts` → `chartsTranslations` (`ChartFrame.*`)
148
- - `src/i18n/messagingTranslations.ts` → `messagingTranslations` (`Messaging*.*`, 116 keys)
149
- - `src/i18n/notificationsTranslations.ts` → `notificationsTranslations` (`NotificationBell.*`)
150
- - `src/i18n/onboardingTranslations.ts` → `onboardingTranslations` (`Onboarding.*`)
151
- - `src/i18n/userMenuTranslations.ts` → `userMenuTranslations` (`UserMenu.*`)
152
-
153
- **Root export site:** `src/index.js` — the six per-feature translation exports currently sit at two
154
- places: `export { authTranslations } ... export { userMenuTranslations } ...` under the `// --- 7.
155
- Translations ---` comment (~line 78-79), and `export { notificationsTranslations } ...
156
- onboardingTranslations ... chartsTranslations ... messagingTranslations` under `// --- 10.
157
- Translations ---` (~line 121-124). Add the new `uiCoreTranslations` export near those, importing all
158
- six bundle modules and merging with a plain object spread (`{ ...authTranslations, ...chartsTranslations,
159
- ... }`) — order doesn't matter, zero-collision is already verified. Do NOT remove or move the existing
160
- six exports.
161
-
162
- **Test file to add:** `tests/i18nAggregate.test.js` (new), following the directory-enumeration pattern
163
- already used in `tests/themeCompleteness.test.js` (`fs.readdirSync` over a directory, don't hand-write
164
- the file list) and the flat-object assertion style in `tests/authTranslations.test.js`. Enumerate
165
- `src/i18n/*.ts`, `require`/dynamic-`import()` each module, find its exported `*Translations` object
166
- (the module's only export), and:
167
- 1. assert every key of every bundle is present in `uiCoreTranslations` with an identical value
168
- (deep-equal, not just key presence — catches a bundle being spread partially);
169
- 2. assert the union of all bundle keys has no duplicates (build a `Map<key, sourceModule>`, fail with
170
- the two colliding module names if a key is seen twice);
171
- 3. assert every value in `uiCoreTranslations` has the `{ de, fr, en, sw }` shape (all four locale keys
172
- present, non-empty strings) — this must run against the aggregate, not against the individual
173
- bundles, or it doesn't actually check the merge preserved shape.
174
- Import `uiCoreTranslations` from `../src/index` (the public export), not from a private merge module —
175
- the ratchet only means something if it tests what a consumer actually imports.
176
-
177
- **Do not touch:** the six existing named exports, any bundle file's content/keys, `src/theme/**`
178
- (`THEME-*` work is active in parallel — check `git status`/`git log` before starting and do not touch
179
- theme files even incidentally).
180
-
181
- **README:** add one line to the i18n section (`grep -n "i18n" README.md` to find it) stating
182
- `uiCoreTranslations` is the supported aggregate import and the six per-feature exports remain for
183
- apps that want to stay selective.
184
-
185
- **Bundle-size measurement:** after implementing, report the built size delta for an auth-only app
186
- switching from `authTranslations` alone to `uiCoreTranslations` — e.g. `du -h` or a byte count on the
187
- relevant JSON/object literal, or diff `dist/index.js` chunk sizes before/after a `pnpm build` if that's
188
- cheaper than hand-measuring. A rough KB figure is enough; this number feeds `I18N-2`, not this WO's
189
- acceptance.
190
-
191
- ### Target repo working directory (absolute)
192
-
193
- `C:\Users\biglmi\Documents\webapps\ui-core-micha` — the repo root (no backend/frontend split here).
194
-
195
- ### Preamble
196
-
197
- > The text above is the COMPLETE spec — the committed WO file's content, not a plan to refine; there
198
- > is no separate plan file. Read the nearest `AGENTS.md`, the relevant `.codex/skills/<role>/SKILL.md`,
199
- > and the app `MEMORY.md` ONLY for conventions. Stay in scope; do not touch auth/permissions/deps/
200
- > schema/CI unless the spec says so; do not update `MEMORY.md`. **Do NOT edit `WORK_ORDERS.md` — the
201
- > register row and the review verdicts are the orchestrator's alone.** Do NOT `git add`/`commit`/
202
- > `push` — leave every change uncommitted in the working tree for the orchestrator's independent
203
- > review. WRITE the tests the `Required tests` section calls for AND **RUN the tests you just wrote**
204
- > to confirm they execute and pass — that is the ONLY test run you do (NOT the app's affected/full
205
- > suite, NOT any review). The orchestrator re-runs the authoritative set + does the independent review
206
- > after you finish — those are the gate; your own run does not count as the gate.
207
- >
208
- > Narrate continuously: a `PLAN: <step1> | <step2> | …` line up front, then a single-line
209
- > `PROGRESS: [<n>/<total>] <present-tense action>` before every relevant action (and `… done` on
210
- > completion), spaced so no gap exceeds ~2 min, stdout unbuffered, plus exactly one final
211
- > `RESULT: DONE|BLOCKED <reason>`.
212
-
213
- ### Mini-handover
214
-
215
- Repo: `ui-core-micha` (`C:\Users\biglmi\Documents\webapps\ui-core-micha`), branch `main`.
216
- WO: `work-orders/I18N-1.md`. Target `2.36.0`. Downstream: `fitness-monitor/FM-14` is blocked on the
217
- release and is the acceptance condition. Follow `orchestrate-codex`.
218
-
219
- ---
220
-
221
- ## C. Orchestrator only — NOT ADDRESSED TO THE IMPLEMENTER
222
-
223
- > **If you are the implementer reading this work order as your own specification: STOP at this line.
224
- > Everything below describes what the Orchestrator does AFTER you finish. You do none of it — no
225
- > reviewers, no verification run, no register edit, no commit.** You ARE the invocation described
226
- > below; do NOT shell out to `codex exec`.
227
-
228
- ### Execution directive
229
-
230
- Implement through `codex exec` in the background — invoked directly via Bash (never the
231
- `debugger`/`*_coder` Agent wrappers) with BOTH flags `--skip-git-repo-check` and
232
- `--dangerously-bypass-approvals-and-sandbox`. Fallback to direct Claude implementation only on Codex
233
- quota/rate-limit/non-zero exit — the fallback flips authorship, so an independent reviewer becomes
234
- mandatory.
235
-
236
- ### Review routing
237
-
238
- Independent `reviewer` **and** `ui_reviewer`, concurrent, same background batch. The `ui_reviewer`
239
- pass is a formality here — the diff renders nothing — but Tier 3 asks for it on a frontend-touching
240
- diff and a shared-core work order is the wrong place to argue an exemption.
241
-
242
- ### Verification
243
-
244
- No rendered check — this work order renders nothing. The verification that matters is `FM-14`'s:
245
- `ChartFrame`'s loading and empty states in fitness-monitor must show real text. That is this work
246
- order's real acceptance condition even though it is executed in another repo — record in the register
247
- Notiz that `FM-14` is the pending downstream confirmation, so the export shipping is never mistaken
248
- for the defect being fixed.
249
-
250
- ### Register + commit
251
-
252
- `WORK_ORDERS.md` row for `I18N-1`: `done` only once `reviewer` + `ui_reviewer` verdicts are named,
253
- the affected-set tests pass, and the bundle-size delta is recorded in the Notiz. Commit to `main`
254
- (this repo's trunk) on green.
@@ -1,207 +0,0 @@
1
- # I18N-3 — Backfill Swahili in `messagingTranslations` and restore the four-locale shape test
2
-
3
- **Target repo:** `ui-core-micha` (branch `main`)
4
- **Tier:** 3 — shared-core, and it re-tightens a test the estate deliberately loosened.
5
-
6
- ---
7
-
8
- ## A. Envelope
9
-
10
- ### Goal
11
-
12
- `src/i18n/messagingTranslations.ts` carries **116 keys with `de`/`fr`/`en` and zero `sw`**. Every one of the
13
- other six bundles carries all four locales:
14
-
15
- | bundle | de | fr | en | sw |
16
- |---|---|---|---|---|
17
- | `auth` | ✓ | ✓ | ✓ | ✓ |
18
- | `charts` | 12 | 12 | 12 | 12 |
19
- | **`messaging`** | **116** | **116** | **116** | **0** |
20
- | `notifications` | 30 | 30 | 30 | 30 |
21
- | `onboarding` | 27 | 27 | 27 | 27 |
22
- | `sectionNav` | 3 | 3 | 3 | 3 |
23
- | `userMenu` | 3 | 3 | 3 | 3 |
24
-
25
- `I18N-1` hit this while writing its aggregate test: the required "every value keeps its `{de,fr,en,sw}` shape"
26
- assertion failed, the gap was confirmed as pre-existing rather than caused by the merge, and the operator
27
- scoped the test down to `{de,fr,en}` with the backfill recorded as a follow-up. **The follow-up was never
28
- written, and a scoped-down test tends to stay scoped down.** That is what this WO closes.
29
-
30
- ### Scope
31
-
32
- 1. **`src/i18n/messagingTranslations.ts`** — add `sw` to all 116 keys.
33
- 2. **`tests/i18nAggregate.test.js`** — restore the shape assertion to `{de,fr,en,sw}` and **remove the comment
34
- recording the scope-down**, since it no longer describes the state.
35
- 3. Nothing else. No other bundle is touched; they already conform.
36
-
37
- ### The translation quality question, which is this WO's real risk
38
-
39
- **Machine-translated UI strings that nobody on the team can check are a worse outcome than an honest gap.**
40
- Messaging strings are user-facing and include the kinds of phrase that go wrong invisibly — actions,
41
- confirmations, error states, relative time. So:
42
-
43
- - **Name the source of the translations in the register note.** If they are machine-produced, say so plainly
44
- rather than shipping them as if reviewed.
45
- - **Flag any key the translator was unsure of** rather than guessing. A `sw` value that is wrong is harder to
46
- find later than one that is missing, because the shape test will then pass.
47
- - **Do not invent terminology.** Where `notifications` or `onboarding` already has a Swahili term for the same
48
- concept — send, reply, unread, conversation, attachment — **reuse their wording** rather than coining a
49
- second one. Those bundles are the existing precedent and consistency across them matters more than any
50
- individual phrasing.
51
-
52
- ### Who this is actually for
53
-
54
- `sw` is configured as a locale in **hram** and in no other app measured. hram does **not** register
55
- `messagingTranslations` today, so nothing is currently broken for a user — this is prevention, and the honest
56
- framing is: it closes an inconsistency and re-arms a test, rather than fixing a live defect.
57
-
58
- That matters for the effort trade-off, and it is why the quality bar above is not negotiable: there is no
59
- urgency justifying unreviewed strings.
60
-
61
- ### Non-goals / do not touch
62
-
63
- - **The other six bundles.** They conform.
64
- - **The aggregate itself, the directory ratchet, or the key/value fidelity and collision checks.** Only the
65
- locale-shape assertion changes.
66
- - **`de`/`fr`/`en` values.** Not a re-translation pass.
67
- - **Adding an eighth locale**, or any change to how consumers register strings (`I18N-2`'s territory).
68
-
69
- ### Risks
70
-
71
- - **116 unreviewable strings.** The mitigation is disclosure, not confidence — see above.
72
- - **Re-tightening the test is the irreversible half.** Once the assertion demands four locales, any future
73
- bundle addition must supply `sw` or fail CI. That is the intent, and it is worth stating so the next person
74
- adding a bundle is not surprised.
75
- - **A push to `main` publishes.** See Part C.
76
-
77
- ### Required tests to WRITE
78
-
79
- None new — **`tests/i18nAggregate.test.js`'s restored four-locale assertion IS the test**, and re-arming it is
80
- scope item 2. It will fail until the backfill is complete, which is the correct behaviour and the reason it
81
- belongs in the same change.
82
-
83
- Scoped run: `i18nAggregate` plus the messaging export specs. Not the full suite — no dependency or theme
84
- change.
85
-
86
- ### Parity guardrail
87
-
88
- No API, behaviour or visual change for `de`/`fr`/`en` consumers. Purely additive.
89
-
90
- ---
91
-
92
- ## B. Implementation map
93
-
94
- *Filled by the Orchestrator on `git pull` — see `AGENTS.md` → "Work Order".*
95
-
96
- **Files to change (exactly two):**
97
- - [`src/i18n/messagingTranslations.ts`](../src/i18n/messagingTranslations.ts) — 118 lines, 116 keys
98
- (`export const messagingTranslations = { 'Key': { de, en, fr }, ... }`), every value currently a
99
- 3-locale object. Add a fourth `sw: '...'` to every one, matching the existing key ordering
100
- `de, en, fr` → append `sw` last (matches the property order already used in
101
- `notificationsTranslations.ts`/`onboardingTranslations.ts`, both `de, fr, en, sw`, so put `sw`
102
- last regardless of the de/en/fr internal order already in this file — do not reorder de/en/fr).
103
- - [`tests/i18nAggregate.test.js`](../tests/i18nAggregate.test.js) — line 30:
104
- `const REQUIRED_LOCALES = ['de', 'en', 'fr'];` → `['de', 'en', 'fr', 'sw'];`, and delete the
105
- explanatory comment at lines 27-29 (`// Scoped to the three locales ... see the Notiz on the
106
- I18N-1 register row ...`) since it will no longer describe the state. Nothing else in this file
107
- changes — the other three `it()` blocks (aggregate completeness, no-collision, per-bundle
108
- availability) are untouched.
109
-
110
- **Existing Swahili glossary to reuse — do not coin alternate wording for these concepts** (grep
111
- `sw:` across `src/i18n/*.ts` yourself to see full context; this is not exhaustive, check for any
112
- other overlap you find):
113
- - Notification/notify → **Arifa** (`notificationsTranslations.ts`, `onboardingTranslations.ts`)
114
- - Save → **Hifadhi** (`onboardingTranslations.ts`: `Onboarding.SAVE`)
115
- - Close → **Funga** (`notificationsTranslations.ts`: `PopupSurface.CLOSE`)
116
- - Continue → **Endelea** (`onboardingTranslations.ts`: `Onboarding.CONTINUE`)
117
- - Skip → **Ruka** (`onboardingTranslations.ts`: `Onboarding.SKIP`)
118
- - Change/switch (section) → **Badilisha** (`sectionNavTranslations.ts`)
119
- - User menu / profile / logout → **Menyu ya mtumiaji / Wasifu / Toka** (`userMenuTranslations.ts`)
120
- - "Could not be saved/loaded" error pattern → e.g. **"...haikuweza kuhifadhiwa"** /
121
- **"...haikuweza kupakiwa"** (`notificationsTranslations.ts` `SAVE_ERROR`/`LOAD_ERROR`) — messaging
122
- has the same error-string shape repeated ~15 times (`... konnte nicht ... werden: {{message}}`),
123
- reuse this grammatical pattern rather than inventing a new one per key.
124
- - "Please try again" → **"Tafadhali jaribu tena"** (`onboardingTranslations.ts`)
125
-
126
- **None of messaging's specific domain terms (conversation, reply, attachment, reaction, poll,
127
- announcement, unread, archive, mute) exist in the other bundles' Swahili** — those need fresh
128
- translation. That is expected and fine; the instruction above is narrower: reuse wording only where
129
- the *same* concept (save/cancel/close/error phrasing/etc.) already has a Swahili rendering
130
- elsewhere, don't invent a second one for it.
131
-
132
- **Do-not-touch:** `de`/`en`/`fr` values in `messagingTranslations.ts` (verify byte-identical before
133
- and after — a diff review will check this); the other six bundles; `tests/i18nAggregate.test.js`'s
134
- other three tests, the aggregate export, the directory ratchet, the ordering (`de, en, fr` internal
135
- order in messaging stays as-is, `sw` only appended).
136
-
137
- **Progress contract:** `PLAN: …` naming the two files, `PROGRESS: [1/2] backfill sw into
138
- messagingTranslations.ts … done`, `PROGRESS: [2/2] restore REQUIRED_LOCALES + drop scope-down
139
- comment in i18nAggregate.test.js … done`, then run the scoped tests named below and report which
140
- keys (if any) you were unsure of, then `RESULT: DONE`.
141
-
142
- ## Preamble
143
-
144
- The text above is the COMPLETE spec — the committed WO file's content, not a plan to refine; there is
145
- no separate plan file. Read the nearest `AGENTS.md`, the relevant `.codex/skills/<role>/SKILL.md`, and
146
- the app `MEMORY.md` ONLY for conventions. Stay in scope; do not touch auth/permissions/deps/schema/CI
147
- unless the spec says so; do not update `MEMORY.md`. **Do NOT edit `WORK_ORDERS.md`** — the register row
148
- and the review verdicts are the orchestrator's alone. Do NOT `git add`/`commit`/`push` — leave every
149
- change uncommitted in the working tree for the orchestrator's independent review. This WO's "Required
150
- tests to WRITE" is explicitly **none new** — the restored `REQUIRED_LOCALES` assertion IS the test;
151
- run it (and the messaging export specs) to confirm your backfill makes it pass — that is the ONLY test
152
- run you do (NOT the app's affected/full suite, NOT any review). **State plainly in your final report:
153
- the source of the Swahili translations (e.g. "machine-translated via <tool>, not reviewed by a fluent
154
- speaker" — say so honestly, do not imply review that didn't happen) and list any specific key you were
155
- uncertain of**, per the Envelope's explicit disclosure requirement. The orchestrator re-runs the
156
- authoritative set + does the independent review after you finish — those are the gate; your own run
157
- does not count as the gate.
158
-
159
- Narrate continuously: a `PLAN: <step1> | <step2> | …` line up front, then a single-line
160
- `PROGRESS: [<n>/<total>] <present-tense action>` before every relevant action (and `… done` on
161
- completion), spaced so no gap exceeds ~2 min, stdout unbuffered, plus exactly one final
162
- `RESULT: DONE|BLOCKED <reason>`.
163
-
164
- ---
165
-
166
- ## C. Orchestrator only
167
-
168
- > **STOP — if you are the implementer reading this work order as your own specification, this section is NOT
169
- > addressed to you. Skip it entirely.** It tells the Orchestrator how to invoke you. **You ARE that
170
- > invocation — do NOT shell out to `codex exec`, do NOT spawn reviewers, do NOT edit `WORK_ORDERS.md`, and do
171
- > NOT `git add`/`commit`/`push`.**
172
-
173
- ### Execution directive
174
-
175
- Check `.claude/codex-status.md` first. **No line for the current date means use Codex.** A dated `unavailable`
176
- line for today means skip the attempt, implement directly in Claude and name the record — that flips
177
- authorship. Otherwise one probe, outcome written back either way.
178
-
179
- ### Review routing
180
-
181
- Tier 3: **independent `reviewer`** — mandatory. Ask it specifically to check **terminology consistency against
182
- `notifications` and `onboarding`**, and to confirm that no `de`/`fr`/`en` value was altered in passing. **No
183
- `ui_reviewer`** — nothing renders. No `sec_reviewer`.
184
-
185
- Neither reviewer can validate Swahili. **Say that in the note** rather than letting a clean verdict imply the
186
- translations were checked.
187
-
188
- ### Verification
189
-
190
- The restored four-locale assertion passing is the verification. Nothing renders, so no gate.
191
-
192
- **A push to `main` here IS the npm publish** — `publish.yml` triggers on `push: branches: [main]` with `src/**`
193
- in its paths, and publishes cannot be undone. Additive strings, so a **patch** by scope.
194
-
195
- ### Register + commit
196
-
197
- One row, `I18N-3`. `done` only with the reviewer and verdict named, **the translation source stated**, and any
198
- uncertain keys listed. Also update `I18N-1`'s note: its recorded follow-up is now closed, and leaving it open
199
- there is how the same gap gets rediscovered.
200
-
201
- ### Mini-handover
202
-
203
- Repo: `ui-core-micha`, branch `main`. WO: `work-orders/I18N-3.md`. 116 `sw` values into
204
- `messagingTranslations.ts`, then restore `i18nAggregate.test.js` to `{de,fr,en,sw}` and drop the scope-down
205
- comment. **Reuse `notifications`/`onboarding` terminology; disclose the translation source; flag uncertain
206
- keys instead of guessing.** No app is broken today — this closes an inconsistency and re-arms a test. Tier 3,
207
- `reviewer` mandatory. **Pushing to main publishes.** Follow `orchestrate-codex`.