next-translate Cannot find module './locales/en/common.json' - node.js

I am trying to integrate the next-translate library into my Next app, however I am getting an error when configuring the loadLocaleFrom function
This is what my i18n.js file looks like:
module.exports = {
locales: ["en", "fr", "es", "ru", "ar", "zh", "hi", "sw"],
defaultLocale: "en",
pages: {
"*": ["common"],
"/": ["home"],
},
loadLocaleFrom: async (lang, ns) => {
try {
const m = await import(`./locales/${lang}/${ns}.json`);
return {
...m.default,
};
} catch (error) {
console.log(error);
}
},
};
And my next.config file:
const withPlugins = require("next-compose-plugins");
const withImages = require("next-images");
const nextTranslate = require("next-translate");
module.exports = withPlugins([withImages, nextTranslate], {
reactStrictMode: true,
images: {
disableStaticImages: true,
},
});
package.json version:
next-translate: ^1.5.0
next: 12.1.6
react: 17.0.2
Even though my directory has both, the common.json and the home.json files in the correct folder structure, the loadLocaleFrom function still throws an error that looks like this:
Error: Cannot find module './locales/en/common.json'
at webpackEmptyContext (D:\projects\mk\mk-academy\.next\server\pages\index.js:529:10)
at eval (webpack-internal:///./i18n.js:64:89)
at runMicrotasks (<anonymous>)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async Object.loadLocaleFrom (webpack-internal:///./i18n.js:63:23)
at async Promise.all (index 0) {
code: 'MODULE_NOT_FOUND'
}
I did try using the appWithI18n hoc in _app.js but that doesn't solve it too. I also did try moving the locales to a different directory under src but that shouldn't make a difference.
The image shows my directory structure

require worked for me instead of import
await require(`./locales/${lang}/${ns}.json`)

Related

Discord.js | interaction.reply is not a function [SlashCommand][Typescript]

I am making a /ping command in my bot, following the discordjs guide, but when I use the command, I get an error:
TypeError: interaction.reply is not a function
at Object.<anonymous> (C:\Users\timda\code\discord bot\bot-data\commands\ping.ts:8:15)
at Generator.next (<anonymous>)
at C:\Users\timda\code\discord bot\bot-data\commands\ping.ts:8:71
at new Promise (<anonymous>)
at __awaiter (C:\Users\timda\code\discord bot\bot-data\commands\ping.ts:4:12)
at Object.execute (C:\Users\timda\code\discord bot\bot-data\commands\ping.ts:18:16)
at C:\Users\timda\code\discord bot\main.ts:43:18
at Generator.next (<anonymous>)
at C:\Users\timda\code\discord bot\main.ts:8:71
at new Promise (<anonymous>)
This is the /ping commands code:
import { SlashCommandBuilder } from 'discord.js';
module.exports = {
data: new SlashCommandBuilder()
.setName('ping')
.setDescription('Replies with Pong!'),
async execute(interaction: { reply: (arg0: string) => any }) {
console.log(interaction);
interaction.reply('Pong!');
},
};
And here is the code in my main file that loads in the SlashCommand files:
import fs from 'node:fs';
import path from 'node:path';
import { Client, Collection, GatewayIntentBits, Partials, REST, Routes } from 'discord.js';
import { clientId, token } from './config.json';
const client = new Client({
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.DirectMessages, GatewayIntentBits.MessageContent],
partials: [Partials.Message, Partials.Channel],
presence: { status: 'online', activities: [{ name: 'you 👀', type: 3 }] }
});
(client as any).commands = new Collection();
const commands: any[] = [];
for (const file of (fs.readdirSync(path.join('./bot-data/commands')).filter(file => file.endsWith('.ts')))) {
const command = require(`./bot-data/commands/${file}`);
(client as any).commands.set(command.data.name, command);
commands.push(command.data.toJSON());
};
client.on('ready', async (client: { user: { tag: any; }; }) => {
const rest = new REST({ version: '10' }).setToken(token);
try {
await rest.put(Routes.applicationCommands(clientId), { body: commands});
} catch (error) {
console.error(error);
}
console.log(`Succesfully logged in as ${client.user.tag}!`);
});
client.on('interactionCreate', async interaction => {
if(interaction.isCommand()) {
const command = (client as any).commands.get(interaction.commandName);
if (!command) {
await interaction.reply({content: `Something went wrong while executing ${interaction.commandName}.`, ephemeral: true});
return;
}
try {
await command.execute(client, interaction);
} catch (error) {
await interaction.reply({content: `Something went wrong while executing ${interaction.commandName}., ephemeral: true});
console.error(error);
}
}
});
The command does get loaded when /ping is used, because it does log the interaction in the console.
I am writing the bot in Typescript, that's why I did interaction: { reply: (arg0: string) => any }
and I'm using node to compile and run it.
NVM: version 1.1.10
NPM: version 8.19.2
I've tried writing interaction: { reply: (arg0: string) => any } in different ways and I've also already done a lot of googling, but I can't find the problem I'm facing here.
If someone could help me I would appreciate it.
Inside of main.ts, you're calling the execute function with these arguments:
await command.execute(client, interaction);
But inside of ping.ts, you're only accepting these arguments:
async execute(interaction: { reply: (arg0: string) => any }) { // etc
You need to include both client and interaction as arguments in ping.ts to prevent the values being passed into the wrong variables.
// I'm fairly certain that these are the right imports
import { BaseInteraction, SlashCommandBuilder, Client} from 'discord.js';
...
async execute(client: Client, interaction: BaseInteraction) { // etc

Firestore keeps saying "fetch is not defined" on electron with vue

I'm trying to get firebase firestore to work in electron. Firebase is initialized fine but when I try to run firestore, it says:
Error adding document: ReferenceError: fetch is not defined
at e (webpack:///./node_modules/#firebase/firestore/dist/lite/index.browser.esm2017.js?:3242:30)
at nn (webpack:///./node_modules/#firebase/firestore/dist/lite/index.browser.esm2017.js?:3243:10)
.
.
.
at __webpack_require__ (D:\Desktop\Projects\casedb\dist_electron\index.js:20:30)
I'm pretty sure that's happening because firestore is thinking it's running on the web and has access to fetch while it's actually running on node.js.
Now, I'm not sure what to do to make this work. I'm using a vue-cli plugin to use electron with vue. I've gone through their documentation and tried the following.
Added firebase and firestore as a native dependency
Tried running my test script in a normal node.js environment
Tried using require instead of import
None of these have worked so far. From what I can gather by googling for 8 hours, it probably has something to do with webpack. But I can't figure out what to do.
Here is my vue.config.js which configures the cli plugin:
module.exports = {
pluginOptions: {
electronBuilder: {
externals: [
"pouchdb-node",
"firebase",
"firebase/firestore",
"firebase/firestore/lite",
"firestore",
],
preload: "src/preload.js",
nodeIntegration: true,
builderOptions: {
nsis: {
oneClick: false,
createDesktopShortcut: true,
perMachine: true,
},
},
},
},
};
Here is my firebase test script just in case:
import { initializeApp } from "firebase/app";
import { getFirestore } from "firebase/firestore/lite";
import { collection, addDoc } from "firebase/firestore/lite";
const firebaseConfig = {
apiKey: "AIzaSyCwzmIhPhUxB7uFsCHlWhARTiSzMylDn0A",
// authDomain: "casedb-29442120.firebaseapp.com",
projectId: "casedb-29442120",
storageBucket: "casedb-29442120.appspot.com",
messagingSenderId: "354561150712",
appId: "1:354561150712:web:3db5b0d737be49a90bf50d",
};
const firebaseApp = initializeApp(firebaseConfig);
const db = getFirestore();
export const syncWithDB = async () => {
try {
const docRef = await addDoc(collection(db, "records"), {
first: "Ada",
last: "Lovelace",
born: 1815,
});
console.log("Document written with ID: ", docRef.id);
} catch (e) {
console.error("Error adding document: ", e);
}
};

Use fileSystem on an API Route with NextJS deployed on Vercel

I need to use fileStystem methods as readdirSync on an API Route in NextJS. It works locally but when deployed on Vercel, the request responds with a 500 status code.
This is Vercel's Funcion Logs:
catch Error: ENOENT: no such file or directory, scandir '/var/task/_posts'
at Object.readdirSync (fs.js:1043:3)
at getAllArticles (/var/task/.next/server/chunks/230.js:135:67)
at __WEBPACK_DEFAULT_EXPORT__ (/var/task/.next/server/pages/api/search.js:37:93)
at Object.apiResolver (/var/task/node_modules/next/dist/server/api-utils.js:101:15)
at processTicksAndRejections (internal/process/task_queues.js:95:5)
at async Server.handleApiRequest (/var/task/node_modules/next/dist/server/next-server.js:770:9)
at async Object.fn (/var/task/node_modules/next/dist/server/next-server.js:661:37)
at async Router.execute (/var/task/node_modules/next/dist/server/router.js:205:32)
at async Server.run (/var/task/node_modules/next/dist/server/next-server.js:841:29)
at async Server.handleRequest (/var/task/node_modules/next/dist/server/next-server.js:292:20) {
errno: -2,
syscall: 'scandir',
code: 'ENOENT',
path: '/var/task/_posts'
}
This is the API Route itself (/pages/api/search.ts):
export default (req: NextApiRequest, res: NextApiResponse) => {
const { query } = req;
try {
if (query.q) {
const posts = getAllArticles(ArticleTypes.POSTS, ['slug', 'href', 'title', 'category'], {
hints: {
hint: query.q as string,
fields: ['title', 'category'],
},
}).map((post) => post.data);
const projects = getAllArticles(ArticleTypes.PROJECTS, ['slug', 'href', 'title', 'category', 'technologies'], {
hints: {
hint: query.q as string,
fields: ['title', 'category', 'technologies'],
},
}).map((project) => project.data);
res.status(200).json({
...(posts.length > 0) && { posts },
...(projects.length > 0) && { projects },
});
} else {
res.status(422).send('El parámetro "q" es necesario.');
}
} catch (e) {
res.status(500).send('Ha ocurrido un error mientras se intentaba hacer la búsqueda.');
}
};
And this is the getAllArticles() function used in it:
export const getAllArticles = (
type: ArticleTypes,
items?: string[],
filters?: IFilters,
): IArticle[] => {
const articlesPath = join(process.cwd(), `_${type}`);
const articlesNames = fs
.readdirSync(articlesPath)
.filter((path) => /\.mdx$/.test(path));
const mergedItems: string[] = Array.from(new Set([
...(items && items.length > 0) ? items : [],
...(filters?.hints && filters.hints.fields.length > 0) ? filters.hints.fields : [],
]));
const allArticles = articlesNames
.map((article) => getArticle(type,
path.parse(article).name,
mergedItems.length > 0
? mergedItems
: undefined));
const filteredArticles = filterArticles(type, allArticles, filters);
return filteredArticles;
};
So I am currently using fs.readdirSync for reading .mdx files. As I noted before, this runs perfectly well locally but not when deployed on Vercel. Do I nees to configure any kind of config files or anything?
Thank you so much!

Promisify mkdir on a recursive directory

I've promisified fs.mkdir(). When I try to create a single directory in /tmp, it works, but tI receive a ENOENT error when I try to create a nested directory, even though I sent in the { recursive: true } option.
const mkdirAsync = util.promisify(fs.mkdir);
...
const ensureDir = ({ logger, createError }, event) => mkdirAsync(`/tmp/${event.mediaAssetUuid}/variants`, { recursive: true }).catch((err) => {
if (err.code !== 'EEXIST') {
const err2 = createError(
err,
{ logger },
`Internal Server Error. Error generating image variant for file: ${event.mediaAssetUuid}`,
null,
);
throw err2;
}
});
Error:
{
"jse_shortmsg": "Internal Server Error. Error generating image variant for file: 83ec01d8-8978-4eb0-9b0b-304f1e65cb14",
"jse_cause": {
"errno": -2,
"code": "ENOENT",
"syscall": "mkdir",
"path": "/tmp/83ec01d8-8978-4eb0-9b0b-304f1e65cb14/variants"
},
Node version 10 is required to use the recursive option.

NUXT: Module not found: Error: Can't resolve 'fs'

I'm starting out with vue and nuxt, I have a project using vuetify and I'm trying to modify the carousel component to dynamically load images from the static folder. So far I've come up with:
<template>
<v-carousel>
<v-carousel-item v-for="(item,i) in items" :key="i" :src="item.src"></v-carousel-item>
</v-carousel>
</template>
<script>
function getImagePaths() {
var glob = require("glob");
var options = {
cwd: "./static"
};
var fileNames = glob.sync("*", options);
var items = [];
fileNames.forEach(fileName =>
items.push({
'src': '/'+fileName
})
);
return items;
}
export default {
data() {
return {items :getImagePaths()};
}
};
</script>
When I test this I see:
ERROR in ./node_modules/fs.realpath/index.js
Module not found: Error: Can't resolve 'fs' in '....\node_modules\fs.realpath'
ERROR in ./node_modules/fs.realpath/old.js
Module not found: Error: Can't resolve 'fs' in ....\node_modules\fs.realpath'
ERROR in ./node_modules/glob/glob.js
Module not found: Error: Can't resolve 'fs' in '....\node_modules\glob'
ERROR in ./node_modules/glob/sync.js
Module not found: Error: Can't resolve 'fs' in '.....\node_modules\glob'
googling this I see a bunch of references like https://github.com/webpack-contrib/css-loader/issues/447.
These suggest that you have to midify the webpack config file with something like:
node: {
fs: 'empty'
}
I know very little about webpack. I found https://nuxtjs.org/faq/extend-webpack/ , but am not sure how to modify the webpack config file in this case.
How do I do this?
You can't use NodeJs specific module on browser.
To solve your issue, you can create an API using Nuxt server middleware. The code below, inspired by https://github.com/nuxt-community/express-template.
Create a file, index.js in api/index.js. Then fill it with:
const express = require('express')
// Create express instance
const app = express()
// Require API routes
const carousel = require('./routes/carousel')
// Import API Routes
app.use(carousel)
// Export the server middleware
module.exports = {
path: '/api',
handler: app
}
Create carousel.js in api/routes/carousel.js. Then fill it with:
const { Router } = require('express')
const glob = require('glob')
const router = Router()
router.get('/carousel/images', async function (req, res) {
const options = {
cwd: './static'
}
const filenames = glob.sync('*', options)
let items = [];
filenames.forEach(filename =>
items.push({
'src': '/'+filename
})
);
return res.json({ data: items })
})
module.exports = router
Register your server middleware in nuxt.config.js
module.exports = {
build: {
...
},
serverMiddleware: [
'~/api/index.js'
]
}
Call the api in your page / component. I assume you're using Axios here (axios-module).
<script>
export default {
async asyncData ({ $axios }) {
const images = (await $axios.$get('/api/carousel/images')).data
return { images }
}
}
</script>
I know this is an old question, but it may be helpful for someone to disable fs in their browser.
Like this:
nuxt.config.js
build: {
extend (config, { isDev, isClient }) {
config.node= {
fs: 'empty'
}
// ....
}
},
Add this in your nuxt-config.js:
build: { extend (config, { isDev, isClient }) {
config.node = {
fs: 'empty'
}
// ....
}},

Resources