1- import { resolve } from "node:path"
1+
22import { PassThrough } from "node:stream"
3- import type { EntryContext } from "@remix-run/node"
3+ import type { AppLoadContext , EntryContext } from "@remix-run/node"
44import { RemixServer } from "@remix-run/react"
5- import { Response } from "@remix-run/web-fetch "
5+ import type { Context } from "hono "
66import { createInstance } from "i18next"
77import Backend from "i18next-fs-backend"
88import { isbot } from "isbot"
99import { renderToPipeableStream } from "react-dom/server"
1010import { I18nextProvider , initReactI18next } from "react-i18next"
11+ import { createHonoServer } from "react-router-hono-server/node"
12+ import { i18next } from "remix-hono/i18next"
1113import i18n from "./localization/i18n" // your i18n configuration file
12- import i18next , { returnLanguageFromRequest } from "./localization/i18n.server"
14+ import i18nextOpts from "./localization/i18n.server"
1315import { resources } from "./localization/resource"
16+ import { getClientEnv , initEnv } from "./server/env.server"
1417
1518const ABORT_DELAY = 5000
1619
1720export default async function handleRequest (
1821 request : Request ,
1922 responseStatusCode : number ,
2023 responseHeaders : Headers ,
21- remixContext : EntryContext
24+ remixContext : EntryContext ,
25+ appContext : AppLoadContext
2226) {
2327 const callbackName = isbot ( request . headers . get ( "user-agent" ) ) ? "onAllReady" : "onShellReady"
2428 const instance = createInstance ( )
25- const lng = await returnLanguageFromRequest ( request )
26- const ns = i18next . getRouteNamespaces ( remixContext )
29+ const lng = appContext . lang ;
30+ const ns = i18nextOpts . getRouteNamespaces ( remixContext )
2731
2832 await instance
2933 . use ( initReactI18next ) // Tell our instance to use react-i18next
@@ -49,7 +53,8 @@ export default async function handleRequest(
4953 responseHeaders . set ( "Content-Type" , "text/html" )
5054
5155 resolve (
52- new Response ( body , {
56+ // @ts -expect-error - We purposely do not define the body as existent so it's not used inside loaders as it's injected there as well
57+ appContext . body ( body , {
5358 headers : responseHeaders ,
5459 status : didError ? 500 : responseStatusCode ,
5560 } )
@@ -71,3 +76,42 @@ export default async function handleRequest(
7176 setTimeout ( abort , ABORT_DELAY )
7277 } )
7378}
79+
80+
81+ // Code below used to initialize our own Hono server!
82+ // Setup the .env vars
83+ const env = initEnv ( )
84+
85+ const getLoadContext = async ( c : Context ) => {
86+ // get the locale from the context
87+ const locale = i18next . getLocale ( c )
88+ // get t function for the default namespace
89+ const t = await i18next . getFixedT ( c )
90+
91+ const clientEnv = getClientEnv ( )
92+ return {
93+ lang : locale ,
94+ t,
95+ env,
96+ clientEnv,
97+ // We do not add this to AppLoadContext type because it's not needed in the loaders, but it's used above to handle requests
98+ body : c . body ,
99+ }
100+ }
101+
102+ interface LoadContext extends Awaited < ReturnType < typeof getLoadContext > > { }
103+
104+ /**
105+ * Declare our loaders and actions context type
106+ */
107+ declare module "@remix-run/node" {
108+ interface AppLoadContext extends Omit < LoadContext , "body" > { }
109+ }
110+
111+ export const server = await createHonoServer ( {
112+ configure ( server ) {
113+ server . use ( "*" , i18next ( i18nextOpts ) )
114+ } ,
115+ defaultLogger : false ,
116+ getLoadContext,
117+ } )
0 commit comments