// renderCategoryLabel — single source of truth for how a balance category's // label is shown in the UI (Bilan axe véhicule, Étape 1 / Issue #203). // // Precedence: an explicit `custom_label` (trimmed, non-empty) always wins; // otherwise fall back to the i18n translation of `i18n_key`, and finally to // the raw `key` if no translation exists. This is what makes category // renaming (which now writes `custom_label`, never `i18n_key`) coexist with // the seeded translations and fixes bug I. // // The 5 call sites carry the same three scalars under DIFFERENT field names: // - BalanceCategory → custom_label / i18n_key / key // - BalanceAccountWithCategory → category_custom_label / category_i18n_key / category_key // - AccountLatestSnapshot → category_custom_label / category_i18n_key / category_key // To avoid a shape mismatch (the "affichage partiel" caveat), the core helper // takes explicit scalar args; thin adapters normalize each object shape. /** Minimal i18n translate signature (matches react-i18next's `t`). */ type TranslateFn = ( key: string, options?: { defaultValue?: string } ) => string; /** * Resolve a category's display label from its three label scalars. * * @param customLabel User-facing override (`custom_label`). NULL/blank ignored. * @param i18nKey Translation key (`i18n_key`), e.g. 'balance.category.cash'. * @param key Stable lookup key (`key`), used as the last-resort label. * @param t Translate function. */ export function renderCategoryLabel( customLabel: string | null | undefined, i18nKey: string, key: string, t: TranslateFn ): string { const trimmed = customLabel?.trim(); if (trimmed) return trimmed; return t(i18nKey, { defaultValue: key }); } /** Adapter for a `BalanceCategory`-shaped object. */ export function renderCategoryLabelFromCategory( cat: { custom_label?: string | null; i18n_key: string; key: string; }, t: TranslateFn ): string { return renderCategoryLabel(cat.custom_label, cat.i18n_key, cat.key, t); } /** * Adapter for the JOIN-prefixed shape carried by `BalanceAccountWithCategory` * and `AccountLatestSnapshot` (`category_custom_label` / `category_i18n_key` / * `category_key`). */ export function renderCategoryLabelFromAccount( acc: { category_custom_label?: string | null; category_i18n_key: string; category_key: string; }, t: TranslateFn ): string { return renderCategoryLabel( acc.category_custom_label, acc.category_i18n_key, acc.category_key, t ); }