commit 4ced117e0569fa42c57c7f444f9f103c74c65fba
parent fc7aa04a44d0c875c5c92a6e6f7703247015df81
Author: Frédéric Wang <fred.wang@free.fr>
Date: Tue, 19 Feb 2013 19:40:52 +0100
Initial implementation of MathJax.Localization. Some experiments with French localization.
Diffstat:
2 files changed, 362 insertions(+), 26 deletions(-)
diff --git a/unpacked/MathJax.js b/unpacked/MathJax.js
@@ -1,3 +1,5 @@
+/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax.js
@@ -2476,3 +2478,313 @@ MathJax.Hub.Startup = {
}}
/**********************************************************/
+
+MathJax.Localization = {
+
+ locale: "fr",
+ directory: "[MathJax]/localization",
+ strings: {
+ fr: {
+ isLoaded: true,
+ domains: {
+ "_": {
+ strings: {
+ }
+ },
+ // FontWarnings: {
+ // isLoaded: true,
+ // strings: {
+ // fonts:
+ // [
+ // ["p"],
+ // "MathJax peut utiliser soit les ",
+ // ["a",{href:"http://www.stixfonts.org/",target:"_blank"},"polices STIX"],
+ // " soit les ",
+ // ["a",{href:"http://www.mathjax.org/help-v2/fonts/",target:"_blank"},["polices TeX de MathJax"]],
+ // ". Téléchargez et installez une de ces familles pour rendre plus confortable votre utilisation de MathJax."
+ // ]
+ // }
+ // },
+
+ Menu: {
+ isLoaded: true,
+ strings: {
+ WebkitNativeMMLWarning:
+
+ "Votre navigateur ne semble pas comporter de support MathML, " +
+ "changer le mode de rendu pourrait rendre illisibles " +
+ "les expressions mathématiques.",
+
+ MSIENativeMMLWarning:
+
+ "Internet Explorer a besoin de module complémentaire MathPlayer " +
+ "pour afficher le MathML.",
+
+ OperaNativeMMLWarning:
+
+ "Le support MathML d'Opera est limité, changer le mode de rendu " +
+ "pourrait entrainer un affichage médiocre de certaines expressions.",
+
+ SafariNativeMMLWarning:
+
+ "Le support MathML natif de votre navigateur ne comporte pas " +
+ "toutes les fonctionnalités requises par MathJax, certaines " +
+ "expressions pourront donc ne pas s'afficher correctement.",
+
+ FirefoxNativeMMLWarning:
+
+ "Le support MathML natif de votre navigateur ne comporte pas " +
+ "toutes les fonctionnalités requises par MathJax, certaines " +
+ "expressions pourront donc ne pas s'afficher correctement.",
+
+ SwitchAnyway:
+ "Êtes vous certain de vouloir changer le mode de rendu ?\n\n" +
+ "Appuyez sur OK pour valider ou Annuler pour continuer avec le " +
+ "mode de rendu actuellement sélectionné.",
+
+ ScaleMath:
+ "Mise à l'échelle des expressions mathématiques (par rapport au " +
+ "text environnant) de %1%%",
+
+ NonZeroScale:
+ "L'échelle ne peut être nulle",
+
+ PercentScale:
+ "L'échelle doit être un pourcentage (e.g. 120%%)",
+
+ IE8warning:
+ "Ceci désactivera le menu de MathJax et les fonctionalités de " +
+ "zoom mais vous pourrez toujours obtenir le menu de MathJax " +
+ "en utilisant la commande Alt+Clic sur une expression.\n\n" +
+ "Êtes vous certain de vouloir choisir les options de MathPlayer?",
+
+ IE9warning:
+ "Le menu contextuel de MathJax sera désactivé, " +
+ "mais vous pourrez toujours obtenir le menu de MathJax " +
+ "en utilisant la commande Alt-Clic sur une expression.",
+
+ NoOriginalForm:
+ "Aucune forme originelle",
+
+ Close:
+ "Fermer",
+
+ EqSource:
+ "Source de l'équation MathJax"
+ }
+ }
+ }
+ }
+ },
+
+ _: function (messageId, englishPhrase) {
+
+ // These variables are used in string parsing
+ var plural = this.plural;
+ var args = arguments;
+ var i, s, result;
+
+ function parseNextUnicodePoint(appendToResult)
+ {
+ var n = s.charCodeAt(i);
+ if (n <= 0xD7FF || 0xE000 <= n) {
+ // Code points U+0000 to U+D7FF and U+E000 to U+FFFF.
+ // Append the character.
+ if (appendToResult) result += s[i]
+ i++;
+ return;
+ } else if (i+1 < m) {
+ // Code points U+10000 to U+10FFFF
+ // Append the surrogate pairs.
+ if (appendToResult) { result += s[i]; result += s[i+1]; }
+ i+=2
+ return;
+ }
+ // Ignore lead surrogate at the end of the string.
+ // This should not happen with valid unicode string.
+ i++;
+ }
+
+ function parseArgument(appendToResult)
+ {
+ if (!(/\d/.test(s[0]))) return false;
+
+ // %INTEGER argument substitution
+ var argIndex = s.match(/^\d+/)[0];
+ i += argIndex.length;
+ var key = +argIndex+1;
+ if (key in args) {
+ if (appendToResult) { result += args[key]; }
+ return true;
+ }
+
+ // invalid index: just %INTEGER and continue
+ if (appendToResult) { result += "%" + argIndex; }
+ i++;
+ return true;
+ }
+
+ function parseInteger(appendToResult)
+ {
+ var number = s.match(/^\{(\d+)\}/);
+ if (!number) return false;
+
+ // %{INTEGER} escaped integer
+ if (appendToResult) { result += number[1]; }
+ i += number[0].length;
+ return true;
+ }
+
+ function parseChoiceBlock(blockName, choiceFunction)
+ {
+ var pattern = "^\\{"+blockName+":%(\\d)+\\|";
+ var blockStart = s.match(pattern);
+ if (!blockStart) return false;
+
+ var key = +blockStart[1]+1;
+ if (!(key in args)) return false;
+
+ // %\{blockName:%INTEGER|form1|form2 ... \}
+ i = blockStart[0].length;
+
+ var choiceIndex = choiceFunction(args[key]), j = 1;
+ var isChosenBlock = (j === choiceIndex);
+ var blockFound = false;
+
+ while (i < m) {
+ if (s[i] == "|") {
+ // new choice block
+ i++; j++;
+ isChosenBlock = (j === choiceIndex);
+ if (isChosenBlock) blockFound = true;
+ continue;
+ }
+ if (s[i] == "}") {
+ // closing brace
+ i++;
+ break;
+ }
+ if (s[i] != "%" || i+1 == m) {
+ // normal char or % at the end of the string
+ parseNextUnicodePoint(isChosenBlock);
+ continue;
+ }
+
+ // keep only the substring after the %
+ i++; s = s.substr(i); m -= i; i = 0;
+
+ // %INTEGER argument substitution
+ if (parseArgument(isChosenBlock)) continue;
+
+ // %{INTEGER} escaped integer
+ if (parseInteger(isChosenBlock)) continue;
+
+ // %CHAR: escaped character
+ parseNextUnicodePoint(isChosenBlock);
+ continue;
+ }
+
+ if (!blockFound) {
+ i = 0;
+ return false;
+ }
+
+ return true;
+ }
+
+ function transformString(string)
+ {
+ s = string;
+ i = 0;
+ m = s.length;
+ result = "";
+
+ while (i < m) {
+ if (s[i] != "%" || i+1 == m) {
+ // normal char or % at the end of the string
+ parseNextUnicodePoint(true);
+ continue;
+ }
+
+ // keep only the substring after the %
+ i++; s = s.substr(i); m -= i; i = 0;
+
+ // %INTEGER argument substitution
+ if (parseArgument(true)) continue;
+
+ // %{INTEGER} escaped integer
+ if (parseInteger(true)) continue;
+
+ // %\{plural:%INTEGER|form1|form2 ... \} plural forms
+ if (parseChoiceBlock("plural", plural)) continue;
+
+ // %CHAR: escaped character
+ parseNextUnicodePoint(true);
+ continue;
+ }
+
+ return result;
+ }
+
+ function transformHTMLSnippet(snippet)
+ {
+ for (key in snippet) {
+ var e = snippet[key];
+ if (typeof e === "string") {
+ snippet[key] = transformString(e);
+ continue;
+ }
+ var lastIndex = e.length-1;
+ if (Array.isArray(e[lastIndex])) {
+ e[lastIndex] = transformHTMLSnippet(e[lastIndex]);
+ }
+ }
+ return snippet;
+ }
+
+ // try to get the translated phrase or use the englishPhrase fallback
+ var phrase = englishPhrase;
+ var translationData = this.strings[this.locale];
+ if (translationData) {
+ if (translationData.isLoaded) {
+ var domain = "_";
+ if (Array.isArray(messageId) && messageId.length == 2) {
+ domain = messageId[0];
+ messageId = messageId[1];
+ }
+ if (domain in translationData.domains) {
+ domain = translationData.domains[domain]
+ if (domain.isLoaded && messageId in domain.strings) {
+ phrase = domain.strings[messageId];
+ }
+ }
+ }
+ }
+
+ if (typeof phrase === "string") {
+ // handle the phrase as a simple string
+ return transformString(phrase);
+ }
+
+ // handle the phrase as a HTML snippet
+ return transformHTMLSnippet(phrase);
+ },
+
+ setLocale: function(locale) {
+ this.locale = locale;
+ // TODO
+ },
+
+ addTranslation: function (locale, domain, definition) {
+ // TODO
+ },
+
+ fontFamily: function () {
+ return null;
+ },
+
+ plural: function(n) {
+ if (n == 1) return 1;
+ return 2;
+ }
+};
diff --git a/unpacked/extensions/MathMenu.js b/unpacked/extensions/MathMenu.js
@@ -1,3 +1,5 @@
+/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax/extensions/MathMenu.js
@@ -33,6 +35,13 @@
signal: SIGNAL
};
+ var _ = function (id) {
+ return MathJax.Localization._.apply(
+ MathJax.Localization,
+ [ ["Menu", id] ].concat([].slice.call(arguments,1))
+ );
+ };
+
var isPC = HUB.Browser.isPC, isMSIE = HUB.Browser.isMSIE, isIE9 = ((document.documentMode||0) > 8);
var ROUND = (isPC ? null : "5px");
@@ -690,7 +699,10 @@
return;
}
} else {
- if (MENU.jax.originalText == null) {alert("No original form available"); return}
+ if (MENU.jax.originalText == null) {
+ alert(_("NoOriginalForm", "No original form available"));
+ return;
+ }
MENU.ShowSource.Text(MENU.jax.originalText,event);
}
};
@@ -706,16 +718,17 @@
var w = MENU.ShowSource.Window(event); delete MENU.ShowSource.w;
text = text.replace(/^\s*/,"").replace(/\s*$/,"");
text = text.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">");
+ var title = _("EqSource", "MathJax Equation Source");
if (MENU.isMobile) {
w.document.open();
- w.document.write("<html><head><meta name='viewport' content='width=device-width, initial-scale=1.0' /><title>MathJax Equation Source</title></head><body style='font-size:85%'>");
+ w.document.write("<html><head><meta name='viewport' content='width=device-width, initial-scale=1.0' /><title>"+title+"</title></head><body style='font-size:85%'>");
w.document.write("<pre>"+text+"</pre>");
- w.document.write("<hr><input type='button' value='Close' onclick='window.close()' />");
+ w.document.write("<hr><input type='button' value='"+_("Close", "Close")+"' onclick='window.close()' />");
w.document.write("</body></html>");
w.document.close();
} else {
w.document.open();
- w.document.write("<html><head><title>MathJax Equation Source</title></head><body style='font-size:85%'>");
+ w.document.write("<html><head><title>"+title+"</title></head><body style='font-size:85%'>");
w.document.write("<table><tr><td><pre>"+text+"</pre></td></tr></table>");
w.document.write("</body></html>");
w.document.close();
@@ -740,7 +753,7 @@
MENU.Scale = function () {
var HTMLCSS = OUTPUT["HTML-CSS"], nMML = OUTPUT.NativeMML, SVG = OUTPUT.SVG;
var SCALE = (HTMLCSS||nMML||SVG||{config:{scale:100}}).config.scale;
- var scale = prompt("Scale all mathematics (compared to surrounding text) by",SCALE+"%");
+ var scale = prompt(_("ScaleMath", "Scale all mathematics (compared to surrounding text) by %1%%",SCALE));
if (scale) {
if (scale.match(/^\s*\d+(\.\d*)?\s*%?\s*$/)) {
scale = parseFloat(scale);
@@ -752,8 +765,9 @@
MENU.cookie.scale = scale;
MENU.saveCookie(); HUB.Reprocess();
}
- } else {alert("The scale should not be zero")}
- } else {alert("The scale should be a percentage (e.g., 120%)")}
+ } else {alert(_("NonZeroScale", "The scale should not be zero"))}
+ } else {alert(_("PercentScale",
+ "The scale should be a percentage (e.g., 120%%)"))}
}
};
@@ -791,8 +805,10 @@
break;
}
if (message) {
- message += "\n\nSwitch the renderer anyway?\n\n" +
- "(Press OK to switch, CANCEL to continue with the current renderer)";
+ message += "\n\n";
+ message += _("SwitchAnyway",
+ "Switch the renderer anyway?\n\n" +
+ "(Press OK to switch, CANCEL to continue with the current renderer)");
MENU.cookie.renderer = jax[0].id; MENU.saveCookie(); if (!confirm(message)) {return}
if (warned) {MENU.cookie[warned] = CONFIG.settings[warned] = true}
MENU.cookie.renderer = CONFIG.settings.renderer; MENU.saveCookie();
@@ -805,28 +821,34 @@
};
MENU.Renderer.Messages = {
MML: {
- WebKit: "Your browser doesn't seem to support MathML natively, " +
- "so switching to MathML output may cause the mathematics " +
- "on the page to become unreadable.",
+ WebKit: _("WebkitNativeMMLWarning",
+ "Your browser doesn't seem to support MathML natively, " +
+ "so switching to MathML output may cause the mathematics " +
+ "on the page to become unreadable."),
- MSIE: "Internet Explorer requires the MathPlayer plugin " +
- "in order to process MathML output.",
+ MSIE: _("MSIENativeMMLWarning",
+ "Internet Explorer requires the MathPlayer plugin " +
+ "in order to process MathML output."),
- Opera: "Opera's support for MathML is limited, so switching to " +
- "MathML output may cause some expressions to render poorly.",
+ Opera: _("OperaNativeMMLWarning",
+ "Opera's support for MathML is limited, so switching to " +
+ "MathML output may cause some expressions to render poorly."),
- Safari: "Your browser's native MathML does not implement all the features " +
- "used by MathJax, so some expressions may not render properly.",
+ Safari: _("SafariNativeMMLWarning",
+ "Your browser's native MathML does not implement all the features " +
+ "used by MathJax, so some expressions may not render properly."),
- Firefox: "Your browser's native MathML does not implement all the features " +
- "used by MathJax, so some expressions may not render properly."
+ Firefox: _("FirefoxNativeMMLWarning",
+ "Your browser's native MathML does not implement all the features " +
+ "used by MathJax, so some expressions may not render properly.")
},
SVG: {
- MSIE: "SVG is not implemented in Internet Explorer prior to " +
- "IE9, or when the browser is emulating IE8 or below. " +
- "Switching to SVG output will cause the mathemtics to " +
- "not display properly."
+ MSIE: _("MSIESVGWarning",
+ "SVG is not implemented in Internet Explorer prior to " +
+ "IE9, or when the browser is emulating IE8 or below. " +
+ "Switching to SVG output will cause the mathemtics to " +
+ "not display properly.")
}
};
@@ -861,13 +883,15 @@
};
MENU.MPEvents.Messages = {
IE8warning:
+ _("IE8warning",
"This will disable the MathJax menu and zoom features, " +
"but you can Alt-Click on an expression to obtain the MathJax " +
- "menu instead.\n\nReally change the MathPlayer settings?",
+ "menu instead.\n\nReally change the MathPlayer settings?"),
IE9warning:
+ _("IE9warning",
"The MathJax contextual menu will be disabled, but you can " +
- "Alt-Click on an expression to obtain the MathJax menu instead."
+ "Alt-Click on an expression to obtain the MathJax menu instead.")
};
/*************************************************************/