NextJS i18next not working with defaultLocale - javascript

I have deployed the website to DigitalOcean, having 3 i18n languages and the default locale definition. Unfortunately, the website's default (index) path https://somewebsite.com does not work and requires using at least one locale from which it supports:
https://somewebsite.com/en
https://somewebsite.com/es
https://somewebsite.com/fi
Here is my next-i18next.config.js configuration.
module.exports = {
i18n: {
defaultLocale: 'en',
locales: ['en', 'es', 'fi']
}
};
Is there a chance this 404 Not Found error somehow be fixed?

Related

How to use __filename in angular library?

I have two angular 13 projects - an application and a library. In both projects I need to use __filename. To do it in the application I use "#angular-builders/custom-webpack:browser" builder with the custom webpack config:
export default (config: webpack.Configuration, options: CustomWebpackBrowserSchema, targetOptions: TargetOptions) => {
config.node = {
__filename: true,
__dirname: true
};
return config;
}
However, I can't find a solution to use __filename in angular library. As I understand webpack is not used in library building.
Could anyone say, how to get __filename in the library, if it is possible.

il8n not working in react app after converting to single spa

After converting a react app to single spa which had il8n implemented I am facing a problem where translation.json cannot be accessed hence not fetching the labels.
Should I modify something in the webpack.config.js to get it right
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import i18nextHttpBackend from "i18next-http-backend";
import Cookies from "js-cookie";
import LanguageDetector from "i18next-browser-languagedetector";
i18n
.use(i18nextHttpBackend)
.use(initReactI18next)
.use(LanguageDetector)
.init({
lng: Cookies.get("locale") || "es",
fallbackLng: "en",
debug: false,
supportedLngs: ["en", "es"],
interpolation: {
escapeValue: false,
},
});
export default i18n;
il8n is imported in App.js
import "./i18n";
Initially before converting to single spa the app was working fine and making a call to
http://localhost:3000/locales/en/translation.json
but after converting the app to single spa the get request would fail.
http://single-spa-playground.org/locales/en/translation.json
I did follow this tutorial https://www.youtube.com/watch?v=W8oaySHuj3Y&list=PLLUD8RtHvsAOhtHnyGx57EYXoaNsxGrTU&index=13 to convert the react app to single spa.
WebPack Config
const { merge } = require("webpack-merge");
const singleSpaDefaults = require("webpack-config-single-spa-react");
const Dotenv = require("dotenv-webpack");
module.exports = (webpackConfigEnv, argv) => {
console.log(webpackConfigEnv);
const defaultConfig = singleSpaDefaults({
orgName: "WHATEVR",
projectName: "WHATEVER",
webpackConfigEnv,
argv,
});
return merge(defaultConfig, {
// modify the webpack config however you'd like to by adding to this object
plugins: [new Dotenv()],
devServer: {
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods":
"GET, POST, PUT, DELETE, PATCH, OPTIONS",
"Access-Control-Allow-Headers":
"X-Requested-With, content-type, Authorization",
},
},
});
};
Tried Solution but still not solved
Reactjs - error loading translation files
The issue is that previously, the React app also served as the server that provided the index.html file along with other static assets (eg. your localized translation json files). In single-spa, that is no longer the case; that is instead now the root-config. You'll need to update your i18next-http-backend loadPath configuration so that the library tries to retrieve them from the right path which is no longer the root url. Without being familiar with what you want to achieve, you have two options:
use __webpack_public_path__ to dynamically create the correct URL to point to the assets served by this microfrontend, eg. loadPath: `${__webpack_public_path__} /locales/{{lng}}/{{ns}}.json`,
if you have a separate i18n service, point the URL to that. This may also require crossDomain and withCredentials depending on how that is also configured.
The answer of #filoxo was very helpful. What didn't help me though was the fact that we needed a public folder outside of src. When deploying my app to s3, it would never add the translation files.
So I moved the locales inside src and used webpack copy plugin to move the file into the dist folder. So setup-wise this looks like this:
Webpack config:
const CopyPlugin = require('copy-webpack-plugin');
plugins: [
new CopyPlugin({
patterns: [
{ from: 'src/assets/locales', to: 'locales' }
]
})
]
i18n Settings:
i18n
.use(Backend)
.use(LanguageDetector)
.use(initReactI18next)
.init({
fallbackLng: 'en',
supportedLngs: ['en', 'de'],
backend: {
loadPath: `${__webpack_public_path__}locales/{{lng}}-translation.json`
}
});
Hope this helps someone who was like me trying to figure out why it wouldn't load the translations.

How to redirect pages/app folder to subdomain in next.js

I search a lot for this on the internet but I don't find any article related to it.
Like I have a folder called pages in the root of my project and below tree is files of it.
| 404.js
| auth.js
| index.js
| _app.js
| _error.js
\---app
index.js
next.js gives default behavior when someone opens project.local:3000 it will openindex.js and project.local:3000/app it will open app/index.js but I want that when someone open app.project.local:3000 it will open app/index.js.
My Hosts file
127.0.0.1 project.local
127.0.0.1 app.project.local
In short
I want to redirect pages/app folder to app.project.local or app.example.com in next.js
Most updated solution
I found the solution while exploring the documentation on redirects.
In your Next.js's root folder, create a vercel.json file and then insert your redirects as object inside redirects array like so:
{
"redirects": [
{ "source": "/blog", "destination": "https://blog.example.com" }
]
}
This will only work on production environment. It should work as intended.
I'm still a noobie in next.js (2nd day learning), but I was searching for subdomain support and I found three solutions on this Github issue: https://github.com/vercel/next.js/issues/5682
Using zones (still no idea how it works)
"Vercel will implement subdomain routing in the near future" (I don't expect to use Vercel in the near future)
(my preferred, but not yet tested) An example using custom servers in Next.js: https://github.com/dcangulo/nextjs-subdomain-example
For #3, see how it was implemented in the server.js file
With the new "middleware" feature of Next.js, you can rewrite it using a function instead of the rewrite object and keep the getStaticProps working.
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { getValidSubdomain } from '#/utils/subdomain';
// RegExp for public files
const PUBLIC_FILE = /\.(.*)$/; // Files
export async function middleware(req: NextRequest) {
// Clone the URL
const url = req.nextUrl.clone();
// Skip public files
if (PUBLIC_FILE.test(url.pathname) || url.pathname.includes('_next')) return;
const host = req.headers.get('host');
const subdomain = getValidSubdomain(host);
if (subdomain) {
// Subdomain available, rewriting
console.log(`>>> Rewriting: ${url.pathname} to /${subdomain}${url.pathname}`);
url.pathname = `/${subdomain}${url.pathname}`;
}
return NextResponse.rewrite(url);
}
You can take a look on nextjs docs about middleware and I've also wrote this medium article with some related content that might help.
NextJS now supports Locales: https://nextjs.org/docs/advanced-features/i18n-routing.
You can specify a locale in your config, e.g. admin and specify the URL like this:
// next.config.js
module.exports = {
i18n: {
// These are all the locales you want to support in
// your application
locales: ['en-US', 'admin', 'nl-NL'],
// This is the default locale you want to be used when visiting
// a non-locale prefixed path e.g. `/hello`
defaultLocale: 'en-US',
// This is a list of locale domains and the default locale they
// should handle (these are only required when setting up domain routing)
// Note: subdomains must be included in the domain value to be matched e.g. "fr.example.com".
domains: [
{
domain: 'example.com',
defaultLocale: 'en-US',
},
{
domain: 'example.nl',
defaultLocale: 'nl-NL',
},
{
domain: 'admin.example.com',
defaultLocale: 'admin',
// an optional http field can also be used to test
// locale domains locally with http instead of https
http: true,
},
],
},
}

Web workers inside a JS library with Rollup

I am building a negamax engine in Typescript that uses Thread.js web-workers. It is a npm library that will be imported by an application built using webpack.
I am using Rollup to build the engine - how can I export the web-worker files so they are copied into the client's build directory as a separate chunk?
There are plugins for that: Alorel/rollup-plugin-web-worker, darionco/rollup-plugin-web-worker-loader
..but I ended up doing it by scratch, using a separate build configuration for the worker(s). This simply gives me more control over the situation.
Attached is the rollup.config.worker.js that I use.
The main rollup.config.mjs imports this file, has its configuration as the first build configuration. The real build config uses #rollup/plugin-replace to inject the worker's hash to the code loading it.
/*
* Rollup config for building web worker(s)
*
* Imported by the main rollup config.
*/
import sizes from '#atomico/rollup-plugin-sizes'
import resolve from '#rollup/plugin-node-resolve'
import replace from '#rollup/plugin-replace'
import { terser } from 'rollup-plugin-terser'
import {dirname} from 'path'
import {fileURLToPath} from 'url'
const myPath = dirname(fileURLToPath(import.meta.url));
const watch = process.env.ROLLUP_WATCH;
const REGION = process.env.REGION;
if (!REGION) throw new Error("'REGION' env.var. not provided");
let loggingAdapterProxyHash;
const catchHashPlugin = {
name: 'my-plugin',
// Below, one can define hooks for various stages of the build.
//
generateBundle(_ /*options*/, bundle) {
Object.keys(bundle).forEach( fileName => {
// filename: "proxy.worker-520aaa52.js"
//
const [_,c1] = fileName.match(/^proxy.worker-([a-f0-9]+)\.js$/) || [];
if (c1) {
loggingAdapterProxyHash = c1;
return;
}
console.warn("Unexpected bundle generated:", fileName);
});
}
};
const pluginsWorker = [
resolve({
mainFields: ["esm2017", "module"],
modulesOnly: true // "inspect resolved files to assert that they are ES2015 modules"
}),
replace({
'env.REGION': JSON.stringify(REGION),
//
preventAssignment: true // to mitigate a console warning (Rollup 2.44.0); remove with 2.45?
}),
//!watch && terser(),
catchHashPlugin,
!watch && sizes(),
];
const configWorker = {
input: './adapters/logging/proxy.worker.js',
output: {
dir: myPath + '/out/worker', // under which 'proxy.worker-{hash}.js' (including imports, tree-shaken-not-stirred)
format: 'es', // "required"
entryFileNames: '[name]-[hash].js', // .."chunks created from entry points"; default is: '[name].js'
sourcemap: true, // have source map even for production
},
plugins: pluginsWorker
}
export default configWorker;
export { loggingAdapterProxyHash }
Using in main config:
replace({
'env.PROXY_WORKER_HASH': () => {
const hash= loggingAdapterProxyHash;
assert(hash, "Worker hash not available, yet!");
return JSON.stringify(hash);
},
//
preventAssignment: true // to mitigate a console warning (Rollup 2.44.0); remove with 2.45?
}),
..and in the Worker-loading code:
const PROXY_WORKER_HASH = env.PROXY_WORKER_HASH; // injected by Rollup build
...
new Worker(`/workers/proxy.worker-${PROXY_WORKER_HASH}.js?...`);
If anyone wants to get a link to the whole repo, leave a message and I'll post it there. It's still in flux.
Edit:
After writing the answer I came across this: Building module web workers for cross browser compatibility with rollup (blog, Jul 2020)
TL;DR If you wish to use EcmaScript Modules for the worker, watch out! Firefox and Safari don't have the support, as of today. source And the Worker constructor needs to be told that the worker source is ESM.

Creating multi language web app with i18n-2 in express

I created an express(node.js) website with two language with i18n-2 module and now i have a problem. i was thinking that if i change a new language except default language, all links in my web site will have /?lang parameter automatically! i18n-2 will do it or myself have to code this feature?
right now if i add /?lang=de by hand, it works but if i back to my websites root, it goes to defalult locale and that parameter removes from the url.
this is my configuration:
I18n.expressBind(app, {
locales: ['en', 'de'],
defaultLocale: 'en',
cookieName: 'locale',
extension: ".json"
});
app.use(function(req, res, next) {
req.i18n.setLocaleFromQuery();
req.i18n.setLocaleFromCookie();
next();
});
In order to perpetuate the selected language you need to install a package called cookie-parser:
npm install --save cookie-parser
Then attach it to the Express application as follows:
var app = require('express')(),
cookieParser = require('coookie-parser'),
i18n2 = require('i18n-2');
app.use(cookieParser());
i18n2.expressBind(app, {
locales: ['en', 'de'],
defaultLocale: 'en',
cookieName: 'locale'
});
app.use(function(req, res, next) {
if (req.query.lang) {
req.i18n.setLocaleFromQuery();
res.cookie(config.locale.cookie, req.i18n.getLocale());
} else {
req.i18n.setLocaleFromCookie();
}
next();
})
This way you can change the language through the lang query parameter and make it permanent using the cookie storage.

Categories