Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions components/mjs/core/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@
"util/entities"
]
},
"copy": {
"to": "[bundle]/core",
"from": "[ts]/core",
"copy": ["__locales__"],
"excludes": ["__locales__/Component.ts"]
},
"webpack": {
"name": "core"
}
Expand Down
1 change: 1 addition & 0 deletions components/mjs/loader/loader.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import '../core/locale.js';
import './lib/loader.js';
import '../core/core.js';

Expand Down
1 change: 1 addition & 0 deletions components/mjs/startup/init.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import './hasown.js'; // Can be removed with ES2024 implementation of Object.hasown
import '../core/locale.js';
import './lib/startup.js';
import '../core/core.js';

Expand Down
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,13 @@
"clean:lib": "clean() { pnpm -s log:single \"Cleaning $1 component libs\"; pnpm rimraf -g components/$1'/**/lib'; }; clean",
"clean:mod": "clean() { pnpm -s log:comp \"Cleaning $1 module\"; pnpm -s clean:dir $1 && pnpm -s clean:lib $1; }; clean",
"=============================================================================== copy": "",
"copy:assets": "pnpm -s log:comp 'Copying assets'; copy() { pnpm -s copy:locales $1 && pnpm -s copy:mj2 $1 && pnpm -s copy:mml3 $1 && pnpm -s copy:html $1; }; copy",
"copy:assets": "pnpm -s log:comp 'Copying assets'; copy() { for name in locales mj2 mml3 html; do pnpm -s copy:$name ${1:-mjs}; done; }; copy",
"copy:bundle": "copy() { components/bin/makeAll --copy --terse components/mjs/${1:-}; }; copy",
"copy:html": "copy() { pnpm -s log:single 'Copying sre auxiliary files'; pnpm copyfiles -u 1 'ts/a11y/sre/*.html' 'ts/a11y/sre/require.*' $1; }; copy",
"copy:locales": "copy() { pnpm -s copy:locales:menu $1; pnpm -s copy:locales:tex $1; }; copy ",
"copy:locales": "copy() { for name in core tex menu; do pnpm -s copy:locales:$name ${1:-mjs}; done; }; copy ",
"copy:locales:core": "pnpm -s log:single 'Copying core locales'; copy() { pnpm copyfiles -u 1 'ts/core/__locales__/*.json' $1; }; copy",
"copy:locales:menu": "pnpm -s log:single 'Copying menu locales'; copy() { pnpm copyfiles -u 1 'ts/ui/menu/__locales__/*.json' $1; }; copy",
"copy:locales:tex": "pnpm -s log:single 'Copying TeX extension locales'; copy() { pnpm copyfiles -u 1 'ts/input/tex/__locales__/*.json' $1 && pnpm copyfiles -u 3 'ts/input/tex/*/__locales__/*.json' $1/input/tex/extensions; }; copy",
"copy:locales:tex": "pnpm -s log:single 'Copying TeX locales'; copy() { pnpm copyfiles -u 1 'ts/input/tex/__locales__/*.json' $1 && pnpm copyfiles -u 3 'ts/input/tex/*/__locales__/*.json' $1/input/tex/extensions; }; copy",
"copy:mj2": "copy() { pnpm -s log:single 'Copying legacy code AsciiMath'; pnpm copyfiles -u 1 'ts/input/asciimath/legacy/**/*' $1; }; copy",
"copy:mml3": "copy() { pnpm -s log:single 'Copying MathML3 extension json'; pnpm copyfiles -u 1 ts/input/mathml/mml3/mml3.sef.json $1; }; copy",
"copy:pkg": "copy() { pnpm -s log:single \"Copying package.json to $1\"; pnpm copyfiles -u 2 components/bin/package.json $1; }; copy",
Expand Down
20 changes: 9 additions & 11 deletions ts/components/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ import { mjxRoot } from '#root/root.js';
import { context } from '../util/context.js';
import { Locale } from '../util/Locale.js';

import { COMPONENT } from '../core/__locales__/Component.js';

/**
* Function used to determine path to a given package.
*/
Expand Down Expand Up @@ -187,7 +189,7 @@ export const Loader = {
/**
* Load the named packages and return a promise that is resolved when they are all loaded
*
* @param {string[]} names The packages to load
* @param {string[]} names The packages to load
* @returns {Promise<any[]>} A promise that resolves when all the named packages are ready
*/
load(...names: string[]): Promise<any[]> {
Expand Down Expand Up @@ -224,9 +226,7 @@ export const Loader = {
extension.isLoaded &&
!Loader.versions.has(Package.resolvePath(name))
) {
console.warn(
`No version information available for component ${name}`
);
Locale.warn(COMPONENT, 'NoVersionFor', name);
}
return extension.result;
}) as Promise<any>
Expand Down Expand Up @@ -346,15 +346,13 @@ export const Loader = {
*
* @param {string} name The name of the extension being checked
* @param {string} version The version of the extension to check
* @param {string} _type The type of extension (future code may use this to check ranges of versions)
* @returns {boolean} True if there was a mismatch, false otherwise
* @param {string} _type The type of extension (future code may use this to check ranges of versions)
* @returns {boolean} True if there was a mismatch, false otherwise
*/
checkVersion(name: string, version: string, _type?: string): boolean {
this.saveVersion(name);
if (CONFIG.versionWarnings && version !== VERSION) {
console.warn(
`Component ${name} uses ${version} of MathJax; version in use is ${VERSION}`
);
Locale.warn(COMPONENT, 'WrongVersion', name, version, VERSION);
return true;
}
return false;
Expand All @@ -363,7 +361,7 @@ export const Loader = {
/**
* Set the version of an extension (used for combined components so they can be loaded)
*
* @param {string} name The name of the extension being checked
* @param {string} name The name of the extension being checked
*/
saveVersion(name: string) {
Loader.versions.set(Package.resolvePath(name), VERSION);
Expand Down Expand Up @@ -407,7 +405,7 @@ if (typeof MathJax.loader === 'undefined') {
load: [],
ready: Loader.defaultReady.bind(Loader),
failed: (error: PackageError) =>
console.log(`MathJax(${error.package || '?'}): ${error.message}`),
console.warn(`MathJax(${error.package || '?'}): ${error.message}`),
require: null,
json: null,
pathFilters: [],
Expand Down
5 changes: 3 additions & 2 deletions ts/components/package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import { CONFIG, Loader } from './loader.js';
import { context } from '../util/context.js';
import { localize } from '../core/__locales__/Component.js';

/**
* A map of package names to Package instances
Expand Down Expand Up @@ -323,7 +324,7 @@ export class Package {
.then((result) => (this.result = result))
.then(() => this.checkLoad())
.catch((err) =>
this.failed('Can\'t load "' + url + '"\n' + err.message.trim())
this.failed(localize('CantLoad', url, ':\n' + err.message.trim()))
);
} else {
this.result = result;
Expand All @@ -344,7 +345,7 @@ export class Package {
script.src = url;
script.charset = 'UTF-8';
script.onload = (_event) => this.checkLoad();
script.onerror = (_event) => this.failed('Can\'t load "' + url + '"');
script.onerror = (_event) => this.failed(localize('CantLoad', url, ''));
// FIXME: Should there be a timeout failure as well?
context.document.head.appendChild(script);
}
Expand Down
18 changes: 6 additions & 12 deletions ts/components/startup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ import { DOMAdaptor } from '../core/DOMAdaptor.js';
import { PrioritizedList } from '../util/PrioritizedList.js';
import { OptionList, OPTIONS } from '../util/Options.js';
import { context } from '../util/context.js';
import { Locale } from '../util/Locale.js';
import { COMPONENT } from '../core/__locales__/Component.js';

import { TeX } from '../input/tex.js';

Expand Down Expand Up @@ -527,9 +529,7 @@ export abstract class Startup {
jax[name] = new inputClass(MathJax.config[name]);
jax.push(jax[name]);
} else {
throw Error(
'Input Jax "' + name + '" is not defined (has it been loaded?)'
);
Locale.throw(COMPONENT, 'InputJaxNotDefined', name);
}
}
return jax;
Expand All @@ -543,9 +543,7 @@ export abstract class Startup {
if (!name) return null;
const outputClass = Startup.constructors[name];
if (!outputClass) {
throw Error(
'Output Jax "' + name + '" is not defined (has it been loaded?)'
);
Locale.throw(COMPONENT, 'OutputJaxNotDefined', name);
}
return new outputClass(MathJax.config[name]);
}
Expand All @@ -559,9 +557,7 @@ export abstract class Startup {
if (!name || name === 'none') return null;
const adaptor = Startup.constructors[name];
if (!adaptor) {
throw Error(
'DOMAdaptor "' + name + '" is not defined (has it been loaded?)'
);
Locale.throw(COMPONENT, 'AdaptorNotDefined', name);
}
return adaptor(MathJax.config[name]);
}
Expand All @@ -574,9 +570,7 @@ export abstract class Startup {
if (!name || name === 'none' || !Startup.adaptor) return null;
const handlerClass = Startup.constructors[name];
if (!handlerClass) {
throw Error(
'Handler "' + name + '" is not defined (has it been loaded?)'
);
Locale.throw(COMPONENT, 'HandlerNotDefined', name);
}
let handler = new handlerClass(Startup.adaptor, 5);
for (const extend of Startup.extensions) {
Expand Down
39 changes: 39 additions & 0 deletions ts/core/__locales__/Component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*************************************************************
*
* Copyright (c) 2026 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* @file Locale component registration for core component
*
* @author dpvc@mathjax.org (Davide P. Cervone)
*/

import { Locale, namedData } from '../../util/Locale.js';

export const COMPONENT = 'core';

Locale.registerLocaleFiles(COMPONENT, '../ts/core');

/**
* Get a localized message for this component
*
* @param {string} id The id of the message
* @param {(string|namedData)[]} args The replacement arguments for the message, if any
* @returns {string} The localized message
*/
export function localize(id: string, ...args: (string | namedData)[]): string {
return Locale.message(COMPONENT, id, ...args);
}
9 changes: 9 additions & 0 deletions ts/core/__locales__/de.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"AdaptorNotDefined": "DOMAdaptor '%1' ist nicht definiert (wurde es geladen?)",
"CantLoad": "'%1' kann nicht geladen werden%2",
"HandlerNotDefined": "Handler '%1' ist nicht definiert (wurde es geladen?)",
"InputJaxNotDefined": "Input Jax '%1' ist nicht definiert (wurde es geladen?)",
"NoVersionFor": "Für die Komponente '%1' liegen keine Versionsinformationen vor",
"OutputJaxNotDefined": "Output Jax '%1' ist nicht definiert (wurde es geladen?)",
"WrongVersion": "Die Komponente %1 verwendet Version %2 von MathJax; die verwendete Version ist %3"
}
9 changes: 9 additions & 0 deletions ts/core/__locales__/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"AdaptorNotDefined": "DOMAdaptor '%1' is not defined (has it been loaded?)",
"CantLoad": "Can't load '%1'%2",
"HandlerNotDefined": "Handler '%1' is not defined (has it been loaded?)",
"InputJaxNotDefined": "Input Jax '%1' is not defined (has it been loaded?)",
"NoVersionFor": "No version information available for component '%1'",
"OutputJaxNotDefined": "Output Jax '%1' is not defined (has it been loaded?)",
"WrongVersion": "Component %1 uses version %2 of MathJax; version in use is %3"
}