Use of async/await to dynamically import the locales on addLocaleData - javascript

I have an 'external' intl provider because I have to handle some labels outside react components.
I am trying to dynamically load the locales without using require statements and I am having a issue I am not sure why it's happening.
So, the following code works:
//intlProvider.js
import { IntlProvider, addLocaleData } from 'react-intl';
import Locale from '../../../../utils/locale';
const locale = Locale.getLocale();
addLocaleData(require(`react-intl/locale-data/${locale}`));
const messages = Locale.getMessages('prot');
const intlProvider = new IntlProvider({ locale, messages });
const { intl } = intlProvider.getChildContext();
export default intl;
then I read the intl in a sharedMessages.js file:
import { defineMessages } from 'react-intl';
import intl from '../components/i18n/Intl';
const messages = defineMessages({
interest: {
id: 'sharedMessages.rate.label',
defaultMessage: 'Interest',
},
bank: {
id: 'sharedMessages.bank.label',
defaultMessage: 'Bank',
},
});
function prepareSharedMessages() {
const msgsObj = {};
Object.keys(messages).forEach(item => {
msgsObj[item] = intl.formatMessage(messages[item]);
});
return msgsObj;
}
const sharedMessages = prepareSharedMessages();
export default sharedMessages;
The above code works fine, but since I want to get rid of the require statement in this line (as dynamic imports increase the bundle a lot):
addLocaleData(require(`react-intl/locale-data/${locale}`));
I tryed to replace it for:
(async localeCode => {
const localeData = await import(`react-intl/locale-data/${localeCode}`);
addLocaleData(localeData.default);
})(locale);
Expected behavior
I'd expect the locale to be loaded properly, but apparently the application is trying to get it before it should. Since I am using async/await, I'd expect it to be set before the rest of the application tries to use it. (If it was inside react components, I could use componentDidMount to trigger the locale, but how can I achieve this behavior for non react components?)
Current behavior
After replacing the require for the import statement above mentioned, I am getting the react-intl warning:
[React Intl] Missing locale data for locale: "de". Using default
locale: "en" as fallback.
My Environment:
react-intl 2.7.0
react 16.0.0
node 9.10.0
OS: macOS Mojave 10.14
Browser Version: Chrome 71.0.3578.98 (Official Build) (64-bit)

Related

Why is dynamic importing of dayjs not working in typescript?

I am working on a web screen inside a .NET app and I am trying to send date time preference from the system to the web screen using CefSharp settings and setting
AcceptLanguageList = CultureInfo.CurrentUICulture.Name
In my typescript code I want to use dayjs and import dynamically 'dayjs/locale/${language}' where language comes from AcceptLanguageList above.
import React, { useState } from 'react';
import dayjs, { Dayjs } from 'dayjs';
import localeData from 'dayjs/plugin/localeData';
dayjs.extend(localeData);
var lang = navigator.languages != null ? navigator.languages[0] : navigator.language;
lang = lang.toLowerCase();
import(`dayjs/locale/${lang}`).then(
() => {
dayjs.locale(lang);
setAdapterLocale(lang);
});
The thing is, when I run this code in browser and try to import 'dayjs/locale/fr-ca', for example, it works fine, but when 'fr-ca' comes from CefSharp, then the import fails with
Uncaught (in promise) TypeError: Failed to resolve module specifier
'dayjs/locale/fr-ca'
Any help is much appreciated.
If you want to use a dynamic path for the dynamic import then you'll first have to list all of the possible paths that you will potentially want to have, otherwise your bundler wont know which files to include.
You can add import('dayjs/locale/fr-ca') anywhere in your code and the bundler will include it when it builds your app for the browser.
And you'll still going to get that error if you don't have a locale for user's language, so you should catch that case:
import(`dayjs/locale/${lang}`).then(
() => {
dayjs.locale(lang);
setAdapterLocale(lang);
},
() => { // in case the import fails
// maybe default to english
dayjs.locale('en');
setAdapterLocale('en');
});
I figured it out. The problem was that when building the package for the .net app, the package was created using rollup (which is not the case when running in browser).
Rollup needs some special config to support dynamic import:
https://www.npmjs.com/package/#rollup/plugin-dynamic-import-vars

Determine javascript framework based on importation

I am writing a python script that determine the type of javascript framework used in file, I am having issue in detecting when whether the code is node.js file or react.js file. I tried detecting via importation , so far when I have import React from 'react'; I know directly it is react file , but the problem is when we don't have react importation but the file is part of react project ( for eg file contain reducer, hooks) and I have have othe importation, my idea is to to check whether that importation is react , the problem is even if I check npm registry it don't give me info about whether the package is for node.js apps or for react or other. For example this code ,how can I determine whetehr it is node or react or other ?
import { GraphQLScalarType } from 'graphql';
import { Kind } from 'graphql/language';
const LowercaseString = new GraphQLScalarType({
name: 'LowercaseString',
description: 'Returns all strings in lower case',
parseValue(value) {
return value.toLowerCase();
},
serialize(value) {
return value.toLowerCase();
},
parseLiteral(ast) {
if (ast.kind === Kind.STRING) {
return ast.value.toLowerCase();
}
return null;
},
});
export default LowercaseString;

NextJS i18n - Locale getting undefined

I'm trying to migrate my website to NextJS, and I'm having trouble to do some internationalization.
I'm following the tutorial from Documentation itself, but my locale in the inspector is coming up as undefined.
What i'm doing wrong?
I'm using the latest version of nextJS.
Im trying to get some info from console.log.
console.log("Locale: " + locale);
console.log(router);
and it prints:
next.config.js
module.exports = {
i18n: {
locales: ['en-US', 'pt-BR'],
defaultLocale: 'pt-BR',
},
}
/pages/index.js
import Head from 'next/head'
import { useRouter } from 'next/router'
import pt from '../locale/index/pt'
import en from '../locale/index/en'
export default function Home() {
const router = useRouter();
const { locale } = router;
const t = locale === 'pt' ? pt : en;
return (
<div className="container">
<Head>
<title>{t.title}</title>
</Head>
</div>
)
}
/locale/pt.js
export default {
title: "Teste Portugues."
}
/locale/en.js
export default {
title: "Test English"
}
Some random info:
NextJS Version: 12.0.4
Chrome Version: 96.0.4664.55
Node Version: 17.0.1
UPDATE: I did a restart of my computer, and after this, 3 days later, when i use console.log({locale}), it get my pt-BR locale normally.
(And i did nothing more)
So, i'll close the thread. Thanks anyway!
This seems to be a bug in older versions of Next.js. yesterday, I had a similar issue, and after upgrading Next, React, and React-dom to their latest version, it worked like charm!.
Just restart the server. If the next.config.js file is modified, you have to restart your server for the changes to take effect

How can I pre-render a react app in gulp/node?

How can I programmatically render a react app in gulp and node 12?
I taking over and upgrading an old react (0.12.0) app to latest. This also involved upgrading to ES6. The react code itself is done, but we also need to prerender the application (The app is an interactive documentation and must be crawled by search engines).
Previously, the gulp build process ran browserify on the code and then ran it with vm.runInContext:
// source code for the bundle
const component = path.resolve(SRC_DIR + subDir, relComponent);
vm.runInNewContext(
fs.readFileSync(BUILD_DIR + 'bundle.js') + // ugly
'\nrequire("react").renderToString(' +
'require("react").createElement(require(component)))',
{
global: {
React: React,
Immutable: Immutable,
},
window: {},
component: component,
console: console,
}
);
I am suprised it worked before, but it really did. But now it fails, because the source uses ES6.
I looked for pre-made solutions, but they seem all targeting old react versions, where react-tools was still around.
I packaged the special server-side script below with browserify & babel and then ran it using runInNewContext. It does not fail but also not output any code, it just logs an empty object
import React from 'react';
import { renderToString } from 'react-dom/server';
import App from './index';
const content = renderToString(<App />);
I found tons of articles about "server-side rendering", but they all seem to be about rendering with express and use the same lines as the script above. I can't run that code directly in gulp, as it does not play well with ES6 imports, which are only available after node 14 (and are experimental).
I failed to show the gulp-browserify task, which was rendering the app component directly, instead of the server-side entrypoint script above. In case anyone ever needs to do this, here is a working solution.
Using vm.runInNewContext allows us to define a synthetic browser context, which require does not. This is important if you access window anywhere in the app.
src/server.js:
import React from 'react';
import { renderToString } from 'react-dom/server';
import App from './index';
const content = renderToString(<App />);
global.output = content;
above script serves as entry point to browserify. Gulp task to compile:
function gulpJS() {
const sourcePath = path.join(SRC_DIR, 'src/server.js');
return browserify(sourcePath, { debug:true })
.transform('babelify', {
presets: [
["#babel/preset-env", { targets: "> 0.25%, not dead" }],
"#babel/preset-react",
],
})
.bundle()
.pipe(source('server_output.js'))
.pipe(buffer())
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(sourcemaps.write('.'))
.pipe(dest(BUILD_DIR));
}
The generated file can now be used by later tasks, e.g. to insert the rendered content into a HTML file.
const componentContent = fs.readFileSync(path.join(BUILD_DIR, 'server.js'));
const context = {
global: {
React: React,
Immutable: Immutable,
data: {
Immutable
},
},
window: {
addEventListener() { /* fake */ },
removeEventListener() { /* fake */ },
},
console,
};
vm.runInNewContext(componentContent, context);
const result = context.global.output;

Is there any reason to use useIntl hook in react-intl v3.x?

We recently updated react-intl from version 2.x to 3.3.2, which meant that we could remove the injectIntl HOC in all files that used any of the format-functions.
Now in v3, we create the intl instance in a separate module and wrap our app in a RawIntlProvider that we provide with this intl object.
Is there any reason to use the useIntl hook provided by react-intl instead of just importing the intl object straight from our created module?
// useIntl hook
const Component = () => {
const intl = useIntl();
intl.formatMessage({});
};
//How we use it atm.
import intl from 'utils/intl';
const Component = () => {
intl.formatMessage({});
};
If we read the documentation react-intl, only benefit of using it by importing is when you want to customized the hooks. Otherwise the way you are using it I don't see any problems.

Categories