Vue3 - vue-cli-plugin-i18n - Can't change language dynamically - vuejs3

I am actually trying to follow this video tutorial : https://www.youtube.com/watch?v=CFGjn3yKMNc
Summary of the problem : I can't change the language dynamically with i18n. It stays on the language i18n was initialised with.
So, my i18n uses a different json file for each languages :
locales/en.json containing : { "message" : "hello world"}
locales/fr.json containing : { "message" : "bonjour"}
In the i18n.js (below) files, if I change locale value to en, "hello world" is displayed, and if I put fr instead of en, "bonjour" is displayed. Works Ok.
This code is what came with the installation of i18n except for the .default
function loadLocaleMessages() {
const locales = require.context('./locales', true, /[A-Za-z0-9-_,\s]+\.json$/i)
const messages = {}
locales.keys().forEach(key => {
const matched = key.match(/([A-Za-z0-9-_]+)\./i)
if (matched && matched.length > 1) {
const locale = matched[1]
messages[locale] = locales(key).default
}
})
console.log(messages)
return messages
}
export default createI18n({
legacy: false,
globalInjection: true,
locale: 'fr',
fallbackLocale: 'fr',
messages: loadLocaleMessages()
})
The default language is fr
Now, in my main.js, I have the code below.
The goal is to pass a lang parameter in the URL. This work, I get the param.
Unfortunately, even if the param is set to 'en', bonjour is still displayed.
I tried to force it by replacing i18n.locale = language with i18n.locale = 'en', no luck.
In fact, in the console, even if the i18n.locale value is set to 'en', it still displays french.
However, like I said, if I replace the locale: 'fr', in the code above with locale: 'en', it works...
router.beforeEach((to, from, next) => {
let language = to.params.lang;
if (!language) {
language = 'en'
}
i18n.locale = language
console.log("Active locale: ", i18n.locale)
next()
})
const app = createApp(App)
app.use(router)
app.use(i18n)
app.mount('#app')
Does Anybody has a clue of why it is not working although the i18n.locale value is changed to 'en' ?
Thank you for your time :)
My version of i18n and vue are
"vue": "^3.0.0",
"vue-i18n": "^9.1.6"
"#intlify/vue-i18n-loader": "^2.1.0",
"#vue/cli-plugin-babel": "~4.5.0",
"#vue/cli-plugin-eslint": "~4.5.0",
"#vue/cli-service": "~4.5.0",
"#vue/compiler-sfc": "^3.0.0",
"vue-cli-plugin-i18n": "~2.1.1"

Related

T3 App `❌ Invalid environment variables:`

I'm using the T3-app (nextjs, tRPC, etc), and I don't know if these env variable errors just happened, or if I haven't noticed them before. However, I have all of the environment variables set in the .env file and have the following configuration set in the schema.mjs file:
export const serverSchema = z.object({
DATABASE_URL: z.string().url(),
NODE_ENV: z.enum(["development", "test", "production"]),
NEXTAUTH_SECRET: z.string(),
NEXTAUTH_URL: z.preprocess(
// This makes Vercel deployments not fail if you don't set NEXTAUTH_URL
// Since NextAuth automatically uses the VERCEL_URL if present.
(str) => process.env.VERCEL_URL ?? str,
// VERCEL_URL doesnt include `https` so it cant be validated as a URL
process.env.VERCEL ? z.string() : z.string().url(),
),
GOOGLE_CLIENT_ID: z.string(),
GOOGLE_CLIENT_SECRET: z.string(),
STRIPE_SECRET_KEY: z.string(),
});
export const serverEnv = {
DATABASE_URL: process.env.DATABASE_URL,
NODE_ENV: process.env.NODE_ENV,
NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET,
GOOGLE_CLIENT_ID: process.env.GOOGLE_CLIENT_ID,
GOOGLE_CLIENT_SECRET: process.env.GOOGLE_CLIENT_SECRET,
NEXTAUTH_URL: process.env.NEXTAUTH_URL,
STRIPE_SECRET_KEY: process.env.STRIPE_SECRET_KEY,
};
However, the process.env object is undefined. The only one that has a value is NODE_ENV but it isn't any different than the rest of the env variables.
I'm pretty lost on why this is happening. I've looked up this problem, but nothing is coming up. Am I doing something incorrectly?

next-i18next switching to default locale after refresh [duplicate]

I'm trying to make my default language in Next.js i18n but always is getting "En" as default language called like fallback.
And I also get this error:
Error: [#formatjs/intl Error MISSING_DATA] Missing locale data for locale: "sq" in Intl.NumberFormat. Using default locale: "en" as fallback
module.exports = {
i18n: {
locales: ['sq', 'en'],
defaultLocale: "sq",
}
}
Next.js will automatically detect which locale the user prefers based on the Accept-Language header sent in the page request.
In your case, although your default locale is sq, the en locale is detected in the Accept-Language header so you get redirected to the locale-prefixed path.
This behaviour can be disabled by setting localeDetection to false in your i18n options.
// next.config.js
module.exports = {
i18n: {
locales: ['sq', 'en'],
defaultLocale: 'sq',
localeDetection: false
}
}
From the Disabling Automatic Locale Detection documentation:
When localeDetection is set to false Next.js will no longer
automatically redirect based on the user's preferred locale and will
only provide locale information detected from either the locale based
domain or locale path as described above.
As a side note, regarding the #formatjs/intl error, it indicates that you're using an environment/browser that doesn't have support for the sq locale. You may want to look into #formatjs/intl-numberformat to polyfill that locale data.

Jest encountered an unexpected token (TinyMCE)

I'm using Jest to run unit tests on one of my components, but I'm getting a few errors.
The component that I am trying to test uses tinymce and as a result, I import a few files from tinymce. I've seen on the offical Jest documentation that I insert the following, which I have in my setupTests.js file:
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation(query => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // Deprecated
removeListener: jest.fn(), // Deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
})),
});
However, I have done that, but I am encountering another problem:
Jest encountered an unexpected token SyntaxError: Unexpected token '.'
import "tinymce/skins/ui/oxide.skin.min.css"
I have tried to follow the advice of mocking everything that comes from Tinymce, as well as mocking non-JS modules, using "moduleNameMapper". For example, my _jest.config.js file includes:
module.exports = {
"moduleNameMapper": {
"^image![a-zA-Z0-9$_-]+$": "GlobalImageStub",
"^[./a-zA-Z0-9$_-]+\\.png$": "<rootDir>/RelativeImageStub.js",
"module_name_(.*)": "<rootDir>/substituted_module_$1.js",
"assets/(.*)": [
"<rootDir>/images/$1",
"<rootDir>/photos/$1",
"<rootDir>/recipes/$1"
]
}
"transformIgnorePatterns": [
"<rootDir>/node_modules/"
]
}
The above doesn't work and I still get the same error.
EDIT:
As per one of the suggestions, I've created a styleMock.js file which contains module.exports = {}; and is included in my src/tests/jest/__mocks__ path. I've then inputted:
"moduleNameMapper": {
'\\.(css|less)$': '<rootDir>/src/tests/jest/__mocks__/styleMock.js'
}
But I'm still getting the same error as above.
Following this documentation worked.
In another words, adding in the package.json the following:
{
"jest": {
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
"\\.(css|less)$": "identity-obj-proxy"
}
}
}
As well as running yarn add --dev identity-obj-proxy

How to set multiple output when build lib with vite

When I try to build a lib in vue3, I want to set multiple output file. Code like this:
rollupOptions {
output: [
{
file: 'bundle.js',
format: 'cjs'
},
{
file: 'bundle.min.js',
format: 'iife',
name: 'version',
}
]
}
Then I will get an error:
You must set either "output.file" for a single-file build or "output.dir" when generating multiple chunks"
So, how should I do can make this work?
vite: 2.3.7
👉 You are missing the input config in rollupOptions.
The following full vite config example will generate a index.bundle.[moduleFormat].js
(you may need to adjust file path according to your setup)* :
import { defineConfig } from "vite";
// https://vitejs.dev/config/
export default (opts: { mode: "production" | "development"; command: "build" | "serve" }) => {
return defineConfig({
build: {
target: "es2020",
commonjsOptions: {
sourceMap: false
},
rollupOptions: {
input: {
index: "./src/index.js"
},
/* single
output: {
format: "umd",
strict: false,
chunkFileNames: `[name].[hash].js`,
entryFileNames: "[name].bundle.umd.js",
dir: "dist"
},
*/
// array config example
// from rollup: export type InternalModuleFormat = 'amd' | 'cjs' | 'es' | 'iife' | 'system' | 'umd';
output: [
{
format: 'cjs',
entryFileNames: "[name].bundle.[format].js",
},
{
format: 'es',
entryFileNames: "[name].bundle.[format].js",
},
{
format: 'umd',
entryFileNames: "[name].bundle.[format].js",
},
]
}
}
});
};
💡 To understand this answer better, please read the following sentence :
If you provide an array of entry points or an object mapping names to entry points, they will be bundled to separate output chunks.
And unless the output.file option is used, generated chunk names will follow the output.entryFileNames option. When using the object form, the [name] portion of the file name will be the name of the object property while for the array form, it will be the file name of the entry point.
Note that it is possible when using the object form to put entry points into different sub-folders by adding a / to the name.
If we follow the doc we can get more precisions and we know that :
output.dir
Type: string
Set in build.rollupOptions
Is for: The directory in which all generated chunks are placed and this option is required if more than one chunk is generated. Otherwise, the file option can be used instead.
output.file
Type: string
The file to write to. Can only be used if not more than one chunk is generated.
I guess your looking for https://vitejs.dev/guide/build.html#library-mode
And see https://vitejs.dev/config/#build-lib to tweak your needs.

Next-offline and WorkboxOpts: Error: "runtimeCaching" is not a supported parameter. How to enable "runtimeCaching" in next.config.js

I'm just getting started with next-offline and found the section regarding workbox integration and its recipes.
According to the docs:
If you're new to workbox, I'd recommend reading this quick guide --
anything inside of workboxOpts will be passed to
workbox-webpack-plugin.
Define a workboxOpts object in your next.config.js and it will gets
passed to workbox-webpack-plugin. Workbox is what next-offline uses
under the hood to generate the service worker, you can learn more
about it here.
After digging around, I found this great section.
Essentially it gives a suggestion to use two different options:
GenerateSW or InjectManifest
I would like to use the InjectManifest, however when I try to implement that in my next.config.js file. I get this error:
"runtimeCaching" is not a supported parameter.
This is my next.config.js:
const withCSS = require('#zeit/next-css');
const withSass = require('#zeit/next-sass');
const withImages = require('next-images');
const optimizedImages = require('next-optimized-images');
const withOffline = require('next-offline');
module.exports = withOffline(
withImages(
optimizedImages(
withCSS(
withSass({
// useFileSystemPublicRoutes: false,
// generateSw: false, // this allows all your workboxOpts to be passed in injectManifest
generateInDevMode: true,
workboxOpts: {
swDest: './service-worker.js', // this is the important part,
exclude: [/.+error\.js$/, /\.map$/, /\.(?:png|jpg|jpeg|svg)$/],
runtimeCaching: [
{
urlPattern: /\.(?:png|jpg|jpeg|svg)$/,
handler: 'CacheFirst',
options: {
cacheName: 'hillfinder-images'
}
},
{
urlPattern: /^https?.*/,
handler: 'NetworkFirst',
options: {
cacheName: 'hillfinder-https-calls',
networkTimeoutSeconds: 15,
expiration: {
maxEntries: 150,
maxAgeSeconds: 30 * 24 * 60 * 60 // 1 month
},
cacheableResponse: {
statuses: [0, 200]
}
}
}
]
},
dontAutoRegisterSw: false,
env: {
MAPBOX_ACCESS_TOKEN: process.env.MAPBOX_ACCESS_TOKEN,
useFileSystemPublicRoutes: false
},
webpack(config, options) {
config.module.rules.push({
test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
use: {
loader: 'url-loader',
options: {
limit: 100000,
target: 'serverless'
}
}
});
return config;
}
})
)
)
)
);
Also when I check the Application pane, in devTools I see this:
You'll notice what appears to me a duplication of fields i.e. https-calls and hillfinder-https-calls and images and hillfinder-images.
I thought the cacheName field in the options: {} in each was allowing one to include a custom name?
Just wondering if anyone has had experience setting this up?
Thank you in advance!
(These comments apply to the basic Workbox build tools, not specifically to the next-offline wrapper, but I think they're still accurate.)
If you're using InjectManifest mode, the idea is that you write all of your service worker logic, using the underlying pieces of Workbox that you need, following a model that's similar to what's described in the Getting Started guide. You should include a call to precacheAndRoute(self.__WB_MANIFEST) somewhere in your service worker, and then the InjectManifest build tool is responsible for swapping out self.__WB_MANIFEST with an array containing the list of URLs to precache, along with revision information for each URL.
The runtimeCaching parameter is not compatible with InjectManifest. It's a parameter that can be used in GenerateSW mode, in with the Workbox build tool creates an entire service worker for you (including runtime caching routes). The GenerateSW mode takes in a declarative configuration and spits out the code for service worker based on that configuration. If that sounds good—if you'd just like to configure some build options and get a complete service worker as a result—then using GenerateSW is the right choice.

Resources