mirror of
https://github.com/Pomax/BezierInfo-2.git
synced 2025-09-02 21:02:49 +02:00
better localization
This commit is contained in:
@@ -102,18 +102,42 @@ drawCurveCoordinates() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onKeyDown() {
|
onKeyDown() {
|
||||||
|
this.mark = false;
|
||||||
if (this.keyboard[`ArrowDown`]) {
|
if (this.keyboard[`ArrowDown`]) {
|
||||||
this.step--;
|
this.stepDown();
|
||||||
if (this.step < 10) this.step = 10;
|
|
||||||
}
|
}
|
||||||
if (this.keyboard[`ArrowUp`]) {
|
if (this.keyboard[`ArrowUp`]) {
|
||||||
this.step++;
|
this.stepUp();
|
||||||
if (this.step > 90) this.step = 90;
|
|
||||||
}
|
}
|
||||||
redraw();
|
redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stepDown(value = 1) {
|
||||||
|
this.step -= value;
|
||||||
|
if (this.step < 10) this.step = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
stepUp(value = 1) {
|
||||||
|
this.step += value;
|
||||||
|
if (this.step > 90) this.step = 90;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMouseDown() {
|
||||||
|
this.mark = this.cursor.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMouseUp() {
|
||||||
|
this.mark = false;
|
||||||
|
}
|
||||||
|
|
||||||
onMouseMove() {
|
onMouseMove() {
|
||||||
this.curve.update();
|
this.curve.update();
|
||||||
|
|
||||||
|
if (this.mark) {
|
||||||
|
let diff = this.mark - this.cursor.y,
|
||||||
|
mapped = map(diff, -this.height/2, this.height/2, 10, 90, true);
|
||||||
|
this.step = mapped | 0;
|
||||||
|
}
|
||||||
|
|
||||||
redraw();
|
redraw();
|
||||||
}
|
}
|
||||||
|
@@ -236,7 +236,7 @@ class GraphicsAPI extends BaseAPI {
|
|||||||
* Add a plain point to the current shape
|
* Add a plain point to the current shape
|
||||||
*/
|
*/
|
||||||
vertex(x, y) {
|
vertex(x, y) {
|
||||||
this.currentShape.vertex({ x, y});
|
this.currentShape.vertex({ x, y });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -244,7 +244,7 @@ class GraphicsAPI extends BaseAPI {
|
|||||||
*/
|
*/
|
||||||
end() {
|
end() {
|
||||||
this.ctx.beginPath();
|
this.ctx.beginPath();
|
||||||
let {x, y} = this.currentShape.first;
|
let { x, y } = this.currentShape.first;
|
||||||
this.ctx.moveTo(x, y);
|
this.ctx.moveTo(x, y);
|
||||||
this.currentShape.segments.forEach((s) =>
|
this.currentShape.segments.forEach((s) =>
|
||||||
this[`draw${s.type}`](this.ctx, s.points, s.factor)
|
this[`draw${s.type}`](this.ctx, s.points, s.factor)
|
||||||
@@ -279,6 +279,58 @@ class GraphicsAPI extends BaseAPI {
|
|||||||
this.line({ x: 0, y }, { x: this.width, y });
|
this.line({ x: 0, y }, { x: this.width, y });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* math functions
|
||||||
|
*/
|
||||||
|
floor(v) {
|
||||||
|
return Math.floor(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
ceil(v) {
|
||||||
|
return Math.ceil(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
round(v) {
|
||||||
|
return Math.round(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
abs(v) {
|
||||||
|
return Math.abs(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
sin(v) {
|
||||||
|
return Math.sin(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
cos(v) {
|
||||||
|
return Math.cos(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
tan(v) {
|
||||||
|
return Math.tan(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
sqrt(v) {
|
||||||
|
return Math.sqrt(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
atan2(dy, dx) {
|
||||||
|
return Math.atan2(dy, dx);
|
||||||
|
}
|
||||||
|
|
||||||
|
pow(v, p) {
|
||||||
|
return Math.pow(v, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
map(v, s, e, ns, ne, constrain = false) {
|
||||||
|
const i1 = e - s,
|
||||||
|
i2 = ne - ns,
|
||||||
|
p = v - s;
|
||||||
|
let r = ns + (p * i2) / i1;
|
||||||
|
if (constrain) r = r < ns ? ns : r > ne ? ne : r;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { GraphicsAPI, Bezier, Vector };
|
export { GraphicsAPI, Bezier, Vector };
|
||||||
|
@@ -1,53 +0,0 @@
|
|||||||
export default {
|
|
||||||
"defaultLocale": "en-GB",
|
|
||||||
"title": {
|
|
||||||
"en-GB": "A Primer on Bézier Curves",
|
|
||||||
"ja-JP": "ベジェ曲線入門",
|
|
||||||
"zh-CN": "贝塞尔曲线底漆"
|
|
||||||
},
|
|
||||||
"subtitle": {
|
|
||||||
"en-GB": "A free, online book for when you really need to know how to do Bézier things.",
|
|
||||||
"ja-JP": "A free, online book for when you really need to know how to do Bézier things.",
|
|
||||||
"zh-CN": "A free, online book for when you really need to know how to do Bézier things."
|
|
||||||
},
|
|
||||||
"description": {
|
|
||||||
"en-GB": "A detailed explanation of Bézier curves, and how to do the many things that we commonly want to do with them.",
|
|
||||||
"ja-JP": "A detailed explanation of Bézier curves, and how to do the many things that we commonly want to do with them.",
|
|
||||||
"zh-CN": "A detailed explanation of Bézier curves, and how to do the many things that we commonly want to do with them."
|
|
||||||
},
|
|
||||||
"tocLabel": {
|
|
||||||
"en-GB": "Table of Contents",
|
|
||||||
"ja-JP": "目次",
|
|
||||||
"zh-CN": "目录"
|
|
||||||
},
|
|
||||||
"localeName": {
|
|
||||||
"en-GB": "English",
|
|
||||||
"zh-CN": "中文",
|
|
||||||
"ja-JP": "日本語"
|
|
||||||
},
|
|
||||||
"langSwitchLabel": {
|
|
||||||
"en-GB": "Read this in your own language:",
|
|
||||||
"zh-CN": "Read this in your own language:",
|
|
||||||
"ja-JP": "Read this in your own language:"
|
|
||||||
},
|
|
||||||
"langHelpLabel": {
|
|
||||||
"en-GB": "Don't see your language listed? <a href=\"https://github.com/Pomax/BezierInfo-2/wiki/localize\">Help translate this content!</a>",
|
|
||||||
"zh-CN": "Don't see your language listed? <a href=\"https://github.com/Pomax/BezierInfo-2/wiki/localize\">Help translate this content!</a>",
|
|
||||||
"ja-JP": "Don't see your language listed? <a href=\"https://github.com/Pomax/BezierInfo-2/wiki/localize\">Help translate this content!</a>"
|
|
||||||
},
|
|
||||||
"disabledMessage": {
|
|
||||||
"en-GB": "Scripts are disabled. Showing fallback image.",
|
|
||||||
"zh-CN": "Scripts are disabled. Showing fallback image.",
|
|
||||||
"ja-JP": "Scripts are disabled. Showing fallback image."
|
|
||||||
},
|
|
||||||
"changelogTitle": {
|
|
||||||
"en-GB": "What's new?",
|
|
||||||
"zh-CN": "What's new?",
|
|
||||||
"ja-JP": "What's new?"
|
|
||||||
},
|
|
||||||
"changelogDescription": {
|
|
||||||
"en-GB": "This primer is a living document, and so depending on when you last look at it, there may be new content. Click the following link to expand this section to have a look at what got added, when.",
|
|
||||||
"zh-CN": "This primer is a living document, and so depending on when you last look at it, there may be new content. Click the following link to expand this section to have a look at what got added, when.",
|
|
||||||
"ja-JP": "This primer is a living document, and so depending on when you last look at it, there may be new content. Click the following link to expand this section to have a look at what got added, when."
|
|
||||||
}
|
|
||||||
}
|
|
@@ -14,7 +14,8 @@
|
|||||||
"url": "https://github.com/Pomax/bezierinfo/issues"
|
"url": "https://github.com/Pomax/bezierinfo/issues"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "run-s build",
|
"start": "run-s lint build",
|
||||||
|
"lint": "prettier ./tools --write",
|
||||||
"build": "node ./tools/build.js",
|
"build": "node ./tools/build.js",
|
||||||
"test": "run-p server browser",
|
"test": "run-p server browser",
|
||||||
"server": "http-server -p 8000 --cors",
|
"server": "http-server -p 8000 --cors",
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
import LocaleStrings from "./locale-strings.js";
|
||||||
import getAllChapterFiles from "./build/get-all-chapter-files.js";
|
import getAllChapterFiles from "./build/get-all-chapter-files.js";
|
||||||
import processLocale from "./build/process-locale.js";
|
import processLocale from "./build/process-locale.js";
|
||||||
import createIndexPages from "./build/create-index-page.js";
|
import createIndexPages from "./build/create-index-page.js";
|
||||||
@@ -9,9 +10,9 @@ import createIndexPages from "./build/create-index-page.js";
|
|||||||
*/
|
*/
|
||||||
getAllChapterFiles().then((chapterFiles) => {
|
getAllChapterFiles().then((chapterFiles) => {
|
||||||
const languageCodes = Object.keys(chapterFiles);
|
const languageCodes = Object.keys(chapterFiles);
|
||||||
|
|
||||||
languageCodes.forEach(async (locale) => {
|
languageCodes.forEach(async (locale) => {
|
||||||
const chapters = await processLocale(locale, chapterFiles);
|
const localeStrings = new LocaleStrings(locale);
|
||||||
createIndexPages(locale, chapters, languageCodes);
|
const chapters = await processLocale(locale, localeStrings, chapterFiles);
|
||||||
|
createIndexPages(locale, localeStrings, chapters);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -8,14 +8,18 @@ nunjucks.configure(".", { autoescape: false });
|
|||||||
/**
|
/**
|
||||||
* ...docs go here...
|
* ...docs go here...
|
||||||
*/
|
*/
|
||||||
export default async function convertMarkDown(chapter, locale, markdown) {
|
export default async function convertMarkDown(
|
||||||
markdown = injectGraphicsFallback(chapter, locale, markdown);
|
chapter,
|
||||||
|
localeStrings,
|
||||||
|
markdown
|
||||||
|
) {
|
||||||
|
markdown = injectGraphicsFallback(chapter, localeStrings, markdown);
|
||||||
|
|
||||||
const { data, latex } = extractLaTeX(markdown);
|
const { data, latex } = extractLaTeX(markdown);
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
Object.keys(latex).map(async (key, pos) => {
|
Object.keys(latex).map(async (key, pos) => {
|
||||||
const svg = await latexToSVG(latex[key], chapter, locale, pos + 1);
|
const svg = await latexToSVG(latex[key], chapter, localeStrings, pos + 1);
|
||||||
return (latex[key] = svg);
|
return (latex[key] = svg);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@@ -3,28 +3,23 @@ import path from "path";
|
|||||||
import prettier from "prettier";
|
import prettier from "prettier";
|
||||||
import generateLangSwitcher from "./generate-lang-switcher.js";
|
import generateLangSwitcher from "./generate-lang-switcher.js";
|
||||||
import nunjucks from "nunjucks";
|
import nunjucks from "nunjucks";
|
||||||
import localeStrings from "../../locale-strings.js";
|
|
||||||
import sectionOrder from "../../chapters/toc.js";
|
import sectionOrder from "../../chapters/toc.js";
|
||||||
import changelog from "../../changelog.js";
|
import changelog from "../../changelog.js";
|
||||||
|
|
||||||
const defaultLocale = localeStrings.defaultLocale;
|
|
||||||
|
|
||||||
nunjucks.configure(".", { autoescape: false });
|
nunjucks.configure(".", { autoescape: false });
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ...docs go here...
|
* ...docs go here...
|
||||||
*/
|
*/
|
||||||
export default async function createIndexPages(locale, chapters, languages) {
|
export default async function createIndexPages(
|
||||||
let base = ``;
|
locale,
|
||||||
|
localeStrings,
|
||||||
if (locale !== defaultLocale) {
|
chapters
|
||||||
base = `<base href="..">`;
|
) {
|
||||||
}
|
const defaultLocale = localeStrings.getDefaultLocale();
|
||||||
|
const base = locale !== defaultLocale ? `<base href="..">` : ``;
|
||||||
const langSwitcher = generateLangSwitcher(locale, languages, defaultLocale);
|
const langSwitcher = generateLangSwitcher(localeStrings);
|
||||||
|
|
||||||
const toc = {};
|
const toc = {};
|
||||||
|
|
||||||
const preface = `<section id="preface">${
|
const preface = `<section id="preface">${
|
||||||
chapters[sectionOrder[0]]
|
chapters[sectionOrder[0]]
|
||||||
}</section>`;
|
}</section>`;
|
||||||
@@ -40,10 +35,12 @@ export default async function createIndexPages(locale, chapters, languages) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let changeLogHTML = [];
|
let changeLogHTML = [];
|
||||||
Object.keys(changelog).forEach(period => {
|
Object.keys(changelog).forEach((period) => {
|
||||||
let changes = changelog[period].map(change => `<li>${change}</li>`).join(`\n`);
|
let changes = changelog[period]
|
||||||
|
.map((change) => `<li>${change}</li>`)
|
||||||
|
.join(`\n`);
|
||||||
changeLogHTML.push(`<h2>${period}</h2><ul>${changes}</ul>`);
|
changeLogHTML.push(`<h2>${period}</h2><ul>${changes}</ul>`);
|
||||||
})
|
});
|
||||||
|
|
||||||
// Set up the templating context
|
// Set up the templating context
|
||||||
const context = {
|
const context = {
|
||||||
@@ -57,11 +54,7 @@ export default async function createIndexPages(locale, chapters, languages) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// And inject all the relevant locale strings
|
// And inject all the relevant locale strings
|
||||||
Object.keys(localeStrings).forEach((key) => {
|
localeStrings.extendContext(context);
|
||||||
if (localeStrings[key][locale]) {
|
|
||||||
context[key] = localeStrings[key][locale];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const index = nunjucks.render(`index.template.html`, context);
|
const index = nunjucks.render(`index.template.html`, context);
|
||||||
|
|
||||||
|
@@ -1,9 +1,8 @@
|
|||||||
import localeStrings from "../../locale-strings.js";
|
export default function generateLangSwitcher(localeStrings) {
|
||||||
|
const defaultLocale = localeStrings.getDefaultLocale();
|
||||||
|
|
||||||
const defaultLocale = localeStrings.defaultLocale;
|
return localeStrings
|
||||||
|
.getAllLocaleCodes()
|
||||||
export default function generateLangSwitcher(currentLocale, allLocales) {
|
|
||||||
return allLocales
|
|
||||||
.map((locale) => {
|
.map((locale) => {
|
||||||
let link;
|
let link;
|
||||||
if (locale === defaultLocale) {
|
if (locale === defaultLocale) {
|
||||||
@@ -11,7 +10,8 @@ export default function generateLangSwitcher(currentLocale, allLocales) {
|
|||||||
} else {
|
} else {
|
||||||
link = `./${locale}/index.html`;
|
link = `./${locale}/index.html`;
|
||||||
}
|
}
|
||||||
return `<li><a href="${link}">${localeStrings.localeName[locale]}</a></li>`;
|
let localeName = localeStrings.getLocaleName(locale);
|
||||||
|
return `<li><a href="${link}">${localeName}</a></li>`;
|
||||||
})
|
})
|
||||||
.join(`\n`);
|
.join(`\n`);
|
||||||
}
|
}
|
||||||
|
@@ -1,12 +1,12 @@
|
|||||||
import fs from "fs-extra";
|
import fs from "fs-extra";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import rewriteGraphicsElement from "./rewrite-graphics-element.js";
|
import rewriteGraphicsElement from "./rewrite-graphics-element.js";
|
||||||
import localeStrings from "../../locale-strings.js";
|
import localeStrings from "../locale-strings.js";
|
||||||
|
|
||||||
const defaultLocale = localeStrings.defaultLocale;
|
const defaultLocale = localeStrings.defaultLocale;
|
||||||
|
|
||||||
const moduleURL = new URL(import.meta.url);
|
const moduleURL = new URL(import.meta.url);
|
||||||
const __dirname = path.dirname(moduleURL.href.replace(`file:///`,``));
|
const __dirname = path.dirname(moduleURL.href.replace(`file:///`, ``));
|
||||||
|
|
||||||
export default async function generatePlaceHolders(locale, markdown) {
|
export default async function generatePlaceHolders(locale, markdown) {
|
||||||
if (locale !== defaultLocale) return;
|
if (locale !== defaultLocale) return;
|
||||||
@@ -29,10 +29,12 @@ export default async function generatePlaceHolders(locale, markdown) {
|
|||||||
} while (pos !== -1);
|
} while (pos !== -1);
|
||||||
|
|
||||||
const keys = Object.keys(elements);
|
const keys = Object.keys(elements);
|
||||||
const sourcePaths = keys.map(key => elements[key].match(/src="([^"]+)"/)[1]);
|
const sourcePaths = keys.map(
|
||||||
|
(key) => elements[key].match(/src="([^"]+)"/)[1]
|
||||||
|
);
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
sourcePaths.map(async(srcPath, i) => {
|
sourcePaths.map(async (srcPath, i) => {
|
||||||
try {
|
try {
|
||||||
// Get the sketch code
|
// Get the sketch code
|
||||||
const sourcePath = path.join(__dirname, "..", "..", srcPath);
|
const sourcePath = path.join(__dirname, "..", "..", srcPath);
|
||||||
@@ -61,8 +63,9 @@ export default async function generatePlaceHolders(locale, markdown) {
|
|||||||
// console.log(`Writing placeholder to ${filename}`);
|
// console.log(`Writing placeholder to ${filename}`);
|
||||||
fs.ensureDirSync(path.dirname(destPath));
|
fs.ensureDirSync(path.dirname(destPath));
|
||||||
fs.writeFileSync(filename, imageData);
|
fs.writeFileSync(filename, imageData);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
}
|
}
|
||||||
catch (e) { console.error(e); }
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,7 @@ import path from "path";
|
|||||||
|
|
||||||
// make sure we know what our base location is
|
// make sure we know what our base location is
|
||||||
const moduleURL = new URL(import.meta.url);
|
const moduleURL = new URL(import.meta.url);
|
||||||
const __dirname = path.dirname(moduleURL.href.replace(`file:///`,``));
|
const __dirname = path.dirname(moduleURL.href.replace(`file:///`, ``));
|
||||||
const BASEDIR = path.join(__dirname, "..", "..");
|
const BASEDIR = path.join(__dirname, "..", "..");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -11,7 +11,6 @@ const BASEDIR = path.join(__dirname, "..", "..");
|
|||||||
*/
|
*/
|
||||||
export default /* async */ function getAllChapterFiles() {
|
export default /* async */ function getAllChapterFiles() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
glob(path.join(BASEDIR, `chapters/**/content*md`), (err, files) => {
|
glob(path.join(BASEDIR, `chapters/**/content*md`), (err, files) => {
|
||||||
if (err) reject(err);
|
if (err) reject(err);
|
||||||
|
|
||||||
|
@@ -1,16 +1,20 @@
|
|||||||
export default function cleanUp(latex) {
|
export default function cleanUp(latex) {
|
||||||
// strip any \[ and \], which is a block-level LaTeX markup indicator for MathJax:
|
// strip any \[ and \], which is a block-level LaTeX markup indicator for MathJax:
|
||||||
latex = latex.replace(/^'/,'').replace(/'$/,'').replace('\\[','').replace('\\]','');
|
latex = latex
|
||||||
|
.replace(/^'/, "")
|
||||||
|
.replace(/'$/, "")
|
||||||
|
.replace("\\[", "")
|
||||||
|
.replace("\\]", "");
|
||||||
|
|
||||||
// wrap some known functor words in italics markup
|
// wrap some known functor words in italics markup
|
||||||
['Bézier'].forEach(term => {
|
["Bézier"].forEach((term) => {
|
||||||
latex = latex.replace(new RegExp(term, 'g'), '\\textit{' + term + '}');
|
latex = latex.replace(new RegExp(term, "g"), "\\textit{" + term + "}");
|
||||||
});
|
});
|
||||||
|
|
||||||
// also unindent the LaTeX.
|
// also unindent the LaTeX.
|
||||||
var indent = false;
|
var indent = false;
|
||||||
var lines = latex.split('\n').filter(line => !!line.trim());
|
var lines = latex.split("\n").filter((line) => !!line.trim());
|
||||||
var clean = function(line, idx) {
|
var clean = function (line, idx) {
|
||||||
if (!indent) {
|
if (!indent) {
|
||||||
var matched = line.match(/^(\s+)/);
|
var matched = line.match(/^(\s+)/);
|
||||||
if (matched) {
|
if (matched) {
|
||||||
@@ -18,10 +22,10 @@ export default function cleanUp(latex) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (indent) {
|
if (indent) {
|
||||||
lines[idx] = line.replace(indent,'').trim();
|
lines[idx] = line.replace(indent, "").trim();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
lines.forEach(clean);
|
lines.forEach(clean);
|
||||||
latex = lines.join('\n');
|
latex = lines.join("\n");
|
||||||
return latex;
|
return latex;
|
||||||
};
|
}
|
||||||
|
@@ -47,7 +47,7 @@ export default async function latexToSVG(latex, chapter, locale, block) {
|
|||||||
"\\usepackage{xeCJK}",
|
"\\usepackage{xeCJK}",
|
||||||
"\\xeCJKsetup{CJKmath=true}",
|
"\\xeCJKsetup{CJKmath=true}",
|
||||||
"\\setCJKmainfont{gbsn00lp.ttf}",
|
"\\setCJKmainfont{gbsn00lp.ttf}",
|
||||||
]
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// The same goes for Japanese, although we obviously want a different
|
// The same goes for Japanese, although we obviously want a different
|
||||||
@@ -69,13 +69,16 @@ export default async function latexToSVG(latex, chapter, locale, block) {
|
|||||||
`\\usepackage{color}`,
|
`\\usepackage{color}`,
|
||||||
`\\usepackage{amsmath}`,
|
`\\usepackage{amsmath}`,
|
||||||
`\\usepackage{unicode-math}`,
|
`\\usepackage{unicode-math}`,
|
||||||
].concat(fonts).concat([
|
]
|
||||||
`\\begin{document}`,
|
.concat(fonts)
|
||||||
`\\[`,
|
.concat([
|
||||||
cleanUp(latex),
|
`\\begin{document}`,
|
||||||
`\\]`,
|
`\\[`,
|
||||||
`\\end{document}`,
|
cleanUp(latex),
|
||||||
]).join(`\n`)
|
`\\]`,
|
||||||
|
`\\end{document}`,
|
||||||
|
])
|
||||||
|
.join(`\n`)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Finally: run the conversion
|
// Finally: run the conversion
|
||||||
|
@@ -1,9 +1,13 @@
|
|||||||
import localeStrings from "../../../locale-strings.js";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ...docs go here...
|
* ...docs go here...
|
||||||
*/
|
*/
|
||||||
export default function injectGraphicsFallback(chapter, locale, markdown) {
|
export default function injectGraphicsFallback(
|
||||||
|
chapter,
|
||||||
|
localeStrings,
|
||||||
|
markdown
|
||||||
|
) {
|
||||||
|
const translate = localeStrings.translate;
|
||||||
|
|
||||||
let pos = -1,
|
let pos = -1,
|
||||||
data = markdown,
|
data = markdown,
|
||||||
startmark = `<graphics-element`,
|
startmark = `<graphics-element`,
|
||||||
@@ -22,7 +26,7 @@ export default function injectGraphicsFallback(chapter, locale, markdown) {
|
|||||||
return `width="${width}" height="${height}" src="${src}">
|
return `width="${width}" height="${height}" src="${src}">
|
||||||
<fallback-image>
|
<fallback-image>
|
||||||
<img width="${width}px" height="${height}px" src="${img}" loading="lazy">
|
<img width="${width}px" height="${height}px" src="${img}" loading="lazy">
|
||||||
${localeStrings.disabledMessage[locale]}
|
${translate`disabledMessage`}
|
||||||
</fallback-image>`;
|
</fallback-image>`;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@@ -4,12 +4,10 @@ import convertMarkDown from "./convert-markdown.js";
|
|||||||
import generatePlaceHolders from "./generate-placeholders.js";
|
import generatePlaceHolders from "./generate-placeholders.js";
|
||||||
import nunjucks from "nunjucks";
|
import nunjucks from "nunjucks";
|
||||||
import toc from "../../chapters/toc.js";
|
import toc from "../../chapters/toc.js";
|
||||||
import localeStrings from "../../locale-strings.js";
|
|
||||||
|
|
||||||
const moduleURL = new URL(import.meta.url);
|
const moduleURL = new URL(import.meta.url);
|
||||||
const __dirname = path.dirname(moduleURL.href.replace(`file:///`, ``));
|
const __dirname = path.dirname(moduleURL.href.replace(`file:///`, ``));
|
||||||
|
|
||||||
const defaultLocale = localeStrings.defaultLocale;
|
|
||||||
const sectionList = toc.map((v) =>
|
const sectionList = toc.map((v) =>
|
||||||
path.posix.join(
|
path.posix.join(
|
||||||
__dirname.split(path.sep).join(path.posix.sep),
|
__dirname.split(path.sep).join(path.posix.sep),
|
||||||
@@ -25,7 +23,14 @@ nunjucks.configure(".", { autoescape: false });
|
|||||||
/**
|
/**
|
||||||
* ...docs go here...
|
* ...docs go here...
|
||||||
*/
|
*/
|
||||||
export default async function processLocale(locale, chapterFiles) {
|
export default async function processLocale(
|
||||||
|
locale,
|
||||||
|
localeStrings,
|
||||||
|
chapterFiles
|
||||||
|
) {
|
||||||
|
const defaultLocale = localeStrings.getDefaultLocale();
|
||||||
|
const translate = localeStrings.translate;
|
||||||
|
|
||||||
const localeFiles = chapterFiles[locale];
|
const localeFiles = chapterFiles[locale];
|
||||||
let localized = 0;
|
let localized = 0;
|
||||||
let missing = 0;
|
let missing = 0;
|
||||||
@@ -53,10 +58,7 @@ export default async function processLocale(locale, chapterFiles) {
|
|||||||
localeFiles.map(async (file) => {
|
localeFiles.map(async (file) => {
|
||||||
const chapter = file.match(/chapters\/([^/]+)\/content./)[1];
|
const chapter = file.match(/chapters\/([^/]+)\/content./)[1];
|
||||||
const markdown = fs.readFileSync(file).toString("utf8");
|
const markdown = fs.readFileSync(file).toString("utf8");
|
||||||
const replaced = nunjucks.renderString(markdown, {
|
const converted = await convertMarkDown(chapter, localeStrings, markdown);
|
||||||
disableMessage: `<span>${localeStrings.disabledMessage[locale]}</span>`,
|
|
||||||
});
|
|
||||||
const converted = await convertMarkDown(chapter, locale, replaced);
|
|
||||||
chapters[chapter] = converted;
|
chapters[chapter] = converted;
|
||||||
generatePlaceHolders(locale, converted); // ← this is super fancy functionality.
|
generatePlaceHolders(locale, converted); // ← this is super fancy functionality.
|
||||||
})
|
})
|
||||||
|
@@ -3,12 +3,12 @@ import performCodeSurgery from "../../lib/custom-element/lib/perform-code-surger
|
|||||||
import prettier from "prettier";
|
import prettier from "prettier";
|
||||||
|
|
||||||
export default function rewriteGraphicsElement(code, width, height) {
|
export default function rewriteGraphicsElement(code, width, height) {
|
||||||
|
const split = splitCodeSections(code);
|
||||||
|
const globalCode = split.quasiGlobal;
|
||||||
|
const classCode = performCodeSurgery(split.classCode);
|
||||||
|
|
||||||
const split = splitCodeSections(code);
|
return prettier.format(
|
||||||
const globalCode = split.quasiGlobal;
|
`
|
||||||
const classCode = performCodeSurgery(split.classCode);
|
|
||||||
|
|
||||||
return prettier.format(`
|
|
||||||
import CanvasBuilder from 'canvas';
|
import CanvasBuilder from 'canvas';
|
||||||
import { GraphicsAPI, Bezier, Vector } from "../../lib/custom-element/api/graphics-api.js";
|
import { GraphicsAPI, Bezier, Vector } from "../../lib/custom-element/api/graphics-api.js";
|
||||||
|
|
||||||
@@ -33,5 +33,7 @@ export default function rewriteGraphicsElement(code, width, height) {
|
|||||||
const canvas = example.canvas;
|
const canvas = example.canvas;
|
||||||
|
|
||||||
export { canvas };
|
export { canvas };
|
||||||
`, { parser: `babel` });
|
`,
|
||||||
};
|
{ parser: `babel` }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
110
tools/locale-strings.js
Normal file
110
tools/locale-strings.js
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
const defaultLocale = "en-GB";
|
||||||
|
|
||||||
|
const localeStringData = {
|
||||||
|
title: {
|
||||||
|
"en-GB": "A Primer on Bézier Curves",
|
||||||
|
"ja-JP": "ベジェ曲線入門",
|
||||||
|
"zh-CN": "贝塞尔曲线底漆",
|
||||||
|
},
|
||||||
|
subtitle: {
|
||||||
|
"en-GB":
|
||||||
|
"A free, online book for when you really need to know how to do Bézier things.",
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
"en-GB":
|
||||||
|
"A detailed explanation of Bézier curves, and how to do the many things that we commonly want to do with them.",
|
||||||
|
},
|
||||||
|
tocLabel: {
|
||||||
|
"en-GB": "Table of Contents",
|
||||||
|
"ja-JP": "目次",
|
||||||
|
"zh-CN": "目录",
|
||||||
|
},
|
||||||
|
localeName: {
|
||||||
|
"en-GB": "English",
|
||||||
|
"zh-CN": "中文",
|
||||||
|
"ja-JP": "日本語",
|
||||||
|
},
|
||||||
|
langSwitchLabel: {
|
||||||
|
"en-GB": "Read this in your own language:",
|
||||||
|
},
|
||||||
|
langHelpLabel: {
|
||||||
|
"en-GB":
|
||||||
|
'Don\'t see your language listed? <a href="https://github.com/Pomax/BezierInfo-2/wiki/localize">Help translate this content!</a>',
|
||||||
|
},
|
||||||
|
disabledMessage: {
|
||||||
|
"en-GB": "Scripts are disabled. Showing fallback image.",
|
||||||
|
},
|
||||||
|
changelogTitle: {
|
||||||
|
"en-GB": "What's new?",
|
||||||
|
},
|
||||||
|
changelogDescription: {
|
||||||
|
"en-GB":
|
||||||
|
"This primer is a living document, and so depending on when you last look at it, there may be new content. Click the following link to expand this section to have a look at what got added, when.",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
class LocaleStrings {
|
||||||
|
constructor(locale) {
|
||||||
|
this.currentLocale = locale;
|
||||||
|
const strings = (this.strings = {});
|
||||||
|
|
||||||
|
Object.keys(localeStringData).forEach((id) => {
|
||||||
|
const map = localeStringData[id];
|
||||||
|
if (typeof map !== "object") return;
|
||||||
|
const value = map[locale] ?? map[defaultLocale];
|
||||||
|
if (!value) throw new Error(`unknown locale string id "${id}".`);
|
||||||
|
strings[id] = value;
|
||||||
|
|
||||||
|
// temporary bug catcher:
|
||||||
|
Object.defineProperty(this, id, {
|
||||||
|
get: () => {
|
||||||
|
throw new Error(`cannot get localestring ${id} via property access`);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// templating tags:
|
||||||
|
|
||||||
|
get translate() {
|
||||||
|
return this.get.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// functions:
|
||||||
|
|
||||||
|
get(id) {
|
||||||
|
return this.strings[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
getDefaultLocale() {
|
||||||
|
return defaultLocale;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCurrentLocale() {
|
||||||
|
return this.currentLocale;
|
||||||
|
}
|
||||||
|
|
||||||
|
getLocaleName(locale) {
|
||||||
|
const name = localeStringData.localeName[locale];
|
||||||
|
if (!name) {
|
||||||
|
throw new Error(`Unknown locale "${locale}"`);
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
getAllLocaleCodes() {
|
||||||
|
return Object.keys(localeStringData.title);
|
||||||
|
}
|
||||||
|
|
||||||
|
extendContext(context) {
|
||||||
|
const strings = this.strings;
|
||||||
|
|
||||||
|
Object.keys(strings).forEach((key) => {
|
||||||
|
if (context[key]) {
|
||||||
|
throw new Error(`Context already has key "${key}"!`);
|
||||||
|
}
|
||||||
|
context[key] = strings[key];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LocaleStrings;
|
Reference in New Issue
Block a user