Architectural cleanup: Trans, FormatDate, FormatNumber, RelativeTime no son visuales — son behavior alrededor del runtime (`uix.langs.t/ts`, `uix.format.*`). Estaban en `eidos/components/` solo porque ahi se inventariaban los wrappers. Naturaleza real: Soma. Beneficio principal: el invariante "Eidos no importa `getActiveUix()`" recupera su pureza — los 4 service components ya no contaban como violación del audit Codex (P1 #1 reducido en 4 archivos + dependencias). Movimientos (4 componentes, 31 archivos staged): - src/uix/eidos/components/{kebab}/ → src/uix/soma/components/{kebab}/ - {kebab}.svelte → components/{kebab}.svelte (subdir convencion Soma) - types.ts → types.ts - README.md → README.md - index.ts → exports.ts (Soma pattern: index re-exports from exports) - + nuevo index.ts: `export * from './exports';` - Eidos dirs eliminados (4 directories). Morfos: scope `['eidos']` → scope `['soma']` (4 archivos): - morfo/components/trans.ts - morfo/components/format-date.ts - morfo/components/format-number.ts - morfo/components/relative-time.ts Demos (4 +page.svelte) updated: - import paths `$uix/eidos/components/{kebab}` → `$soma/components/{kebab}` - meta-pill `scope: eidos` → `scope: soma` Headers de los .svelte updated: "Eidos `<X>`" → "Soma `<X>` — service component" + parrafo explicando por que vive en Soma (behavior, no visual primitive). Verificación: - `npm run check`: 0 errors (mantenido). - HTTP probes /uix/components/{trans,format-date,format-number,relative-time}: todos 200. Sin barrel re-exports a limpiar (no existían). Sin consumers fuera de los 4 demos. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>active-uix
parent
546aa8d0ee
commit
540abee026
@ -1,20 +0,0 @@
|
||||
// FormatDate — service component wrapping uix.format.dates.
|
||||
//
|
||||
// import { FormatDate } from '$uix/eidos/components/format-date';
|
||||
//
|
||||
// <FormatDate value={post.publishedAt} dateStyle="medium" />
|
||||
// <FormatDate value={meeting.startsAt} mode="dateTime" />
|
||||
// <FormatDate value={now} mode="time" timeZoneName="short" />
|
||||
//
|
||||
// Renders as <time datetime="..."> for semantic ISO 8601 access.
|
||||
import FormatDate from './format-date.svelte';
|
||||
|
||||
export { FormatDate };
|
||||
export default FormatDate;
|
||||
export type {
|
||||
FormatDateProps,
|
||||
FormatDateInput,
|
||||
FormatDateMode,
|
||||
FormatDateStyle,
|
||||
FormatTimeStyle
|
||||
} from './types';
|
||||
@ -1,19 +0,0 @@
|
||||
// RelativeTime — service component rendering Intl.RelativeTimeFormat
|
||||
// output ("hace 2 horas" / "in 3 days") with an auto-refresh tick.
|
||||
//
|
||||
// import { RelativeTime } from '$uix/eidos/components/relative-time';
|
||||
//
|
||||
// <RelativeTime value={post.publishedAt} />
|
||||
// <RelativeTime value={createdAt} style="short" />
|
||||
// <RelativeTime value={dueDate} unit="day" updateInterval={0} />
|
||||
import RelativeTime from './relative-time.svelte';
|
||||
|
||||
export { RelativeTime };
|
||||
export default RelativeTime;
|
||||
export type {
|
||||
RelativeTimeProps,
|
||||
RelativeTimeInput,
|
||||
RelativeTimeUnit,
|
||||
RelativeTimeNumeric,
|
||||
RelativeTimeStyle
|
||||
} from './types';
|
||||
@ -1,82 +0,0 @@
|
||||
# Eidos Trans
|
||||
|
||||
`<Trans>` es un **service component** — un wrapper greppable de
|
||||
`getActiveUix().langs.t / ts`. Resuelve un `idlangref` o un `path` a
|
||||
traves del catalogo activo de langs y renderiza el texto traducido.
|
||||
|
||||
Familia con `<FormatDate>`, `<FormatNumber>`, `<RelativeTime>`: todos
|
||||
son wrappers tipados del runtime para que un audit i18n encuentre cada
|
||||
sitio que toca el catalogo con `grep "<Trans"`.
|
||||
|
||||
## Superficie
|
||||
|
||||
```svelte
|
||||
<!-- 5 modos de resolucion -->
|
||||
<Trans>#?common.save|Save</Trans> <!-- children como idlangref -->
|
||||
<Trans value="#?common.save|Save" /> <!-- value prop -->
|
||||
<Trans path="common.save">Save</Trans> <!-- path + children=fallback -->
|
||||
<Trans path="common.greet" params={{name: 'Juan'}} />
|
||||
<Trans as="strong">#?ui.required|Required</Trans>
|
||||
<Trans path="common.save" locale="en-US">Save</Trans>
|
||||
```
|
||||
|
||||
## Props clave
|
||||
|
||||
| Prop | Tipo | Default | Notas |
|
||||
| --- | --- | --- | --- |
|
||||
| `value` | `LangString` | — | `idlangref` (`#?path\|fallback`) o literal. |
|
||||
| `path` | `string` | — | Dotted path al catalogo (ej. `'common.save'`). |
|
||||
| `params` | `Record<string, unknown>` | — | Interpolacion para `path`. |
|
||||
| `locale` | `SupportedLocale` | runtime | Override por instancia. |
|
||||
| `trim` | `boolean` | `true` | Trim del texto capturado de children. |
|
||||
| `as` | `keyof HTMLElementTagNameMap` | `'span'` | Tag HTML. |
|
||||
| `children` | snippet | — | Fallback / source si no hay `value` / `path`. |
|
||||
|
||||
## Modos de resolucion
|
||||
|
||||
| Modo | Forma | Source |
|
||||
| --- | --- | --- |
|
||||
| 1. Children-only | `<Trans>#?common.save\|Save</Trans>` | DOM `textContent` parseado como `idlangref`. |
|
||||
| 2. Value prop | `<Trans value="#?common.save\|Save" />` | `value` parseado. |
|
||||
| 3. Path + children fallback | `<Trans path="common.save">Save</Trans>` | `t(path)` con `children` como fallback si la key no existe. |
|
||||
| 4. Path + params | `<Trans path="common.greet" params={{name}} />` | `t(path, params)`. |
|
||||
| 5. Pass-through | `<Trans value="literal text" />` | Texto literal sin resolver. |
|
||||
|
||||
## Decisiones
|
||||
|
||||
- **Reactivo al locale**: el `$derived` re-corre cuando el locale activo
|
||||
cambia. La lectura va a traves de `uix.langs.t / ts` que estan
|
||||
acopladas al sistema reactivo de runes.
|
||||
- **Captura de children**: cuando ni `value` ni `path` estan
|
||||
presentes, el componente captura `textContent` del nodo via
|
||||
`bind:this={captureNode}` + `$effect`. La primera render emite el
|
||||
children original (`#?path|fallback` sin resolver); en `$effect`
|
||||
intercepta y resuelve.
|
||||
- **Cast del path**: `langs.t()` tipa su primer overload con
|
||||
`${string}.${string}` (template literal estricto). Como el runtime
|
||||
acepta paths dinamicos en runtime, se castea via
|
||||
`Parameters<typeof t>[0]`.
|
||||
- **Fallback a children**: cuando `t(path)` devuelve el path original
|
||||
(signal de "key no encontrada"), el componente cae al `capturedText`
|
||||
si existe.
|
||||
- **No CSS recipe**: marker `[data-trans]` solo para tooling.
|
||||
- **No emite eventos sema**.
|
||||
|
||||
## Comparativa
|
||||
|
||||
| Capacidad | Eidos | i18next `Trans` | formatjs `FormattedMessage` | svelte-i18n `_` |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Greppable site marker | Si: `<Trans` | Si | Si | No: `$_('key')` inline |
|
||||
| Children-as-idlangref | Si: `#?path\|fallback` | Si | No | No |
|
||||
| Path + params | Si | Si | Si | Si |
|
||||
| Locale override per-instance | Si | Limitado | Si | No |
|
||||
| Reactivo al cambio de locale | Si | Si | Si | Si |
|
||||
| Tag HTML configurable | Si: `as` | Si: `as` | Si: `tagName` | No |
|
||||
| Pluralizacion | Via params del catalogo | Si | Si | Si |
|
||||
|
||||
## Referencias
|
||||
|
||||
- i18next Trans: https://react.i18next.com/latest/trans-component
|
||||
- formatjs: https://formatjs.io/docs/react-intl/components#formattedmessage
|
||||
- Active langs: `src/arts/langs/`
|
||||
- Sistema idlangref: `src/uix/langs/`
|
||||
@ -1,17 +0,0 @@
|
||||
// Trans — i18n primitive that resolves an idlangref or path through
|
||||
// the active langs catalog and renders the translated string.
|
||||
//
|
||||
// import { Trans } from '$uix/eidos/components/trans';
|
||||
//
|
||||
// <Trans>#?common.save|Save</Trans>
|
||||
// <Trans value="#?common.save|Save" />
|
||||
// <Trans path="common.save">Save</Trans>
|
||||
// <Trans path="common.greet" params={{ name: 'Juan' }} />
|
||||
// <Trans as="strong">#?ui.required|Required</Trans>
|
||||
//
|
||||
// Reactive to locale changes; greppable as the canonical i18n marker.
|
||||
import Trans from './trans.svelte';
|
||||
|
||||
export { Trans };
|
||||
export default Trans;
|
||||
export type { TransProps } from './types';
|
||||
@ -0,0 +1,24 @@
|
||||
// FormatDate — service component wrapping uix.format.dates.
|
||||
//
|
||||
// import { FormatDate } from '$soma/components/format-date';
|
||||
//
|
||||
// <FormatDate value={post.publishedAt} dateStyle="medium" />
|
||||
// <FormatDate value={meeting.startsAt} mode="dateTime" />
|
||||
// <FormatDate value={now} mode="time" timeZoneName="short" />
|
||||
//
|
||||
// Renders as <time datetime="..."> for semantic ISO 8601 access.
|
||||
//
|
||||
// Lives under `soma/` (not `eidos/`) because the component owns runtime
|
||||
// access. Eidos invariant — "no `getActiveUix()` imports" — is enforced
|
||||
// across the visual layer; service components like `Trans` /
|
||||
// `FormatDate` / `FormatNumber` / `RelativeTime` are their Soma-side peers.
|
||||
export { default as FormatDate } from './components/format-date.svelte';
|
||||
export { default as Provider } from './components/format-date.svelte';
|
||||
|
||||
export type {
|
||||
FormatDateProps,
|
||||
FormatDateInput,
|
||||
FormatDateMode,
|
||||
FormatDateStyle,
|
||||
FormatTimeStyle
|
||||
} from './types';
|
||||
@ -0,0 +1 @@
|
||||
export * from './exports';
|
||||
@ -0,0 +1 @@
|
||||
export * from './exports';
|
||||
@ -0,0 +1,23 @@
|
||||
// RelativeTime — service component rendering Intl.RelativeTimeFormat
|
||||
// output ("hace 2 horas" / "in 3 days") with an auto-refresh tick.
|
||||
//
|
||||
// import { RelativeTime } from '$soma/components/relative-time';
|
||||
//
|
||||
// <RelativeTime value={post.publishedAt} />
|
||||
// <RelativeTime value={createdAt} style="short" />
|
||||
// <RelativeTime value={dueDate} unit="day" updateInterval={0} />
|
||||
//
|
||||
// Lives under `soma/` (not `eidos/`) because the component owns runtime
|
||||
// access. Eidos invariant — "no `getActiveUix()` imports" — is enforced
|
||||
// across the visual layer; service components like `Trans` /
|
||||
// `FormatDate` / `FormatNumber` / `RelativeTime` are their Soma-side peers.
|
||||
export { default as RelativeTime } from './components/relative-time.svelte';
|
||||
export { default as Provider } from './components/relative-time.svelte';
|
||||
|
||||
export type {
|
||||
RelativeTimeProps,
|
||||
RelativeTimeInput,
|
||||
RelativeTimeUnit,
|
||||
RelativeTimeNumeric,
|
||||
RelativeTimeStyle
|
||||
} from './types';
|
||||
@ -0,0 +1 @@
|
||||
export * from './exports';
|
||||
@ -0,0 +1,22 @@
|
||||
// Trans — i18n service component. Renders translated text through the
|
||||
// active langs catalog (`uix.langs.t / ts`).
|
||||
//
|
||||
// import { Trans } from '$soma/components/trans';
|
||||
//
|
||||
// <Trans>#?common.save|Save</Trans>
|
||||
// <Trans value="#?common.save|Save" />
|
||||
// <Trans path="common.save">Save</Trans>
|
||||
// <Trans path="common.greet" params={{ name: 'Juan' }} />
|
||||
// <Trans as="strong">#?ui.required|Required</Trans>
|
||||
//
|
||||
// Reactive to locale changes; greppable as the canonical i18n marker.
|
||||
//
|
||||
// Lives under `soma/` (not `eidos/`) because the component owns runtime
|
||||
// access. Eidos invariant — "no `getActiveUix()` imports" — is enforced
|
||||
// across the visual layer; service components like `Trans` /
|
||||
// `FormatDate` / `FormatNumber` / `RelativeTime` are their Soma-side
|
||||
// peers.
|
||||
export { default as Trans } from './components/trans.svelte';
|
||||
export { default as Provider } from './components/trans.svelte';
|
||||
|
||||
export type { TransProps } from './types';
|
||||
@ -0,0 +1 @@
|
||||
export * from './exports';
|
||||
Loading…
Reference in new issue