{"version":3,"file":"index.mjs","names":["React","LocaleContext","getTranslator","LocaleProvider","props","locales","children","concatenatedLocales","Array","isArray","join","useLocales","localesConcat","useContext","useMemo","split","useI18n","book","i18n","throwPromise","Translate","id","renderInElement","params","extractComponents","length","fillComponentKeys","translator","interpolator","getInterpolator","translatedChildren","translateWithComponents","cloneElement","Dynamic","Todo","node","state","isValidElement","key","child","value","Object","entries","keys","generateKey","hasOwn","defineProperty","writable","configurable","enumerable","test","collect","submessages","wrap","component","message","newKey","o","s","prototype","hasOwnProperty","call"],"sources":["../src/index.tsx"],"sourcesContent":["import React from \"react\";\nimport { LocaleContext } from \"@hi18n/react-context\";\nimport {\n  Book,\n  VocabularyBase,\n  TranslationId,\n  TranslatorObject,\n  MessageArguments,\n  getTranslator,\n  InstantiateComponentTypes,\n  ComponentInterpolator,\n} from \"@hi18n/core\";\n\nexport { LocaleContext } from \"@hi18n/react-context\";\n\n/**\n * Renders the children with the specified locale.\n *\n * @since 0.1.0 (`@hi18n/react`)\n *\n * @example\n *   ```tsx\n *   ReactDOM.render(\n *     root,\n *     <LocaleProvider locales=\"ja\">\n *       <Translate id=\"example/greeting\" book={book} />\n *     </LocaleProvider>\n *   );\n *   ```\n */\nexport const LocaleProvider: React.FC<{\n  children?: React.ReactNode;\n  /**\n   * A list of locales in the order of preference.\n   */\n  locales: string | string[];\n}> = (props) => {\n  const { locales, children } = props;\n  const concatenatedLocales = Array.isArray(locales)\n    ? locales.join(\"\\n\")\n    : locales;\n  return (\n    <LocaleContext.Provider value={concatenatedLocales}>\n      {children}\n    </LocaleContext.Provider>\n  );\n};\n/**\n * Returns the locales from the context.\n *\n * @returns A list of locales in the order of preference.\n *\n * @since 0.1.2 (`@hi18n/react`)\n *\n * @example\n *   ```tsx\n *   const Greeting: React.FC = () => {\n *     const { t } = useI18n(book);\n *     return (\n *       <section>\n *         <h1>{t(\"example/greeting\")}</h1>\n *         {\n *           messages.length > 0 &&\n *             <p>{t(\"example/messages\", { count: messages.length })}</p>\n *         }\n *       </section>\n *     );\n *   };\n *   ```\n */\nexport function useLocales(): string[] {\n  const localesConcat = React.useContext(LocaleContext);\n  const locales = React.useMemo(\n    () => (localesConcat === \"\" ? [] : localesConcat.split(\"\\n\")),\n    [localesConcat]\n  );\n  return locales;\n}\n\n/**\n * Retrieves translation helpers, using the locale from the context.\n *\n * If the catalog is not loaded yet, it suspends the component being\n * rendered. This is an **experimental API** which relies on React's\n * undocumented API for suspension.\n * To avoid this behavior,\n * initialize the Book statically or use preloadCatalog from @hi18n/core\n * to ensure the catalog is loaded before using this function.\n *\n * @param book A \"book\" object containing translated messages\n * @returns An object containing functions necessary for translation\n *\n * @since 0.1.0 (`@hi18n/react`)\n *\n * @example\n *   ```tsx\n *   const Greeting: React.FC = () => {\n *     const { t } = useI18n(book);\n *     return (\n *       <section>\n *         <h1>{t(\"example/greeting\")}</h1>\n *         {\n *           messages.length > 0 &&\n *             <p>{t(\"example/messages\", { count: messages.length })}</p>\n *         }\n *       </section>\n *     );\n *   };\n *   ```\n */\nexport function useI18n<M extends VocabularyBase>(\n  book: Book<M>\n): TranslatorObject<M> {\n  const locales = useLocales();\n  const i18n = React.useMemo(\n    () => getTranslator(book, locales, { throwPromise: true }),\n    [book, locales]\n  );\n  return i18n;\n}\n\nexport type BaseTranslateProps<\n  Vocabulary extends VocabularyBase,\n  // TODO: restrict to string\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  K extends keyof any\n> = {\n  /**\n   * The book to look up in for the translation.\n   *\n   * @since 0.1.0 (`@hi18n/react`)\n   */\n  book: Book<Vocabulary>;\n  /**\n   * The translation id.\n   *\n   * @since 0.1.0 (`@hi18n/react`)\n   */\n  id: K;\n  /**\n   * The children. hi18n searches for elements in the node and names each one in the following way:\n   *\n   * - If it has a `key` prop, use the value.\n   * - Otherwise, give it a number in the order of occurrence of the opening tags starting with 0.\n   *\n   * They are merged into the props as the parameters for the translation.\n   *\n   * @since 0.1.0 (`@hi18n/react`)\n   */\n  children?: React.ReactNode | undefined;\n  /**\n   * When given, the results are wrapped in the element given.\n   *\n   * Note that you don't need to use the prop in most cases.\n   * You can just wrap the `<Translate>` element in whatever wrapper components.\n   *\n   * One valid use case would be to pass a component that analyzes the texts or elements within the component,\n   * such as one that splits texts using `Intl.Segmenter` for better word-wrapping experience.\n   *\n   * @since 0.1.2 (`@hi18n/react`)\n   *\n   * @example\n   *   ```tsx\n   *   <Translate book={book} id=\"example/greeting\" renderInElement={<TextWrapper />}>\n   *   </Translate>\n   *   ```\n   */\n  renderInElement?: React.ReactElement | undefined;\n};\n\nexport type TranslateProps<\n  M extends VocabularyBase,\n  // TODO: restrict to string\n  K extends keyof M\n> = BaseTranslateProps<M, K> &\n  PartialForComponents<MessageArguments<M[K], React.ReactElement>>;\n\ntype PartialForComponents<T> = Partial<T> & Omit<T, ComponentKeys<T>>;\ntype ComponentKeys<T, K extends keyof T = keyof T> = K extends unknown\n  ? T[K] extends React.ReactElement\n    ? K\n    : never\n  : never;\n\n/**\n * Renders the translated message, possibly interleaved with the elements you provide.\n *\n * If the catalog is not loaded yet, it suspends the component being\n * rendered. This is an **experimental API** which relies on React's\n * undocumented API for suspension.\n * To avoid this behavior,\n * initialize the Book statically or use preloadCatalog from @hi18n/core\n * to ensure the catalog is loaded before rendering this component.\n *\n * @since 0.1.0 (`@hi18n/react`)\n *\n * @example\n *   ```tsx\n *   <Translate id=\"example/signin\" book={book}>\n *     {\n *       // These elements are inserted into the translation.\n *     }\n *     <a href=\"\" />\n *     <a href=\"\" />\n *   </Translate>\n *   ```\n *\n * @example You can add a placeholder for readability.\n *   ```tsx\n *   <Translate id=\"example/signin\" book={book}>\n *     You need to <a href=\"\">sign in</a> or <a href=\"\">sign up</a> to continue.\n *   </Translate>\n *   ```\n *\n * @example Naming the elements\n *   ```tsx\n *   <Translate id=\"example/signin\" book={book}>\n *     <a key=\"signin\" href=\"\" />\n *     <a key=\"signup\" href=\"\" />\n *   </Translate>\n *   ```\n *\n * @example to supply non-component parameters, you can:\n *   ```tsx\n *   <Translate id=\"example/greeting\" book={book} name={name} />\n *   ```\n *\n *   This is almost equivalent to the following:\n *   ```tsx\n *   const { t } = useI18n(book);\n *   return t(\"example/greeting\", { name });\n *   ```\n */\nexport function Translate<M extends VocabularyBase, K extends string & keyof M>(\n  props: TranslateProps<M, K>\n): React.ReactElement | null {\n  const { book, id, children, renderInElement, ...params } = props;\n  extractComponents(children, params, { length: 0 });\n  fillComponentKeys(params);\n  const translator = useI18n(book);\n  const interpolator = getInterpolator();\n  const translatedChildren = translator.translateWithComponents<\n    React.ReactNode,\n    React.ReactElement,\n    K\n  >(\n    id,\n    interpolator,\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    params as any\n  );\n  if (renderInElement) {\n    return React.cloneElement(renderInElement, {}, <>{translatedChildren}</>);\n  } else {\n    return <>{translatedChildren}</>;\n  }\n}\n\nexport type DynamicTranslateProps<\n  Vocabulary extends VocabularyBase,\n  Args\n> = BaseTranslateProps<Vocabulary, TranslationId<Vocabulary, Args>> &\n  PartialForComponents<InstantiateComponentTypes<Args, React.ReactElement>>;\n\n/**\n * A variant of {@link Translate} for dynamic translation keys\n *\n * @since 0.1.1 (`@hi18n/react`)\n *\n * @example\n *   ```tsx\n *   const id = translationId(book, \"example/signin\");\n *   <Translate.Dynamic id={id} book={book}>\n *     <a href=\"\" />\n *     <a href=\"\" />\n *   </Translate.Dynamic>\n *   ```\n */\n// eslint-disable-next-line @typescript-eslint/ban-types\nTranslate.Dynamic = Translate as <Vocabulary extends VocabularyBase, Args = {}>(\n  props: DynamicTranslateProps<Vocabulary, Args>\n) => React.ReactElement | null;\n\nexport type TodoTranslateProps<Vocabulary extends VocabularyBase> =\n  BaseTranslateProps<Vocabulary, string> & {\n    [key: string]: unknown;\n  };\n\n/**\n * A variant of {@link Translate} for translation bootstrap.\n *\n * At runtime, it just renders a TODO text.\n *\n * @since 0.1.1 (`@hi18n/react`)\n *\n * @example\n *   ```tsx\n *   <Translate.Todo id=\"example/message-to-work-on\" book={book}>\n *   </Translate.Todo>\n *   ```\n */\nTranslate.Todo = function Todo<Vocabulary extends VocabularyBase>(\n  props: TodoTranslateProps<Vocabulary>\n): React.ReactElement | null {\n  return <>[TODO: {props.id}]</>;\n};\n\n// <Translate>foo<a/> <strong>bar</strong> </Translate> => { 0: <a/>, 1: <strong/> }\n// <Translate><strong><em></em></strong></Translate> => { 0: <strong/>, 1: <em/> }\n// <Translate><a key=\"foo\" /> <button key=\"bar\" /></Translate> => { foo: <a/>, bar: <button/> }\nfunction extractComponents(\n  node: React.ReactNode,\n  params: Record<string | number, unknown>,\n  state: { length: number }\n) {\n  if (React.isValidElement(node)) {\n    if (node.key != null) {\n      params[node.key] = React.cloneElement(node, { key: node.key });\n    } else {\n      params[state.length] = React.cloneElement(node, { key: state.length });\n      state.length++;\n    }\n    extractComponents(node.props.children, params, state);\n  } else if (Array.isArray(node)) {\n    for (const child of node) {\n      extractComponents(child, params, state);\n    }\n  }\n}\n\nfunction fillComponentKeys(params: Record<string | number, unknown>) {\n  for (const [key, value] of Object.entries(\n    // eslint-disable-next-line @typescript-eslint/ban-types\n    params as Record<string | number, {} | null | undefined>\n  )) {\n    if (!React.isValidElement(value)) continue;\n    if (value.key == null) {\n      params[key] = React.cloneElement(value, { key });\n    }\n  }\n}\n\nfunction getInterpolator(): ComponentInterpolator<\n  React.ReactNode,\n  React.ReactElement\n> {\n  const keys: Record<string, number> = {};\n\n  function generateKey(key: string): string {\n    if (!hasOwn(keys, key)) {\n      Object.defineProperty(keys, key, {\n        value: 1,\n        writable: true,\n        configurable: true,\n        enumerable: true,\n      });\n    }\n    const id = keys[key]++;\n    if (id === 1 && !/\\$/.test(key)) {\n      return key;\n    } else {\n      return `${key}$${id}`;\n    }\n  }\n\n  function collect(submessages: React.ReactNode[]): React.ReactNode {\n    return submessages;\n  }\n\n  function wrap(\n    component: React.ReactElement,\n    message: React.ReactNode\n  ): React.ReactNode {\n    const newKey = generateKey(`${component.key}`);\n    return React.cloneElement(component, { key: newKey }, message);\n  }\n\n  return { collect, wrap };\n}\n\nfunction hasOwn(o: object, s: PropertyKey): boolean {\n  return Object.prototype.hasOwnProperty.call(o, s);\n}\n"],"mappings":"AAAA,OAAOA,KAAP,MAAkB,OAAlB;AACA,SAASC,aAAT,QAA8B,sBAA9B;AACA,SAMEC,aANF,QASO,aATP;AAWA,SAASD,aAAT,QAA8B,sBAA9B;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACA,OAAO,MAAME,cAMX,GAAIC,KAAD,IAAW;EACd,MAAM;IAAEC,OAAF;IAAWC;EAAX,IAAwBF,KAA9B;EACA,MAAMG,mBAAmB,GAAGC,KAAK,CAACC,OAAN,CAAcJ,OAAd,IACxBA,OAAO,CAACK,IAAR,CAAa,IAAb,CADwB,GAExBL,OAFJ;EAGA,oBACE,oBAAC,aAAD,CAAe,QAAf;IAAwB,KAAK,EAAEE;EAA/B,GACGD,QADH,CADF;AAKD,CAhBM;AAiBP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACA,OAAO,SAASK,UAAT,GAAgC;EACrC,MAAMC,aAAa,GAAGZ,KAAK,CAACa,UAAN,CAAiBZ,aAAjB,CAAtB;EACA,MAAMI,OAAO,GAAGL,KAAK,CAACc,OAAN,CACd,MAAOF,aAAa,KAAK,EAAlB,GAAuB,EAAvB,GAA4BA,aAAa,CAACG,KAAd,CAAoB,IAApB,CADrB,EAEd,CAACH,aAAD,CAFc,CAAhB;EAIA,OAAOP,OAAP;AACD;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACA,OAAO,SAASW,OAAT,CACLC,IADK,EAEgB;EACrB,MAAMZ,OAAO,GAAGM,UAAU,EAA1B;EACA,MAAMO,IAAI,GAAGlB,KAAK,CAACc,OAAN,CACX,MAAMZ,aAAa,CAACe,IAAD,EAAOZ,OAAP,EAAgB;IAAEc,YAAY,EAAE;EAAhB,CAAhB,CADR,EAEX,CAACF,IAAD,EAAOZ,OAAP,CAFW,CAAb;EAIA,OAAOa,IAAP;AACD;;AAiED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASE,SAAT,CACLhB,KADK,EAEsB;EAC3B,MAAM;IAAEa,IAAF;IAAQI,EAAR;IAAYf,QAAZ;IAAsBgB,eAAtB;IAAuC,GAAGC;EAA1C,IAAqDnB,KAA3D;EACAoB,iBAAiB,CAAClB,QAAD,EAAWiB,MAAX,EAAmB;IAAEE,MAAM,EAAE;EAAV,CAAnB,CAAjB;EACAC,iBAAiB,CAACH,MAAD,CAAjB;EACA,MAAMI,UAAU,GAAGX,OAAO,CAACC,IAAD,CAA1B;EACA,MAAMW,YAAY,GAAGC,eAAe,EAApC;EACA,MAAMC,kBAAkB,GAAGH,UAAU,CAACI,uBAAX,CAKzBV,EALyB,EAMzBO,YANyB,EAOzB;EACAL,MARyB,CAA3B;;EAUA,IAAID,eAAJ,EAAqB;IACnB,oBAAOtB,KAAK,CAACgC,YAAN,CAAmBV,eAAnB,EAAoC,EAApC,eAAwC,0CAAGQ,kBAAH,CAAxC,CAAP;EACD,CAFD,MAEO;IACL,oBAAO,0CAAGA,kBAAH,CAAP;EACD;AACF;;AAQD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACAV,SAAS,CAACa,OAAV,GAAoBb,SAApB;;AASA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACAA,SAAS,CAACc,IAAV,GAAiB,SAASA,IAAT,CACf9B,KADe,EAEY;EAC3B,oBAAO,qDAAUA,KAAK,CAACiB,EAAhB,MAAP;AACD,CAJD,C,CAMA;AACA;AACA;;;AACA,SAASG,iBAAT,CACEW,IADF,EAEEZ,MAFF,EAGEa,KAHF,EAIE;EACA,kBAAIpC,KAAK,CAACqC,cAAN,CAAqBF,IAArB,CAAJ,EAAgC;IAC9B,IAAIA,IAAI,CAACG,GAAL,IAAY,IAAhB,EAAsB;MACpBf,MAAM,CAACY,IAAI,CAACG,GAAN,CAAN,gBAAmBtC,KAAK,CAACgC,YAAN,CAAmBG,IAAnB,EAAyB;QAAEG,GAAG,EAAEH,IAAI,CAACG;MAAZ,CAAzB,CAAnB;IACD,CAFD,MAEO;MACLf,MAAM,CAACa,KAAK,CAACX,MAAP,CAAN,gBAAuBzB,KAAK,CAACgC,YAAN,CAAmBG,IAAnB,EAAyB;QAAEG,GAAG,EAAEF,KAAK,CAACX;MAAb,CAAzB,CAAvB;MACAW,KAAK,CAACX,MAAN;IACD;;IACDD,iBAAiB,CAACW,IAAI,CAAC/B,KAAL,CAAWE,QAAZ,EAAsBiB,MAAtB,EAA8Ba,KAA9B,CAAjB;EACD,CARD,MAQO,IAAI5B,KAAK,CAACC,OAAN,CAAc0B,IAAd,CAAJ,EAAyB;IAC9B,KAAK,MAAMI,KAAX,IAAoBJ,IAApB,EAA0B;MACxBX,iBAAiB,CAACe,KAAD,EAAQhB,MAAR,EAAgBa,KAAhB,CAAjB;IACD;EACF;AACF;;AAED,SAASV,iBAAT,CAA2BH,MAA3B,EAAqE;EACnE,KAAK,MAAM,CAACe,GAAD,EAAME,KAAN,CAAX,IAA2BC,MAAM,CAACC,OAAP,EACzB;EACAnB,MAFyB,CAA3B,EAGG;IACD,IAAI,eAACvB,KAAK,CAACqC,cAAN,CAAqBG,KAArB,CAAL,EAAkC;;IAClC,IAAIA,KAAK,CAACF,GAAN,IAAa,IAAjB,EAAuB;MACrBf,MAAM,CAACe,GAAD,CAAN,gBAActC,KAAK,CAACgC,YAAN,CAAmBQ,KAAnB,EAA0B;QAAEF;MAAF,CAA1B,CAAd;IACD;EACF;AACF;;AAED,SAAST,eAAT,GAGE;EACA,MAAMc,IAA4B,GAAG,EAArC;;EAEA,SAASC,WAAT,CAAqBN,GAArB,EAA0C;IACxC,IAAI,CAACO,MAAM,CAACF,IAAD,EAAOL,GAAP,CAAX,EAAwB;MACtBG,MAAM,CAACK,cAAP,CAAsBH,IAAtB,EAA4BL,GAA5B,EAAiC;QAC/BE,KAAK,EAAE,CADwB;QAE/BO,QAAQ,EAAE,IAFqB;QAG/BC,YAAY,EAAE,IAHiB;QAI/BC,UAAU,EAAE;MAJmB,CAAjC;IAMD;;IACD,MAAM5B,EAAE,GAAGsB,IAAI,CAACL,GAAD,CAAJ,EAAX;;IACA,IAAIjB,EAAE,KAAK,CAAP,IAAY,CAAC,KAAK6B,IAAL,CAAUZ,GAAV,CAAjB,EAAiC;MAC/B,OAAOA,GAAP;IACD,CAFD,MAEO;MACL,iBAAUA,GAAV,cAAiBjB,EAAjB;IACD;EACF;;EAED,SAAS8B,OAAT,CAAiBC,WAAjB,EAAkE;IAChE,OAAOA,WAAP;EACD;;EAED,SAASC,IAAT,CACEC,SADF,EAEEC,OAFF,EAGmB;IACjB,MAAMC,MAAM,GAAGZ,WAAW,WAAIU,SAAS,CAAChB,GAAd,EAA1B;IACA,oBAAOtC,KAAK,CAACgC,YAAN,CAAmBsB,SAAnB,EAA8B;MAAEhB,GAAG,EAAEkB;IAAP,CAA9B,EAA+CD,OAA/C,CAAP;EACD;;EAED,OAAO;IAAEJ,OAAF;IAAWE;EAAX,CAAP;AACD;;AAED,SAASR,MAAT,CAAgBY,CAAhB,EAA2BC,CAA3B,EAAoD;EAClD,OAAOjB,MAAM,CAACkB,SAAP,CAAiBC,cAAjB,CAAgCC,IAAhC,CAAqCJ,CAArC,EAAwCC,CAAxC,CAAP;AACD"}