mathjax / MathJax

Beautiful and accessible math in all browsers
http://www.mathjax.org/
Apache License 2.0
10.1k stars 1.16k forks source link

migrate from version 2 to 3 #3150

Open saraOrkide opened 8 months ago

saraOrkide commented 8 months ago

I want to migrate from version 2 to 3 But I found many problems I can't convert English numbers to Farsi and the Persian word is displayed in the formula as letters and separate from each other

Configuration version 2.7.9:

MathJax.Hub.Config(
      {
        showMathMenu: false,
      //   preview: "true",
      //   extensions: ["tex2jax.js","mml2jax.js","MathMenu.js","MathZoom.js","AssistiveMML.js", "a11y/accessibility-menu.js", "toMathML.js"],
        TeX: {
          // extensions: ["AMSmath.js","AMSsymbols.js","noErrors.js","noUndefined.js"],
          inlineMath: [['$', '$'], ['\\(', '\\)']]

        },
      "fast-preview": {disabled: true},
      // بقیه متن ها رو خراب میکنه  اگر علایم ریاضی داخلشون باشه
      // tex2jax: {
      //     inlineMath: [['$ ', ' $'], ["\\(", "\\)"]],
      //     displayMath: [['$$', '$$'], ["\\[", "\\]"]],
      //     processEscapes: true,
      //     preview: "none"
      // },
      jax: ["input/TeX","output/CommonHTML"],
      MatchWebFonts: {
        matchFor: {
          "HTML-CSS": true,
          NativeMML: false,
          SVG: false
        },
        // fontCheckDelay: 2000,
        // fontCheckTimeout: 30 * 1000
      },
      'HTML-CSS':
        {
            webFont: "TeX",
            preferredFont:"var(--font-r)",
            undefinedFamily: "var(--font-r) STGeneral, 'Arial Unicode MS', serif",
            availableFonts: ["var(--font-r)", "TeX", "STIX"],
            mtextFontInherit: true,
            noReflows: true,
            scale: 100,
            minScaleAdjust: 100,
            matchFontHeight: true,
            linebreaks: {automatic: true},
        },
        CommonHTML: {
          scale: 100,
          mtextFontInherit: true,
        },
        SVG: {
          mtextFontInherit: true,
        },
      }
      );
      MathJax.Hub.Register.StartupHook("HTML-CSS Jax Ready", function () {
        var REMAP = MathJax.OutputJax["HTML-CSS"].FONTDATA.REMAP;
        var ZERO = 0x6F0;     // use 0x660 for Arabic, 0x6F0 for Persian
        for (var i = 0; i < 10; i++) {REMAP[0x30+i] = ZERO+i}
      });
      MathJax.Hub.Register.StartupHook("Begin",function () {
        MathJax.Hub.Queue(
          console.log("start-render")
        )
      });
      MathJax.Hub.Register.StartupHook("End",function () {
        MathJax.Hub.Queue(
          console.log("finish-render")
        )
      });
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.9/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>

I converted this configuration to version 3:

    <script type="text/x-mathjax-config">
        window.MathJax = {
            loader: {
                load: ['[mml]/mml3'],
                source: {'[tex]/mhchem': '[persian]/mhchem.min.js'},
                paths: {persian: '.'}
            },
            options: {
              enableMenu: false,
              ignoreHtmlClass: 'tex2jax_ignore',
              processHtmlClass: 'tex2jax_process'
            },
            tex: {
                packages: {'[+]': ['mhchem']},
                digits: /^(?:[\d۰-۹]+(?:[,٬'][\d۰-۹]{3})*(?:[\.٫][\d۰-۹]*)?|[\.٫][\d۰-۹]+)/,
                tags:"ams"
            },
            "%s is now handled through direct CSS": "var(--font-r) STGeneral, 'Arial Unicode MS', serif",
            chtml: {
              mtextInheritFont: true,
              scale: 1,
              minScale: 1,
              matchFontHeight: true
            },
            svg: {
              mtextInheritFont: true
            },
            startup: {
                ready() {
                    console.log("ready!!!!!");
                    var ParseMethods = MathJax._.input.tex.ParseMethods.default;
                    var RegExpMap = MathJax._.input.tex.SymbolMap.RegExpMap;
                    new RegExpMap('digit', ParseMethods.digit, /[\d.٫۰-۹]/);
                    MathJax.startup.defaultReady();
                }
            }
          };
      </script>
     <script type="text/javascript" id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js">

ex mml code:

<math xmlns='http://www.w3.org/1998/Math/MathML'
                    display='inline-block'>
                    <mtable xmlns='http://www.w3.org/1998/Math/MathML' columnalign='left'>
                        <mtr>
                            <mtd>
                                <mo>(</mo>
                                <mi>a</mi>
                                <mo>,</mo>
                                <mn>1</mn>
                                <mo>)</mo>
                                <mover accent='false'>
                                    <mo>→</mo>
                                    <mrow>
                                        <mtext>تابع همانی</mtext>
                                    </mrow>
                                </mover>
                                <mi>a</mi>
                                <mo>=</mo>
                                <mn>1</mn>
                            </mtd>
                            <mtd />
                        </mtr>
                    </mtable>
                </math>

Screenshot from 2023-12-23 14-14-42

dpvc commented 8 months ago

The main issue is that MathJax v3 doesn't use <script type="text/x-mathjax-config">, but rather just <script>, so your configuration is never being executed. In particular, the mtextInheritFont: true options aren't taking effect, which is why the Persian letters are not being combined properly. Once you remove type="text/x-mathjax-config", the Persian should display better.

On the other hand, there are some other problems with your configuration. First, you are adding the mhchem package in the tex.packages list, but you have not loaded mhchem, so that will do nothing. You probably want to add [tex]/mhchem to the loader.load list, or remove the tex.packages configuration option.

Second, the

            "%s is now handled through direct CSS": "var(--font-r) STGeneral, 'Arial Unicode MS', serif",

line should probably really be a comment. As it stands, this is a configuration option named %s is now handled through direct CSS with value var(--font-r) STGeneral, 'Arial Unicode MS', serif. This will be ignored, since there is not MathJax option with that name, but it is probably better as a comment.

Third, the inlineMath option was in the wrong location in your original v2 configuration, so was flagged as not having a conversion value when you used the conversion tool to translate your v2 configuration to a v3 one. You can add inlineMath to the tex block in your v3 configuration if you want.

In order to handle the automatic translation of English to Persian numbers, you can use the following ready() function:

  startup: {
    ready() {
      const ParseMethods = MathJax._.input.tex.ParseMethods.default;
      const {RegExpMap} = MathJax._.input.tex.SymbolMap;
      new RegExpMap('digit', ParseMethods.digit, /[\d.٫۰-۹]/);

      const {CHTMLmn} = MathJax._.output.chtml.Wrappers.mn;
      CHTMLmn.prototype.remapChars = function (chars) {
        const C = [];
        for (const c of chars) {
          const text = this.font.getRemappedChar('mn', c);
          C.push(...(text ? this.unicodeChars(text, this.variant) : [c]));
        }
        return C;
      };

      const FontData = MathJax.config.chtml.font;
      const REMAP = FontData.remapChars.mn;
      var ZERO = 0x6F0;     // use 0x660 for Arabic, 0x6F0 for Persian
      for (var i = 0; i < 10; i++) {REMAP[0x30 + i] = String.fromCodePoint(ZERO + i)}

      MathJax.startup.defaultReady();
    }
  }

The CHTMLmn output wrapper needs to be modified like this to allow it to remap the digits (right now it is only set up to remap the initial minus sign from a hyphen to the math minus sign.

With those changes, I think you will get better results.

saraOrkide commented 8 months ago

Does the configuration not work on version 4? Every time we update to a higher version, we have to change the settings completely

dpvc commented 8 months ago

Does the configuration not work on version 4?

I'm not sure which configuration you mean.

Every time we update to a higher version, we have to change the settings completely

Version 3 was a complete rewrite of MathJax from the ground up, and it did change the API in a significant way. That is why the configuration changed so drastically. We did provide a conversion tool to help you update your configuration from v2 to v3, which it looks like you may have used.

Version 4 is an extension of v3, not a complete rewrite, so the configuration will remain essentially the same (there are some new options). Because v4 includes many new features, and some changes to the defaults that may not be backward compatible, we have given it a new major version number, but the v3 configurations should work largely without change in v4. The one caveat is that if you are making changes to the internals of MathJax in your startup.ready() function, it is possible that those will need to be updated for v4.

saraOrkide commented 8 months ago

Ok, well, for example, in startup.ready, I am changing the numbers to Farsi with the code you sent me, which did not work in version 4. This item is now supported in version 4.

dpvc commented 8 months ago

Yes, that is exactly the kind of thing I mentioned as possibly needing updating for v4. The internals of MathJax have changed, and code in startup.ready() that manipulates those internals, as the Farsi number code does, may need updating. That is to be expected when you make those kinds of adjustments, and is one of the reasons that v4 is a major update with a higher major version number.

saraOrkide commented 8 months ago

Ok, how can I find out that this possibility is available on v4 and switch to it?

saraOrkide commented 8 months ago

Ok, how can I find out that this possibility is available on v4 and switch to it?

dpvc commented 8 months ago

What do you mean by "this possibility"?

saraOrkide commented 8 months ago
  startup: {
    ready() {
      const {CHTMLmn} = MathJax._.output.chtml.Wrappers.mn;
      CHTMLmn.prototype.remapChars = function (chars) {
        const C = [];
        for (const c of chars) {
          const text = this.font.getRemappedChar('mn', c);
          C.push(...(text ? this.unicodeChars(text, this.variant) : [c]));
        }
        return C;
      };

      const FontData = MathJax.config.chtml.font;
      const REMAP = FontData.remapChars.mn;
      var ZERO = 0x6F0;     // use 0x660 for Arabic, 0x6F0 for Persian
      for (var i = 0; i < 10; i++) {REMAP[0x30 + i] = String.fromCodePoint(ZERO + i)}

      MathJax.startup.defaultReady();
    }
  }

Convert numbers to Farsi in starup.ready()

dpvc commented 8 months ago

Since you have this code in v3, you could try it in v4. When it doesn't work, you would look at the error messages and work from there. You could use the GitHub comparison tools (available by starting a new pull request) to compare the 4.0.0-beta.4 tag to the current master branch (there are a lot of changes, however), and look for what may have changed in the file where the code that is causing the error occurs.

For example, the first error you will get is that there is no CHTMLmn properly in the MathJax._.output.chtml.Wrappers.mn object. The MathJax._ object corresponds to the source tree for MathJax, so you would look at the ts/output/chtml/Wrappers/mn.ts file in the comparison and see that CHTMLmn has been renamed to ChtmlMn. The is what lead to that change in the v4 update that I posted in one of your other issues.

You would have to continue that way until you resolved the problems.

Note that there is information in the beta.4, beta.2, and alpha.1 release notes about what changes are being made, so that may also give you some hints about what to do.

Also, since the v3 code was posted in this issue tracker, you could make a comment here asking for a v4 version.

dpvc commented 8 months ago

For the record this is the code updated for v4:

  startup: {
    ready() {
      const ParseMethods = MathJax._.input.tex.ParseMethods.default;
      const {RegExpMap} = MathJax._.input.tex.TokenMap;
      new RegExpMap('digit', ParseMethods.digit, /[\d.٫۰-۹]/);

      const {ChtmlMn} = MathJax._.output.chtml.Wrappers.mn;
      ChtmlMn.prototype.remapChars = function (chars) {
        const C = [];
        for (const c of chars) {
          const text = this.font.getRemappedChar('mn', c);
          C.push(...(text ? this.unicodeChars(text, this.variant) : [c]));
        }
        return C;
      };

      const {FontData} = MathJax._.output.common.FontData;
      const REMAP = FontData.defaultMnMap;
      var ZERO = 0x6F0;     // use 0x660 for Arabic, 0x6F0 for Persian
      for (var i = 0; i < 10; i++) {REMAP[0x30 + i] = String.fromCodePoint(ZERO + i)}

      MathJax.startup.defaultReady();
    }
  }
saraOrkide commented 8 months ago

For the record this is the code updated for v4:

  startup: {
    ready() {
      const ParseMethods = MathJax._.input.tex.ParseMethods.default;
      const {RegExpMap} = MathJax._.input.tex.TokenMap;
      new RegExpMap('digit', ParseMethods.digit, /[\d.٫۰-۹]/);

      const {ChtmlMn} = MathJax._.output.chtml.Wrappers.mn;
      ChtmlMn.prototype.remapChars = function (chars) {
        const C = [];
        for (const c of chars) {
          const text = this.font.getRemappedChar('mn', c);
          C.push(...(text ? this.unicodeChars(text, this.variant) : [c]));
        }
        return C;
      };

      const {FontData} = MathJax._.output.common.FontData;
      const REMAP = FontData.defaultMnMap;
      var ZERO = 0x6F0;     // use 0x660 for Arabic, 0x6F0 for Persian
      for (var i = 0; i < 10; i++) {REMAP[0x30 + i] = String.fromCodePoint(ZERO + i)}

      MathJax.startup.defaultReady();
    }
  }

very thanx

dpvc commented 8 months ago

@saraOrkide: I had originally posted the v4 version here in response to another of your questions. Perhaps you didn't see it there.