1
0
mirror of https://github.com/Pomax/BezierInfo-2.git synced 2025-08-07 09:17:14 +02:00
This commit is contained in:
Pomax
2017-03-26 11:24:40 -07:00
parent d4b8dcd396
commit 6fcf9c9378
11 changed files with 3813 additions and 192 deletions

3234
lib/site/handlers.js Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -3,11 +3,11 @@
"version": "2.0.0", "version": "2.0.0",
"description": "pomax.github.io/bezierinfo", "description": "pomax.github.io/bezierinfo",
"scripts": { "scripts": {
"localize": "node make-locales", "localize": "node tools/make-locales",
"prebuild": "node buildmark", "prebuild": "node tools/buildmark -- set",
"build": "run-s localize less build:** default", "build": "run-s localize less build:** default",
"default": "node copy-default-locale", "default": "node tools/copy-default-locale",
"postbuild": "node buildmark", "postbuild": "node tools/buildmark -- resolve",
"build:en-GB": "webpack -p", "build:en-GB": "webpack -p",
"build:zh-CN": "cross-env LOCALE=zh-CN webpack -p", "build:zh-CN": "cross-env LOCALE=zh-CN webpack -p",
"build:ja-JP": "cross-env LOCALE=ja-JP webpack -p", "build:ja-JP": "cross-env LOCALE=ja-JP webpack -p",

View File

@@ -0,0 +1,33 @@
/**********************************************************************
*
* This script is a JS handling aggregator that grabs all handler.js
* files defined for any section, and turns it into a giant master
* handler file for later use, keyed on section dir names.
*
**********************************************************************/
var fs = require("fs-extra");
var glob = require('glob');
var path = require("path");
var jsxshim = require("./lib/jsx-shim");
const BASEDIR = path.join(__dirname, "..");
var index = require(path.join(BASEDIR, "components/sections"));
var handlers = [];
Object.keys(index).forEach( section => {
var handlerFile = path.join(BASEDIR, `components/sections/${section}/handler.js`);
if (fs.existsSync(handlerFile)) {
let content = fs.readFileSync(handlerFile).toString();
content = content.replace("module.exports = ","return ");
content = `(function() { ${content} }())`;
let def = ` ${section}: {
handler: ${content}`;
if (content.indexOf('keyHandlingOptions') > -1) { def += `,\n withKeys: true`; }
def += `\n }`;
handlers.push(def);
}
});
var masterFile = `module.exports = {\n${ handlers.join(',\n') }\n};\n`;
fs.writeFileSync(path.join(BASEDIR, "lib/site/handlers.js"), masterFile);

View File

@@ -1,6 +1,8 @@
var fs = require('fs'); var fs = require('fs');
var markfile = '.buildmark'; var markfile = '.buildmark';
if (!fs.existsSync(markfile)) { var resolve = process.argv.indexOf('resolve') > -1;
if (!resolve) {
fs.writeFileSync(markfile, Date.now()); fs.writeFileSync(markfile, Date.now());
} else { } else {
let mark = parseInt(fs.readFileSync(markfile).toString()); let mark = parseInt(fs.readFileSync(markfile).toString());

View File

@@ -1,24 +1,3 @@
var ReactDOMServer = require('react-dom/server');
var marked = require("marked");
var fs = require("fs-extra");
// bundle all content in a specific locale for use by the app
const defaultLocale = "en-GB";
var locale = defaultLocale;
var lpos = process.argv.indexOf('--locale');
if (lpos !== -1) { locale = process.argv[lpos+1]; }
// shim nodejs so that it knows what to do with jsx files: return empty objects.
var Module = require('module');
var originalRequire = Module.prototype.require;
Module.prototype.require = function() {
try {
return originalRequire.apply(this, arguments);
} catch (e) {
return {};
}
};
/** /**
* fix the stupid nonsense inability for markdown parsers to see link * fix the stupid nonsense inability for markdown parsers to see link
* syntax with `)` in the links themselves. * syntax with `)` in the links themselves.
@@ -284,7 +263,7 @@ function performChunking(data, chunks, chunker, moreChunkers) {
* Split data up into "markdown" and "not markdown" parts. * Split data up into "markdown" and "not markdown" parts.
* We'll only run markdown conversion on the markdown parts. * We'll only run markdown conversion on the markdown parts.
*/ */
function chunk(data) { module.exports = function chunk(data) {
var chunks = []; var chunks = [];
var chunkers = [ var chunkers = [
chunkDivs, chunkDivs,
@@ -296,164 +275,4 @@ function chunk(data) {
]; ];
performChunking(data, chunks, chunkLatex,chunkers); performChunking(data, chunks, chunkLatex,chunkers);
return chunks; return chunks;
} };
/**
* turn locale markdown into locale javascript data
*/
function processLocation(loc, fragmentid, number) {
var processed = { data: '', title: `Unknown title (${fragmentid})` };
try {
data = fs.readFileSync(loc).toString();
data = chunk(data).map(block => {
// preserver is simple
if (!block.convert) return block.data;
// markdown conversion is a little more work
let d = marked(block.data.trim());
// serious can we fucking not, please.
d = d.replace('<p></div></p>', '</div>')
.replace(/&amp;/g, '&')
.replace(/&#39;/g, "'")
.replace(/&quot;/g, '"')
// ``` conversion does odd things with <code> tags inside <pre> tags.
d = d.replace(/<pre>(\r?\n)*<code>/g,'<pre>')
.replace(/<\/code>(\r?\n)*<\/pre>/g,'</pre>');
// And then title extraction/rewriting
d = d.replace(/<h1[^>]+>([^<]+)<\/h1>/,function(_,t) {
processed.title = t;
return `<SectionHeader name="${fragmentid}" title="` + t + `"${ number ? ' number="'+number+'"': ''}/>`;
});
return d;
}).join('');
processed.data = data;
} catch (e) {
// console.warn(e);
}
return processed;
}
/**
* Form the content.js file content as a single string for file-writing.
*/
function formContentBundle(locale, content) {
var bcode = JSON.stringify(content, false, 2);
bcode = bcode.replace(/"<section>/g, "function(handler) { return <section>")
.replace(/this\.(\w)/g, "handler.$1")
.replace(/<\/section>"(,?)/g, "</section>; }$1\n")
.replace(/\\"/g,'"')
.replace(/\\n/g,'\n')
.replace(/></g,'>\n<')
.replace(/\\\\/g, '\\');
var bundle = [
`var React = require('react');`,
`var Graphic = require("../../components/Graphic.jsx");`,
`var SectionHeader = require("../../components/SectionHeader.jsx");`,
`var BSplineGraphic = require("../../components/BSplineGraphic.jsx");`,
`var KnotController = require("../../components/KnotController.jsx");`,
`var WeightController = require("../../components/WeightController.jsx");`,
``,
`SectionHeader.locale="${locale}";`,
``,
`module.exports = ${bcode};`,
``
].join('\n');
return bundle;
}
/**
* Process the locale switcher component.
*/
function processLocaleSwitcher(locale, content) {
// We also need to localize the "LocaleSwitcher"
var localeCode = locale;
var loc = `./components/localized/LocaleSwitcher/content.${localeCode}.md`;
if (!fs.existsSync(loc)) {
localeCode = defaultLocale;
loc = `./components/localized/LocaleSwitcher/content.${localeCode}.md`;
}
var key = "locale-switcher";
var processed = processLocation(loc, key);
content[key] = {
locale: localeCode,
title: key,
getContent: "<section>" + processed.data + "</section>"
};
}
/**
* Write a content.js bundle to the filesystem
*/
function writeContentBundle(locale, content) {
var bundle = formContentBundle(locale, content);
// write the content.js file for bundling purposes
var dir = `./locales/${locale}`;
fs.ensureDirSync(dir);
fs.writeFileSync(`${dir}/content.js`, bundle);
// Write the actual locale directory and generate a locale-specific index.html
var html = fs.readFileSync('./index.template.html').toString();
var preface = content.preface.getContent.replace(/<SectionHeader name="preface" title="([^"]+)"\/>/, "<h2>$1</h2>");
html = html.replace("{{ PREFACE }}", preface);
html = html.replace("{{ locale }}", locale);
fs.ensureDirSync(locale);
fs.writeFileSync(`./${locale}/index.html`, html);
}
/**
* Process a single locale, with `en-GB` fallback for missing files.
*/
function processLocale(locale) {
// Get the section map. This will try to load .jsx code, which will fail,
// but the above shim makes a failure simply return an empty object instead.
// This is good: we only care about the keys, not the content.
var index = require("./components/sections");
var sections = Object.keys(index);
var content = { locale };
var processSection = (key, number) => {
// Grab locale file, or defaultLocale file if the chosen locale has
// has no translated content (yet)...
var localeCode = locale;
var loc = `./components/sections/${key}/content.${localeCode}.md`;
if (!fs.existsSync(loc)) {
localeCode = defaultLocale;
loc = `./components/sections/${key}/content.${localeCode}.md`;
}
// Read in the content.{lang}.md file
var processed = processLocation(loc, key, number);
content[key] = {
locale: localeCode,
title: processed.title,
getContent: "<section>" + processed.data + "</section>"
};
};
sections.forEach(processSection);
processLocaleSwitcher(locale, content);
writeContentBundle(locale, content);
}
// find all locales used and generate their respective content dirs
var glob = require('glob');
glob("components/sections/**/content*md", (err, files) => {
var locales = [];
files.forEach(file => {
let locale = file.match(/content\.([^.]+)\.md/)[1];
if (locales.indexOf(locale) === -1) {
locales.push(locale);
}
});
locales.forEach(processLocale);
});

View File

@@ -1,13 +1,15 @@
var fs = require("fs-extra"); var fs = require("fs-extra");
var path = require("path");
const BASEDIR = path.join(__dirname, "..");
// copy the en-GB content as default content // copy the en-GB content as default content
fs.copySync("en-GB/index.html", "index.html"); fs.copySync(path.join(BASEDIR, "en-GB/index.html"), path.join(BASEDIR, "index.html"));
fs.copySync("en-GB/article.js", "article.js"); fs.copySync(path.join(BASEDIR, "en-GB/article.js"), path.join(BASEDIR, "article.js"));
// make sure to remove the `<base>` tag from the index, and replace the JSX "className" with "class" // make sure to remove the `<base>` tag from the index, and replace the JSX "className" with "class"
var html = fs.readFileSync("index.html").toString(); var html = fs.readFileSync(path.join(BASEDIR, "index.html")).toString();
html = html.replace(' <base href="..">\n', ''); html = html.replace(' <base href="..">\n', '');
html = html.replace('className=', 'class='); html = html.replace('className=', 'class=');
html = html.replace('<script src="en-GB/article.js', '<script src="article.js'); html = html.replace('<script src="en-GB/article.js', '<script src="article.js');
html = "<!-- AUTOGENERATED CONTENT, PLEASE EDIT 'index.template.html' INSTEAD! -->\n" + html; html = "<!-- AUTOGENERATED CONTENT, PLEASE EDIT 'index.template.html' INSTEAD! -->\n" + html;
fs.writeFileSync("index.html", html); fs.writeFileSync(path.join(BASEDIR, "index.html"), html);

42
tools/form-index-jsx.js Normal file
View File

@@ -0,0 +1,42 @@
/**********************************************************************
*
* This script is responsible for building the index.js file for each
* section based on whether or not it has a handler, and whether or not
* that handler requires any keyhandling for its interaction.
*
**********************************************************************/
var fs = require("fs-extra");
var glob = require('glob');
var path = require("path");
var jsxshim = require("./lib/jsx-shim");
const BASEDIR = path.join(__dirname, "..");
var index = require(path.join(BASEDIR, "components/sections"));
var handlers = [];
Object.keys(index).forEach( section => {
var handlerFile = path.join(BASEDIR, `components/sections/${section}/handler.js`);
var hasHandler = false;
var withKeys = false;
if (fs.existsSync(handlerFile)) {
hasHandler = true;
let content = fs.readFileSync(handlerFile).toString();
withKeys = (content.indexOf('keyHandlingOptions') > -1);
}
var indexCode = [
hasHandler ? `var handler = require("./handler.js");` : '',
`var generateBase = require("../../generate-base");`,
withKeys ? `var keyHandling = require("../../decorators/keyhandling-decorator.jsx");` : '',
hasHandler ?
withKeys ?
`module.exports = keyHandling(generateBase("${section}", handler));`
:
`module.exports = generateBase("${section}", handler);`
:
`module.exports = generateBase("${section}");`
].filter(l => !!l).join('\n');
console.log('[',section,"]\n", indexCode,'\n');
});

278
tools/lib/chunk.js Normal file
View File

@@ -0,0 +1,278 @@
/**
* fix the stupid nonsense inability for markdown parsers to see link
* syntax with `)` in the links themselves.
*/
function fixMarkDownLinks(data, chunks, chunkMore) {
var next = chunkMore ? chunkMore[0] : false,
otherChunkers = chunkMore ? chunkMore.slice(1) : false,
fixes = [];
data.replace(/\[[^\]]+\]\(/g, function(_match, pos, _fullstring) {
// this is the start of a link. Find the offset at which the next `)`
// is actually the link closer.
var offset = 0;
var start = pos + _match.length;
var complex = false;
for (let d=0, i=start; i<data.length; i++) {
if (data[i] === '(') { d++; complex = true; }
else if (data[i] === ')') { d--; }
if (d<0) { offset = i - start; break; }
}
var end = start + offset;
// we now know the *actual* link length. Safify it.
if (complex) { fixes.push({ start, end, data: data.substring(start,end) }); }
// and return the matched text because we don't want to replace right now.
return _match
});
// let's safify this data, if there was a complex pattern that needs fixin'
if (fixes.length>0) {
fixes.forEach(fix => {
let s = fix.start,
e = fix.end,
newdata = fix.data.replace(/\(/g, '%28').replace(/\)/g, '%29');
// I can't believe I still have to do this in 2017...
data = data.substring(0,s) + newdata + data.substring(e);
});
}
// alright, let "the rest" deal with this data now.
performChunking(data, chunks, next, otherChunkers);
}
/**
* ...
*/
function chunkBSplineGraphicsJSX(data, chunks, chunkMore) {
var p = 0,
next = chunkMore ? chunkMore[0] : false,
otherChunkers = chunkMore ? chunkMore.slice(1) : false,
bgfxTag = '<BSplineGraphic',
bgfxEnd = '/>',
bgfxEnd2 = '</BSplineGraphic>';
while (p !== -1) {
// Let's check a BSplineGraphic tag
let bgfx = data.indexOf(bgfxTag, p);
if (bgfx === -1) {
// No <BSplineGraphic/> block found: we're done here. Parse the remaining
// data for whatever else might be in there.
performChunking(data.substring(p), chunks, next, otherChunkers);
break;
}
// First parse the non-<BSplineGraphic/> data for whatever else might be in there.
performChunking(data.substring(p, bgfx), chunks, next, otherChunkers);
let tail = data.substring(bgfx),
noContent = !!tail.match(/^<BSplineGraphic[^>]+\/>/),
eol;
// Then capture the <BSplineGraphic>...</BSplineGraphic> or <BSplineGraphic .../> block and mark it as "don't convert".
if (noContent) {
eol = data.indexOf(bgfxEnd, bgfx) + bgfxEnd.length;
} else {
eol = data.indexOf(bgfxEnd2, bgfx) + bgfxEnd2.length;
}
chunks.push({ convert: false, type: "bgfx", s:bgfx, e:eol, data: data.substring(bgfx, eol) });
p = eol;
}
}
/**
* ...
*/
function chunkGraphicJSX(data, chunks, chunkMore) {
var p = 0,
next = chunkMore ? chunkMore[0] : false,
otherChunkers = chunkMore ? chunkMore.slice(1) : false,
gfxTag = '<Graphic',
gfxEnd = '/>',
gfxEnd2 = '</Graphic>';
while (p !== -1) {
// Let's check a Graphic tag
let gfx = data.indexOf(gfxTag, p);
if (gfx === -1) {
// No <Graphic/> block found: we're done here. Parse the remaining
// data for whatever else might be in there.
performChunking(data.substring(p), chunks, next, otherChunkers);
break;
}
// First parse the non-<Graphic/> data for whatever else might be in there.
performChunking(data.substring(p, gfx), chunks, next, otherChunkers);
let tail = data.substring(gfx),
noContent = !!tail.match(/^<Graphic[^>]+\/>/),
eol;
// Then capture the <Graphic>...</Graphic> or <Graphic .../> block and mark it as "don't convert".
if (noContent) {
eol = data.indexOf(gfxEnd, gfx) + gfxEnd.length;
} else {
eol = data.indexOf(gfxEnd2, gfx) + gfxEnd2.length;
}
chunks.push({ convert: false, type: "gfx", s:gfx, e:eol, data: data.substring(gfx, eol) });
p = eol;
}
}
/**
* ...
*/
function chunkDivEnds(data, chunks, chunkMore) {
var next = chunkMore ? chunkMore[0] : false,
otherChunkers = chunkMore ? chunkMore.slice(1) : false;
var splt = data.split('</div>');
var dlen = splt.length;
splt.forEach( function(segment, pos) {
performChunking(segment, chunks, next, otherChunkers);
if (pos < dlen-1) {
chunks.push({ convert: false, type: '</div>', s:-1, e:-1, data: '</div>' });
}
});
}
/**
* ...
*/
function chunkTable(data, chunks, chunkMore) {
var p = 0,
next = chunkMore ? chunkMore[0] : false,
otherChunkers = chunkMore ? chunkMore.slice(1) : false,
tableMatch = '\n<table',
tableClosingTag = '</table>\n';
while (p !== -1) {
// Let's check for a <table> tag
let table = data.indexOf(tableMatch, p);
if (table === -1) {
// No tables found: we're done here. Parse the remaining
// data for whatever else might be in there.
performChunking(data.substring(p), chunks, next, otherChunkers);
break;
}
// First parse the non-table data for whatever else might be in there.
performChunking(data.substring(p, table), chunks, next, otherChunkers);
// then mark the table code as no-convert
let eod = data.indexOf(tableClosingTag, table) + tableClosingTag.length;
chunks.push({ convert: false, type: "table", s:table, e:eod, data: data.substring(table, eod) });
p = eod;
}
}
/**
* ...
*/
function chunkDivs(data, chunks, chunkMore) {
var p = 0,
next = chunkMore ? chunkMore[0] : false,
otherChunkers = chunkMore ? chunkMore.slice(1) : false,
divMatch = '\n<div className="',
divEnd = '">\n',
divClosingTag = '</div>\n';
while (p !== -1) {
// Let's check for a <div className="..."> tag
let div = data.indexOf(divMatch, p);
if (div === -1) {
// No div tags found: we're done here. Parse the remaining
// data for whatever else might be in there.
performChunking(data.substring(p), chunks, next, otherChunkers);
break;
}
// First parse the non-div data for whatever else might be in there.
performChunking(data.substring(p, div), chunks, next, otherChunkers);
// Now, if we have a div, there's a few options:
//
// - "figure" contains HTML content, not to be converted
// - "note" contains markdown content, to be converted
// - "howtocode" contains markdown content, to be converted
let className = data.substring(div).match(/className="([^"]+)"/);
if (className !== null) { className = className[1]; }
let eod, type="div";
if (className === "figure" || className === "two-column") {
eod = data.indexOf(divClosingTag, div) + divClosingTag.length;
type += "." + className;
} else {
eod = data.indexOf(divEnd, div) + divEnd.length;
}
chunks.push({ convert: false, type: type, s:div, e:eod, data: data.substring(div, eod) });
p = eod;
}
}
/**
* Split data up into "latex" and "not latex".
* Anything that is not latex might still be "not markdown"
* though, so we hand that data off to additional chunkers
*/
function chunkLatex(data, chunks, chunkMore) {
var p = 0,
next = chunkMore ? chunkMore[0] : false,
otherChunkers = chunkMore ? chunkMore.slice(1) : false,
latexEnd = '\\]';
while (p !== -1) {
// Let's check a LaTeX block
let latex = data.indexOf('\\[', p);
if (latex === -1) {
// No LaTeX block found: we're done here. Parse the remaining
// data for whatever else might be in there.
performChunking(data.substring(p), chunks, next, otherChunkers);
break;
}
// First parse the non-LaTeX data for whatever else might be in there.
performChunking(data.substring(p, latex), chunks, next, otherChunkers);
// Then capture the LaTeX block and mark it as "don't convert"
let eol = data.indexOf(latexEnd, latex) + latexEnd.length;
chunks.push({ convert: false, type: "latex", s:latex, e:eol, data: data.substring(latex, eol) });
p = eol;
}
}
// in-place chunking
function performChunking(data, chunks, chunker, moreChunkers) {
// If there's no further chunking function to run, just
// record this data as a chunk of convertible data.
if (!chunker) {
if (data.trim()!=='') {
chunks.push({ convert: true, data: data });
}
return "early";
}
// otherwise, perform more chunking.
chunker(data, chunks, moreChunkers);
}
/**
* Split data up into "markdown" and "not markdown" parts.
* We'll only run markdown conversion on the markdown parts.
*/
module.exports = function chunk(data) {
var chunks = [];
var chunkers = [
chunkDivs,
chunkDivEnds,
chunkTable,
chunkGraphicJSX,
chunkBSplineGraphicsJSX,
fixMarkDownLinks
];
performChunking(data, chunks, chunkLatex,chunkers);
return chunks;
};

11
tools/lib/jsx-shim.js Normal file
View File

@@ -0,0 +1,11 @@
// shim nodejs so that it "knows" what to do with jsx files:
// namely just return empty objects.
var Module = require('module');
var originalRequire = Module.prototype.require;
Module.prototype.require = function() {
try {
return originalRequire.apply(this, arguments);
} catch (e) {
return {};
}
};

200
tools/make-locales.js Normal file
View File

@@ -0,0 +1,200 @@
/**********************************************************************
*
* This script is a locale aggregator and JSX generator, yielding
* locale-specific node modules that contain the section content
* keyed on section dir names.
*
* 1. find out which sections exist
* 2. find out how many different locales exist
* 3. for each locale:
*
* 1. for each section:
*
* 1. grab the associated locale
* 2. chunk the data for "should be preserved" vs.
* "should be processed as markdown".
* 3. join the chunks back up after converting the
* still acknowledged as markdown bits.
* 4. aggregate with a function wrapper to allow for
* JS bindings to a handler object.
*
* 2. dump the aggregated locale data as a content.js file
* 3. generate a locale-specific index.html
*
*
**********************************************************************/
var fs = require("fs-extra");
var glob = require('glob');
var path = require("path");
var marked = require("marked");
var chunk = require("./lib/chunk");
var jsxshim = require("./lib/jsx-shim");
// make sure we know what our base location is
const BASEDIR = path.join(__dirname,"..");
// bundle all content in a specific locale for use by the app
const defaultLocale = "en-GB";
var locale = defaultLocale;
var lpos = process.argv.indexOf('--locale');
if (lpos !== -1) { locale = process.argv[lpos+1]; }
/**
* turn locale markdown into locale javascript data
*/
function processLocation(loc, fragmentid, number) {
var processed = { data: '', title: `Unknown title (${fragmentid})` };
try {
data = fs.readFileSync(loc).toString();
data = chunk(data).map(block => {
// preserver is simple
if (!block.convert) return block.data;
// markdown conversion is a little more work
let d = marked(block.data.trim());
// serious can we fucking not, please.
d = d.replace('<p></div></p>', '</div>')
.replace(/&amp;/g, '&')
.replace(/&#39;/g, "'")
.replace(/&quot;/g, '"')
// ``` conversion does odd things with <code> tags inside <pre> tags.
d = d.replace(/<pre>(\r?\n)*<code>/g,'<pre>')
.replace(/<\/code>(\r?\n)*<\/pre>/g,'</pre>');
// And then title extraction/rewriting
d = d.replace(/<h1[^>]+>([^<]+)<\/h1>/,function(_,t) {
processed.title = t;
return `<SectionHeader name="${fragmentid}" title="` + t + `"${ number ? ' number="'+number+'"': ''}/>`;
});
return d;
}).join('');
processed.data = data;
} catch (e) {
// console.warn(e);
}
return processed;
}
/**
* Form the content.js file content as a single string for file-writing.
*/
function formContentBundle(locale, content) {
var bcode = JSON.stringify(content, false, 2);
bcode = bcode.replace(/"<section>/g, "function(handler) { return <section>")
.replace(/this\.(\w)/g, "handler.$1")
.replace(/<\/section>"(,?)/g, "</section>; }$1\n")
.replace(/\\"/g,'"')
.replace(/\\n/g,'\n')
.replace(/></g,'>\n<')
.replace(/\\\\/g, '\\');
var bundle = [
`var React = require('react');`,
`var Graphic = require("../../components/Graphic.jsx");`,
`var SectionHeader = require("../../components/SectionHeader.jsx");`,
`var BSplineGraphic = require("../../components/BSplineGraphic.jsx");`,
`var KnotController = require("../../components/KnotController.jsx");`,
`var WeightController = require("../../components/WeightController.jsx");`,
``,
`SectionHeader.locale="${locale}";`,
``,
`module.exports = ${bcode};`,
``
].join('\n');
return bundle;
}
/**
* Process the locale switcher component.
*/
function processLocaleSwitcher(locale, content) {
// We also need to localize the "LocaleSwitcher"
var localeCode = locale;
var loc = `./components/localized/LocaleSwitcher/content.${localeCode}.md`;
if (!fs.existsSync(loc)) {
localeCode = defaultLocale;
loc = `./components/localized/LocaleSwitcher/content.${localeCode}.md`;
}
var key = "locale-switcher";
var processed = processLocation(loc, key);
content[key] = {
locale: localeCode,
title: key,
getContent: "<section>" + processed.data + "</section>"
};
}
/**
* Write a content.js bundle to the filesystem
*/
function writeContentBundle(locale, content) {
var bundle = formContentBundle(locale, content);
// write the content.js file for bundling purposes
var dir = `./locales/${locale}`;
fs.ensureDirSync(dir);
fs.writeFileSync(`${dir}/content.js`, bundle);
// Write the actual locale directory and generate a locale-specific index.html
var html = fs.readFileSync('./index.template.html').toString();
var preface = content.preface.getContent.replace(/<SectionHeader name="preface" title="([^"]+)"\/>/, "<h2>$1</h2>");
html = html.replace("{{ PREFACE }}", preface);
html = html.replace("{{ locale }}", locale);
fs.ensureDirSync(locale);
fs.writeFileSync(`./${locale}/index.html`, html);
}
/**
* Process a single locale, with `en-GB` fallback for missing files.
*/
function processLocale(locale) {
// Get the section map. This will try to load .jsx code, which will fail,
// but the above shim makes a failure simply return an empty object instead.
// This is good: we only care about the keys, not the content.
var index = require(path.join(BASEDIR, "components/sections"));
var sections = Object.keys(index);
var content = { locale };
var processSection = (key, number) => {
// Grab locale file, or defaultLocale file if the chosen locale has
// has no translated content (yet)...
var localeCode = locale;
var loc = path.join(BASEDIR, `./components/sections/${key}/content.${localeCode}.md`);
if (!fs.existsSync(loc)) {
localeCode = defaultLocale;
loc = path.join(BASEDIR, `./components/sections/${key}/content.${localeCode}.md`);
}
// Read in the content.{lang}.md file
var processed = processLocation(loc, key, number);
content[key] = {
locale: localeCode,
title: processed.title,
getContent: "<section>" + processed.data + "</section>"
};
};
sections.forEach(processSection);
processLocaleSwitcher(locale, content);
writeContentBundle(locale, content);
}
// find all locales used and generate their respective content dirs
glob(path.join(BASEDIR,"components/sections/**/content*md"), (err, files) => {
var locales = [];
files.forEach(file => {
let locale = file.match(/content\.([^.]+)\.md/)[1];
if (locales.indexOf(locale) === -1) {
locales.push(locale);
}
});
locales.forEach(processLocale);
});