diff --git a/examples/basics/core/Footer.js b/examples/basics/core/Footer.js index 2aff77ca2c..1cb53c4ab3 100644 --- a/examples/basics/core/Footer.js +++ b/examples/basics/core/Footer.js @@ -8,16 +8,6 @@ const React = require('react'); class Footer extends React.Component { - docUrl(doc, language) { - const baseUrl = this.props.config.baseUrl; - return baseUrl + 'docs/' + (language ? language + '/' : '') + doc; - } - - pageUrl(doc, language) { - const baseUrl = this.props.config.baseUrl; - return baseUrl + (language ? language + '/' : '') + doc; - } - render() { const currentYear = new Date().getFullYear(); return ( @@ -35,19 +25,40 @@ class Footer extends React.Component {
Docs
- + Getting Started (or other categories) - + Guides (or other categories) - + API Reference (or other categories)
Community
- + User Showcase ( class HomeSplash extends React.Component { render() { - let language = this.props.language || ''; + let language = this.props.language || 'en'; return ( diff --git a/lib/core/nav/HeaderNav.js b/lib/core/nav/HeaderNav.js index 7b4adeece7..1532be3b91 100644 --- a/lib/core/nav/HeaderNav.js +++ b/lib/core/nav/HeaderNav.js @@ -11,11 +11,16 @@ const React = require('react'); const fs = require('fs'); 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 ENABLE_TRANSLATION = fs.existsSync(CWD + '/languages.js'); +const ENABLE_VERSIONING = fs.existsSync(CWD + '/versions.json'); +let versions; +if (ENABLE_VERSIONING) { + versions = require(CWD + '/versions.json'); +} const readMetadata = require('../../server/readMetadata.js'); readMetadata.generateMetadataDocs(); const Metadata = require('../metadata.js'); @@ -23,24 +28,26 @@ const Metadata = require('../metadata.js'); // language dropdown nav item for when translations are enabled class LanguageDropDown extends React.Component { render() { - if (!env.translation.enabled) { - return null; - } - + const enabledLanguages = []; let currentLanguage = 'English'; setLanguage(this.props.language); 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 !== this.props.language) - .map(lang => ( + translation['languages'].map(lang => { + if (lang.tag == this.props.language) { + currentLanguage = lang.name; + } + if (lang.tag == this.props.language) { + return; + } + enabledLanguages.push(
  • {lang.name}
  • - )); + ); + }); // if no languages are enabled besides English, return null if (enabledLanguages.length < 1) { return null; @@ -119,14 +126,17 @@ class HeaderNav extends React.Component { ); } else if (link.doc) { // set link to document with current page's language/version - const langPart = env.translation.enabled ? this.props.language + '-' : ''; - const versionPart = - env.translation.enabled && this.props.version !== 'next' - ? '-version-' + - (this.props.version || env.versioning.latestVersion) + - '-' - : ''; - const id = langPart + versionPart + link.doc; + let id; + if (!ENABLE_VERSIONING || this.props.version === 'next') { + id = this.props.language + '-' + link.doc; + } else { + id = + this.props.language + + '-version-' + + (this.props.version || versions[0]) + + '-' + + link.doc; + } if (!Metadata[id]) { if (id != link.doc) { throw new Error( @@ -143,13 +153,9 @@ class HeaderNav extends React.Component { href = this.props.config.baseUrl + Metadata[id].permalink; } 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'; + siteConfig.baseUrl + this.props.language + '/' + link.page + '.html'; } else { href = siteConfig.baseUrl + link.page + '.html'; } @@ -174,7 +180,7 @@ class HeaderNav extends React.Component { render() { const versionsLink = this.props.baseUrl + - (env.translation.enabled + (ENABLE_TRANSLATION ? this.props.language + '/versions.html' : 'versions.html'); return ( @@ -192,9 +198,9 @@ class HeaderNav extends React.Component {

    {this.props.title}

    )} - {env.versioning.enabled && ( + {ENABLE_VERSIONING && ( -

    {this.props.version || env.versioning.latestVersion}

    +

    {this.props.version || versions[0]}

    )} {this.renderResponsiveNav()} diff --git a/lib/server/env.js b/lib/server/env.js deleted file mode 100644 index afe7563582..0000000000 --- a/lib/server/env.js +++ /dev/null @@ -1,68 +0,0 @@ -/** - * 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 fs = require('fs-extra'); -const path = require('path'); - -const join = path.join; - -const languages_js = join(CWD, 'lanauages.js'); -const translation_js = join(CWD, 'translation.js'); -const versions_json = join(CWD, 'versions.json'); - -class Translation { - constructor() { - this.enabled = false; - this.languages = [ - { - enabled: true, - name: 'English', - tag: 'en', - }, - ]; - - this._load(); - } - - enabledLanguages() { - return this.languages.filter(lang => lang.enabled); - } - - _load() { - if (fs.existsSync(languages_js)) { - this.enabled = true; - this.languages = require(language_js); - this.translation = require(translation_js); - } - } -} - -class Versioning { - constructor() { - this.enabled = false; - this.latestVersion = null; - this.versions = []; - - this._load(); - } - - _load() { - if (fs.existsSync(versions_json)) { - this.enabled = true; - this.versions = JSON.parse(fs.readFileSync(versions_json, 'utf8')); - this.latestVersion = this.versions[0]; - } - } -} - -const env = { - translation: new Translation(), - versioning: new Versioning(), -}; - -module.exports = env; diff --git a/lib/server/generate.js b/lib/server/generate.js index 85389c7b42..d71e74627c 100644 --- a/lib/server/generate.js +++ b/lib/server/generate.js @@ -20,15 +20,30 @@ function execute() { const glob = require('glob'); const chalk = require('chalk'); const Site = require('../core/Site.js'); - const env = require('./env.js'); const siteConfig = require(CWD + '/siteConfig.js'); const translate = require('./translate.js'); + const versionFallback = require('./versionFallback.js'); const feed = require('./feed.js'); const sitemap = require('./sitemap.js'); const join = path.join; + const ENABLE_TRANSLATION = fs.existsSync(join(CWD, 'languages.js')); + const ENABLE_VERSIONING = fs.existsSync(join(CWD, 'versions.json')); + + let languages; + if (ENABLE_TRANSLATION) { + languages = require(CWD + '/languages.js'); + } else { + languages = [ + { + enabled: true, + name: 'English', + tag: 'en', + }, + ]; + } // create the folder path for a file if it does not exist, then write the file function writeFileAndCreateFolder(file, content) { mkdirp.sync(file.replace(new RegExp('/[^/]*$'), '')); @@ -72,9 +87,10 @@ function execute() { console.log('generate.js triggered...'); // array of tags of enabled languages - const enabledLanguages = env.translation - .enabledLanguages() - .map(lang => lang.tag); + const enabledLanguages = []; + languages.filter(lang => lang.enabled).map(lang => { + enabledLanguages.push(lang.tag); + }); readMetadata.generateMetadataDocs(); const Metadata = require('../core/metadata.js'); @@ -118,7 +134,7 @@ function execute() { // determine what file to use according to its id let file; if (metadata.original_id) { - if (env.translation.enabled && metadata.language !== 'en') { + if (ENABLE_TRANSLATION && metadata.language !== 'en') { file = join(CWD, 'translated_docs', metadata.language, metadata.source); } else { file = join(CWD, 'versioned_docs', metadata.source); @@ -145,7 +161,12 @@ function execute() { rawContent = insertTableOfContents(rawContent); } - let latestVersion = env.versioning.latestVersion; + let latestVersion; + if (ENABLE_VERSIONING) { + latestVersion = JSON.parse( + fs.readFileSync(join(CWD, 'versions.json'), 'utf8') + )[0]; + } // replace any links to markdown files to their website html links Object.keys(mdToHtml).forEach(function(key, index) { @@ -186,10 +207,7 @@ function execute() { writeFileAndCreateFolder(targetFile, str); // generate english page redirects when languages are enabled - if ( - env.translation.enabled && - metadata.permalink.indexOf('docs/en') !== -1 - ) { + if (ENABLE_TRANSLATION && metadata.permalink.indexOf('docs/en') !== -1) { const redirectComp = ( - - - ); - writeFileAndCreateFolder(targetFile.replace('/en/', '/'), str); } else { // allow for rendering of other files not in pages/en folder - let language = ''; + let language = 'en'; + for (let i = 0; i < langParts.length; i++) { + if (enabledLanguages.indexOf(langParts[i]) !== -1) { + language = langParts[i]; + } + } translate.setLanguage(language); const str = renderToStaticMarkup( ); - writeFileAndCreateFolder(targetFile.replace('/en/', '/'), str); + writeFileAndCreateFolder(targetFile, str); } fs.removeSync(tempFile); } else if (!fs.lstatSync(file).isDirectory()) { @@ -455,6 +469,15 @@ function execute() { } }); + // copy html files in 'en' to base level as well + files = glob.sync(join(buildDir, 'en', '**')); + files.forEach(file => { + let targetFile = file.replace(join(buildDir, 'en'), join(buildDir)); + if (file.match(/\.html$/)) { + fs.copySync(file, targetFile); + } + }); + // Generate CNAME file if a custom domain is specified in siteConfig if (siteConfig.cname) { let targetFile = join(buildDir, 'CNAME'); diff --git a/lib/server/readMetadata.js b/lib/server/readMetadata.js index 501ba5ab80..cf6a066451 100644 --- a/lib/server/readMetadata.js +++ b/lib/server/readMetadata.js @@ -11,12 +11,25 @@ const path = require('path'); const fs = require('fs'); const glob = require('glob'); const chalk = require('chalk'); - -const env = require('./env'); const siteConfig = require(CWD + '/siteConfig.js'); const versionFallback = require('./versionFallback.js'); const escapeStringRegexp = require('escape-string-regexp'); +const ENABLE_VERSIONING = fs.existsSync(CWD + '/versions.json'); + +let languages; +if (fs.existsSync(CWD + '/languages.js')) { + languages = require(CWD + '/languages.js'); +} else { + languages = [ + { + enabled: true, + name: 'English', + tag: 'en', + }, + ]; +} + // Can have a custom docs path. Top level folder still needs to be in directory // at the same level as `website`, not inside `website`. // e.g., docs/whereDocsReallyExist @@ -116,8 +129,11 @@ function processMetadata(file) { '/' + escapeStringRegexp(getDocsPath()) + '/(.*)/.*/' ); + let language = 'en'; const match = regexSubFolder.exec(file); - let language = match ? match[1] : 'en'; + if (match) { + language = match[1]; + } const metadata = result.metadata; const rawContent = result.rawContent; @@ -133,20 +149,28 @@ function processMetadata(file) { metadata.title = metadata.id; } - const langPart = - env.translation.enabled || siteConfig.useEnglishUrl ? language + '/' : ''; - let versionPart = ''; - if (env.versioning.enabled) { - metadata.version = 'next'; - versionPart = 'next/'; + if (languages.length === 1 && !siteConfig.useEnglishUrl) { + metadata.permalink = 'docs/' + metadata.id + '.html'; + } else { + metadata.permalink = 'docs/' + language + '/' + metadata.id + '.html'; } - metadata.permalink = 'docs/' + langPart + versionPart + metadata.id + '.html'; + if (ENABLE_VERSIONING) { + metadata.version = 'next'; + if (languages.length === 1 && !siteConfig.useEnglishUrl) { + metadata.permalink = metadata.permalink.replace('docs/', 'docs/next/'); + } else { + metadata.permalink = metadata.permalink.replace( + 'docs/' + language + '/', + 'docs/' + language + '/next/' + ); + } + } // change ids previous, next metadata.localized_id = metadata.id; - metadata.id = (env.translation.enabled ? language + '-' : '') + metadata.id; - metadata.language = env.translation.enabled ? language : 'en'; + metadata.id = language + '-' + metadata.id; + metadata.language = language; const order = readSidebar(); const id = metadata.localized_id; @@ -157,13 +181,11 @@ function processMetadata(file) { if (order[id].next) { metadata.next_id = order[id].next; - metadata.next = - (env.translation.enabled ? language + '-' : '') + order[id].next; + metadata.next = language + '-' + order[id].next; } if (order[id].previous) { metadata.previous_id = order[id].previous; - metadata.previous = - (env.translation.enabled ? language + '-' : '') + order[id].previous; + metadata.previous = language + '-' + order[id].previous; } } @@ -182,9 +204,10 @@ function generateMetadataDocs() { const regexSubFolder = /translated_docs\/(.*)\/.*/; - const enabledLanguages = env.translation - .enabledLanguages() - .map(language => language.tag); + const enabledLanguages = []; + languages.filter(lang => lang.enabled).map(lang => { + enabledLanguages.push(lang.tag); + }); const metadatas = {}; const defaultMetadatas = {}; diff --git a/lib/server/server.js b/lib/server/server.js index ac2dbd3aba..8558b14922 100644 --- a/lib/server/server.js +++ b/lib/server/server.js @@ -9,7 +9,6 @@ function execute(port) { const extractTranslations = require('../write-translations.js'); - const env = require('./env.js'); const translation = require('./translation.js'); const express = require('express'); const React = require('react'); @@ -24,12 +23,15 @@ function execute(port) { const glob = require('glob'); const chalk = require('chalk'); const translate = require('./translate.js'); + const versionFallback = require('./versionFallback'); const feed = require('./feed.js'); const sitemap = require('./sitemap.js'); // const sitemap = require("sitemap"); const CWD = process.cwd(); + const ENABLE_TRANSLATION = fs.existsSync(CWD + '/languages.js'); + const ENABLE_VERSIONING = fs.existsSync(CWD + '/versions.json'); // remove a module and child modules from require cache, so server does not have // to be restarted @@ -166,14 +168,14 @@ function execute(port) { // determine what file to use according to its id let file; if (metadata.original_id) { - if (env.translation.enabled && metadata.language !== 'en') { + if (ENABLE_TRANSLATION && metadata.language !== 'en') { file = CWD + '/translated_docs/' + metadata.language + '/' + metadata.source; } else { file = CWD + '/versioned_docs/' + metadata.source; } } else { - if (!env.translation.enabled || metadata.language === 'en') { + if (metadata.language === 'en') { file = CWD + '/../' + readMetadata.getDocsPath() + '/' + metadata.source; } else { @@ -195,7 +197,12 @@ function execute(port) { rawContent = insertTableOfContents(rawContent); } - let latestVersion = env.latestVersion; + let latestVersion; + if (ENABLE_VERSIONING) { + latestVersion = JSON.parse( + fs.readFileSync(CWD + '/versions.json', 'utf8') + )[0]; + } // replace any links to markdown files to their website html links Object.keys(mdToHtml).forEach(function(key, index) { @@ -376,21 +383,21 @@ function execute(port) { file = file.replace(siteConfig.baseUrl, ''); let userFile = CWD + '/pages/' + file; - let language = ''; + let language = 'en'; const regexLang = /(.*)\/.*\.html$/; const match = regexLang.exec(req.path); const parts = match[1].split('/'); - const enabledLangTags = env.translation - .enabledLanguages() - .map(lang => lang.tag); - + const enabledLangTags = []; + for (let i = 0; i < translation['languages'].length; i++) { + enabledLangTags.push(translation['languages'][i].tag); + } for (let i = 0; i < parts.length; i++) { if (enabledLangTags.indexOf(parts[i]) !== -1) { language = parts[i]; } } let englishFile = CWD + '/pages/' + file; - if (language && language !== 'en') { + if (language !== 'en') { englishFile = englishFile.replace('/' + language + '/', '/en/'); }