javascript - ¿Hay alguna manera de acceder a `__filename` en Next.js?
Estoy trabajando en un módulo i18n personalizado y me encantaría reemplazar este código (esta es una página de "sobre nosotros"):
const messages = (await import(`./about-us.${locale}.json`))
.default as Messages;
Por
const messages = (
await import(`./${__filename.replace('.tsx', `.${locale}.json`)}`)
).default as Messages;
Desafortunadamente, __filename se resuelve en /index.js (supongo que por Webpack) - ¿hay alguna manera de lograr lo que estoy intentando hacer en mi ejemplo o esto necesitaría estar incorporado directamente en Next.js para funcionar?
Respuesta #1
Refactoriza esto para que los consumidores no sepan sobre el sistema de archivos
Spoiler: No voy a decirte cómo acceder a __filename con Next.js; no sé nada sobre eso.
Aquí hay un patrón que es mejor que lo que propones y que evita el problema por completo.
Primero, configuración: parece que tienes una carpeta llena de estos archivos JSON. Me imagino esto:
l10n/
about-us.en-US.json
about-us.fr-FR.json
contact-us.en-US.json
contact-us.fr-FR.json
... <package>.<locale>.json
Esa organización de archivos es buena, pero es un error hacer que todos los posibles consumidores de l10n lo sepan.
- ¿Y si cambias el esquema de nombres más adelante? ¿Vas a editar a mano cada archivo que importe texto localizado? ¿Por qué tratarías tan mal a tu Yo del futuro?
- Si un archivo de localización en particular no existe, ¿preferirías que la aplicación se bloquee o simplemente que vuelva a otro idioma?1
Es mejor crear una función que tome packageName y localeCode como argumentos, y devuelva el contenido deseado. Esa función se convierte entonces en la única parte de la aplicación que tiene que conocer los nombres de los archivos, la lógica de reserva, etc.
// l10n/index.js
export default function getLang( packageName, localeCode ) {
let contentPath = `${packageName}.${localeCode}.json`
// TODO: fallback logic
return JSON.parse(FS.readFileSync(contentPath, 'utf8'))
}
Es un trabajo complejo localizar y leer los datos deseados mientras también se asegura de que ninguna solicitud nunca reciba una carga útil vacía y que cada clave de texto se resuelva en un valor. La importación dinámica + un sistema de archivos sensato es un buen comienzo (:applause:), pero esa combinación no es lo suficientemente robusta por sí sola.
En un trabajo anterior, construimos un microservicio completo solo para hacer esta única cosa. (También construimos un servicio separado para obtener traducciones y algunos paquetes privados de npm para permitir que las aplicaciones web soliciten y usen paquetes de idiomas desde nuestro CMS). No tienes que llegar tan lejos, pero con suerte ilustra que el espacio del problema no es pequeño.
1 Lógica de reserva: por ejemplo, en-UK y en-US generalmente son intercambiables; algunos grupos de lenguas romances podrían ser aceptables en una emergencia (vienen a la mente el español/portugués/brasileño); también lenguas germánicas, etc. Lo que funciona y lo que no depende del contenido y del contexto, pero ninguna versión de reserva encajará en un import dinámico.
Respuesta #2
¿Puedes acceder a __filename en getStaticProps y getServerSideProps si eso ayuda?
Paso __filename a una función que lo necesita (que tiene una llamada a la API local en ella), antes de devolver los resultados al renderizado.
export async function getStaticProps(context) {
return {
props: {
html: await getData({ page: __filename })
}, // will be passed to the page component as props
};
}
