mirror of
https://github.com/facebook/docusaurus.git
synced 2025-04-30 10:48:05 +02:00
Fix: conflicting strings issue in translations (#917)
* Fix conflicting strings issue in translations * Preserve structure of `customTranslations` * Use `deepmerge` to merge whole of `localized-strings` * Simplify and make deep property access on an object safe * Fix deep property accessor and rename it to idx
This commit is contained in:
parent
d18b09954b
commit
cfabaedc99
12 changed files with 94 additions and 66 deletions
|
@ -100,8 +100,16 @@ If you want to add additional custom translation strings, or override any of the
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"localized-strings": {
|
"localized-strings": {
|
||||||
"id": "string",
|
"docs": {
|
||||||
"id2": "string2"
|
"id": {
|
||||||
|
"title": "string1",
|
||||||
|
"sidebar_label": "string2"
|
||||||
|
},
|
||||||
|
"version-0.0.1-id": {
|
||||||
|
"title": "string3",
|
||||||
|
"sidebar_label": "string4"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"pages-strings" : {
|
"pages-strings" : {
|
||||||
"id3": "string3",
|
"id3": "string3",
|
||||||
|
|
|
@ -16,6 +16,7 @@ const DocsSidebar = require('./DocsSidebar.js');
|
||||||
const OnPageNav = require('./nav/OnPageNav.js');
|
const OnPageNav = require('./nav/OnPageNav.js');
|
||||||
const Site = require('./Site.js');
|
const Site = require('./Site.js');
|
||||||
const translation = require('../server/translation.js');
|
const translation = require('../server/translation.js');
|
||||||
|
const {idx} = require('./utils.js');
|
||||||
|
|
||||||
// component used to generate whole webpage for docs, including sidebar/header/footer
|
// component used to generate whole webpage for docs, including sidebar/header/footer
|
||||||
class DocsLayout extends React.Component {
|
class DocsLayout extends React.Component {
|
||||||
|
@ -35,16 +36,15 @@ class DocsLayout extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
const metadata = this.props.metadata;
|
const metadata = this.props.metadata;
|
||||||
const content = this.props.children;
|
const content = this.props.children;
|
||||||
const i18n = translation[this.props.metadata.language];
|
const i18n = translation[metadata.language];
|
||||||
|
const id = metadata.localized_id;
|
||||||
|
const defaultTitle = metadata.title;
|
||||||
let DocComponent = Doc;
|
let DocComponent = Doc;
|
||||||
if (this.props.Doc) {
|
if (this.props.Doc) {
|
||||||
DocComponent = this.props.Doc;
|
DocComponent = this.props.Doc;
|
||||||
}
|
}
|
||||||
const title = i18n
|
const title =
|
||||||
? translation[this.props.metadata.language]['localized-strings'][
|
idx(i18n, ['localized-strings', 'docs', id, 'title']) || defaultTitle;
|
||||||
this.props.metadata.localized_id
|
|
||||||
] || this.props.metadata.title
|
|
||||||
: this.props.metadata.title;
|
|
||||||
const hasOnPageNav = this.props.config.onPageNav === 'separate';
|
const hasOnPageNav = this.props.config.onPageNav === 'separate';
|
||||||
return (
|
return (
|
||||||
<Site
|
<Site
|
||||||
|
@ -65,7 +65,7 @@ class DocsLayout extends React.Component {
|
||||||
content={content}
|
content={content}
|
||||||
config={this.props.config}
|
config={this.props.config}
|
||||||
source={metadata.source}
|
source={metadata.source}
|
||||||
hideTitle={this.props.metadata.hide_title}
|
hideTitle={metadata.hide_title}
|
||||||
title={title}
|
title={title}
|
||||||
version={metadata.version}
|
version={metadata.version}
|
||||||
language={metadata.language}
|
language={metadata.language}
|
||||||
|
@ -79,15 +79,10 @@ class DocsLayout extends React.Component {
|
||||||
metadata.previous_id
|
metadata.previous_id
|
||||||
)}>
|
)}>
|
||||||
←{' '}
|
←{' '}
|
||||||
{i18n
|
{idx(i18n, ['localized-strings', metadata.previous_id]) ||
|
||||||
? translation[this.props.metadata.language][
|
idx(i18n, ['localized-strings', 'previous']) ||
|
||||||
'localized-strings'
|
metadata.previous_title ||
|
||||||
][metadata.previous_id] ||
|
'Previous'}
|
||||||
translation[this.props.metadata.language][
|
|
||||||
'localized-strings'
|
|
||||||
].previous ||
|
|
||||||
'Previous'
|
|
||||||
: metadata.previous_title || 'Previous'}
|
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
{metadata.next_id && (
|
{metadata.next_id && (
|
||||||
|
@ -97,15 +92,10 @@ class DocsLayout extends React.Component {
|
||||||
metadata.localized_id,
|
metadata.localized_id,
|
||||||
metadata.next_id
|
metadata.next_id
|
||||||
)}>
|
)}>
|
||||||
{i18n
|
{idx(i18n, ['localized-strings', metadata.next_id]) ||
|
||||||
? translation[this.props.metadata.language][
|
idx(i18n, ['localized-strings', 'next']) ||
|
||||||
'localized-strings'
|
metadata.next_title ||
|
||||||
][metadata.next_id] ||
|
'Next'}{' '}
|
||||||
translation[this.props.metadata.language][
|
|
||||||
'localized-strings'
|
|
||||||
].next ||
|
|
||||||
'Next'
|
|
||||||
: metadata.next_title || 'Next'}{' '}
|
|
||||||
→
|
→
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
|
@ -113,7 +103,7 @@ class DocsLayout extends React.Component {
|
||||||
</Container>
|
</Container>
|
||||||
{hasOnPageNav && (
|
{hasOnPageNav && (
|
||||||
<nav className="onPageNav">
|
<nav className="onPageNav">
|
||||||
<OnPageNav rawContent={this.props.children} />
|
<OnPageNav rawContent={content} />
|
||||||
</nav>
|
</nav>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -8,13 +8,14 @@
|
||||||
const React = require('react');
|
const React = require('react');
|
||||||
const Head = require('./Head.js');
|
const Head = require('./Head.js');
|
||||||
const translation = require('../server/translation.js');
|
const translation = require('../server/translation.js');
|
||||||
|
const {idx} = require('./utils.js');
|
||||||
|
|
||||||
// Component used to provide same head, header, footer, other scripts to all pages
|
// Component used to provide same head, header, footer, other scripts to all pages
|
||||||
class Redirect extends React.Component {
|
class Redirect extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
const tagline = translation[this.props.language]
|
const tagline =
|
||||||
? translation[this.props.language]['localized-strings'].tagline
|
idx(translation, [this.props.language, 'localized-strings', 'tagline']) ||
|
||||||
: this.props.config.tagline;
|
this.props.config.tagline;
|
||||||
const title = this.props.title
|
const title = this.props.title
|
||||||
? `${this.props.title} · ${this.props.config.title}`
|
? `${this.props.title} · ${this.props.config.title}`
|
||||||
: (!this.props.config.disableTitleTagline &&
|
: (!this.props.config.disableTitleTagline &&
|
||||||
|
|
|
@ -14,15 +14,16 @@ const Head = require('./Head.js');
|
||||||
const Footer = require(`${process.cwd()}/core/Footer.js`);
|
const Footer = require(`${process.cwd()}/core/Footer.js`);
|
||||||
const translation = require('../server/translation.js');
|
const translation = require('../server/translation.js');
|
||||||
const constants = require('./constants');
|
const constants = require('./constants');
|
||||||
|
const {idx} = require('./utils.js');
|
||||||
|
|
||||||
const CWD = process.cwd();
|
const CWD = process.cwd();
|
||||||
|
|
||||||
// Component used to provide same head, header, footer, other scripts to all pages
|
// Component used to provide same head, header, footer, other scripts to all pages
|
||||||
class Site extends React.Component {
|
class Site extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
const tagline = translation[this.props.language]
|
const tagline =
|
||||||
? translation[this.props.language]['localized-strings'].tagline
|
idx(translation, [this.props.language, 'localized-strings', 'tagline']) ||
|
||||||
: this.props.config.tagline;
|
this.props.config.tagline;
|
||||||
const title = this.props.title
|
const title = this.props.title
|
||||||
? `${this.props.title} · ${this.props.config.title}`
|
? `${this.props.title} · ${this.props.config.title}`
|
||||||
: (!this.props.config.disableTitleTagline &&
|
: (!this.props.config.disableTitleTagline &&
|
||||||
|
|
|
@ -22,7 +22,7 @@ const readMetadata = require('../../server/readMetadata.js');
|
||||||
|
|
||||||
readMetadata.generateMetadataDocs();
|
readMetadata.generateMetadataDocs();
|
||||||
const Metadata = require('../metadata.js');
|
const Metadata = require('../metadata.js');
|
||||||
const utils = require('../utils.js');
|
const {idx, getPath} = require('../utils.js');
|
||||||
|
|
||||||
const extension = siteConfig.cleanUrl ? '' : '.html';
|
const extension = siteConfig.cleanUrl ? '' : '.html';
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ class LanguageDropDown extends React.Component {
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<li key={lang.tag}>
|
<li key={lang.tag}>
|
||||||
<a href={utils.getPath(href, this.props.cleanUrl)}>{lang.name}</a>
|
<a href={getPath(href, this.props.cleanUrl)}>{lang.name}</a>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -188,7 +188,7 @@ class HeaderNav extends React.Component {
|
||||||
}
|
}
|
||||||
href =
|
href =
|
||||||
this.props.config.baseUrl +
|
this.props.config.baseUrl +
|
||||||
utils.getPath(Metadata[id].permalink, this.props.config.cleanUrl);
|
getPath(Metadata[id].permalink, this.props.config.cleanUrl);
|
||||||
|
|
||||||
const {id: currentID, sidebar} = this.props.current;
|
const {id: currentID, sidebar} = this.props.current;
|
||||||
docItemActive = currentID && currentID === id;
|
docItemActive = currentID && currentID === id;
|
||||||
|
@ -220,12 +220,11 @@ class HeaderNav extends React.Component {
|
||||||
(link.blog && this.props.current.blogListing) ||
|
(link.blog && this.props.current.blogListing) ||
|
||||||
(link.page && link.page === this.props.current.id),
|
(link.page && link.page === this.props.current.id),
|
||||||
});
|
});
|
||||||
|
const i18n = translation[this.props.language];
|
||||||
return (
|
return (
|
||||||
<li key={`${link.label}page`} className={itemClasses}>
|
<li key={`${link.label}page`} className={itemClasses}>
|
||||||
<a href={href} target={link.external ? '_blank' : '_self'}>
|
<a href={href} target={link.external ? '_blank' : '_self'}>
|
||||||
{translation[this.props.language]
|
{idx(i18n, ['localized-strings', 'links', link.label]) || link.label}
|
||||||
? translation[this.props.language]['localized-strings'][link.label]
|
|
||||||
: link.label}
|
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
|
|
|
@ -10,15 +10,18 @@ const classNames = require('classnames');
|
||||||
|
|
||||||
const siteConfig = require(`${process.cwd()}/siteConfig.js`);
|
const siteConfig = require(`${process.cwd()}/siteConfig.js`);
|
||||||
const translation = require('../../server/translation.js');
|
const translation = require('../../server/translation.js');
|
||||||
const utils = require('../utils.js');
|
const {getPath, idx} = require('../utils.js');
|
||||||
|
|
||||||
class SideNav extends React.Component {
|
class SideNav extends React.Component {
|
||||||
// return appropriately translated category string
|
// return appropriately translated category string
|
||||||
getLocalizedCategoryString(category) {
|
getLocalizedCategoryString(category) {
|
||||||
const categoryString = translation[this.props.language]
|
const categoryString =
|
||||||
? translation[this.props.language]['localized-strings'][category] ||
|
idx(translation, [
|
||||||
category
|
this.props.language,
|
||||||
: category;
|
'localized-strings',
|
||||||
|
'categories',
|
||||||
|
category,
|
||||||
|
]) || category;
|
||||||
return categoryString;
|
return categoryString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,17 +29,16 @@ class SideNav extends React.Component {
|
||||||
getLocalizedString(metadata) {
|
getLocalizedString(metadata) {
|
||||||
let localizedString;
|
let localizedString;
|
||||||
const i18n = translation[this.props.language];
|
const i18n = translation[this.props.language];
|
||||||
|
const id = metadata.localized_id;
|
||||||
const sbTitle = metadata.sidebar_label;
|
const sbTitle = metadata.sidebar_label;
|
||||||
|
|
||||||
if (sbTitle) {
|
if (sbTitle) {
|
||||||
localizedString = i18n
|
localizedString =
|
||||||
? i18n['localized-strings'][sbTitle] || sbTitle
|
idx(i18n, ['localized-strings', 'docs', id, 'sidebar_label']) ||
|
||||||
: sbTitle;
|
sbTitle;
|
||||||
} else {
|
} else {
|
||||||
const id = metadata.original_id || metadata.localized_id;
|
localizedString =
|
||||||
localizedString = i18n
|
idx(i18n, ['localized-strings', 'docs', id, 'title']) || metadata.title;
|
||||||
? i18n['localized-strings'][id] || metadata.title
|
|
||||||
: metadata.title;
|
|
||||||
}
|
}
|
||||||
return localizedString;
|
return localizedString;
|
||||||
}
|
}
|
||||||
|
@ -44,14 +46,14 @@ class SideNav extends React.Component {
|
||||||
// return link to doc in sidebar
|
// return link to doc in sidebar
|
||||||
getLink(metadata) {
|
getLink(metadata) {
|
||||||
if (metadata.permalink) {
|
if (metadata.permalink) {
|
||||||
const targetLink = utils.getPath(metadata.permalink, siteConfig.cleanUrl);
|
const targetLink = getPath(metadata.permalink, siteConfig.cleanUrl);
|
||||||
if (targetLink.match(/^https?:/)) {
|
if (targetLink.match(/^https?:/)) {
|
||||||
return targetLink;
|
return targetLink;
|
||||||
}
|
}
|
||||||
return siteConfig.baseUrl + targetLink;
|
return siteConfig.baseUrl + targetLink;
|
||||||
}
|
}
|
||||||
if (metadata.path) {
|
if (metadata.path) {
|
||||||
return `${siteConfig.baseUrl}blog/${utils.getPath(
|
return `${siteConfig.baseUrl}blog/${getPath(
|
||||||
metadata.path,
|
metadata.path,
|
||||||
siteConfig.cleanUrl
|
siteConfig.cleanUrl
|
||||||
)}`;
|
)}`;
|
||||||
|
|
|
@ -28,9 +28,14 @@ function getPath(pathStr, cleanUrl = false) {
|
||||||
: removeExtension(pathStr);
|
: removeExtension(pathStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function idx(target, path) {
|
||||||
|
return path.reduce((obj, key) => obj && obj[key], target);
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
blogPostHasTruncateMarker,
|
blogPostHasTruncateMarker,
|
||||||
extractBlogPostBeforeTruncate,
|
extractBlogPostBeforeTruncate,
|
||||||
getPath,
|
getPath,
|
||||||
removeExtension,
|
removeExtension,
|
||||||
|
idx,
|
||||||
};
|
};
|
||||||
|
|
|
@ -180,7 +180,7 @@ function generateMetadataDocs() {
|
||||||
|
|
||||||
// metadata for english files
|
// metadata for english files
|
||||||
const docsDir = path.join(CWD, '../', getDocsPath());
|
const docsDir = path.join(CWD, '../', getDocsPath());
|
||||||
let files = glob.sync(`${CWD}/../${getDocsPath()}/**`);
|
let files = glob.sync(`${docsDir}/**`);
|
||||||
files.forEach(file => {
|
files.forEach(file => {
|
||||||
const extension = path.extname(file);
|
const extension = path.extname(file);
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ const fs = require('fs-extra');
|
||||||
const glob = require('glob');
|
const glob = require('glob');
|
||||||
const mkdirp = require('mkdirp');
|
const mkdirp = require('mkdirp');
|
||||||
const nodePath = require('path');
|
const nodePath = require('path');
|
||||||
|
const deepmerge = require('deepmerge');
|
||||||
|
|
||||||
const readMetadata = require('./server/readMetadata.js');
|
const readMetadata = require('./server/readMetadata.js');
|
||||||
|
|
||||||
|
@ -34,12 +35,19 @@ const siteConfig = require(`${CWD}/siteConfig.js`);
|
||||||
const sidebars = require(`${CWD}/sidebars.json`);
|
const sidebars = require(`${CWD}/sidebars.json`);
|
||||||
|
|
||||||
let customTranslations = {
|
let customTranslations = {
|
||||||
'localized-strings': {},
|
'localized-strings': {
|
||||||
|
docs: {},
|
||||||
|
links: {},
|
||||||
|
categories: {},
|
||||||
|
},
|
||||||
'pages-strings': {},
|
'pages-strings': {},
|
||||||
};
|
};
|
||||||
if (fs.existsSync(`${CWD}/data/custom-translation-strings.json`)) {
|
if (fs.existsSync(`${CWD}/data/custom-translation-strings.json`)) {
|
||||||
customTranslations = JSON.parse(
|
customTranslations = deepmerge(
|
||||||
|
JSON.parse(
|
||||||
fs.readFileSync(`${CWD}/data/custom-translation-strings.json`, 'utf8')
|
fs.readFileSync(`${CWD}/data/custom-translation-strings.json`, 'utf8')
|
||||||
|
),
|
||||||
|
customTranslations
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,13 +62,20 @@ function execute() {
|
||||||
next: 'Next',
|
next: 'Next',
|
||||||
previous: 'Previous',
|
previous: 'Previous',
|
||||||
tagline: siteConfig.tagline,
|
tagline: siteConfig.tagline,
|
||||||
|
docs: {},
|
||||||
|
links: {},
|
||||||
|
categories: {},
|
||||||
},
|
},
|
||||||
'pages-strings': {},
|
'pages-strings': {},
|
||||||
};
|
};
|
||||||
|
|
||||||
// look through markdown headers of docs for titles and categories to translate
|
// look through markdown headers of docs for titles and categories to translate
|
||||||
const docsDir = nodePath.join(CWD, '../', readMetadata.getDocsPath());
|
const docsDir = nodePath.join(CWD, '../', readMetadata.getDocsPath());
|
||||||
let files = glob.sync(`${CWD}/../${readMetadata.getDocsPath()}/**`);
|
const versionedDocsDir = nodePath.join(CWD, 'versioned_docs');
|
||||||
|
let files = [
|
||||||
|
...glob.sync(`${docsDir}/**`),
|
||||||
|
...glob.sync(`${versionedDocsDir}/**`),
|
||||||
|
];
|
||||||
files.forEach(file => {
|
files.forEach(file => {
|
||||||
const extension = nodePath.extname(file);
|
const extension = nodePath.extname(file);
|
||||||
if (extension === '.md' || extension === '.markdown') {
|
if (extension === '.md' || extension === '.markdown') {
|
||||||
|
@ -75,11 +90,13 @@ function execute() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const metadata = res.metadata;
|
const metadata = res.metadata;
|
||||||
|
const id = metadata.localized_id;
|
||||||
|
|
||||||
translations['localized-strings'][metadata.localized_id] = metadata.title;
|
translations['localized-strings'].docs[id] = {};
|
||||||
|
translations['localized-strings'].docs[id].title = metadata.title;
|
||||||
|
|
||||||
if (metadata.sidebar_label) {
|
if (metadata.sidebar_label) {
|
||||||
translations['localized-strings'][metadata.sidebar_label] =
|
translations['localized-strings'].docs[id].sidebar_label =
|
||||||
metadata.sidebar_label;
|
metadata.sidebar_label;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,7 +104,7 @@ function execute() {
|
||||||
// look through header links for text to translate
|
// look through header links for text to translate
|
||||||
siteConfig.headerLinks.forEach(link => {
|
siteConfig.headerLinks.forEach(link => {
|
||||||
if (link.label) {
|
if (link.label) {
|
||||||
translations['localized-strings'][link.label] = link.label;
|
translations['localized-strings'].links[link.label] = link.label;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -95,7 +112,7 @@ function execute() {
|
||||||
Object.keys(sidebars).forEach(sb => {
|
Object.keys(sidebars).forEach(sb => {
|
||||||
const categories = sidebars[sb];
|
const categories = sidebars[sb];
|
||||||
Object.keys(categories).forEach(category => {
|
Object.keys(categories).forEach(category => {
|
||||||
translations['localized-strings'][category] = category;
|
translations['localized-strings'].categories[category] = category;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -120,7 +137,7 @@ function execute() {
|
||||||
Object.keys(sidebarContent).forEach(sb => {
|
Object.keys(sidebarContent).forEach(sb => {
|
||||||
const categories = sidebarContent[sb];
|
const categories = sidebarContent[sb];
|
||||||
Object.keys(categories).forEach(category => {
|
Object.keys(categories).forEach(category => {
|
||||||
translations['localized-strings'][category] = category;
|
translations['localized-strings'].categories[category] = category;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -170,7 +187,7 @@ function execute() {
|
||||||
translations['pages-strings'],
|
translations['pages-strings'],
|
||||||
customTranslations['pages-strings']
|
customTranslations['pages-strings']
|
||||||
);
|
);
|
||||||
translations['localized-strings'] = Object.assign(
|
translations['localized-strings'] = deepmerge(
|
||||||
translations['localized-strings'],
|
translations['localized-strings'],
|
||||||
customTranslations['localized-strings']
|
customTranslations['localized-strings']
|
||||||
);
|
);
|
||||||
|
|
|
@ -70,6 +70,7 @@
|
||||||
"commander": "^2.16.0",
|
"commander": "^2.16.0",
|
||||||
"crowdin-cli": "^0.3.0",
|
"crowdin-cli": "^0.3.0",
|
||||||
"cssnano": "^3.10.0",
|
"cssnano": "^3.10.0",
|
||||||
|
"deepmerge": "^2.1.1",
|
||||||
"escape-string-regexp": "^1.0.5",
|
"escape-string-regexp": "^1.0.5",
|
||||||
"express": "^4.15.3",
|
"express": "^4.15.3",
|
||||||
"feed": "^1.1.0",
|
"feed": "^1.1.0",
|
||||||
|
|
|
@ -1969,6 +1969,10 @@ deep-is@~0.1.3:
|
||||||
version "0.1.3"
|
version "0.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
|
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
|
||||||
|
|
||||||
|
deepmerge@^2.1.1:
|
||||||
|
version "2.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.1.1.tgz#e862b4e45ea0555072bf51e7fd0d9845170ae768"
|
||||||
|
|
||||||
default-require-extensions@^2.0.0:
|
default-require-extensions@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-2.0.0.tgz#f5f8fbb18a7d6d50b21f641f649ebb522cfe24f7"
|
resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-2.0.0.tgz#f5f8fbb18a7d6d50b21f641f649ebb522cfe24f7"
|
||||||
|
|
Loading…
Add table
Reference in a new issue