mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-01 19:27:48 +02:00
Even if we were on Spanish pages, it still showed English in the Header nav. This makes it so that the Header nav shows the currently selected language.
316 lines
10 KiB
JavaScript
316 lines
10 KiB
JavaScript
/**
|
|
* Copyright (c) 2017-present, Facebook, Inc.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
const CWD = process.cwd();
|
|
|
|
const React = require('react');
|
|
const fs = require('fs');
|
|
const classNames = require('classnames');
|
|
const siteConfig = require(CWD + '/siteConfig.js');
|
|
const translation = require('../../server/translation.js');
|
|
const env = require('../../server/env.js');
|
|
|
|
const translate = require('../../server/translate.js').translate;
|
|
const setLanguage = require('../../server/translate.js').setLanguage;
|
|
|
|
const readMetadata = require('../../server/readMetadata.js');
|
|
readMetadata.generateMetadataDocs();
|
|
const Metadata = require('../metadata.js');
|
|
|
|
// language dropdown nav item for when translations are enabled
|
|
class LanguageDropDown extends React.Component {
|
|
render() {
|
|
setLanguage(this.props.language || 'en');
|
|
let helpTranslateString = translate(
|
|
'Help Translate|recruit community translators for your project'
|
|
);
|
|
// add all enabled languages to dropdown
|
|
const enabledLanguages = env.translation
|
|
.enabledLanguages()
|
|
.filter(lang => lang.tag !== this.props.language)
|
|
.map(lang => (
|
|
<li key={lang.tag}>
|
|
<a href={siteConfig.baseUrl + lang.tag}>{lang.name}</a>
|
|
</li>
|
|
));
|
|
// if no languages are enabled besides English, return null
|
|
if (enabledLanguages.length < 1) {
|
|
return null;
|
|
}
|
|
|
|
// Get the current language full name for display in the header nav
|
|
const currentLanguage = env.translation
|
|
.enabledLanguages()
|
|
.filter(lang => lang.tag === this.props.language)
|
|
.map(lang => lang.name);
|
|
|
|
// add Crowdin project recruiting link
|
|
if (siteConfig.translationRecruitingLink) {
|
|
enabledLanguages.push(
|
|
<li key="recruiting">
|
|
<a
|
|
href={siteConfig.translationRecruitingLink}
|
|
target="_blank"
|
|
rel="noreferrer noopener">
|
|
{helpTranslateString}
|
|
</a>
|
|
</li>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<span>
|
|
<li key="languages">
|
|
<a id="languages-menu" href="#">
|
|
<img
|
|
className="languages-icon"
|
|
src={this.props.baseUrl + 'img/language.svg'}
|
|
/>
|
|
{currentLanguage}
|
|
</a>
|
|
<div id="languages-dropdown" className="hide">
|
|
<ul id="languages-dropdown-items">{enabledLanguages}</ul>
|
|
</div>
|
|
</li>
|
|
<script
|
|
dangerouslySetInnerHTML={{
|
|
__html: `
|
|
const languagesMenuItem = document.getElementById("languages-menu");
|
|
const languagesDropDown = document.getElementById("languages-dropdown");
|
|
languagesMenuItem.addEventListener("click", function(){
|
|
if(languagesDropDown.className == "hide") {
|
|
languagesDropDown.className = "visible";
|
|
} else {
|
|
languagesDropDown.className = "hide";
|
|
}
|
|
});
|
|
`,
|
|
}}
|
|
/>
|
|
</span>
|
|
);
|
|
}
|
|
}
|
|
|
|
// header navbar used by all pages generated with docusaurus
|
|
class HeaderNav extends React.Component {
|
|
constructor() {
|
|
super();
|
|
this.state = {
|
|
slideoutActive: false,
|
|
};
|
|
}
|
|
// function to generate each header link, used with each object in siteConfig.headerLinks
|
|
makeLinks(link) {
|
|
let href;
|
|
let docItemActive = false;
|
|
let docGroupActive = false;
|
|
if (link.search && this.props.config.algolia) {
|
|
// return algolia search bar
|
|
return (
|
|
<li className="navSearchWrapper reactNavSearchWrapper" key="search">
|
|
<input
|
|
id="search_input_react"
|
|
type="text"
|
|
placeholder="Search"
|
|
title="Search"
|
|
/>
|
|
</li>
|
|
);
|
|
} else if (link.languages) {
|
|
if (
|
|
env.translation.enabled &&
|
|
env.translation.enabledLanguages().length > 1
|
|
) {
|
|
return (
|
|
<LanguageDropDown
|
|
baseUrl={this.props.baseUrl}
|
|
language={this.props.language}
|
|
key="languagedropdown"
|
|
/>
|
|
);
|
|
} else {
|
|
return null;
|
|
}
|
|
} else if (link.doc) {
|
|
// set link to document with current page's language/version
|
|
const langPart = env.translation.enabled
|
|
? (this.props.language || 'en') + '-'
|
|
: '';
|
|
const versionPart =
|
|
env.versioning.enabled && this.props.version !== 'next'
|
|
? 'version-' +
|
|
(this.props.version || env.versioning.latestVersion) +
|
|
'-'
|
|
: '';
|
|
const id = langPart + versionPart + link.doc;
|
|
if (!Metadata[id]) {
|
|
let errorStr =
|
|
"Processing the following `doc` field in `headerLinks` within `siteConfig.js`: '" +
|
|
link.doc +
|
|
"'";
|
|
if (id === link.doc) {
|
|
errorStr +=
|
|
' It looks like there is no document with that id that exists in your docs directory. Please double check the spelling of your `doc` field and the `id` fields of your docs.';
|
|
} else {
|
|
errorStr +=
|
|
'. Check the spelling of your `doc` field. If that seems sane, and a document in your docs folder exists with that `id` value, \nthen this is likely a bug in Docusaurus.' +
|
|
' Docusaurus thinks one or both of translations (currently set to: ' +
|
|
env.translation.enabled +
|
|
') or versioning (currently set to: ' +
|
|
env.versioning.enabled +
|
|
") is enabled when maybe they should not be. \nThus my internal id for this doc is: '" +
|
|
id +
|
|
"'. Please file an issue for this possible bug on GitHub.";
|
|
}
|
|
throw new Error(errorStr);
|
|
}
|
|
href = this.props.config.baseUrl + Metadata[id].permalink;
|
|
|
|
const {id: currentID, sidebar} = this.props.current;
|
|
docItemActive = currentID && currentID === id;
|
|
docGroupActive = sidebar && sidebar === Metadata[id].sidebar;
|
|
} else if (link.page) {
|
|
// set link to page with current page's language if appropriate
|
|
const language = this.props.language || '';
|
|
if (fs.existsSync(CWD + '/pages/en/' + link.page + '.js')) {
|
|
href =
|
|
siteConfig.baseUrl +
|
|
(language ? language + '/' : '') +
|
|
link.page +
|
|
'.html';
|
|
} else {
|
|
href = siteConfig.baseUrl + link.page + '.html';
|
|
}
|
|
} else if (link.href) {
|
|
// set link to specified href
|
|
href = link.href;
|
|
} else if (link.blog) {
|
|
// set link to blog url
|
|
href = this.props.baseUrl + 'blog';
|
|
}
|
|
const itemClasses = classNames({
|
|
siteNavGroupActive:
|
|
(link.doc && docGroupActive) || (link.blog && this.props.current.blog),
|
|
siteNavItemActive:
|
|
docItemActive ||
|
|
(link.blog && this.props.current.blogListing) ||
|
|
(link.page && link.page === this.props.current.id),
|
|
});
|
|
return (
|
|
<li key={link.label + 'page'} className={itemClasses}>
|
|
<a href={href} target={link.external ? '_blank' : '_self'}>
|
|
{translation[this.props.language]
|
|
? translation[this.props.language]['localized-strings'][link.label]
|
|
: link.label}
|
|
</a>
|
|
</li>
|
|
);
|
|
}
|
|
|
|
render() {
|
|
const versionsLink =
|
|
this.props.baseUrl +
|
|
(env.translation.enabled
|
|
? this.props.language + '/versions.html'
|
|
: 'versions.html');
|
|
return (
|
|
<div className="fixedHeaderContainer">
|
|
<div className="headerWrapper wrapper">
|
|
<header>
|
|
<a
|
|
href={
|
|
this.props.baseUrl +
|
|
(env.translation.enabled ? this.props.language : '')
|
|
}>
|
|
{siteConfig.headerIcon && (
|
|
<img
|
|
className="logo"
|
|
src={this.props.baseUrl + siteConfig.headerIcon}
|
|
alt={siteConfig.title}
|
|
/>
|
|
)}
|
|
{!this.props.config.disableHeaderTitle && (
|
|
<h2 className="headerTitle">{this.props.title}</h2>
|
|
)}
|
|
</a>
|
|
{env.versioning.enabled && (
|
|
<a href={versionsLink}>
|
|
<h3>{this.props.version || env.versioning.latestVersion}</h3>
|
|
</a>
|
|
)}
|
|
{this.renderResponsiveNav()}
|
|
</header>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
renderResponsiveNav() {
|
|
const headerLinks = this.props.config.headerLinks;
|
|
// add language drop down to end if location not specified
|
|
let languages = false;
|
|
headerLinks.forEach(link => {
|
|
if (link.languages) {
|
|
languages = true;
|
|
}
|
|
});
|
|
if (!languages) {
|
|
headerLinks.push({languages: true});
|
|
}
|
|
let search = false;
|
|
headerLinks.forEach(link => {
|
|
if (
|
|
link.doc &&
|
|
!fs.existsSync(CWD + '/../' + readMetadata.getDocsPath() + '/')
|
|
) {
|
|
throw new Error(
|
|
"You have 'doc' in your headerLinks, but no '" +
|
|
readMetadata.getDocsPath() +
|
|
"' folder exists one level up from " +
|
|
"'website' folder. Did you run `docusaurus-init` or `npm run examples`? If so, " +
|
|
"make sure you rename 'docs-examples-from-docusaurus' to 'docs'."
|
|
);
|
|
}
|
|
if (link.blog && !fs.existsSync(CWD + '/blog/')) {
|
|
throw new Error(
|
|
"You have 'blog' in your headerLinks, but no 'blog' folder exists in your " +
|
|
"'website' folder. Did you run `docusaurus-init` or `npm run examples`? If so, " +
|
|
"make sure you rename 'blog-examples-from-docusaurus' to 'blog'."
|
|
);
|
|
}
|
|
if (link.page && !fs.existsSync(CWD + '/pages/')) {
|
|
throw new Error(
|
|
"You have 'page' in your headerLinks, but no 'pages' folder exists in your " +
|
|
"'website' folder."
|
|
);
|
|
}
|
|
// We will add search bar to end if location not specified
|
|
if (link.search) {
|
|
search = true;
|
|
}
|
|
});
|
|
if (!search && this.props.config.algolia) {
|
|
headerLinks.push({search: true});
|
|
}
|
|
return (
|
|
<div className="navigationWrapper navigationSlider">
|
|
<nav className="slidingNav">
|
|
<ul className="nav-site nav-site-internal">
|
|
{headerLinks.map(this.makeLinks, this)}
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
HeaderNav.defaultProps = {
|
|
current: {},
|
|
};
|
|
|
|
module.exports = HeaderNav;
|