astro-i18next Tfunction showing keys instead of translation - i18next

I use t() function to translate text.
The function is acting like there are no locales in astros /public folder.
My file structure
My translation.json file for en:
{
"index": {
"testHeader": "Test Header"
}
}
Here is my index page code:
---
import Layout from "../layouts/Layout.astro";
import { t, changeLanguage } from "i18next";
changeLanguage("en");
---
<Layout>
<h1>{t("index.testHeader")}</h1>
</Layout>
My astro-i18next.config.mts:
/** #type {import('astro-i18next').AstroI18nextConfig} */
export default {
defaultLocale: "en",
locales: ["en", "cs"],
};
My astro.config.mjs:
import { defineConfig } from 'astro/config';
import astroI18next from "astro-i18next";
import tailwind from '#astrojs/tailwind';
// https://astro.build/config
import react from "#astrojs/react";
// https://astro.build/config
export default defineConfig({
integrations: [astroI18next(), react(), tailwind({
config: './tailwind.config.cjs',
})]
});
the t() function shows the passed key instead of translation.
I runned npx astro-i18next generate which did nothing

I had a similar issue; I fixed it with a config change and a downgrade.
(since it's still in beta, gotta keep an eye on that)
NOTE: The current version of "astro-i18next" is "1.0.0-beta.17".
Add the following to your astro-i18next.config.*: baseLanguage: "en"
Downgrade your version to 1.0.0-beta.13, between versions 10 to 17 only this one worked for me.
Good but not Necessary: add this to your package.json scripts: "i18n": "npx astro-i18next generate"
Run this command and should be successful: pnpm i && pnpm run i18n && pnpm run build
Considering this fix, I'm looking forward for similar issues to be resolved in stable release; However, for the time being this should get you going.

I fixed it using npm update.
For some reason my app's dependencies weren't updated.

Related

Web3js fails to import in Vue3 composition api project

I've created a brand new project with npm init vite bar -- --template vue. I've done an npm install web3 and I can see my package-lock.json includes this package. My node_modules directory also includes the web3 modules.
So then I added this line to main.js:
import { createApp } from 'vue'
import App from './App.vue'
import Web3 from 'web3' <-- This line
createApp(App).mount('#app')
And I get the following error:
I don't understand what is going on here. I'm fairly new to using npm so I'm not super sure what to Google. The errors are coming from node_modules/web3/lib/index.js, node_modules/web3-core/lib/index.js, node_modules/web3-core-requestmanager/lib/index.js, and finally node_modules/util/util.js. I suspect it has to do with one of these:
I'm using Vue 3
I'm using Vue 3 Composition API
I'm using Vue 3 Composition API SFC <script setup> tag (but I imported it in main.js so I don't think it is this one)
web3js is in Typescript and my Vue3 project is not configured for Typescript
But as I am fairly new to JavaScript and Vue and Web3 I am not sure how to focus my Googling on this error. My background is Python, Go, Terraform. Basically the back end of the back end. Front end JavaScript is new to me.
How do I go about resolving this issue?
Option 1: Polyfill Node globals/modules
Polyfilling the Node globals and modules enables the web3 import to run in the browser:
Install the ESBuild plugins that polyfill Node globals/modules:
npm i -D #esbuild-plugins/node-globals-polyfill
npm i -D #esbuild-plugins/node-modules-polyfill
Configure optimizeDeps.esbuildOptions to use these ESBuild plugins.
Configure define to replace global with globalThis (the browser equivalent).
import { defineConfig } from 'vite'
import GlobalsPolyfills from '#esbuild-plugins/node-globals-polyfill'
import NodeModulesPolyfills from '#esbuild-plugins/node-modules-polyfill'
export default defineConfig({
⋮
optimizeDeps: {
esbuildOptions: {
2️⃣
plugins: [
NodeModulesPolyfills(),
GlobalsPolyfills({
process: true,
buffer: true,
}),
],
3️⃣
define: {
global: 'globalThis',
},
},
},
})
demo 1
Note: The polyfills add considerable size to the build output.
Option 2: Use pre-bundled script
web3 distributes a bundled script at web3/dist/web3.min.js, which can run in the browser without any configuration (listed as "pure js"). You could configure a resolve.alias to pull in that file:
import { defineConfig } from 'vite'
export default defineConfig({
⋮
resolve: {
alias: {
web3: 'web3/dist/web3.min.js',
},
// or
alias: [
{
find: 'web3',
replacement: 'web3/dist/web3.min.js',
},
],
},
})
demo 2
Note: This option produces 469.4 KiB smaller output than Option 1.
You can avoid the Uncaught ReferenceError: process is not defined error by adding this in your vite config
export default defineConfig({
// ...
define: {
'process.env': process.env
}
})
I found the best solution.
The problem is because you lose window.process variable, and process exists only on node, not the browser.
So you should inject it to browser when the app loads.
Add this line to your app:
window.process = {
...window.process,
};

What is the right way to import vue package in nuxt?

I try to import this package into my nuxt project.
All my coding experiments can be found here. I will refer to different branches.
There are several ways to do so:
Just import it right in the page like here (master branch)
This way worked well. You can go to the uploading page via a button on a home page.
Until you manually refresh the page
Then you will get this error SyntaxError Cannot use import statement outside a module
The same error happens when you try to build it.
Import it via plugins (like in plugin-use branch with or without vendor option in build)
I've got the same error.
Import it via plugins with some options (like in plugin-options branch)
Then the package loads only when you refresh the page and only in dev mode.
If you will go to that button on a home page (referenced before) - there will be an empty page.
Import it through modules (like in modules branch).
Then the nuxt cannot load at all, this error happens SyntaxError: Invalid or unexpected token
Could you comment on each method and why it doesn't work?
How to import it correctly?
The final answer is following (I've looked up the projects which use this package).
There was a project which run on Nuxt.
These are changes which you should add to #tamzid-oronno 's answer
//vue-upload-multiple-image.js
import Vue from 'vue'
import VueLazyload from 'vue-lazyload'
import VueUploadMultipleImage from 'vue-upload-multiple-image'
Vue.use(VueLazyload) // this is from the package installation guide
Vue.component('VueUploadMultipleImage', VueUploadMultipleImage)
And list it in plugins the same way.
//nuxt.config.js
plugins: [
{ src: '~plugins/vue-upload-multiple-image', ssr: false }
]
Thus you will be able to use the package without importing it in pages as tags. This was implemented in plugin_plus_lazy branch.
Both tags will work vue-upload-multiple-image and VueUploadMultipleImage.
//your-index-file.vue
<template>
<div id="my-strictly-unique-vue-upload-multiple-image" style="display: flex; justify-content: center;">
<vue-upload-multiple-image
#upload-success="uploadImageSuccess"
#before-remove="beforeRemove"
#edit-image="editImage"
:data-images="images"
idUpload="myIdUpload"
editUpload="myIdEdit"
dragText = "Drag an image here"
browseText = "(or click here to browse)"
primaryText = "Default Image"
markIsPrimaryText = "Set as default image"
popupText = "This image will be set as default"
dropText = "Drag and drop"
accept = image/jpeg,image/png,image/jpg,image/tif,image/tiff
></vue-upload-multiple-image>
</div>
</template>
<script>
export default {
name: "AppUpload",
data(){
return{
file:"",
images: []
}
},
methods:{
uploadImageSuccess(formData, index, fileList) { },
beforeRemove (index, done, fileList) { },
editImage (formData, index, fileList) { },
}
}
</script>
<style scoped>
</style>
To create a static version and test it on your local machine do the following:
$ npm run generate
# test the project
$ npm install http-server
$ cd dist
$ http-server -p 3000
I still have a question - why does it work? :)
Use it as plugin.
In the plugins folder, make a file named vue-upload-multiple-image.js
//vue-upload-multiple-image.js
import Vue from 'vue'
import {VueUploadMultiple} from 'vue-upload-multiple-image'
Vue.use(VueUploadMultiple)
List it under plugins block on nuxt.config.js
//nuxt.config.js
plugins: [
{ src: '~plugins/vue-upload-multiple-image', ssr: false }
]
Thus you will be able to use the package on any component of your project

Bundle size is big, how to reduce size of app.js?

I am using Vue.js and have only 4 components in my project.
I imported only bootstrap, jquery and lodash:
import { map } from 'lodash';
import 'bootstrap/js/dist/modal';
import $ from "jquery";
But npm run production creates
bundle of 400kb size.
npm run production is configured as shown below.
cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js
Is it possible to reduce bundle size to ~100KB ? If yes how?
You should add bundle analyzer to your webpack config.
That tool will help you to understand what is going on with your final bundle for example:
you have imported something accidentally and didn't noticed that
one of your dependencies is really big and you should avoid using it
you accidentally imported whole library when you just wanted to import single function from that library (that is common with lodash)
Here is an example of how you can add bundle analyzer to your webpack config:
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const isBundleAnalyze = true; // turn it too true only when you want to analyze your bundle, should be false by default
module.exports = {
// ... rest webpack config here
plugins: [
// ... rest webpack plugins here
...isBundleAnalyze ? [ new BundleAnalyzerPlugin() ] : []
]
};
Also check your final js file.
It should be a single line of code with simple variables. Something like this: !function(e){function t(t){for(var n,r,o=t[0],i=t[1],s=0,l=[];s<o.length;s++) if it doesn't looks like that it means that you configured your production webpack build incorrectly.
It's pretty obvious why your bundle is over 400kb, you are importing lodash and jquery, you are just missing moment.js (a little joke), but one thing that you can do is use only what you need.
First, if you are using Vue, or React, or any of those jQuery UI libraries you shouldn't be using jQuery unless is necessary.
Another thing that you can do is import only what you need, instead of:
import { map } from 'lodash';
try
import map from 'lodash/map';
or even better
import map from 'lodash.map';
https://www.npmjs.com/package/lodash.map
Lazy imports, read more here. This will allow splitting your bundle into pieces that can be called at execution time, reducing considerably your app size.
const Foo = () => import('./Foo.vue')
There is also SSR (Server Side Rendering), which is basically generating the initial HTML code of your app at build time and rendering outputting that, to show the users that something is on the site, but you also need to understand that, this won't do much, since the browser needs to parse the Javascript code (the hydration process) in order to make the site functional.
If you are using React as of April 2021, the React team announced React Server Components, which seems like a big thing coming up, I supposed that many other libraries will be moving components to the server (and I hope Vue does).
Again as of today don't use it on production.
Other answers mentioned the use of webpack-bundle-analyzer, here is a trick how to use it:
webpack.config.js
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const analyzing = process.env.NODE_ENV === 'analyze';
module.exports = {
plugin: [
...(analyzing ? [new BundleAnalyzerPlugin()] : [])
]
}
on your package.json
{
"scripts": {
"analyze": "NODE_ENV=analyze webpack build"
}
}
use CompressionWebpackPlugin and try gzip

How to use npm package dependency

I am learning to create npm packages by creating a session check function sessionFn that will popup a modal 1 minute before the session expires.
The function works as expected on the main app (a nuxtJS app) but when I make use it as an npm module I have to pass moment as an argument even though moment is listed as a dependency and is imported on the module.
I am missing something, why is my module not picking up moment? I want to use the module like sessionFn(this, to.path); instead of sessionFn(this, to.path, moment); moment is undefined when I don't pass it
Package files
package.json
{
"name": "hello-stratech",
"version": "1.0.17",
"description": "Hello Stratech",
"main": "index.js",
"keywords": [
"npm",
"hello",
"stratech"
],
"author": "Simo Mafuxwana",
"license": "ISC",
"dependencies": {
"moment": "^2.22.2"
}
}
index.js (main js file)
import moment from "moment";
module.exports = {
greeting(name) {
alert("Hello.. " + name);
},
department(dev) {
...
},
sessionFn(context) {
const exp = context.$store.state.session.exp;
let userSystemTime = new Date();
userSystemTime = moment.utc(userSystemTime)
const diff = moment(userSystemTime).diff(moment(exp), 'minutes');
if (diff = 1) {
// open modal
}
}
}
Usage
This is how I use the package in the main app
import moment from 'moment';
import { sessionFn } from "hello-stratech";
export default {
...
watch: {
$route(to) {
sessionFn(this, to.path, moment);
}
}
...
}
You dont need to import and pass moment into your function since you are importing it in your function file. You are not even using the passed argument in your function. So you can just safely dont pass it. You are also not using second argument that u pass to.path, so u can omit it too.
As a suggestion you should install and use eslint, which will catch such things. You can setup a nuxt project with eslint using create nuxt app for example.
There is also a bug in esm 3.21-3.22 that prevent commonjs and es6 imports work together https://github.com/standard-things/esm/issues/773 . That should be fixed when a new esm will be released
Try making moment as devDependancy through npm i moment --save-dev instead of dependency.
That way moment will only be needed when the package is development (means when you are developing the project) but not when it is used.
Hope it fixes your issue
for more depth knowledge

pass environment variables during babel build phase for importing different files

I'm building a web (react with webpack & babel) and mobile apps (react-native with expo) for a project. I therefore created a common library for business logic and redux/api library.
Some code will be slightly different between web and mobile. In my case it's localStorage vs AsyncStorage, which I use for authentication among other things...
I'm trying to pass an environment variable for the build stage to switch import of certain files so that the correct file is loaded for each build which are simply path linked (ie no pre-build of my library, I just do import '../mylib') ex:
if(PLATFORM === 'mobile'){
import StorageModule from './mobile-storage-module`
} else {
import StorageModule from './mobile-storage-module`
}
export default StorageModule
Try 1
#babel/preset-env to say if it's mobile or web so that it imports different libraries depending on build like so:
My .babelrc has this:
{
"presets": [
[
"#babel/preset-env",
{
"platform": "mobile"
}
]
]
}
And then in local storage file I do this:
export default () => {
const platform = process.env.platform
if (platform === 'mobile') {
return import './storage-modules/storage-mobile'
}
return import './storage-modules/storage-web'
}
That didn't work, and this also didn't work for me.
Try 2
I installed react-native-dotenv and created a .env file with:
PLATFORM=mobile
And set the plugin in my .babelrc:
{
"presets": [
"babel-preset-expo",
"react-native-dotenv"
]
}
And in my example file, I tried this:
import { PLATFORM } from 'react-native-dotenv'
export default PLATFORM === 'mobile' ? import './storage-modules/storage-mobile' : import './storage-modules/storage-web'
But now my build doesn't work. Any idea how I do dynamic imports during the build process that works for babel in react-native app and webpack build (also uses babel)?
First, #babel/preset-env does not do what you think it does. This is not for specifying your own variables, it is a plugin to automatically use the right target and pollyfills for the browsers you want to support.
The easiest way to get environment variables is with the webpack define plugin (which is part of webpack, so no need to install anything extra)
Just add this to your webpack config.
plugins: [
new webpack.DefinePlugin({
'process.env': {
platform: 'mobile',
},
}),
],
Next, you can't use normal import statements inside of ifs.
import gets resolved before any code runs, either on build by webpack, or in supported environments on script load.
To import something on runtime, you need to use dynamic imports.
Here is an example of how this could look like.
export default new Promise(async resolve => {
resolve(
process.env.platform === 'mobile'
? (await import('./mobile.js')).default
: (await import('./desktop.js')).default
);
});
You can now import from this file like you normally would, but be aware that the default export is a promise.
As your question's title says "during babel build phase", I assume you would like to make different builds for desktop and mobile (not one build for both and load the needed modules dynamically run-time). So I would go like this:
Define the run scripts in package.json for desktop and mobile:
"scripts": {
"devmobile": "cross-env NODE_ENV=development PLATFORM=mobile webpack --progress",
"dev": "cross-env NODE_ENV=development webpack --progress",
}
... or you can create two different webpack.config.js files for desktop and mobile builds but I think the above is easier...
Then npm run devmobile to build for mobile and npm run dev for desktop.
Since I'm on Windows I use the cross-env package but this is the recommended way to be OS independent.
Then I would use Webpack's NormalModuleReplacementPlugin:
(based on this exmaple)
In your webpack.config.js:
// defining the wanted platform for the build (comfing form the npm run script)
const targetPlatform = process.env.PLATFORM || 'desktop';
// then use the plugin like this
plugins: [
new webpack.NormalModuleReplacementPlugin(/(.*)-PLATFORM(\.*)/, function(resource) {
resource.request = resource.request.replace(/-PLATFORM/, `-${targetPlatform}`);
}),
]
...then if you have these two files:
./storage-modules/storage-mobile.js
./storage-modules/storage-desktop.js
import the needed one in your script like this:
import './storage-modules/storage-PLATFORM';
This way the generated build will only contain the needed file for the current PLATFORM used for the build process.
Another possible solution could be the ifdef-loader but I haven't tested it. Maybe worth to try, seems easy.
If you want one build though and import the needed module dynamically, you could do something like this in your app.js (or whatever):
// this needs to have defined when the app is running
const targetPlatform = process.env.PLATFORM || 'desktop';
import(
/* webpackChunkName: "[request]" */
`./storage-modules/storage-${targetPlatform}`
).then(storageModule => {
// use the loaded module
});
or:
(async () => {
const storageModule = await import(
/* webpackChunkName: "[request]" */
`./storage-modules/storage-${targetPlatform}`
);
// use the loaded module
})();
For this to work Babel has to be configured.
More on Webpack with dynamic imports here.
You can use transform-inline-environment-variablesto pass platform to babel
"build-mobile": "PLATFORM=mobile ...",
"build-app": "PLATFORM=app ...",