Adding i18n support. Fixes #6

This commit is contained in:
Dessalines 2021-03-21 17:12:02 -04:00
parent 5c9bf3ae15
commit 5156537d1a
19 changed files with 300 additions and 149 deletions

1
.gitignore vendored
View file

@ -13,3 +13,4 @@ node_modules
*.log
*.swp
*.orig
src/shared/translations

4
.gitmodules vendored
View file

@ -2,3 +2,7 @@
path = lemmy-docs
url = https://github.com/lemmynet/lemmy-docs
branch = main
[submodule "joinlemmy-translations"]
path = joinlemmy-translations
url = https://github.com/lemmynet/joinlemmy-translations
branch = main

68
generate_translations.js Normal file
View file

@ -0,0 +1,68 @@
const fs = require("fs");
const translationDir = "joinlemmy-translations/translations/";
const outDir = "src/shared/translations/";
fs.mkdirSync(outDir, { recursive: true });
fs.readdir(translationDir, (_err, files) => {
files.forEach(filename => {
const lang = filename.split(".")[0];
try {
const json = JSON.parse(
fs.readFileSync(translationDir + filename, "utf8")
);
let data = `export const ${lang} = {\n translation: {`;
for (const key in json) {
if (key in json) {
const value = json[key].replace(/"/g, '\\"');
data += `\n ${key}: "${value}",`;
}
}
data += "\n },\n};";
const target = outDir + lang + ".ts";
fs.writeFileSync(target, data);
} catch (err) {
console.error(err);
}
});
});
// generate types for i18n keys
const baseLanguage = "en";
fs.readFile(`${translationDir}${baseLanguage}.json`, "utf8", (_, fileStr) => {
const keys = Object.keys(JSON.parse(fileStr));
const data = `import { i18n } from "i18next";
declare module "i18next" {
export type I18nKeys =
${keys.map(key => ` | "${key}"`).join("\n")};
export interface TFunctionTyped {
// basic usage
<
TResult extends TFunctionResult = string,
TInterpolationMap extends Record<string, unknown> = StringMap
>(
key: I18nKeys | I18nKeys[],
options?: TOptions<TInterpolationMap> | string
): TResult;
// overloaded usage
<
TResult extends TFunctionResult = string,
TInterpolationMap extends Record<string, unknown> = StringMap
>(
key: I18nKeys | I18nKeys[],
defaultValue?: string,
options?: TOptions<TInterpolationMap> | string
): TResult;
}
export interface i18nTyped extends i18n {
t: TFunctionTyped;
}
}
`;
fs.writeFileSync(`${outDir}i18next.d.ts`, data);
});

@ -0,0 +1 @@
Subproject commit c6811ee56e38bf38eaa0fb4e9d5b4665f51d92c0

@ -1 +1 @@
Subproject commit 25e104c1cd6f2a2fc5de095314747814d3d0c71d
Subproject commit 322a2a730ccd3835bbb1391d47daeab2a1492f32

View file

@ -7,10 +7,10 @@
"build:dev": "webpack --mode=development",
"build:prod": "webpack --mode=production",
"clean": "yarn run rimraf dist",
"lint": "tsc --noEmit && eslint --report-unused-disable-directives --ext .js,.ts,.tsx src",
"lint": "node generate_translations.js && tsc --noEmit && eslint --report-unused-disable-directives --ext .js,.ts,.tsx src",
"postinstall": "husky install",
"prebuild:dev": "yarn clean",
"prebuild:prod": "yarn clean",
"prebuild:dev": "yarn clean && node generate_translations.js",
"prebuild:prod": "yarn clean && node generate_translations.js",
"start": "yarn build:dev --watch"
},
"repository": "https://github.com/LemmyNet/joinlemmy-site",
@ -23,6 +23,7 @@
"inferno-create-element": "^7.4.8",
"inferno-helmet": "^5.2.1",
"inferno-hydrate": "^7.4.8",
"inferno-i18next": "github:nimbusec-oss/inferno-i18next#semver:^7.4.2",
"inferno-router": "^7.4.8",
"inferno-server": "^7.4.8"
},

View file

@ -1,6 +1,10 @@
import { hydrate } from "inferno-hydrate";
import { BrowserRouter } from "inferno-router";
import { App } from "../shared/components/app";
import { i18n } from "../shared/i18next";
// Setting the language for js browsers
i18n.changeLanguage(navigator.language);
const wrapper = (
<BrowserRouter>

View file

@ -7,6 +7,7 @@ import { App } from "../shared/components/app";
// import { routes } from "../shared/routes";
import process from "process";
import { Helmet } from "inferno-helmet";
import { i18n } from "../shared/i18next";
const server = express();
const port = 1234;
@ -21,6 +22,12 @@ server.get("/*", async (req, res) => {
// const activeRoute = routes.find(route => matchPath(req.path, route)) || {};
const context = {} as any;
// Setting the language for non-js browsers
let lang = req.headers["accept-language"]
? req.headers["accept-language"].split(",")[0]
: "en";
i18n.changeLanguage(lang);
const wrapper = (
<StaticRouter location={req.url} context={context}>
<App />

View file

@ -1,5 +1,7 @@
import { Component } from "inferno";
import { Route, Switch } from "inferno-router";
import { Provider } from "inferno-i18next";
import { i18n } from "../i18next";
import { routes } from "../routes";
import { NoMatch } from "./no-match";
import { Symbols } from "./symbols";
@ -15,6 +17,7 @@ export class App extends Component<any, any> {
return (
<>
<div>
<Provider i18next={i18n}>
<Navbar />
<Switch>
{routes.map(({ path, exact, component: C, ...rest }) => (
@ -29,6 +32,7 @@ export class App extends Component<any, any> {
</Switch>
<Footer />
<Symbols />
</Provider>
</div>
</>
);

View file

@ -1,8 +1,9 @@
import { Component } from "inferno";
import { AppDetails } from "./app-details";
import { Helmet } from "inferno-helmet";
import { i18n } from "../i18next";
const title = "Lemmy - Apps and Libraries";
const title = i18n.t("apps_title");
export class Apps extends Component<any, any> {
constructor(props: any, context: any) {
@ -15,8 +16,8 @@ export class Apps extends Component<any, any> {
<meta property={"title"} content={title} />
</Helmet>
<div class="container">
<h1>Lemmy Apps</h1>
<p>Choose from any of the apps below.</p>
<h1>{i18n.t("lemmy_apps")}</h1>
<p>{i18n.t("choose_from_apps")}</p>
<div class="row">
<div class="card col-6">
@ -66,7 +67,7 @@ export class Apps extends Component<any, any> {
</div>
</div>
<h1>Web Apps</h1>
<h1>{i18n.t("web_apps")}</h1>
<div class="row">
<div class="card col-6">
@ -100,7 +101,7 @@ export class Apps extends Component<any, any> {
</div>
</div>
<h1>Lemmy API Libraries</h1>
<h1>{i18n.t("api_libraries")}</h1>
<ul>
<li>
<a href="https://github.com/LemmyNet/lemmy-js-client">

View file

@ -1,7 +1,8 @@
import { Component } from "inferno";
import { Helmet } from "inferno-helmet";
import { i18n } from "../i18next";
const title = "Lemmy - Contact";
const title = i18n.t("contact_title");
export class Contact extends Component<any, any> {
constructor(props: any, context: any) {
@ -14,8 +15,7 @@ export class Contact extends Component<any, any> {
<meta property={"title"} content={title} />
</Helmet>
<div class="container">
<h1>Contact</h1>
<h1>{i18n.t("contact")}</h1>
<ul>
<li>
<a href="https://mastodon.social/@LemmyDev">Mastodon</a>

View file

@ -1,4 +1,7 @@
import { Component } from "inferno";
import { Link } from "inferno-router";
import { i18n } from "../i18next";
import { T } from "inferno-i18next";
export class DonateLines extends Component<any, any> {
constructor(props: any, context: any) {
@ -8,20 +11,19 @@ export class DonateLines extends Component<any, any> {
return (
<>
<p>
Lemmy is free, open-source software, meaning no advertising,
monetizing, or venture capital, ever.{" "}
<a href="/sponsors">Your donations</a> directly support full-time
development of the project.
<T i18nKey="donate_desc">
#<Link to="/sponsors">#</Link>#
</T>
</p>
<div class="row is-horizontal-align">
<div class="col-3">
<a class="button primary" href="https://liberapay.com/Lemmy">
Support on Liberapay
{i18n.t("support_on_liberapay")}
</a>
</div>
<div class="col-3">
<a class="button primary" href="https://www.patreon.com/dessalines">
Support on Patreon
{i18n.t("support_on_patreon")}
</a>
</div>
<div class="col-3">
@ -29,7 +31,7 @@ export class DonateLines extends Component<any, any> {
class="col button primary"
href="https://opencollective.com/lemmy"
>
Support on OpenCollective
{i18n.t("support_on_opencollective")}
</a>
</div>
</div>

View file

@ -1,5 +1,6 @@
import { Component } from "inferno";
import { LinkLine } from "./link-line";
import { T } from "inferno-i18next";
export class Footer extends Component<any, any> {
constructor(props: any, context: any) {
@ -13,17 +14,18 @@ export class Footer extends Component<any, any> {
<nav class="nav">
<div class="nav-left">
<p style="padding-left: 2rem">
Made with
<T i18nKey="footer_desc">
#
<a style="display: inline-block" href="https://infernojs.org">
Inferno
#
</a>
and
<a
style="display: inline-block"
href="https://jenil.github.io/chota"
>
Chota
#
</a>
</T>
</p>
</div>
<div class="nav-right hide-sm hide-md hide-lg">

View file

@ -1,7 +1,8 @@
import { Component } from "inferno";
import { Helmet } from "inferno-helmet";
import { i18n } from "../i18next";
const title = "Lemmy - Join a Server";
const title = i18n.t("join_title");
// TODO wait until new lemmy-instances is written to refactor this
@ -16,8 +17,8 @@ export class Join extends Component<any, any> {
<meta property={"title"} content={title} />
</Helmet>
<div class="container">
<h1>Lemmy servers</h1>
<p>Choose and join a server from the approved servers below.</p>
<h1>{i18n.t("lemmy_servers")}</h1>
<p>{i18n.t("choose_and_join")}</p>
<div class="row">
<div class="card col-6">

View file

@ -1,5 +1,6 @@
import { Component } from "inferno";
import { Link } from "inferno-router";
import { i18n } from "../i18next";
export class LinkLine extends Component<any, any> {
constructor(props: any, context: any) {
@ -8,14 +9,17 @@ export class LinkLine extends Component<any, any> {
render() {
return (
<>
<Link to="/join">Join</Link>
<Link to="/apps">Apps</Link>
<Link to="/sponsors">Sponsors</Link>
<a href="/docs/en/index.html">Docs</a>
<a href="/docs/en/code_of_conduct.html" title="Code of Conduct">
CoC
<Link to="/join">{i18n.t("join")}</Link>
<Link to="/apps">{i18n.t("apps")}</Link>
<Link to="/sponsors">{i18n.t("sponsors")}</Link>
<a href="/docs/en/index.html">{i18n.t("docs")}</a>
<a
href="/docs/en/code_of_conduct.html"
title={i18n.t("code_of_conduct")}
>
{i18n.t("coc")}
</a>
<Link to="/contact">Contact</Link>
<Link to="/contact">{i18n.t("contact")}</Link>
</>
);
}

View file

@ -2,8 +2,10 @@ import { Component } from "inferno";
import { Link } from "inferno-router";
import { Helmet } from "inferno-helmet";
import { DonateLines } from "./donate-lines";
import { i18n } from "../i18next";
import { T } from "inferno-i18next";
const title = "Lemmy - A link aggregator for the fediverse";
const title = i18n.t("lemmy_title");
export class Main extends Component<any, any> {
constructor(props: any, context: any) {
@ -13,7 +15,7 @@ export class Main extends Component<any, any> {
joinServer() {
return (
<Link className="button primary" to="/join">
Join a Server
{i18n.t("join_a_server")}
</Link>
);
}
@ -24,7 +26,7 @@ export class Main extends Component<any, any> {
class="button primary"
href="/docs/en/administration/administration.html"
>
Run a Server
{i18n.t("run_a_server")}
</a>
);
}
@ -38,8 +40,8 @@ export class Main extends Component<any, any> {
<div class="bg-image"></div>
<div class="container">
<div class="text-center">
<h1 class="stylized">Lemmy</h1>
<h4>A link aggregator for the fediverse.</h4>
<h1 class="stylized">{i18n.t("lemmy")}</h1>
<h4>{i18n.t("lemmy_desc")}</h4>
<div class="row is-horizontal-align">
<div class="col-2-lg">{this.joinServer()}</div>
<div class="col-2-lg">{this.runServer()}</div>
@ -51,18 +53,15 @@ export class Main extends Component<any, any> {
<div class="container">
<div class="text-center">
<h2>Follow communities anywhere in the world</h2>
<h2>{i18n.t("follow_communities")}</h2>
<p>
<a href="https://github.com/LemmyNet">Lemmy</a> is similar to
sites like <a href="https://reddit.com">Reddit</a>,{" "}
<a href="https://lobste.rs">Lobste.rs</a>, or{" "}
<a href="https://news.ycombinator.com/">Hacker News</a>: you
subscribe to communities you're interested in, post links and
discussions, then vote and comment on them. Lemmy isn't just a
reddit alternative; its a network of interconnected communities
ran by different people and organizations, all combining to create{" "}
<b>a single, personalized front page</b> of your favorite news,
articles, and memes.{" "}
<T i18nKey="lemmy_long_desc">
#<a href="https://github.com/LemmyNet">#</a>
<a href="https://reddit.com">#</a>
<a href="https://lobste.rs">#</a>
<a href="https://news.ycombinator.com/">#</a>
<b>#</b>
</T>
</p>
<p>{this.joinServer()}</p>
</div>
@ -83,18 +82,15 @@ export class Main extends Component<any, any> {
/>
</header>
<br />
<h4 class="text-center">Open Source</h4>
<h4 class="text-center">{i18n.t("open_source")}</h4>
<p>
Lemmy is and will always remain free,{" "}
<a href="https://github.com/LemmyNet">open source</a>{" "}
software, using the strong{" "}
<a href="https://en.wikipedia.org/wiki/Copyleft">
copyleft
</a>{" "}
<T i18nKey="open_source_desc">
#<a href="https://github.com/LemmyNet">#</a>
<a href="https://en.wikipedia.org/wiki/Copyleft">#</a>
<a href="https://github.com/LemmyNet/lemmy/blob/master/LICENSE">
AGPL License
#
</a>
.
</T>
</p>
</div>
</div>
@ -107,14 +103,15 @@ export class Main extends Component<any, any> {
/>
</header>
<br />
<h4 class="text-center">Blazing Fast</h4>
<h4 class="text-center">{i18n.t("blazing_fast")}</h4>
<p>
Made using some of the fastest frameworks and tools,
including <a href="https://www.rust-lang.org">Rust</a>,{" "}
<a href="https://actix.rs/">Actix</a>,{" "}
<a href="http://diesel.rs/">Diesel</a>,{" "}
<a href="https://infernojs.org">Inferno</a>, and{" "}
<a href="https://www.typescriptlang.org/">Typescript</a>.
<T i18nKey="blazing_fast_desc">
#<a href="https://www.rust-lang.org">#</a>
<a href="https://actix.rs/">#</a>
<a href="http://diesel.rs/">#</a>
<a href="https://infernojs.org">#</a>
<a href="https://www.typescriptlang.org/">#</a>
</T>
</p>
</div>
</div>
@ -127,12 +124,8 @@ export class Main extends Component<any, any> {
/>
</header>
<br />
<h4 class="text-center">Powerful Mod Tools</h4>
<p>
Each server can set its own moderation policy, to help
foster a healthy environment where all can feel comfortable
contributing.
</p>
<h4 class="text-center">{i18n.t("mod_tools")}</h4>
<p>{i18n.t("mod_tools_desc")}</p>
</div>
</div>
</div>
@ -143,18 +136,13 @@ export class Main extends Component<any, any> {
<div class="container">
<div class="text-center">
<h2>Create your own discussion platform</h2>
<h2>{i18n.t("create_discussion_platform")}</h2>
<p>
With Lemmy, you can{" "}
<a href="/docs/en/administration/administration.html">
easily host your own server
</a>
, and all these servers are <i>federated</i> (think email), and
connected to the same universe, called the{" "}
<a href="https://en.wikipedia.org/wiki/Fediverse">Fediverse</a>.
For a link aggregator, this means that someone registered on one
server can subscribe to communities elsewhere, and can have
discussions with people on a completely different server.
<T i18nKey="create_discussion_platform_desc">
#<a href="/docs/en/administration/administration.html">#</a>
<i>#</i>
<a href="https://en.wikipedia.org/wiki/Fediverse">#</a>
</T>
</p>
<p>{this.runServer()}</p>
</div>
@ -167,11 +155,8 @@ export class Main extends Component<any, any> {
<div class="container">
<div class="row">
<div class="col-6">
<h4>Live Updates</h4>
<p>
New comments and posts stream in to your front page and inbox;
No more page refreshes required.
</p>
<h4>{i18n.t("live_updates")}</h4>
<p>{i18n.t("live_updates_desc")}</p>
</div>
<div class="col-6 is-center">
<video height={325} autoPlay loop>
@ -190,48 +175,54 @@ export class Main extends Component<any, any> {
<img height={325} src="/static/assets/images/mobile_pic.webp" />
</div>
<div class="col-6">
<h4 class="is-marginless">More Features</h4>
<h4 class="is-marginless">{i18n.t("more_features")}</h4>
<ul class="is-marginless">
<li>
Self hostable, easy to deploy, via{" "}
<a href="/docs/en/administration/install_docker.html">
Docker
</a>
, or{" "}
<a href="/docs/en/administration/install_ansible.html">
Ansible
</a>
.
<T i18nKey="self_hostable">
#<a href="/docs/en/administration/install_docker.html">#</a>
<a href="/docs/en/administration/install_ansible.html">#</a>
</T>
</li>
<li>Clean, mobile-friendly interface.</li>
<li>User avatar support.</li>
<li>{i18n.t("clean_interface")}</li>
<li>{i18n.t("avatar_support")}</li>
<li>
Full vote scores <code>(+/-)</code> like old Reddit.
<T i18nKey="full_vote_scores">
#<code>#</code>#
</T>
</li>
<li>Themes, including light, dark, and solarized.</li>
<li>{i18n.t("themes_including")}</li>
<li>
Emojis with autocomplete support. Start typing <code>:</code>
<T i18nKey="emojis_autocomplete">
#<code>#</code>
</T>
</li>
<li>
User tagging using <code>@</code>, Community tagging using{" "}
<code>!</code>.
<T i18nKey="user_tagging">
#<code>#</code>
<code>#</code>
</T>
</li>
<li>Integrated image uploading in both posts and comments.</li>
<li>Notifications, including via email.</li>
<li>{i18n.t("integrated_image_uploading")}</li>
<li>{i18n.t("notifications_including")}</li>
<li>
<T i18nKey="i18n_support">
#
<a href="https://weblate.yerbamate.ml/projects/lemmy/lemmy/">
i18n / internationalization support for &gt; 30 languages.
#
</a>
</T>
</li>
<li>
RSS / Atom feeds for <code>All</code>, <code>Subscribed</code>
, <code>Inbox</code>, <code>User</code>, and{" "}
<code>Community</code>.
<T i18nKey="rss_feeds">
#<code>#</code>
<code>#</code>
<code>#</code>
<code>#</code>
<code>#</code>
</T>
</li>
<li>
Can fully erase your data, replacing all posts and comments.
</li>
<li>NSFW post / community support.</li>
<li>{i18n.t("can_fully_erase")}</li>
<li>{i18n.t("nsfw_support")}</li>
</ul>
</div>
</div>
@ -243,7 +234,7 @@ export class Main extends Component<any, any> {
<div class="container">
<div class="text-center">
<h2>
<a href="/sponsors">Support / Donate</a>
<Link to="/sponsors">{i18n.t("support_donate")}</Link>
</h2>
<DonateLines />
</div>

View file

@ -1,8 +1,9 @@
import { Component } from "inferno";
import { Helmet } from "inferno-helmet";
import { DonateLines } from "./donate-lines";
import { i18n } from "../i18next";
const title = "Lemmy - Sponsors";
const title = i18n.t("sponsors_title");
interface LinkedSponsor {
name: string;
@ -40,15 +41,15 @@ export class Sponsors extends Component<any, any> {
</Helmet>
<div class="container">
<div class="text-center">
<h1>Donate to Lemmy</h1>
<h1>{i18n.t("donate_to_lemmy")}</h1>
<DonateLines />
</div>
<hr />
<div class="text-center">
<h2>Sponsors</h2>
<p>Silver Sponsors are those that pledged $40 to Lemmy.</p>
<h2>{i18n.t("sponsors")}</h2>
<p>{i18n.t("silver_sponsors_desc")}</p>
<div class="row is-horizontal-align">
{silverSponsors.map(s => (
<div class="col">
@ -59,7 +60,7 @@ export class Sponsors extends Component<any, any> {
))}
</div>
<br />
<p>General Sponsors are those that pledged $10 to $39 to Lemmy.</p>
<p>{i18n.t("general_sponsors_desc")}</p>
<div class="row is-horizontal-align">
{highlightedSponsors.map(s => (
<div class="col">

29
src/shared/i18next.ts Normal file
View file

@ -0,0 +1,29 @@
import i18next, { i18nTyped } from "i18next";
// Languages
import { en } from "./translations/en";
import { ru } from "./translations/ru";
// https://github.com/nimbusec-oss/inferno-i18next/blob/master/tests/T.test.js#L66
const resources = {
en,
ru,
};
function format(value: any, format: any): any {
return format === "uppercase" ? value.toUpperCase() : value;
}
i18next.init({
debug: false,
// load: 'languageOnly',
// initImmediate: false,
lng: "en", // This is changed later
fallbackLng: "en",
resources,
interpolation: { format },
});
export const i18n = i18next as i18nTyped;
export { resources };

View file

@ -3872,6 +3872,13 @@ html-entities@^1.3.1:
resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.4.0.tgz#cfbd1b01d2afaf9adca1b10ae7dffab98c71d2dc"
integrity sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==
html-parse-stringify2@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/html-parse-stringify2/-/html-parse-stringify2-2.0.1.tgz#dc5670b7292ca158b7bc916c9a6735ac8872834a"
integrity sha1-3FZwtyksoVi3vJFsmmc1rIhyg0o=
dependencies:
void-elements "^2.0.1"
http-cache-semantics@^3.8.0, http-cache-semantics@^3.8.1:
version "3.8.1"
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2"
@ -4089,7 +4096,14 @@ infer-owner@^1.0.4:
resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467"
integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==
inferno-create-element@^7.4.8:
inferno-clone-vnode@^7.4.2:
version "7.4.8"
resolved "https://registry.yarnpkg.com/inferno-clone-vnode/-/inferno-clone-vnode-7.4.8.tgz#fafdb21f86e566f662da7e58ff9be1fc76baff08"
integrity sha512-Un9Saio4TJ+1DFehPd7JuNDJV2Fy2aPhK5hD4zmG+JWLUIphi/nuhbwrlsCNmTTDmOsB7GrqyrXFvOUEKX4YpA==
dependencies:
inferno "7.4.8"
inferno-create-element@^7.4.2, inferno-create-element@^7.4.8:
version "7.4.8"
resolved "https://registry.yarnpkg.com/inferno-create-element/-/inferno-create-element-7.4.8.tgz#77bbf24288645c359cf65b4821a3938c6537eb5e"
integrity sha512-hCkA+RAiqoeWlmmCrb3VIUDV+4lEeLDCI98RcB4HqzAJwjH8dMR4ZeDQO3f9crygPnmSW7r1L0Ykjf0O2oHYFQ==
@ -4112,6 +4126,17 @@ inferno-hydrate@^7.4.8:
dependencies:
inferno "7.4.8"
"inferno-i18next@github:nimbusec-oss/inferno-i18next#semver:^7.4.2":
version "7.4.2"
resolved "https://codeload.github.com/nimbusec-oss/inferno-i18next/tar.gz/54b9be591ccd62c53799ad23e35f17144a62f909"
dependencies:
html-parse-stringify2 "^2.0.1"
inferno "^7.4.2"
inferno-clone-vnode "^7.4.2"
inferno-create-element "^7.4.2"
inferno-shared "^7.4.2"
inferno-vnode-flags "^7.4.2"
inferno-router@^7.4.8:
version "7.4.8"
resolved "https://registry.yarnpkg.com/inferno-router/-/inferno-router-7.4.8.tgz#7268f4ad0e5e3f1ca6df272d80d59594c33759ff"
@ -4129,7 +4154,7 @@ inferno-server@^7.4.8:
dependencies:
inferno "7.4.8"
inferno-shared@7.4.8:
inferno-shared@7.4.8, inferno-shared@^7.4.2:
version "7.4.8"
resolved "https://registry.yarnpkg.com/inferno-shared/-/inferno-shared-7.4.8.tgz#2b554a36683b770339008749096d9704846dd337"
integrity sha512-I0jnqsBcQvGJ7hqZF3vEzspQ80evViCe8joP3snWkPXPElk9WBVGLBHX5tHwuFuXv6wW4zeVVA4kBRAs47B+NQ==
@ -4143,12 +4168,12 @@ inferno-side-effect@^1.1.5:
npm "^5.8.0"
shallowequal "^1.0.1"
inferno-vnode-flags@7.4.8:
inferno-vnode-flags@7.4.8, inferno-vnode-flags@^7.4.2:
version "7.4.8"
resolved "https://registry.yarnpkg.com/inferno-vnode-flags/-/inferno-vnode-flags-7.4.8.tgz#275d70e3c8b2b3f4eb56041cc9b8c832ce1fb26d"
integrity sha512-wOUeO7Aho8VH+s2V2K/53KwS0DtQFgT7TdzPE/s6P26ZIxQj+vt7oTJqzXn+xjRIjnfkTLm2eQ8qfInOWCu1rw==
inferno@7.4.8, inferno@^7.4.8:
inferno@7.4.8, inferno@^7.4.2, inferno@^7.4.8:
version "7.4.8"
resolved "https://registry.yarnpkg.com/inferno/-/inferno-7.4.8.tgz#0d5504753e79903b0e4bbeff76fc11fd0b9ffe92"
integrity sha512-4XwGe5Kd0QkSaM/jqAQWjM0GfDLv+KujcWm5zbIow80G1tOEnZurQqhyF8u6m/HX3SnrCi+njlVdtPKDJXQiDw==
@ -8296,6 +8321,11 @@ verror@1.10.0:
core-util-is "1.0.2"
extsprintf "^1.2.0"
void-elements@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec"
integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=
watchpack@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.1.1.tgz#e99630550fca07df9f90a06056987baa40a689c7"