@idioma/react 0.1.2 → 0.1.6
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.
- package/dist/createUseT.d.ts +3 -0
- package/dist/createUseT.d.ts.map +1 -1
- package/dist/createUseT.js +1 -1
- package/dist/createUseT.js.map +1 -1
- package/dist/runtime-suspense/index.d.ts +1 -1
- package/dist/runtime-suspense/index.d.ts.map +1 -1
- package/dist/runtime-suspense/index.js +1 -1
- package/dist/runtime-suspense/index.js.map +1 -1
- package/package.json +2 -2
package/dist/createUseT.d.ts
CHANGED
|
@@ -62,16 +62,19 @@ type TFunction<C extends BaseIdiomaConfig = BaseIdiomaConfig> = {
|
|
|
62
62
|
<K$1 extends StringOnlyKeys<C['TranslationKey'], C['MessageComponents']> & string>(args: K$1 extends KeysWithValues<C['MessageValues']> ? {
|
|
63
63
|
id: K$1;
|
|
64
64
|
values: C['MessageValues'][K$1];
|
|
65
|
+
source?: string;
|
|
65
66
|
context?: string;
|
|
66
67
|
ns?: string;
|
|
67
68
|
} : K$1 extends KeysWithoutValues<C['MessageValues']> ? {
|
|
68
69
|
id: K$1;
|
|
69
70
|
values?: never;
|
|
71
|
+
source?: string;
|
|
70
72
|
context?: string;
|
|
71
73
|
ns?: string;
|
|
72
74
|
} : {
|
|
73
75
|
id: K$1;
|
|
74
76
|
values?: Record<string, unknown>;
|
|
77
|
+
source?: string;
|
|
75
78
|
context?: string;
|
|
76
79
|
ns?: string;
|
|
77
80
|
}): string;
|
package/dist/createUseT.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createUseT.d.ts","names":[],"sources":["../src/createUseT.ts"],"sourcesContent":[],"mappings":";;AAsBA;;;;;AAaA;;;;;;AAEmC,UAflB,gBAAA,CAekB;EAAgC,cAAA,EAAA,MAAA;EACzD,aAAA,EAdO,MAcP,CAAA,MAAA,EAdsB,MActB,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA;EAAE,iBAAA,EAbS,MAaT,CAAA,MAAA,EAAA,OAAA,EAAA,CAAA;AAGZ;;AACa,KAPD,cAOC,CAAA,WAPyB,MAOzB,CAAA,MAAA,EAPwC,MAOxC,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,CAAA,GAAA,QAEC,MAPE,EAOF,GAPO,EAOP,CAPU,CAOV,CAAA,SAPqB,MAOrB,CAAA,MAAA,EAAA,KAAA,CAAA,GAAA,KAAA,GAPqD,CAOrD,EAAK,CAAA,MANT,EAMS,CAAA;;AAAc,KAHrB,iBAGqB,CAAA,WAFpB,MAEoB,CAAA,MAAA,EAFL,MAEK,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,CAAA,GAAA,QAAwB,MAA3C,EAA2C,GAAtC,EAAsC,CAAnC,CAAmC,CAAA,SAAxB,MAAwB,CAAA,MAAA,EAAA,KAAA,CAAA,GAAA,CAAA,GAAA,KAAA,EACjD,CAAA,MAAA,EAAA,CAAA;;AAOR;;;;AAIwB,KAJZ,cAIY,CAAA,WAAA,MAAA,EAAA,WAFX,MAEW,CAAA,MAAA,EAAA,OAAA,EAAA,CAAA,CAAA,GAAA,QAAhB,EAAmB,GAAA,MAAR,EAAQ,GAAH,EAAG,CAAA,CAAA,CAAA,SAAA,EAAA,GAAgB,CAAhB,GAAA,KAAA,EAAgB,CACzC,EADyC,GAAA,MAC9B,EAD8B,CAAA;;;;AAS3C;AACE,KADU,mBACV,CAAA,UAAA,MAAA,CAAA,GAAA,CAAA,SAAA,GAAA,KAAA,EAAA,IAAA,KAAA,IAAA,IAAA,KAAA,KAAA,EAAA,GACI,GADJ,GACU,mBADV,CAC8B,IAD9B,CAAA,GAAA,KAAA;;;;;AASF;AACsB,KADV,iBACU,CAAA,UAAA,MAAA,CAAA,GAApB,mBAAoB,CAAA,CAAA,CAAA,SAAA,KAAA,GAAA,SAAA,GAAA,QAER,mBAFZ,CAEgC,CAFhC,CAAA,GAAA,MAAA,GAAA,MAAA,EAEgC;;AAAD,KAGrB,eAHqB,CAAA,UAAA,MAAA,CAAA,GAI/B,mBAJ+B,CAIX,CAJW,CAAA,SAAA,KAAA,GAAA,KAAA,GAAA,IAAA;AAGjC;AAMA;AAiBA;AAAgC,UAjBf,iBAAA,CAiBe;EAAmB;EAKtB,OAAA,CAAA,EAAA,MAAA;EAAqB;EAApC,OAAA,CAAA,EAAA,MAAA;EAGJ;EAAyB,EAAA,CAAA,EAAA,MAAA;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"createUseT.d.ts","names":[],"sources":["../src/createUseT.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/createUseT.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{IdiomaContext as e}from"./context.js";import{interpolateValues as t}from"./interpolate.js";import{useCallback as n,useContext as r}from"react";function i(){return function(){let i=r(e);if(!i)throw Error(`[idioma] useT must be used within an IdiomaProvider. Make sure to wrap your app with <IdiomaProvider>.`);let{locale:a}=i;return n((e,n,r)=>{if(typeof e==`object`){let{id:
|
|
1
|
+
import{IdiomaContext as e}from"./context.js";import{interpolateValues as t}from"./interpolate.js";import{useCallback as n,useContext as r}from"react";function i(){return function(){let i=r(e);if(!i)throw Error(`[idioma] useT must be used within an IdiomaProvider. Make sure to wrap your app with <IdiomaProvider>.`);let{locale:a}=i;return n((e,n,r)=>{if(typeof e==`object`){let{id:n,source:r,values:i}=e;console.warn(`[idioma] t({ id: "${n}" }) was not transformed by Babel. Make sure @idioma/core Babel plugin is configured.`);let a=r||n;return i&&Object.keys(i).length>0?t(a,i):a}let i=e,o=n,s,c=n?Object.keys(n):[],l=c[0],u=l&&n?n[l]:void 0;if(c.length===1&&u&&typeof u==`object`&&u[a]!==void 0&&(s=u,o=r),!s)return o&&Object.keys(o).length>0?t(i,o):i;let d=s[a]??Object.values(s)[0];return d===void 0?o&&Object.keys(o).length>0?t(i,o):i:typeof d==`function`?d(o||{}):o&&Object.keys(o).length>0?t(d,o):d},[a])}}export{i as createUseT};
|
|
2
2
|
//# sourceMappingURL=createUseT.js.map
|
package/dist/createUseT.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createUseT.js","names":["useCallback","useContext","IdiomaContext","interpolateValues","createUseT","useT","ctx","Error","locale","sourceOrArgs","values","options","id","console","warn","source","actualValues","localeMessages","valuesKeys","Object","keys","firstKey","firstValue","undefined","length","msg"],"sources":["../src/createUseT.ts"],"sourcesContent":["import { useCallback, useContext } from 'react';\nimport { IdiomaContext } from './context';\nimport { interpolateValues } from './interpolate';\n\ntype MessageFunction = (args: Record<string, unknown>) => string;\n\n// =============================================================================\n// IdiomaTypes - Single type parameter for cleaner API\n// =============================================================================\n\n/**\n * Base interface for project-specific Idioma types.\n * Generated by the compiler in types.d.ts.\n *\n * @example\n * // In generated types.d.ts:\n * export interface IdiomaTypes {\n * TranslationKey: 'greeting' | 'farewell';\n * MessageValues: { greeting: { name: string } };\n * MessageComponents: { greeting: [] };\n * }\n */\nexport interface BaseIdiomaConfig {\n TranslationKey: string;\n MessageValues: Record<string, Record<string, unknown>>;\n MessageComponents: Record<string, unknown[]>;\n}\n\n// =============================================================================\n// Helper Types for Strict Typing\n// =============================================================================\n\n// --- Key-only mode helpers ---\n\n/** Keys in MessageValues that have at least one required value */\nexport type KeysWithValues<MV extends Record<string, Record<string, unknown>>> =\n {\n [K in keyof MV]: MV[K] extends Record<string, never> ? never : K;\n }[keyof MV];\n\n/** Keys in MessageValues that have no required values */\nexport type KeysWithoutValues<\n MV extends Record<string, Record<string, unknown>>,\n> = {\n [K in keyof MV]: MV[K] extends Record<string, never> ? K : never;\n}[keyof MV];\n\n/**\n * Derive string-only keys from TranslationKey + MessageComponents.\n * Keys with empty component arrays [] can be used with useT.\n * Keys with non-empty component arrays [TransComponent, ...] must use Trans.\n */\nexport type StringOnlyKeys<\n TK extends string,\n MC extends Record<string, unknown[]>,\n> = {\n [K in TK & keyof MC]: MC[K] extends [] ? K : never;\n}[TK & keyof MC];\n\n// --- Source text mode helpers ---\n\n/**\n * Recursively extract placeholder names from a template string.\n * \"Hello {name}, you have {count} items\" → \"name\" | \"count\"\n */\nexport type ExtractPlaceholders<S extends string> =\n S extends `${infer _}{${infer Key}}${infer Rest}`\n ? Key | ExtractPlaceholders<Rest>\n : never;\n\n/**\n * Build the required values object from extracted placeholders.\n * \"Hello {name}\" → { name: string | number }\n * \"No placeholders\" → undefined\n */\nexport type PlaceholderValues<S extends string> =\n ExtractPlaceholders<S> extends never\n ? undefined\n : { [K in ExtractPlaceholders<S>]: string | number };\n\n/** Check if a string has any placeholders */\nexport type HasPlaceholders<S extends string> =\n ExtractPlaceholders<S> extends never ? false : true;\n\n/**\n * Source text mode options: t(\"Submit\", undefined, { context: \"button\", ns: \"common\" })\n */\nexport interface SourceTextOptions {\n /** Translator context (changes key hash) */\n context?: string;\n /** Translator comment (extracted to PO #. comment for translators) */\n comment?: string;\n /** Namespace for scoped lookups (placeholder for future) */\n ns?: string;\n}\n\n/**\n * Type for the t function returned by useT.\n * Supports both source text mode and key-only mode with full type safety.\n *\n * @template C - IdiomaTypes interface containing TranslationKey, MessageValues, MessageComponents\n *\n * The TFunction only accepts keys where MessageComponents[K] is an empty array (string-only keys).\n */\nexport type TFunction<C extends BaseIdiomaConfig = BaseIdiomaConfig> = {\n // === Key-only mode ===\n\n // Keys that require values (only string-only keys allowed)\n <\n K extends StringOnlyKeys<C['TranslationKey'], C['MessageComponents']> &\n string,\n >(\n args: K extends KeysWithValues<C['MessageValues']>\n ? { id: K; values: C['MessageValues'][K]; context?: string; ns?: string }\n : K extends KeysWithoutValues<C['MessageValues']>\n ? { id: K; values?: never; context?: string; ns?: string }\n : {\n id: K;\n values?: Record<string, unknown>;\n context?: string;\n ns?: string;\n },\n ): string;\n\n // === Source text mode ===\n\n // Source text WITH placeholders - values required\n <S extends string>(\n source: HasPlaceholders<S> extends true ? S : never,\n values: PlaceholderValues<S>,\n ): string;\n\n // Source text WITHOUT placeholders - no values\n <S extends string>(\n source: HasPlaceholders<S> extends false ? S : never,\n ): string;\n\n // Source text with options (3rd arg)\n <S extends string>(\n source: S,\n values: PlaceholderValues<S>,\n options: SourceTextOptions,\n ): string;\n};\n\n/**\n * Creates a typed useT hook for imperative translations.\n *\n * Supports both source text mode and key-only mode:\n * - Source text: t('Hello world!') - hashes and looks up\n * - Key-only: t({ id: 'welcome' }) - direct key lookup\n *\n * Only works with messages that don't require component interpolation,\n * since it returns a string. For messages with <0>...</0> tags, use <Trans>.\n *\n * @example\n * // In generated idioma/index.ts:\n * export const useT = createUseT<IdiomaTypes>()\n *\n * // Usage:\n * const t = useT()\n * t('Hello world!') // source text mode\n * t('Hello {name}', { name: 'Ben' }) // with values (2nd arg)\n * t('Submit', undefined, { context: 'button' }) // with options (3rd arg)\n * t('Hello {name}', { name: 'Ben' }, { context: 'greeting' }) // both\n * t({ id: 'welcome' }) // key-only mode\n * t({ id: 'greeting', values: { name: 'Ben' }, ns: 'common' }) // with ns\n */\n// Internal runtime type for key-only args (untyped at runtime)\ninterface KeyOnlyArgsRuntime {\n id: string;\n values?: Record<string, unknown>;\n context?: string;\n ns?: string;\n}\n\nexport function createUseT<\n C extends BaseIdiomaConfig = BaseIdiomaConfig,\n>(): () => TFunction<C> {\n /**\n * useT hook for imperative translations.\n *\n * Babel transforms t() calls to include inlined translations.\n * This hook handles the transformed calls and provides fallback behavior.\n */\n return function useT(): TFunction<C> {\n const ctx = useContext(IdiomaContext);\n if (!ctx) {\n throw new Error(\n '[idioma] useT must be used within an IdiomaProvider. ' +\n 'Make sure to wrap your app with <IdiomaProvider>.',\n );\n }\n\n const { locale } = ctx;\n\n return useCallback(\n (\n sourceOrArgs: string | KeyOnlyArgsRuntime,\n values?: Record<string, unknown>,\n options?: SourceTextOptions,\n ): string => {\n // Key-only mode: t({ id: 'welcome', values: { name }, ns: 'common' })\n // Babel should transform this, but if not, return the id as fallback\n if (typeof sourceOrArgs === 'object') {\n const { id } = sourceOrArgs;\n console.warn(\n `[idioma] t({ id: \"${id}\" }) was not transformed by Babel. ` +\n 'Make sure @idioma/core Babel plugin is configured.',\n );\n return id;\n }\n\n // Source text mode: t('Hello {name}', { name: 'Ben' }, { context: 'button' })\n // OR after Babel transformation: t('Hello {name}', { key: { en: '...', es: '...' } }, { name: 'Ben' })\n const source = sourceOrArgs;\n\n // Detect if Babel has inlined translations in arg 2\n // Babel transforms: t('src', { key: { en: '...', es: '...' } }, { actualValues })\n // The inlined object has ONE key (the message key) whose value has locale keys\n let actualValues = values;\n let localeMessages:\n | Record<string, string | MessageFunction>\n | undefined;\n\n const valuesKeys = values ? Object.keys(values) : [];\n const firstKey = valuesKeys[0];\n const firstValue =\n firstKey && values\n ? (values as Record<string, unknown>)[firstKey]\n : undefined;\n\n // Check if this looks like Babel-inlined translations:\n // - Has exactly one key (the message key)\n // - That key's value is an object with locale as a property\n if (\n valuesKeys.length === 1 &&\n firstValue &&\n typeof firstValue === 'object' &&\n typeof (firstValue as Record<string, unknown>)[locale] !== 'undefined'\n ) {\n // Babel transformed: arg 2 is { messageKey: { en: '...', es: '...' } }\n localeMessages = firstValue as Record<\n string,\n string | MessageFunction\n >;\n actualValues = options as unknown as Record<string, unknown>;\n }\n\n if (!localeMessages) {\n // Not transformed by Babel - fallback to source text\n return actualValues && Object.keys(actualValues).length > 0\n ? interpolateValues(source, actualValues)\n : source;\n }\n\n const msg = localeMessages[locale] ?? Object.values(localeMessages)[0];\n if (msg === undefined) {\n return actualValues && Object.keys(actualValues).length > 0\n ? interpolateValues(source, actualValues)\n : source;\n }\n\n if (typeof msg === 'function') {\n return msg(actualValues || {});\n }\n\n return actualValues && Object.keys(actualValues).length > 0\n ? interpolateValues(msg, actualValues)\n : msg;\n },\n [locale],\n ) as TFunction<C>;\n };\n}\n"],"mappings":"sJAgLA,SAAgBI,GAEQ,CAOtB,OAAO,UAA8B,CACnC,IAAME,EAAML,EAAWC,EAAc,CACrC,GAAI,CAACI,EACH,MAAUC,MACR,yGAED,CAGH,GAAM,CAAEC,UAAWF,EAEnB,OAAON,GAEHS,EACAC,EACAC,IACW,CAGX,GAAI,OAAOF,GAAiB,SAAU,CACpC,GAAM,CAAEG,MAAOH,EAKf,OAJAI,QAAQC,KACN,qBAAqBF,EAAE,uFAExB,CACMA,EAKT,IAAMG,EAASN,EAKXO,EAAeN,EACfO,EAIEC,EAAaR,EAASS,OAAOC,KAAKV,EAAO,CAAG,EAAE,CAC9CW,EAAWH,EAAW,GACtBI,EACJD,GAAYX,EACPA,EAAmCW,GACpCE,IAAAA,GAmBN,GAbEL,EAAWM,SAAW,GACtBF,GACA,OAAOA,GAAe,UACdA,EAAuCd,KAAY,SAG3DS,EAAiBK,EAIjBN,EAAeL,GAGb,CAACM,EAEH,OAAOD,GAAgBG,OAAOC,KAAKJ,EAAa,CAACQ,OAAS,EACtDrB,EAAkBY,EAAQC,EAAa,CACvCD,EAGN,IAAMU,EAAMR,EAAeT,IAAWW,OAAOT,OAAOO,EAAe,CAAC,GAWpE,OAVIQ,IAAQF,IAAAA,GACHP,GAAgBG,OAAOC,KAAKJ,EAAa,CAACQ,OAAS,EACtDrB,EAAkBY,EAAQC,EAAa,CACvCD,EAGF,OAAOU,GAAQ,WACVA,EAAIT,GAAgB,EAAE,CAAC,CAGzBA,GAAgBG,OAAOC,KAAKJ,EAAa,CAACQ,OAAS,EACtDrB,EAAkBsB,EAAKT,EAAa,CACpCS,GAEN,CAACjB,EACH,CAAC"}
|
|
1
|
+
{"version":3,"file":"createUseT.js","names":["useCallback","useContext","IdiomaContext","interpolateValues","createUseT","useT","ctx","Error","locale","sourceOrArgs","values","options","id","source","objValues","console","warn","fallbackText","Object","keys","length","actualValues","localeMessages","valuesKeys","firstKey","firstValue","undefined","msg"],"sources":["../src/createUseT.ts"],"sourcesContent":["import { useCallback, useContext } from 'react';\nimport { IdiomaContext } from './context';\nimport { interpolateValues } from './interpolate';\n\ntype MessageFunction = (args: Record<string, unknown>) => string;\n\n// =============================================================================\n// IdiomaTypes - Single type parameter for cleaner API\n// =============================================================================\n\n/**\n * Base interface for project-specific Idioma types.\n * Generated by the compiler in types.d.ts.\n *\n * @example\n * // In generated types.d.ts:\n * export interface IdiomaTypes {\n * TranslationKey: 'greeting' | 'farewell';\n * MessageValues: { greeting: { name: string } };\n * MessageComponents: { greeting: [] };\n * }\n */\nexport interface BaseIdiomaConfig {\n TranslationKey: string;\n MessageValues: Record<string, Record<string, unknown>>;\n MessageComponents: Record<string, unknown[]>;\n}\n\n// =============================================================================\n// Helper Types for Strict Typing\n// =============================================================================\n\n// --- Key-only mode helpers ---\n\n/** Keys in MessageValues that have at least one required value */\nexport type KeysWithValues<MV extends Record<string, Record<string, unknown>>> =\n {\n [K in keyof MV]: MV[K] extends Record<string, never> ? never : K;\n }[keyof MV];\n\n/** Keys in MessageValues that have no required values */\nexport type KeysWithoutValues<\n MV extends Record<string, Record<string, unknown>>,\n> = {\n [K in keyof MV]: MV[K] extends Record<string, never> ? K : never;\n}[keyof MV];\n\n/**\n * Derive string-only keys from TranslationKey + MessageComponents.\n * Keys with empty component arrays [] can be used with useT.\n * Keys with non-empty component arrays [TransComponent, ...] must use Trans.\n */\nexport type StringOnlyKeys<\n TK extends string,\n MC extends Record<string, unknown[]>,\n> = {\n [K in TK & keyof MC]: MC[K] extends [] ? K : never;\n}[TK & keyof MC];\n\n// --- Source text mode helpers ---\n\n/**\n * Recursively extract placeholder names from a template string.\n * \"Hello {name}, you have {count} items\" → \"name\" | \"count\"\n */\nexport type ExtractPlaceholders<S extends string> =\n S extends `${infer _}{${infer Key}}${infer Rest}`\n ? Key | ExtractPlaceholders<Rest>\n : never;\n\n/**\n * Build the required values object from extracted placeholders.\n * \"Hello {name}\" → { name: string | number }\n * \"No placeholders\" → undefined\n */\nexport type PlaceholderValues<S extends string> =\n ExtractPlaceholders<S> extends never\n ? undefined\n : { [K in ExtractPlaceholders<S>]: string | number };\n\n/** Check if a string has any placeholders */\nexport type HasPlaceholders<S extends string> =\n ExtractPlaceholders<S> extends never ? false : true;\n\n/**\n * Source text mode options: t(\"Submit\", undefined, { context: \"button\", ns: \"common\" })\n */\nexport interface SourceTextOptions {\n /** Translator context (changes key hash) */\n context?: string;\n /** Translator comment (extracted to PO #. comment for translators) */\n comment?: string;\n /** Namespace for scoped lookups (placeholder for future) */\n ns?: string;\n}\n\n/**\n * Type for the t function returned by useT.\n * Supports both source text mode and key-only mode with full type safety.\n *\n * @template C - IdiomaTypes interface containing TranslationKey, MessageValues, MessageComponents\n *\n * The TFunction only accepts keys where MessageComponents[K] is an empty array (string-only keys).\n */\nexport type TFunction<C extends BaseIdiomaConfig = BaseIdiomaConfig> = {\n // === Key-only mode ===\n\n // Keys that require values (only string-only keys allowed)\n <\n K extends StringOnlyKeys<C['TranslationKey'], C['MessageComponents']> &\n string,\n >(\n args: K extends KeysWithValues<C['MessageValues']>\n ? {\n id: K;\n values: C['MessageValues'][K];\n source?: string;\n context?: string;\n ns?: string;\n }\n : K extends KeysWithoutValues<C['MessageValues']>\n ? {\n id: K;\n values?: never;\n source?: string;\n context?: string;\n ns?: string;\n }\n : {\n id: K;\n values?: Record<string, unknown>;\n source?: string;\n context?: string;\n ns?: string;\n },\n ): string;\n\n // === Source text mode ===\n\n // Source text WITH placeholders - values required\n <S extends string>(\n source: HasPlaceholders<S> extends true ? S : never,\n values: PlaceholderValues<S>,\n ): string;\n\n // Source text WITHOUT placeholders - no values\n <S extends string>(\n source: HasPlaceholders<S> extends false ? S : never,\n ): string;\n\n // Source text with options (3rd arg)\n <S extends string>(\n source: S,\n values: PlaceholderValues<S>,\n options: SourceTextOptions,\n ): string;\n};\n\n/**\n * Creates a typed useT hook for imperative translations.\n *\n * Supports both source text mode and key-only mode:\n * - Source text: t('Hello world!') - hashes and looks up\n * - Key-only: t({ id: 'welcome' }) - direct key lookup\n *\n * Only works with messages that don't require component interpolation,\n * since it returns a string. For messages with <0>...</0> tags, use <Trans>.\n *\n * @example\n * // In generated idioma/index.ts:\n * export const useT = createUseT<IdiomaTypes>()\n *\n * // Usage:\n * const t = useT()\n * t('Hello world!') // source text mode\n * t('Hello {name}', { name: 'Ben' }) // with values (2nd arg)\n * t('Submit', undefined, { context: 'button' }) // with options (3rd arg)\n * t('Hello {name}', { name: 'Ben' }, { context: 'greeting' }) // both\n * t({ id: 'welcome' }) // key-only mode\n * t({ id: 'greeting', values: { name: 'Ben' }, ns: 'common' }) // with ns\n */\n// Internal runtime type for key-only args (untyped at runtime)\ninterface KeyOnlyArgsRuntime {\n id: string;\n source?: string;\n values?: Record<string, unknown>;\n context?: string;\n ns?: string;\n}\n\nexport function createUseT<\n C extends BaseIdiomaConfig = BaseIdiomaConfig,\n>(): () => TFunction<C> {\n /**\n * useT hook for imperative translations.\n *\n * Babel transforms t() calls to include inlined translations.\n * This hook handles the transformed calls and provides fallback behavior.\n */\n return function useT(): TFunction<C> {\n const ctx = useContext(IdiomaContext);\n if (!ctx) {\n throw new Error(\n '[idioma] useT must be used within an IdiomaProvider. ' +\n 'Make sure to wrap your app with <IdiomaProvider>.',\n );\n }\n\n const { locale } = ctx;\n\n return useCallback(\n (\n sourceOrArgs: string | KeyOnlyArgsRuntime,\n values?: Record<string, unknown>,\n options?: SourceTextOptions,\n ): string => {\n // Key-only mode: t({ id: 'welcome', source: 'Hello', values: { name }, ns: 'common' })\n // Babel should transform this, but if not, use source as fallback text\n if (typeof sourceOrArgs === 'object') {\n const { id, source, values: objValues } = sourceOrArgs;\n console.warn(\n `[idioma] t({ id: \"${id}\" }) was not transformed by Babel. ` +\n 'Make sure @idioma/core Babel plugin is configured.',\n );\n const fallbackText = source || id;\n if (objValues && Object.keys(objValues).length > 0) {\n return interpolateValues(fallbackText, objValues);\n }\n return fallbackText;\n }\n\n // Source text mode: t('Hello {name}', { name: 'Ben' }, { context: 'button' })\n // OR after Babel transformation: t('Hello {name}', { key: { en: '...', es: '...' } }, { name: 'Ben' })\n const source = sourceOrArgs;\n\n // Detect if Babel has inlined translations in arg 2\n // Babel transforms: t('src', { key: { en: '...', es: '...' } }, { actualValues })\n // The inlined object has ONE key (the message key) whose value has locale keys\n let actualValues = values;\n let localeMessages:\n | Record<string, string | MessageFunction>\n | undefined;\n\n const valuesKeys = values ? Object.keys(values) : [];\n const firstKey = valuesKeys[0];\n const firstValue =\n firstKey && values\n ? (values as Record<string, unknown>)[firstKey]\n : undefined;\n\n // Check if this looks like Babel-inlined translations:\n // - Has exactly one key (the message key)\n // - That key's value is an object with locale as a property\n if (\n valuesKeys.length === 1 &&\n firstValue &&\n typeof firstValue === 'object' &&\n typeof (firstValue as Record<string, unknown>)[locale] !== 'undefined'\n ) {\n // Babel transformed: arg 2 is { messageKey: { en: '...', es: '...' } }\n localeMessages = firstValue as Record<\n string,\n string | MessageFunction\n >;\n actualValues = options as unknown as Record<string, unknown>;\n }\n\n if (!localeMessages) {\n // Not transformed by Babel - fallback to source text\n return actualValues && Object.keys(actualValues).length > 0\n ? interpolateValues(source, actualValues)\n : source;\n }\n\n const msg = localeMessages[locale] ?? Object.values(localeMessages)[0];\n if (msg === undefined) {\n return actualValues && Object.keys(actualValues).length > 0\n ? interpolateValues(source, actualValues)\n : source;\n }\n\n if (typeof msg === 'function') {\n return msg(actualValues || {});\n }\n\n return actualValues && Object.keys(actualValues).length > 0\n ? interpolateValues(msg, actualValues)\n : msg;\n },\n [locale],\n ) as TFunction<C>;\n };\n}\n"],"mappings":"sJA8LA,SAAgBI,GAEQ,CAOtB,OAAO,UAA8B,CACnC,IAAME,EAAML,EAAWC,EAAc,CACrC,GAAI,CAACI,EACH,MAAUC,MACR,yGAED,CAGH,GAAM,CAAEC,UAAWF,EAEnB,OAAON,GAEHS,EACAC,EACAC,IACW,CAGX,GAAI,OAAOF,GAAiB,SAAU,CACpC,GAAM,CAAEG,KAAIC,OAAAA,EAAQH,OAAQI,GAAcL,EAC1CM,QAAQC,KACN,qBAAqBJ,EAAE,uFAExB,CACD,IAAMK,EAAeJ,GAAUD,EAI/B,OAHIE,GAAaI,OAAOC,KAAKL,EAAU,CAACM,OAAS,EACxCjB,EAAkBc,EAAcH,EAAU,CAE5CG,EAKT,IAAMJ,EAASJ,EAKXY,EAAeX,EACfY,EAIEC,EAAab,EAASQ,OAAOC,KAAKT,EAAO,CAAG,EAAE,CAC9Cc,EAAWD,EAAW,GACtBE,EACJD,GAAYd,EACPA,EAAmCc,GACpCE,IAAAA,GAmBN,GAbEH,EAAWH,SAAW,GACtBK,GACA,OAAOA,GAAe,UACdA,EAAuCjB,KAAY,SAG3Dc,EAAiBG,EAIjBJ,EAAeV,GAGb,CAACW,EAEH,OAAOD,GAAgBH,OAAOC,KAAKE,EAAa,CAACD,OAAS,EACtDjB,EAAkBU,EAAQQ,EAAa,CACvCR,EAGN,IAAMc,EAAML,EAAed,IAAWU,OAAOR,OAAOY,EAAe,CAAC,GAWpE,OAVIK,IAAQD,IAAAA,GACHL,GAAgBH,OAAOC,KAAKE,EAAa,CAACD,OAAS,EACtDjB,EAAkBU,EAAQQ,EAAa,CACvCR,EAGF,OAAOc,GAAQ,WACVA,EAAIN,GAAgB,EAAE,CAAC,CAGzBA,GAAgBH,OAAOC,KAAKE,EAAa,CAACD,OAAS,EACtDjB,EAAkBwB,EAAKN,EAAa,CACpCM,GAEN,CAACnB,EACH,CAAC"}
|
|
@@ -128,7 +128,7 @@ type TFunction<C extends BaseIdiomaConfig = BaseIdiomaConfig> = <Key extends Str
|
|
|
128
128
|
* Internal useT for Suspense mode.
|
|
129
129
|
* Requires chunk and loader from Babel transform.
|
|
130
130
|
*/
|
|
131
|
-
declare function __useTSuspense(
|
|
131
|
+
declare function __useTSuspense(chunk: string, loader: Loader): (key: string, values?: Record<string, unknown>) => string;
|
|
132
132
|
/**
|
|
133
133
|
* Creates a typed useT hook for Suspense mode.
|
|
134
134
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/runtime-suspense/index.tsx"],"sourcesContent":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/runtime-suspense/index.tsx"],"sourcesContent":[],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{interpolateValues as e,renderMessage as t}from"../interpolate.js";import{createContext as n,use as r,useContext as i,useMemo as a,version as o}from"react";import{jsx as s}from"react/jsx-runtime";import{c}from"react/compiler-runtime";if(parseInt(o.split(`.`)[0],10)<19)throw Error(`[idioma] useSuspense mode requires React 19+. You're using React ${o}. Either upgrade React or set useSuspense: false.`);const l=new Map;function u(e,t,n){let r=`${e}:${t}`;if(!l.has(r)){let t=n[e]().then(e=>e.default);l.set(r,t)}return l.get(r)}function d(e,t,n){u(e,t,n)}const f=n(null);function p(){return function({children:e,locale:t}){let n=a(()=>({locale:t}),[t]);return s(f.Provider,{value:n,children:e})}}function m(){return function(){let e=i(f);if(!e)throw Error(`[idioma] useLocale must be used within an IdiomaProvider. Make sure to wrap your app with <IdiomaProvider>.`);return e.locale}}function h({__key:e,__chunk:n,__load:a,__a:o,__c:s,__cn:c}){let l=i(f);if(!l)throw Error(`[idioma] Trans must be used within an IdiomaProvider. Make sure to wrap your app with <IdiomaProvider>.`);let{locale:d}=l,p=r(u(d,n,a))[e];return p===void 0?e:t(p,o,s,c)}function g(e){function t(e){let t=c(6);if(`children`in e&&e.children!==void 0)return e.children;let{__chunk:n,__load:r,id:i,values:a,components:o}=e;if(n&&r){let e;return t[0]!==n||t[1]!==r||t[2]!==o||t[3]!==i||t[4]!==a?(e=s(h,{__key:i,__chunk:n,__load:r,__a:a,__c:o}),t[0]=n,t[1]=r,t[2]=o,t[3]=i,t[4]=a,t[5]=e):e=t[5],e}throw Error(`[idioma] Key-only Trans in Suspense mode requires Babel transform. Make sure the Babel plugin is configured correctly.`)}return t}function _(t,n){let
|
|
1
|
+
import{interpolateValues as e,renderMessage as t}from"../interpolate.js";import{createContext as n,use as r,useContext as i,useMemo as a,version as o}from"react";import{jsx as s}from"react/jsx-runtime";import{c}from"react/compiler-runtime";if(parseInt(o.split(`.`)[0],10)<19)throw Error(`[idioma] useSuspense mode requires React 19+. You're using React ${o}. Either upgrade React or set useSuspense: false.`);const l=new Map;function u(e,t,n){let r=`${e}:${t}`;if(!l.has(r)){let t=n[e]().then(e=>e.default);l.set(r,t)}return l.get(r)}function d(e,t,n){u(e,t,n)}const f=n(null);function p(){return function({children:e,locale:t}){let n=a(()=>({locale:t}),[t]);return s(f.Provider,{value:n,children:e})}}function m(){return function(){let e=i(f);if(!e)throw Error(`[idioma] useLocale must be used within an IdiomaProvider. Make sure to wrap your app with <IdiomaProvider>.`);return e.locale}}function h({__key:e,__chunk:n,__load:a,__a:o,__c:s,__cn:c}){let l=i(f);if(!l)throw Error(`[idioma] Trans must be used within an IdiomaProvider. Make sure to wrap your app with <IdiomaProvider>.`);let{locale:d}=l,p=r(u(d,n,a))[e];return p===void 0?e:t(p,o,s,c)}function g(e){function t(e){let t=c(6);if(`children`in e&&e.children!==void 0)return e.children;let{__chunk:n,__load:r,id:i,values:a,components:o}=e;if(n&&r){let e;return t[0]!==n||t[1]!==r||t[2]!==o||t[3]!==i||t[4]!==a?(e=s(h,{__key:i,__chunk:n,__load:r,__a:a,__c:o}),t[0]=n,t[1]=r,t[2]=o,t[3]=i,t[4]=a,t[5]=e):e=t[5],e}throw Error(`[idioma] Key-only Trans in Suspense mode requires Babel transform. Make sure the Babel plugin is configured correctly.`)}return t}function _(t,n){let a=i(f);if(!a)throw Error(`[idioma] useT must be used within an IdiomaProvider. Make sure to wrap your app with <IdiomaProvider>.`);let{locale:o}=a,s=r(u(o,t,n));return(t,n)=>{let r=s[t];return r===void 0?n&&Object.keys(n).length>0?e(t,n):t:typeof r==`function`?String(r(n||{})):n&&Object.keys(n).length>0?e(r,n):r}}function v(e){return function(){throw Error(`[idioma] useT in Suspense mode requires Babel transform. Make sure the Babel plugin is configured correctly.`)}}export{f as IdiomaContext,h as __TransSuspense,_ as __useTSuspense,p as createIdiomaProvider,g as createTransSuspense,m as createUseLocale,v as createUseTSuspense,d as preloadTranslations};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["createContext","use","useContext","useMemo","version","interpolateValues","renderMessage","majorVersion","parseInt","split","Error","cache","Map","getTranslations","locale","chunk","loader","key","has","promise","then","mod","default","set","get","preloadTranslations","IdiomaContext","createIdiomaProvider","IdiomaProvider","children","value","createUseLocale","useLocale","context","__TransSuspense","__key","__chunk","__load","__a","__c","__cn","translations","msg","undefined","createTransSuspense","_config","Trans","props","$","_c","id","values","components","t0","__useTSuspense","_chunk","_loader","_locale","source","process","env","NODE_ENV","console","error","Object","keys","length","createUseTSuspense","useT"],"sources":["../../src/runtime-suspense/index.tsx"],"sourcesContent":["/**\n * Suspense-based runtime for @idioma/react.\n *\n * This module provides React components that use dynamic imports\n * and the React 19 `use()` hook for Suspense-based lazy loading.\n *\n * Requires React 19+.\n */\n\nimport {\n createContext,\n use,\n useContext,\n useMemo,\n version,\n type ReactNode,\n} from 'react';\nimport {\n interpolateValues,\n renderMessage,\n type TransComponent,\n} from '../interpolate';\n\n// ============ React Version Check ============\n\nconst majorVersion = parseInt(version.split('.')[0]!, 10);\n\nif (majorVersion < 19) {\n throw new Error(\n `[idioma] useSuspense mode requires React 19+. ` +\n `You're using React ${version}. ` +\n `Either upgrade React or set useSuspense: false.`,\n );\n}\n\n// ============ Types ============\n\ntype MessageFunction = (args: Record<string, unknown>) => string | ReactNode;\ntype MessageValue = string | MessageFunction;\n\ntype LoaderFn = () => Promise<{ default: Record<string, MessageValue> }>;\ntype Loader = Record<string, LoaderFn>;\n\ninterface SuspenseConfig {\n locales: readonly string[];\n}\n\n// ============ Promise Cache ============\n\nconst cache = new Map<string, Promise<Record<string, MessageValue>>>();\n\nfunction getTranslations(\n locale: string,\n chunk: string,\n loader: Loader,\n): Promise<Record<string, MessageValue>> {\n const key = `${locale}:${chunk}`;\n\n if (!cache.has(key)) {\n const promise = loader[locale]!().then((mod) => mod.default);\n cache.set(key, promise);\n }\n\n return cache.get(key)!;\n}\n\n/**\n * Preload translations for a locale/chunk combination.\n * Call this to warm the cache before rendering.\n */\nexport function preloadTranslations(\n locale: string,\n chunk: string,\n loader: Loader,\n): void {\n getTranslations(locale, chunk, loader);\n}\n\n// ============ Context ============\n\nexport interface IdiomaContextValue {\n locale: string;\n}\n\nexport const IdiomaContext = createContext<IdiomaContextValue | null>(null);\n\nexport interface IdiomaProviderProps {\n children: ReactNode;\n locale: string;\n}\n\n/**\n * Creates an IdiomaProvider for Suspense mode.\n * Same controlled API as the inlined runtime.\n */\nexport function createIdiomaProvider() {\n return function IdiomaProvider({ children, locale }: IdiomaProviderProps) {\n const value = useMemo(() => ({ locale }), [locale]);\n\n return (\n <IdiomaContext.Provider value={value}>{children}</IdiomaContext.Provider>\n );\n };\n}\n\n/**\n * Creates a useLocale hook that returns the current locale.\n */\nexport function createUseLocale() {\n return function useLocale(): string {\n const context = useContext(IdiomaContext);\n if (!context) {\n throw new Error(\n '[idioma] useLocale must be used within an IdiomaProvider. ' +\n 'Make sure to wrap your app with <IdiomaProvider>.',\n );\n }\n return context.locale;\n };\n}\n\n// ============ Trans Component ============\n\n/**\n * Props for Babel-transformed Trans in Suspense mode.\n */\nexport interface TransSuspenseProps {\n /** Translation key */\n __key: string;\n /** Chunk identifier */\n __chunk: string;\n /** Loader object with locale → dynamic import */\n __load: Loader;\n /** Arguments for interpolation */\n __a?: Record<string, unknown>;\n /** Components for tag interpolation */\n __c?: TransComponent[];\n /** Component names for named tag matching (parallel to __c array) */\n __cn?: string[];\n}\n\n/**\n * Internal Trans component for Suspense mode.\n * Used by Babel-compiled output.\n */\nexport function __TransSuspense({\n __key,\n __chunk,\n __load,\n __a,\n __c,\n __cn,\n}: TransSuspenseProps): ReactNode {\n const context = useContext(IdiomaContext);\n if (!context) {\n throw new Error(\n '[idioma] Trans must be used within an IdiomaProvider. ' +\n 'Make sure to wrap your app with <IdiomaProvider>.',\n );\n }\n\n const { locale } = context;\n\n // use() suspends until promise resolves\n const translations = use(getTranslations(locale, __chunk, __load));\n const msg = translations[__key];\n\n if (msg === undefined) {\n return __key; // Fallback to key\n }\n\n // Use shared rendering logic (handles ICU functions, tags, and values)\n return renderMessage(msg, __a, __c, __cn);\n}\n\n/**\n * Props for key-only Trans in Suspense mode.\n */\nexport interface TransKeyOnlyModeProps<\n K extends string,\n MV extends Record<string, Record<string, unknown>>,\n MC extends Record<string, TransComponent[]>,\n> {\n id: K;\n children?: never;\n context?: never;\n ns?: string;\n values?: K extends keyof MV ? MV[K] : Record<string, unknown>;\n components?: K extends keyof MC ? MC[K] : TransComponent[];\n // Suspense mode requires chunk/load from Babel transform\n __chunk?: string;\n __load?: Loader;\n}\n\n/**\n * Props for inline Trans in Suspense mode (dev only).\n */\nexport interface TransInlineModeProps {\n children: ReactNode;\n id?: string;\n context?: string;\n ns?: string;\n}\n\n/**\n * Base interface for project-specific Idioma types (for Trans).\n */\ninterface BaseIdiomaConfigForTrans {\n TranslationKey: string;\n MessageValues: Record<string, Record<string, unknown>>;\n MessageComponents: Record<string, TransComponent[]>;\n}\n\n/**\n * Creates a typed Trans component for Suspense mode.\n *\n * In development: renders children directly\n * In production: Babel transforms to __TransSuspense\n */\nexport function createTransSuspense<\n C extends BaseIdiomaConfigForTrans = BaseIdiomaConfigForTrans,\n>(_config: SuspenseConfig) {\n type TK = C['TranslationKey'];\n type MV = C['MessageValues'];\n type MC = C['MessageComponents'];\n\n function Trans(props: TransInlineModeProps): ReactNode;\n function Trans<K extends TK>(\n props: TransKeyOnlyModeProps<K & string, MV, MC>,\n ): ReactNode;\n function Trans(\n props: TransInlineModeProps | TransKeyOnlyModeProps<TK & string, MV, MC>,\n ): ReactNode {\n // Inline mode: children present - render them directly\n // In production, Babel transforms this to __TransSuspense\n if ('children' in props && props.children !== undefined) {\n return props.children;\n }\n\n // Key-only mode in Suspense: requires __chunk and __load from Babel\n const { __chunk, __load, id, values, components } =\n props as TransKeyOnlyModeProps<TK & string, MV, MC>;\n\n if (__chunk && __load) {\n return (\n <__TransSuspense\n __key={id}\n __chunk={__chunk}\n __load={__load}\n __a={values}\n __c={components}\n />\n );\n }\n\n // Fallback: no loader available (shouldn't happen in production)\n throw new Error(\n '[idioma] Key-only Trans in Suspense mode requires Babel transform. ' +\n 'Make sure the Babel plugin is configured correctly.',\n );\n }\n\n return Trans;\n}\n\n// ============ useT Hook ============\n\n/**\n * Base interface for project-specific Idioma types.\n * Same as BaseIdiomaConfig from createUseT.\n */\ninterface BaseIdiomaConfig {\n TranslationKey: string;\n MessageValues: Record<string, Record<string, unknown>>;\n MessageComponents: Record<string, unknown[]>;\n}\n\n/**\n * Derive string-only keys from TranslationKey + MessageComponents.\n * Keys with empty component arrays [] can be used with useT.\n * Keys with non-empty component arrays [TransComponent, ...] must use Trans.\n */\ntype StringOnlyKeys<TK extends string, MC extends Record<string, unknown[]>> = {\n [K in TK & keyof MC]: MC[K] extends [] ? K : never;\n}[TK & keyof MC];\n\nexport type TFunction<C extends BaseIdiomaConfig = BaseIdiomaConfig> = <\n Key extends StringOnlyKeys<C['TranslationKey'], C['MessageComponents']> &\n string,\n>(\n key: Key,\n values?: Key extends keyof C['MessageValues']\n ? C['MessageValues'][Key]\n : Record<string, unknown>,\n) => string;\n\n/**\n * Internal useT for Suspense mode.\n * Requires chunk and loader from Babel transform.\n */\nexport function __useTSuspense(\n _chunk: string,\n _loader: Loader,\n): (key: string, values?: Record<string, unknown>) => string {\n const context = useContext(IdiomaContext);\n if (!context) {\n throw new Error(\n '[idioma] useT must be used within an IdiomaProvider. ' +\n 'Make sure to wrap your app with <IdiomaProvider>.',\n );\n }\n\n const { locale: _locale } = context;\n\n // Note: In properly transformed code, Babel provides the key directly.\n // This function is a fallback when Babel didn't transform.\n\n return (source: string, values?: Record<string, unknown>) => {\n // In Suspense mode, Babel should transform useT calls to include the key\n // If we get here with source text, Babel didn't transform - graceful fallback\n if (process.env.NODE_ENV !== 'production') {\n console.error(\n `Idioma: Missing translations for \"${source}\". ` +\n 'Ensure the Babel plugin is configured.',\n );\n }\n // Fallback: return source with values interpolated if possible\n if (values && Object.keys(values).length > 0) {\n return interpolateValues(source, values);\n }\n return source;\n };\n}\n\n/**\n * Creates a typed useT hook for Suspense mode.\n *\n * Note: In Suspense mode, useT is transformed by Babel to include\n * chunk and loader information.\n */\nexport function createUseTSuspense<\n C extends BaseIdiomaConfig = BaseIdiomaConfig,\n>(_config: SuspenseConfig): () => TFunction<C> {\n // Return a hook that throws when called\n // In production with proper Babel setup, this would be transformed\n return function useT(): TFunction<C> {\n throw new Error(\n '[idioma] useT in Suspense mode requires Babel transform. ' +\n 'Make sure the Babel plugin is configured correctly.',\n );\n };\n}\n"],"mappings":"gPA2BA,GAFqBQ,SAASJ,EAAQK,MAAM,IAAI,CAAC,GAAK,GAAG,CAEtC,GACjB,MAAUC,MACR,oEACwBN,EAAO,mDAEhC,CAiBH,MAAMO,EAAQ,IAAIC,IAElB,SAASC,EACPC,EACAC,EACAC,EACuC,CACvC,IAAMC,EAAM,GAAGH,EAAM,GAAIC,IAEzB,GAAI,CAACJ,EAAMO,IAAID,EAAI,CAAE,CACnB,IAAME,EAAUH,EAAOF,IAAU,CAACM,KAAMC,GAAQA,EAAIC,QAAQ,CAC5DX,EAAMY,IAAIN,EAAKE,EAAQ,CAGzB,OAAOR,EAAMa,IAAIP,EAAI,CAOvB,SAAgBQ,EACdX,EACAC,EACAC,EACM,CACNH,EAAgBC,EAAQC,EAAOC,EAAO,CASxC,MAAaU,EAAgB1B,EAAyC,KAAK,CAW3E,SAAgB2B,GAAuB,CACrC,OAAO,SAAwB,CAAEE,WAAUf,UAA+B,CACxE,IAAMgB,EAAQ3B,OAAe,CAAEW,SAAQ,EAAG,CAACA,EAAO,CAAC,CAEnD,OACE,EAAC,EAAc,SAAA,CAAgBgB,QAAQD,YAAkC,EAQ/E,SAAgBE,GAAkB,CAChC,OAAO,UAA6B,CAClC,IAAME,EAAU/B,EAAWwB,EAAc,CACzC,GAAI,CAACO,EACH,MAAUvB,MACR,8GAED,CAEH,OAAOuB,EAAQnB,QA4BnB,SAAgBoB,EAAgB,CAC9BC,QACAC,UACAC,SACAC,MACAC,MACAC,QACgC,CAChC,IAAMP,EAAU/B,EAAWwB,EAAc,CACzC,GAAI,CAACO,EACH,MAAUvB,MACR,0GAED,CAGH,GAAM,CAAEI,UAAWmB,EAIbS,EADezC,EAAIY,EAAgBC,EAAQsB,EAASC,EAAO,CAAC,CACzCF,GAOzB,OALIO,IAAQC,IAAAA,GACHR,EAIF7B,EAAcoC,EAAKJ,EAAKC,EAAKC,EAAK,CA+C3C,SAAgBI,EAEdC,EAAyB,CASzB,SAAAC,EAAAC,EAAA,CAAA,IAAAC,EAAAC,EAAA,EAAA,CAAA,GAKM,aAAcF,GAASA,EAAKlB,WAAAc,IAAAA,GAAuB,OAC9CI,EAAKlB,SAId,GAAA,CAAAO,UAAAC,SAAAa,KAAAC,SAAAC,cACEL,EAAoD,GAElDX,GAAWC,EAAM,CAAA,IAAAgB,EAQf,OAReL,EAAA,KAAAZ,GAAAY,EAAA,KAAAX,GAAAW,EAAA,KAAAI,GAAAJ,EAAA,KAAAE,GAAAF,EAAA,KAAAG,GAEjBE,EAAA,EAAA,EAAA,CACSH,MAAAA,EACEd,UACDC,SACHc,IAAAA,EACAC,IAAAA,GACL,CAAAJ,EAAA,GAAAZ,EAAAY,EAAA,GAAAX,EAAAW,EAAA,GAAAI,EAAAJ,EAAA,GAAAE,EAAAF,EAAA,GAAAG,EAAAH,EAAA,GAAAK,GAAAA,EAAAL,EAAA,GANFK,EAME,MAAA3C,MAMJ,yHACuD,CAI3D,OAAOoC,EAsCT,SAAgBQ,EACdC,EACAC,EAC2D,CAC3D,IAAMvB,EAAU/B,EAAWwB,EAAc,CACzC,GAAI,CAACO,EACH,MAAUvB,MACR,yGAED,CAGH,GAAM,CAAEI,OAAQ2C,GAAYxB,EAK5B,OAAQyB,EAAgBP,KAGlBQ,QAAQC,IAAIC,WAAa,cAC3BC,QAAQC,MACN,qCAAqCL,EAAM,2CAE5C,CAGCP,GAAUa,OAAOC,KAAKd,EAAO,CAACe,OAAS,EAClC7D,EAAkBqD,EAAQP,EAAO,CAEnCO,GAUX,SAAgBS,EAEdtB,EAA6C,CAG7C,OAAO,UAA8B,CACnC,MAAUnC,MACR,+GAED"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["createContext","use","useContext","useMemo","version","interpolateValues","renderMessage","majorVersion","parseInt","split","Error","cache","Map","getTranslations","locale","chunk","loader","key","has","promise","then","mod","default","set","get","preloadTranslations","IdiomaContext","createIdiomaProvider","IdiomaProvider","children","value","createUseLocale","useLocale","context","__TransSuspense","__key","__chunk","__load","__a","__c","__cn","translations","msg","undefined","createTransSuspense","_config","Trans","props","$","_c","id","values","components","t0","__useTSuspense","Object","keys","length","String","createUseTSuspense","useT"],"sources":["../../src/runtime-suspense/index.tsx"],"sourcesContent":["/**\n * Suspense-based runtime for @idioma/react.\n *\n * This module provides React components that use dynamic imports\n * and the React 19 `use()` hook for Suspense-based lazy loading.\n *\n * Requires React 19+.\n */\n\nimport {\n createContext,\n use,\n useContext,\n useMemo,\n version,\n type ReactNode,\n} from 'react';\nimport {\n interpolateValues,\n renderMessage,\n type TransComponent,\n} from '../interpolate';\n\n// ============ React Version Check ============\n\nconst majorVersion = parseInt(version.split('.')[0]!, 10);\n\nif (majorVersion < 19) {\n throw new Error(\n `[idioma] useSuspense mode requires React 19+. ` +\n `You're using React ${version}. ` +\n `Either upgrade React or set useSuspense: false.`,\n );\n}\n\n// ============ Types ============\n\ntype MessageFunction = (args: Record<string, unknown>) => string | ReactNode;\ntype MessageValue = string | MessageFunction;\n\ntype LoaderFn = () => Promise<{ default: Record<string, MessageValue> }>;\ntype Loader = Record<string, LoaderFn>;\n\ninterface SuspenseConfig {\n locales: readonly string[];\n}\n\n// ============ Promise Cache ============\n\nconst cache = new Map<string, Promise<Record<string, MessageValue>>>();\n\nfunction getTranslations(\n locale: string,\n chunk: string,\n loader: Loader,\n): Promise<Record<string, MessageValue>> {\n const key = `${locale}:${chunk}`;\n\n if (!cache.has(key)) {\n const promise = loader[locale]!().then((mod) => mod.default);\n cache.set(key, promise);\n }\n\n return cache.get(key)!;\n}\n\n/**\n * Preload translations for a locale/chunk combination.\n * Call this to warm the cache before rendering.\n */\nexport function preloadTranslations(\n locale: string,\n chunk: string,\n loader: Loader,\n): void {\n getTranslations(locale, chunk, loader);\n}\n\n// ============ Context ============\n\nexport interface IdiomaContextValue {\n locale: string;\n}\n\nexport const IdiomaContext = createContext<IdiomaContextValue | null>(null);\n\nexport interface IdiomaProviderProps {\n children: ReactNode;\n locale: string;\n}\n\n/**\n * Creates an IdiomaProvider for Suspense mode.\n * Same controlled API as the inlined runtime.\n */\nexport function createIdiomaProvider() {\n return function IdiomaProvider({ children, locale }: IdiomaProviderProps) {\n const value = useMemo(() => ({ locale }), [locale]);\n\n return (\n <IdiomaContext.Provider value={value}>{children}</IdiomaContext.Provider>\n );\n };\n}\n\n/**\n * Creates a useLocale hook that returns the current locale.\n */\nexport function createUseLocale() {\n return function useLocale(): string {\n const context = useContext(IdiomaContext);\n if (!context) {\n throw new Error(\n '[idioma] useLocale must be used within an IdiomaProvider. ' +\n 'Make sure to wrap your app with <IdiomaProvider>.',\n );\n }\n return context.locale;\n };\n}\n\n// ============ Trans Component ============\n\n/**\n * Props for Babel-transformed Trans in Suspense mode.\n */\nexport interface TransSuspenseProps {\n /** Translation key */\n __key: string;\n /** Chunk identifier */\n __chunk: string;\n /** Loader object with locale → dynamic import */\n __load: Loader;\n /** Arguments for interpolation */\n __a?: Record<string, unknown>;\n /** Components for tag interpolation */\n __c?: TransComponent[];\n /** Component names for named tag matching (parallel to __c array) */\n __cn?: string[];\n}\n\n/**\n * Internal Trans component for Suspense mode.\n * Used by Babel-compiled output.\n */\nexport function __TransSuspense({\n __key,\n __chunk,\n __load,\n __a,\n __c,\n __cn,\n}: TransSuspenseProps): ReactNode {\n const context = useContext(IdiomaContext);\n if (!context) {\n throw new Error(\n '[idioma] Trans must be used within an IdiomaProvider. ' +\n 'Make sure to wrap your app with <IdiomaProvider>.',\n );\n }\n\n const { locale } = context;\n\n // use() suspends until promise resolves\n const translations = use(getTranslations(locale, __chunk, __load));\n const msg = translations[__key];\n\n if (msg === undefined) {\n return __key; // Fallback to key\n }\n\n // Use shared rendering logic (handles ICU functions, tags, and values)\n return renderMessage(msg, __a, __c, __cn);\n}\n\n/**\n * Props for key-only Trans in Suspense mode.\n */\nexport interface TransKeyOnlyModeProps<\n K extends string,\n MV extends Record<string, Record<string, unknown>>,\n MC extends Record<string, TransComponent[]>,\n> {\n id: K;\n children?: never;\n context?: never;\n ns?: string;\n values?: K extends keyof MV ? MV[K] : Record<string, unknown>;\n components?: K extends keyof MC ? MC[K] : TransComponent[];\n // Suspense mode requires chunk/load from Babel transform\n __chunk?: string;\n __load?: Loader;\n}\n\n/**\n * Props for inline Trans in Suspense mode (dev only).\n */\nexport interface TransInlineModeProps {\n children: ReactNode;\n id?: string;\n context?: string;\n ns?: string;\n}\n\n/**\n * Base interface for project-specific Idioma types (for Trans).\n */\ninterface BaseIdiomaConfigForTrans {\n TranslationKey: string;\n MessageValues: Record<string, Record<string, unknown>>;\n MessageComponents: Record<string, TransComponent[]>;\n}\n\n/**\n * Creates a typed Trans component for Suspense mode.\n *\n * In development: renders children directly\n * In production: Babel transforms to __TransSuspense\n */\nexport function createTransSuspense<\n C extends BaseIdiomaConfigForTrans = BaseIdiomaConfigForTrans,\n>(_config: SuspenseConfig) {\n type TK = C['TranslationKey'];\n type MV = C['MessageValues'];\n type MC = C['MessageComponents'];\n\n function Trans(props: TransInlineModeProps): ReactNode;\n function Trans<K extends TK>(\n props: TransKeyOnlyModeProps<K & string, MV, MC>,\n ): ReactNode;\n function Trans(\n props: TransInlineModeProps | TransKeyOnlyModeProps<TK & string, MV, MC>,\n ): ReactNode {\n // Inline mode: children present - render them directly\n // In production, Babel transforms this to __TransSuspense\n if ('children' in props && props.children !== undefined) {\n return props.children;\n }\n\n // Key-only mode in Suspense: requires __chunk and __load from Babel\n const { __chunk, __load, id, values, components } =\n props as TransKeyOnlyModeProps<TK & string, MV, MC>;\n\n if (__chunk && __load) {\n return (\n <__TransSuspense\n __key={id}\n __chunk={__chunk}\n __load={__load}\n __a={values}\n __c={components}\n />\n );\n }\n\n // Fallback: no loader available (shouldn't happen in production)\n throw new Error(\n '[idioma] Key-only Trans in Suspense mode requires Babel transform. ' +\n 'Make sure the Babel plugin is configured correctly.',\n );\n }\n\n return Trans;\n}\n\n// ============ useT Hook ============\n\n/**\n * Base interface for project-specific Idioma types.\n * Same as BaseIdiomaConfig from createUseT.\n */\ninterface BaseIdiomaConfig {\n TranslationKey: string;\n MessageValues: Record<string, Record<string, unknown>>;\n MessageComponents: Record<string, unknown[]>;\n}\n\n/**\n * Derive string-only keys from TranslationKey + MessageComponents.\n * Keys with empty component arrays [] can be used with useT.\n * Keys with non-empty component arrays [TransComponent, ...] must use Trans.\n */\ntype StringOnlyKeys<TK extends string, MC extends Record<string, unknown[]>> = {\n [K in TK & keyof MC]: MC[K] extends [] ? K : never;\n}[TK & keyof MC];\n\nexport type TFunction<C extends BaseIdiomaConfig = BaseIdiomaConfig> = <\n Key extends StringOnlyKeys<C['TranslationKey'], C['MessageComponents']> &\n string,\n>(\n key: Key,\n values?: Key extends keyof C['MessageValues']\n ? C['MessageValues'][Key]\n : Record<string, unknown>,\n) => string;\n\n/**\n * Internal useT for Suspense mode.\n * Requires chunk and loader from Babel transform.\n */\nexport function __useTSuspense(\n chunk: string,\n loader: Loader,\n): (key: string, values?: Record<string, unknown>) => string {\n const context = useContext(IdiomaContext);\n if (!context) {\n throw new Error(\n '[idioma] useT must be used within an IdiomaProvider. ' +\n 'Make sure to wrap your app with <IdiomaProvider>.',\n );\n }\n\n const { locale } = context;\n\n // Suspend until chunk loads (same pattern as __TransSuspense)\n const translations = use(getTranslations(locale, chunk, loader));\n\n return (key: string, values?: Record<string, unknown>) => {\n const msg = translations[key];\n\n if (msg === undefined) {\n if (values && Object.keys(values).length > 0) {\n return interpolateValues(key, values);\n }\n return key;\n }\n\n // Compiled ICU function (plural/select)\n if (typeof msg === 'function') {\n return String(msg(values || {}));\n }\n\n // Plain string with optional value interpolation\n if (values && Object.keys(values).length > 0) {\n return interpolateValues(msg, values);\n }\n return msg;\n };\n}\n\n/**\n * Creates a typed useT hook for Suspense mode.\n *\n * Note: In Suspense mode, useT is transformed by Babel to include\n * chunk and loader information.\n */\nexport function createUseTSuspense<\n C extends BaseIdiomaConfig = BaseIdiomaConfig,\n>(_config: SuspenseConfig): () => TFunction<C> {\n // Return a hook that throws when called\n // In production with proper Babel setup, this would be transformed\n return function useT(): TFunction<C> {\n throw new Error(\n '[idioma] useT in Suspense mode requires Babel transform. ' +\n 'Make sure the Babel plugin is configured correctly.',\n );\n };\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@idioma/react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Compile-time React i18n - runtime package",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
],
|
|
50
50
|
"license": "MIT",
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@idioma/core": "0.1.
|
|
52
|
+
"@idioma/core": "0.1.6"
|
|
53
53
|
},
|
|
54
54
|
"scripts": {
|
|
55
55
|
"build": "tsdown",
|