Initial implementation of Locale framework, with updates to asyncLoad to handle json files, and updates to testsuite. #1407
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR is a replacement for #1122, which had numerous merge conflicts, as it was originally written in the summer of 2024, and things have progressed in the code base since then. I have updated the files, and made several improvements so that it works properly in node applications, among other things. I also added test files to get full coverage of the localization utility, and updated some of the test framework to properly handle loading of the locale data. Note that you will need to recompile the test scripts in order to properly handle the localization, so do
The
MathJax-demos-nodeutilities need some updating to work with this branch, as they don't currently handle the locale files. I will make a branch in that repository for testing purposes.The main file is the
ts/util/Locale.tsfile. It defines aLocaleclass that is used for registering and loading localization files. Those are JSON files that make the message ids to the message strings, with each component registering its own localization files. This is so that third-party components can register localizations, for example, and so that we don't have to transfer all the strings for components that are never loaded.When a component file is loaded, it registers itself with the Locale object so that its messages can be loaded when needed. This is done by calling
Locale.registerLocaleFiles(), which is passed the component name (like 'input/tex' or '[tex]/bbox') and the directory where the locale files are loaded (for use by node applications that are loading the MathJax modules directly rather than through components).This is illustrated by example changes to the
bboxTeX extension. TheBboxConfiguration.tsfile shows the registration call, and defines abboxError()function that creates aTexErrorobject and looks up the localized message for it before throwing the error. Eventually, this lookup will be part ofTeXErroritself, but I only wanted to illustrate the process here, and didn't want to go through and change everyTeXErrorcall at this point. In the end, one will callTexError(components, id, ...args)rather than needed a specialbboxError()command, so this is just for now.The rest of the changes in
BboxConfiguration.tsare to replace thethrow TexError()commands with correspondingbboxError()commands for now, just to show how it works.The localization files are stored in
ts/input/tex/bbox/locales, and I've only provided theen.jsonfile there was an example. Thebboxcomponentconfig.jsonfile gets a newcopysection that copies the locale files to the bundle directory. Because this uses the new[bundle]and[ts]paths, this PR targets theupdate/copy-configbranch where those are introduced (which is why I made that separate PR -- these had been combined in the original #1122).Because the locale files are JSON files, MathJax's file loaders need to be modified to handle JSON files. Unfortunately, how that has to be done differs depending on if you are using the browser or a node application, and whether you are using
import()orrequire(). In order to handle these variations, we introduce a newmathjax.json()function similar to themathjax.asyncLoad()function, but for loading JSON files. The files ints/utility/asyncLoadare modified to set up this function appropriately for the given mechanism (except forsystem.ts, as I'm not sure what the mechanism should be for that, and it is no longer used in any case).To help with this,
ts/util/AsyncLoad.tshas a new method,resolvePath()that gives a consistent mechanism for find the path to a file being loaded, whether it is a component name like[tex]/bbox, a relative path, an absolute path, or a node module reference. Theesm,node,node-import, andsystemimplementations use this to guarantee that paths are treated consistently in all cases.Because using
importorimport()to load JSON files in node currently is an experimental feature, which produces a warning message when used, theesm.tsimplementation doesn't useimportand instead usesfs.readFileSync()to avoid that. In order to resolve node module directories (like@mathjax/src), theinput.meta.resolvefunction is used. Butjestdoesn't implementinput.meta.resolve, so there is a check to use a default function if that isn't available. A newfs.d.tsfile is added to get a type for thereadFileSync()function.The
node.tsimplementation is easier, asrequire()works to load JSON files, and also handles the node module paths, so nothing really needs to be done there. Similarly, thenode-import.tsfile usesrequire()to load JSON files (andimport()for others).The
mathjax.tsfile sets upmathjax.jsonto usefetch(), which is the mechanism used in the browser. Butfetch()forfile://URLs is not allowed in node, which is whymathjax.jsonis overridden in node applications by loading one of the asyncLoad implementations just discussed.The test files for AsyncLoad and its individual implementations have new tests to check the handling of JSON files.
The
components/mjs/core/core.jsfile's implementation ofmathjax.asyncLoadis modified to handle JSON file usingconfig.jsonif it exists, ormathjax.jsonotherwise. This allows users to configure thejsonloader just like they configure therequirefunction, via setting theMathJax.loader.jsonconfiguration option. For example, one could doto use
import()for loading all files, including JSON files. Because this would result in a warning message when used in a node application, however, there is a newcomponents/json.cjsfile that exports ajsonfunction (and arequirefunction) that can be used in node applications aswhich will use
require()for both. Thejson.cjsfile is copied to the bundle directory via the config files for therequirecomponent.The
corecomponent also loads a newlocal.jsfile that imports theLocaleutility and setsLocale.isComponent = true. This is used by theLocaleobject to determine where to load the locale file (either using the component name or the explicit path). In browsers or node applications that use components, this will use thePackage.resolvePath()function to map component names to their proper locations. In node applications with direct imports of MathJax modules, this will use the direct paths to the locale data in the locale folders in thetsdirectory.The
node-maincomponent has had itsasyncLoadmodified to use theresolvePathmethod fromAsyncLoadand to handle JSON files.The
package.jsonfile gets a newcopy:localesscript to copy any tex extension locale files (I forgot about that, so I guess the change to thebbox/config.jsonweren't needed; we can decide which way to go with that).Then there are new test files and support files for testing loading of JSON files. I also added some
.d.tsfiles to avoid typescript complaints about missing types. ThesetupTex.jsfile now handles setup of locales. This makes a couple of functions asynchronous, so some calls tosetupTex()need to beasync.The
jsonoption is added to thets/components/loader.tsfile, and I fixed some typing mistakes there.The
ts/components/startup.tsfile now loads and configures theLocalelibrary. TheLocale.setLocale()call is what loads the needed JSON files.The
requireTeX extension now callsLocale.setLocale()to load any localizations needed by the newly loaded package. That way, ifbboxis loaded, for example, is localizations will be loaded automatically when\require{bbox}is used, or when it is autoloaded.That should get you through most of the changes here.