add translation

This commit is contained in:
muhammadeko 2022-05-06 06:39:24 +07:00
parent 083623681f
commit b5fb66d917
No known key found for this signature in database
GPG Key ID: 51366716C10E98B1
9 changed files with 185 additions and 17 deletions

View File

@ -17,10 +17,14 @@
"autoprefixer": "^10.4.5",
"axios": "^0.27.2",
"fs": "^0.0.1-security",
"i18next": "^21.6.16",
"i18next-browser-languagedetector": "^6.1.4",
"i18next-http-backend": "^1.4.0",
"lodash": "^4.17.21",
"postcss": "^8.4.12",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-i18next": "^11.16.8",
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.1",
"react-select-search": "^3.0.9",

View File

@ -5,9 +5,7 @@
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
<meta name="description" content="Grasscutter tools"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
@ -24,7 +22,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
<title>Grasscutter tools</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>

View File

@ -0,0 +1,44 @@
{
"navigation": "Artifact",
"title": "Artifact Command Generator",
"fill_details": "Please fill in the details",
"uid": "UID",
"name": "Artifact Name",
"main_stats": "Main Stats",
"sub_stats": "Sub Stats",
"enhancement_level": "Enhancement Level",
"FIGHT_PROP_HP": "HP",
"FIGHT_PROP_HP_PERCENT": "HP %",
"FIGHT_PROP_ATTACK": "ATK",
"FIGHT_PROP_ATTACK_PERCENT": "ATK %",
"FIGHT_PROP_DEFENSE": "DEF",
"FIGHT_PROP_DEFENSE_PERCENT": "DEF %",
"FIGHT_PROP_CHARGE_EFFICIENCY": "Energy Recharge",
"FIGHT_PROP_ELEMENT_MASTERY": "Elemental Mastery",
"FIGHT_PROP_FIRE_SUB_HURT": "Pyro RES",
"FIGHT_PROP_ELEC_SUB_HURT": "Electro RES",
"FIGHT_PROP_WATER_SUB_HURT": "Hydro RES",
"FIGHT_PROP_ICE_SUB_HURT": "Cryo RES",
"FIGHT_PROP_WIND_SUB_HURT": "Anemo RES",
"FIGHT_PROP_ROCK_SUB_HURT": "Geo RES",
"FIGHT_PROP_GRASS_SUB_HURT": "Dendro RES",
"FIGHT_PROP_PHYSICAL_SUB_HURT": "Phys RES",
"FIGHT_PROP_CRITICAL": "CRIT Rate",
"FIGHT_PROP_CRITICAL_HURT": "CRIT DMG",
"FIGHT_PROP_HEAL_ADD": "Healing Bonus",
"FIGHT_PROP_FIRE_ADD_HURT": "Pyro DMG Bonus",
"FIGHT_PROP_ELEC_ADD_HURT": "Electro DMG Bonus",
"FIGHT_PROP_WATER_ADD_HURT": "Hydro DMG Bonus",
"FIGHT_PROP_ICE_ADD_HURT": "Cryo DMG Bonus",
"FIGHT_PROP_WIND_ADD_HURT": "Anemo DMG Bonus",
"FIGHT_PROP_ROCK_ADD_HURT": "Geo DMG Bonus",
"FIGHT_PROP_GRASS_ADD_HURT": "Dendro DMG Bonus",
"FIGHT_PROP_PHYSICAL_ADD_HURT": "Physical DMG Bonus",
"FIGHT_PROP_SHIELD_COST_MINUS_RATIO": "Shield Strength",
"FIGHT_PROP_HEALED_ADD": "Incoming Healing Bonus",
"FIGHT_PROP_SKILL_CD_MINUS_RATIO": "CD Reduction",
"FIGHT_PROP_SPEED_PERCENT": "Movement Speed",
"FIGHT_PROP_ADD_HURT": "DMG Bonus",
"FIGHT_PROP_SUB_HURT": "DMG Reduction"
}

View File

@ -5,6 +5,7 @@ import Main from "./components/Main";
import {BrowserRouter} from "react-router-dom";
import Navbar from "./components/Navbar";
import Header from "./components/Header";
import "./i18n";
interface IState{
headerTitle: string;
@ -14,7 +15,7 @@ export default class App extends Component<{},IState>{
constructor(props:{}) {
super(props);
this.state = {
headerTitle: 'Hello World'
headerTitle: 'Hello World',
}
}
@ -36,6 +37,7 @@ export default class App extends Component<{},IState>{
const MainProps = {
handleHeaderTitleChange: this.handleHeaderTitleChange
}
return(
<BrowserRouter>
<Navbar {...NavbarProps}/>

View File

@ -0,0 +1,16 @@
import {useTranslation} from "react-i18next";
export default function LanguageChange() {
const {t, i18n} = useTranslation();
const changeLanguage = async (lang: string) => {
await i18n.changeLanguage(lang);
}
return (
<div className="language-change ml-auto">
<select defaultValue={i18n.language} className="w-full flex-none block shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm border-gray-300 rounded-md" onChange={(e) => changeLanguage(e.target.value)}>
<option value="en-US">English</option>
</select>
</div>
)
}

View File

@ -1,6 +1,10 @@
import React from "react";
import MenuDesktop from "./MenuDesktop";
import MenuMobile from "./MenuMobile";
import {Menu} from "@mui/material";
import i18n from "i18next";
import {useTranslation} from "react-i18next";
import LanguageChange from "./LanguageChange";
class Navbar extends React.Component {
handleHeaderTitleChange;
@ -59,6 +63,7 @@ class Navbar extends React.Component {
<div className="hidden sm:block sm:ml-6 w-full">
<div className="flex w-full">
<MenuDesktop handleHeaderTitleChange={this.handleHeaderTitleChange}/>
<LanguageChange/>
</div>
</div>
</div>
@ -68,6 +73,7 @@ class Navbar extends React.Component {
<div className="hidden sm:hidden" id="mobile-menu">
<div className="px-2 pt2 pb-3 space-y-1">
<MenuMobile handleHeaderTitleChange={this.handleHeaderTitleChange}/>
<LanguageChange/>
</div>
</div>
</nav>

View File

@ -1,8 +1,10 @@
import {ChangeEvent, useEffect, useState} from "react";
import ReliquaryDataProvider, {IReliquaryAffix, IReliquaryMain} from "../providers/ReliquaryDataProvider";
import {Autocomplete, Chip, createFilterOptions, TextField} from "@mui/material";
//@ts-ignore
import _ from "lodash";
import {useTranslation} from "react-i18next";
interface IArtifact {
id: number;
@ -19,6 +21,7 @@ export default function Artifacts() {
const [selectedAffixesAmount, setSelectedAffixesAmount] = useState<Record<number, number>>({});
const [artifactEnhancements, setArtifactEnhancements] = useState(0);
const {t} = useTranslation("artifact");
const [artifactData, setArtifactData] = useState<IArtifact[]>([]);
const [generatedArtifact, setGeneratedArtifact] = useState("/giveart ");
@ -86,7 +89,7 @@ export default function Artifacts() {
};
const getPercent = (affix:IReliquaryAffix)=>{
if (affix.propType.indexOf("PERCENT") !== -1 || affix.propType.indexOf("CRITICAL") !== -1 || affix.propType.indexOf("EFFICIENCY") !== -1 || affix.propType.indexOf("HURT") !== -1) {
if (affix.propType.indexOf("PERCENT") !== -1 || affix.propType.indexOf("CRITICAL") !== -1 || affix.propType.indexOf("EFFICIENCY") !== -1 || affix.propType.indexOf("HURT") !== -1 || affix.propType.indexOf("RATIO") !== -1 || affix.propType.indexOf("ADD") !== -1) {
return parseFloat(String(affix.propValue*100)).toPrecision(3) + "%";
}
return parseInt(String(affix.propValue));
@ -110,14 +113,14 @@ export default function Artifacts() {
<div className="space-y-8 divide-y divide-gray-200 sm:space-y-5">
<div>
<div>
<p className="mt-1 max-w-2xl text-sm text-gray-500">Please fill artifact details</p>
<p className="mt-1 max-w-2xl text-sm text-gray-500">{t('fill_details')}</p>
</div>
<div className="mt-6 sm:mt-5 space-y-6 sm:space-y-5">
<div
className="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5">
<label htmlFor="name"
className="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2">
UID
{t("uid")}
</label>
<div className="mt-1 sm:mt-0 sm:col-span-2">
<input type="text" aria-label="UID" name="uid" id="uid" className="block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm border-gray-300 rounded-md" onChange={(event) => setUid(parseInt(event.target.value))}/>
@ -127,14 +130,14 @@ export default function Artifacts() {
className="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5">
<label htmlFor="description"
className="block text-sm font-medium leading-5 text-gray-700 sm:mt-px sm:pt-2">
Artifact Name
{t('name')}
</label>
<div className="mt-1 sm:mt-0 sm:col-span-2">
<Autocomplete
aria-label="Artifact Name" id="ArtifactName"
className="block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm border-gray-300 rounded-md"
options={artifactData}
getOptionLabel={(option) => option.name}
getOptionLabel={(option) => t(option.name)}
onChange={handleArtifactChange}
renderInput={(params) => <TextField {...params} label="Artifact Name" variant="outlined"/>}
/>
@ -144,7 +147,7 @@ export default function Artifacts() {
className="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5">
<label htmlFor="image"
className="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2">
Main Stats
{t('main_stats')}
</label>
<div className="mt-1 sm:mt-0 sm:col-span-2">
<div
@ -153,7 +156,7 @@ export default function Artifacts() {
aria-label="Artifact Main Stats" id="ArtifactMainStats"
className="block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm border-gray-300 rounded-md"
options={reliquaryMains}
getOptionLabel={(option) => option.propType}
getOptionLabel={(option) => t(option.propType)}
onChange={handleMainStatChange}
renderInput={(params) => <TextField {...params} label="Main Stats" variant="outlined"/>}
/>
@ -164,14 +167,14 @@ export default function Artifacts() {
className="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5">
<label htmlFor="start_date"
className="block text-sm font-medium leading-5 text-gray-700 sm:mt-px sm:pt-2">
Artifact Sub Stats
{t('sub_stats')}
</label>
<div className="mt-1 sm:mt-0 sm:col-span-2 h-48 overflow-auto">
{reliquaryAffixes.map((affix, index) => {
return (
<div key={index} className="flex">
<input type="checkbox" className="mr-4 ml-4 focus:ring-indigo-500 h-4 w-4 mt-1 text-indigo-600 border-gray-300 rounded" value={affix.id} id={"select-"+affix.id} onChange={(e)=>handleAffixSelected(e,false,0)}/>
<label className="flex-grow" htmlFor={"select-"+affix.id}>{affix.propType +" - "+getPercent(affix)}</label>
<label className="flex-grow" htmlFor={"select-"+affix.id}>{t(affix.propType) +" - "+getPercent(affix)}</label>
<input type="number" defaultValue="1" min="1" className="flex-none block shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm border-gray-300 rounded-md" onChange={(e)=>handleAffixSelected(e,true, affix.id)}/>
</div>
);
@ -182,7 +185,7 @@ export default function Artifacts() {
className="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5">
<label htmlFor="start_date"
className="block text-sm font-medium leading-5 text-gray-700 sm:mt-px sm:pt-2">
Artifact Enhancement Level
{t('enhancement_level')}
</label>
<div className="mt-1 sm:mt-0 sm:col-span-2">
<input type="number" defaultValue="1" min="1" max="20" className="w-full flex-none block shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm border-gray-300 rounded-md" onChange={(e)=>setArtifactEnhancements(Number(e.currentTarget.value))}/>

21
src/i18n.ts Normal file
View File

@ -0,0 +1,21 @@
import i18n from 'i18next';
import Backend from 'i18next-http-backend';
import LanguageDetector from 'i18next-browser-languagedetector';
import { initReactI18next } from 'react-i18next';
i18n
.use(Backend)
.use(LanguageDetector)
.use(initReactI18next) // bind react-i18next to the instance
.init({
fallbackLng: 'en-US',
debug: false,
interpolation: {
escapeValue: false, // not needed for react!!
},
ns: ["artifact"],
defaultNS: "",
});
export default i18n;

View File

@ -1018,7 +1018,7 @@
core-js-pure "^3.20.2"
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.2", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
"@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.14.5", "@babel/runtime@^7.14.6", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.2", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
version "7.17.9"
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz"
integrity sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==
@ -3362,6 +3362,13 @@ cosmiconfig@^7.0.0:
path-type "^4.0.0"
yaml "^1.10.0"
cross-fetch@3.1.5:
version "3.1.5"
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f"
integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==
dependencies:
node-fetch "2.6.7"
cross-spawn@^7.0.2, cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz"
@ -4843,7 +4850,7 @@ html-entities@^2.1.0, html-entities@^2.3.2:
resolved "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz"
integrity sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==
html-escaper@^2.0.0:
html-escaper@^2.0.0, html-escaper@^2.0.2:
version "2.0.2"
resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz"
integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==
@ -4861,6 +4868,13 @@ html-minifier-terser@^6.0.2:
relateurl "^0.2.7"
terser "^5.10.0"
html-parse-stringify@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2"
integrity sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==
dependencies:
void-elements "3.1.0"
html-webpack-plugin@^5.5.0:
version "5.5.0"
resolved "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz"
@ -4955,6 +4969,27 @@ human-signals@^2.1.0:
resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz"
integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
i18next-browser-languagedetector@^6.1.4:
version "6.1.4"
resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-6.1.4.tgz#7b087c5edb6f6acd38ef54ede2160ab9cde0108f"
integrity sha512-wukWnFeU7rKIWT66VU5i8I+3Zc4wReGcuDK2+kuFhtoxBRGWGdvYI9UQmqNL/yQH1KogWwh+xGEaIPH8V/i2Zg==
dependencies:
"@babel/runtime" "^7.14.6"
i18next-http-backend@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/i18next-http-backend/-/i18next-http-backend-1.4.0.tgz#e6abef0615316e00837798d2385c13395096f963"
integrity sha512-wsvx7E/CT1pHmBM99Vu57YLJpsrHbVjxGxf25EIJ/6oTjsvCkZZ6c3SA4TejcK5jIHfv9oLxQX8l+DFKZHZ0Gg==
dependencies:
cross-fetch "3.1.5"
i18next@^21.6.16:
version "21.6.16"
resolved "https://registry.yarnpkg.com/i18next/-/i18next-21.6.16.tgz#8cff8c3ba2ffaf8438a8c83fe284083f15cf3941"
integrity sha512-xJlzrVxG9CyAGsbMP1aKuiNr1Ed2m36KiTB7hjGMG2Zo4idfw3p9THUEu+GjBwIgEZ7F11ZbCzJcfv4uyfKNuw==
dependencies:
"@babel/runtime" "^7.17.2"
iconv-lite@0.4.24:
version "0.4.24"
resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz"
@ -6261,6 +6296,13 @@ no-case@^3.0.4:
lower-case "^2.0.2"
tslib "^2.0.3"
node-fetch@2.6.7:
version "2.6.7"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
dependencies:
whatwg-url "^5.0.0"
node-forge@^1:
version "1.3.1"
resolved "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz"
@ -7374,6 +7416,15 @@ react-error-overlay@^6.0.11:
resolved "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz"
integrity sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==
react-i18next@^11.16.8:
version "11.16.8"
resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.16.8.tgz#e71621c16f8f77152e85795a88ba6a371e46687d"
integrity sha512-uuhSuwY0iMOPV9HUsN1OC4cGCrATPvzZ1O8UfvLR+imz/XjPmfDgZM1e4dPS0Suc2+aCQqJ0FmWP891lUkB2Cg==
dependencies:
"@babel/runtime" "^7.14.5"
html-escaper "^2.0.2"
html-parse-stringify "^3.0.1"
react-is@^16.13.1, react-is@^16.7.0:
version "16.13.1"
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
@ -8445,6 +8496,11 @@ tr46@^2.1.0:
dependencies:
punycode "^2.1.1"
tr46@~0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=
tryer@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz"
@ -8652,6 +8708,11 @@ vary@~1.1.2:
resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz"
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
void-elements@3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09"
integrity sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=
w3c-hr-time@^1.0.2:
version "1.0.2"
resolved "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz"
@ -8693,6 +8754,11 @@ web-vitals@^2.1.4:
resolved "https://registry.npmjs.org/web-vitals/-/web-vitals-2.1.4.tgz"
integrity sha512-sVWcwhU5mX6crfI5Vd2dC4qchyTqxV8URinzt25XqVh+bHEPGH4C3NPrNionCP7Obx59wrYEbNlw4Z8sjALzZg==
webidl-conversions@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=
webidl-conversions@^4.0.2:
version "4.0.2"
resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz"
@ -8844,6 +8910,14 @@ whatwg-mimetype@^2.3.0:
resolved "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz"
integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==
whatwg-url@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0=
dependencies:
tr46 "~0.0.3"
webidl-conversions "^3.0.0"
whatwg-url@^7.0.0:
version "7.1.0"
resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz"