feat: add ActionTools component documentation and update navigation links

This commit is contained in:
Firman Ramdhani
2026-07-01 17:27:53 +07:00
parent 8f14c4bc7b
commit 95692b2bcf
4 changed files with 245 additions and 18 deletions
+55 -18
View File
@@ -114,10 +114,42 @@ apps/web/src/apps/modules/booking/
└── en/booking.json
```
### Lazy Loading & Type Safety
Register the namespace when the component mounts. To get native TypeScript autocomplete for nested keys (e.g., `header.title`), augment the global `react-i18next` types.
### Namespace Registration & Context
To prevent unnecessary React re-renders and ensure dictionaries are loaded before the first paint, translations are registered at the module scope using `registerModuleNamespace`.
**1. Register the Namespace in the Module Factory:**
Call `registerModuleNamespace` at the top level of your module factory (e.g., `index.tsx`). This function is idempotent and safe to call outside the React render cycle. The namespace provided must match the `translationNamespace` defined in your module configuration.
```tsx
// apps/web/src/apps/modules/booking/presentation/factory/index.tsx
import { EnterpriseModuleProvider } from '@repo/ui/foundations';
import { registerModuleNamespace } from '@repo/core-i18n';
import { BookingModuleConfig } from '../../domain/constants';
import bookingId from '../locales/id/booking.json';
import bookingEn from '../locales/en/booking.json';
// Called once at import time — safe, idempotent, outside React render cycle.
registerModuleNamespace(BookingModuleConfig.translationNamespace, {
id: bookingId,
en: bookingEn,
});
export default function BookingModule() {
return (
<EnterpriseModuleProvider config={BookingModuleConfig}>
{/* Routes and Pages */}
</EnterpriseModuleProvider>
);
}
```
**2. Augment Types for Autocomplete:**
To get native TypeScript autocomplete for nested keys (e.g., `header.title`), augment the global `react-i18next` types.
**1. Augment Types:**
```ts
// apps/web/src/types/i18next.d.ts
import 'react-i18next';
@@ -132,26 +164,31 @@ declare module 'react-i18next' {
}
```
**2. Use in Component:**
**3. Consume in Components:**
Inside your pages and components, use `useEnterpriseModuleTranslationContext()` instead of the raw `useTranslation` hook. The context automatically scopes the `t` function to your module's namespace and the global `common` namespace.
> [!WARNING]
> **Best Practice:** Do not hardcode the module namespace prefix (e.g., `t('booking:header.title')`) when using `useEnterpriseModuleTranslationContext`. The provider already scopes it. Simply use `t('header.title')`. You can still access global keys using the common prefix: `t('common:edit')`.
```tsx
import { useEffect } from 'react';
import { i18n, useTranslation } from '@repo/core-i18n';
import bookingId from '../locales/id/booking.json';
import bookingEn from '../locales/en/booking.json';
// apps/web/src/apps/modules/booking/presentation/pages/booking.page.index.tsx
import { Title } from '@repo/ui/components';
import { useEnterpriseModuleTranslationContext } from '@repo/ui/foundations';
export default function BookingFeature() {
const { t } = useTranslation(['common', 'booking']);
export default function BookingPageIndex() {
const { t } = useEnterpriseModuleTranslationContext();
useEffect(() => {
i18n.addResourceBundle('id', 'booking', bookingId, true, false);
i18n.addResourceBundle('en', 'booking', bookingEn, true, false);
}, []);
return <h1>{t('booking:header.title')}</h1>; // Autocomplete works!
return (
<div>
<Title>{t('title')}</Title> {/* Automatically resolves to booking:title */}
<button>{t('common:edit')}</button> {/* Fallback to global common vocabulary */}
</div>
);
}
```
**3. Dynamic Variables (Interpolation):**
**4. Dynamic Variables (Interpolation):**
```json
// booking.json
{
@@ -162,7 +199,7 @@ export default function BookingFeature() {
```
```tsx
// Inside component
<h1>{t('booking:messages.welcome', { name: 'Firman', count: 5 })}</h1>
<h1>{t('messages.welcome', { name: 'Firman', count: 5 })}</h1>
```
---