mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-09 04:25:38 +00:00
Bug 730209: Parse spellchecker dictionary names as BCP 47 language tags. r=gavin
This commit is contained in:
parent
720215548d
commit
809beca2af
@ -183,16 +183,6 @@ InlineSpellChecker.prototype = {
|
||||
this.mDictionaryNames = [];
|
||||
this.mDictionaryItems = [];
|
||||
|
||||
if (! gLanguageBundle) {
|
||||
// create the bundles for language and region
|
||||
var bundleService = Components.classes["@mozilla.org/intl/stringbundle;1"]
|
||||
.getService(Components.interfaces.nsIStringBundleService);
|
||||
gLanguageBundle = bundleService.createBundle(
|
||||
"chrome://global/locale/languageNames.properties");
|
||||
gRegionBundle = bundleService.createBundle(
|
||||
"chrome://global/locale/regionNames.properties");
|
||||
}
|
||||
|
||||
if (! this.mInlineSpellChecker || ! this.enabled)
|
||||
return 0;
|
||||
var spellchecker = this.mInlineSpellChecker.spellChecker;
|
||||
@ -204,33 +194,12 @@ InlineSpellChecker.prototype = {
|
||||
try {
|
||||
curlang = spellchecker.GetCurrentDictionary();
|
||||
} catch(e) {}
|
||||
var isoStrArray;
|
||||
|
||||
for (var i = 0; i < list.length; i ++) {
|
||||
// get the display name for this dictionary
|
||||
isoStrArray = list[i].split(/[-_]/);
|
||||
var displayName = "";
|
||||
if (gLanguageBundle && isoStrArray[0]) {
|
||||
try {
|
||||
displayName = gLanguageBundle.GetStringFromName(isoStrArray[0].toLowerCase());
|
||||
} catch(e) {} // ignore language bundle errors
|
||||
if (gRegionBundle && isoStrArray[1]) {
|
||||
try {
|
||||
displayName += " / " + gRegionBundle.GetStringFromName(isoStrArray[1].toLowerCase());
|
||||
} catch(e) {} // ignore region bundle errors
|
||||
if (isoStrArray[2])
|
||||
displayName += " (" + isoStrArray[2] + ")";
|
||||
}
|
||||
}
|
||||
|
||||
// if we didn't get a name, just use the raw dictionary name
|
||||
if (displayName.length == 0)
|
||||
displayName = list[i];
|
||||
|
||||
this.mDictionaryNames.push(list[i]);
|
||||
var item = menu.ownerDocument.createElement("menuitem");
|
||||
item.setAttribute("id", "spell-check-dictionary-" + list[i]);
|
||||
item.setAttribute("label", displayName);
|
||||
item.setAttribute("label", this.getDictionaryDisplayName(list[i]));
|
||||
item.setAttribute("type", "radio");
|
||||
this.mDictionaryItems.push(item);
|
||||
if (curlang == list[i]) {
|
||||
@ -247,6 +216,65 @@ InlineSpellChecker.prototype = {
|
||||
return list.length;
|
||||
},
|
||||
|
||||
// Formats a valid BCP 47 language tag based on available localized names.
|
||||
getDictionaryDisplayName: function(dictionaryName) {
|
||||
try {
|
||||
// Get the display name for this dictionary.
|
||||
let languageTagMatch = /^([a-z]{2,3}|[a-z]{4}|[a-z]{5,8})(?:[-_]([a-z]{4}))?(?:[-_]([A-Z]{2}|[0-9]{3}))?((?:[-_](?:[a-z0-9]{5,8}|[0-9][a-z0-9]{3}))*)$/i;
|
||||
var [languageTag, languageSubtag, scriptSubtag, regionSubtag, variantSubtags] = dictionaryName.match(languageTagMatch);
|
||||
} catch(e) {
|
||||
// If we weren't given a valid language tag, just use the raw dictionary name.
|
||||
return dictionaryName;
|
||||
}
|
||||
|
||||
if (!gLanguageBundle) {
|
||||
// Create the bundles for language and region names.
|
||||
var bundleService = Components.classes["@mozilla.org/intl/stringbundle;1"]
|
||||
.getService(Components.interfaces.nsIStringBundleService);
|
||||
gLanguageBundle = bundleService.createBundle(
|
||||
"chrome://global/locale/languageNames.properties");
|
||||
gRegionBundle = bundleService.createBundle(
|
||||
"chrome://global/locale/regionNames.properties");
|
||||
}
|
||||
|
||||
var displayName = "";
|
||||
|
||||
// Language subtag will normally be 2 or 3 letters, but could be up to 8.
|
||||
try {
|
||||
displayName += gLanguageBundle.GetStringFromName(languageSubtag.toLowerCase());
|
||||
} catch(e) {
|
||||
displayName += languageSubtag.toLowerCase(); // Fall back to raw language subtag.
|
||||
}
|
||||
|
||||
// Region subtag will be 2 letters or 3 digits.
|
||||
if (regionSubtag) {
|
||||
displayName += " (";
|
||||
|
||||
try {
|
||||
displayName += gRegionBundle.GetStringFromName(regionSubtag.toLowerCase());
|
||||
} catch(e) {
|
||||
displayName += regionSubtag.toUpperCase(); // Fall back to raw region subtag.
|
||||
}
|
||||
|
||||
displayName += ")";
|
||||
}
|
||||
|
||||
// Script subtag will be 4 letters.
|
||||
if (scriptSubtag) {
|
||||
displayName += " / ";
|
||||
|
||||
// XXX: See bug 666662 and bug 666731 for full implementation.
|
||||
displayName += scriptSubtag; // Fall back to raw script subtag.
|
||||
}
|
||||
|
||||
// Each variant subtag will be 4 to 8 chars.
|
||||
if (variantSubtags)
|
||||
// XXX: See bug 666662 and bug 666731 for full implementation.
|
||||
displayName += " (" + variantSubtags.substr(1).split(/[-_]/).join(" / ") + ")"; // Collapse multiple variants.
|
||||
|
||||
return displayName;
|
||||
},
|
||||
|
||||
// undoes the work of addDictionaryListToMenu for the menu
|
||||
// (call on popup hiding)
|
||||
clearDictionaryListFromMenu: function()
|
||||
@ -290,7 +318,7 @@ InlineSpellChecker.prototype = {
|
||||
// Prevent the undo stack from growing over the max depth
|
||||
if (this.mAddedWordStack.length == MAX_UNDO_STACK_DEPTH)
|
||||
this.mAddedWordStack.shift();
|
||||
|
||||
|
||||
this.mAddedWordStack.push(this.mMisspelling);
|
||||
this.mInlineSpellChecker.addWordToDictionary(this.mMisspelling);
|
||||
},
|
||||
|
@ -55,6 +55,7 @@ _BROWSER_TEST_FILES = \
|
||||
browser_bug295977_autoscroll_overflow.js \
|
||||
browser_bug594509.js \
|
||||
browser_Geometry.js \
|
||||
browser_InlineSpellChecker.js \
|
||||
browser_save_resend_postdata.js \
|
||||
browser_browserDrop.js \
|
||||
browser_Services.js \
|
||||
|
59
toolkit/content/tests/browser/browser_InlineSpellChecker.js
Normal file
59
toolkit/content/tests/browser/browser_InlineSpellChecker.js
Normal file
@ -0,0 +1,59 @@
|
||||
function test() {
|
||||
let tempScope = {};
|
||||
Components.utils.import("resource://gre/modules/InlineSpellChecker.jsm", tempScope);
|
||||
let InlineSpellChecker = tempScope.InlineSpellChecker;
|
||||
|
||||
ok(InlineSpellChecker, "InlineSpellChecker class exists");
|
||||
for (var fname in tests) {
|
||||
tests[fname]();
|
||||
}
|
||||
}
|
||||
|
||||
let tests = {
|
||||
// Test various possible dictionary name to ensure they display as expected.
|
||||
// XXX: This only works for the 'en-US' locale, as the testing involves localized output.
|
||||
testDictionaryDisplayNames: function() {
|
||||
let isc = new InlineSpellChecker();
|
||||
|
||||
// Check for valid language tag.
|
||||
is(isc.getDictionaryDisplayName("-invalid-"), "-invalid-", "'-invalid-' should display as '-invalid-'");
|
||||
|
||||
// Check if display name is available for language subtag.
|
||||
is(isc.getDictionaryDisplayName("en"), "English", "'en' should display as 'English'");
|
||||
is(isc.getDictionaryDisplayName("qaz"), "qaz", "'qaz' should display as 'qaz'"); // Private use subtag
|
||||
|
||||
// Check if display name is available for region subtag.
|
||||
is(isc.getDictionaryDisplayName("en-US"), "English (United States)", "'en-US' should display as 'English (United States)'");
|
||||
is(isc.getDictionaryDisplayName("en-QZ"), "English (QZ)", "'en-QZ' should display as 'English (QZ)'"); // Private use subtag
|
||||
todo_is(isc.getDictionaryDisplayName("es-419"), "Spanish (Latin America and the Caribbean)", "'es-419' should display as 'Spanish (Latin America and the Caribbean)'");
|
||||
|
||||
// Check if display name is available for script subtag.
|
||||
todo_is(isc.getDictionaryDisplayName("en-Cyrl"), "English / Cyrillic", "'en-Cyrl' should display as 'English / Cyrillic'");
|
||||
todo_is(isc.getDictionaryDisplayName("en-Cyrl-US"), "English (United States) / Cyrillic", "'en-Cyrl-US' should display as 'English (United States) / Cyrillic'");
|
||||
todo_is(isc.getDictionaryDisplayName("en-Cyrl-QZ"), "English (QZ) / Cyrillic", "'en-Cyrl-QZ' should display as 'English (QZ) / Cyrillic'"); // Private use subtag
|
||||
todo_is(isc.getDictionaryDisplayName("qaz-Cyrl"), "qaz / Cyrillic", "'qaz-Cyrl' should display as 'qaz / Cyrillic'"); // Private use subtag
|
||||
todo_is(isc.getDictionaryDisplayName("qaz-Cyrl-US"), "qaz (United States) / Cyrillic", "'qaz-Cyrl-US' should display as 'qaz (United States) / Cyrillic'"); // Private use subtag
|
||||
todo_is(isc.getDictionaryDisplayName("qaz-Cyrl-QZ"), "qaz (QZ) / Cyrillic", "'qaz-Cyrl-QZ' should display as 'qaz (QZ) / Cyrillic'"); // Private use subtags
|
||||
is(isc.getDictionaryDisplayName("en-Qaaz"), "English / Qaaz", "'en-Qaaz' should display as 'English / Qaaz'"); // Private use subtag
|
||||
is(isc.getDictionaryDisplayName("en-Qaaz-US"), "English (United States) / Qaaz", "'en-Qaaz-US' should display as 'English (United States) / Qaaz'"); // Private use subtag
|
||||
is(isc.getDictionaryDisplayName("en-Qaaz-QZ"), "English (QZ) / Qaaz", "'en-Qaaz-QZ' should display as 'English (QZ) / Qaaz'"); // Private use subtags
|
||||
is(isc.getDictionaryDisplayName("qaz-Qaaz"), "qaz / Qaaz", "'qaz-Qaaz' should display as 'qaz / Qaaz'"); // Private use subtags
|
||||
is(isc.getDictionaryDisplayName("qaz-Qaaz-US"), "qaz (United States) / Qaaz", "'qaz-Qaaz-US' should display as 'qaz (United States) / Qaaz'"); // Private use subtags
|
||||
is(isc.getDictionaryDisplayName("qaz-Qaaz-QZ"), "qaz (QZ) / Qaaz", "'qaz-Qaaz-QZ' should display as 'qaz (QZ) / Qaaz'"); // Private use subtags
|
||||
|
||||
// Check if display name is available for variant subtag.
|
||||
// XXX: It isn't clear how we'd ideally want to display variant subtags.
|
||||
is(isc.getDictionaryDisplayName("de-1996"), "German (1996)", "'de-1996' should display as 'German (1996)'");
|
||||
is(isc.getDictionaryDisplayName("de-CH-1996"), "German (Switzerland) (1996)", "'de-CH-1996' should display as 'German (Switzerland) (1996)'");
|
||||
|
||||
// Complex cases.
|
||||
// XXX: It isn't clear how we'd ideally want to display variant subtags.
|
||||
todo_is(isc.getDictionaryDisplayName("en-Cyrl-US-fonipa"), "English (United States) / Cyrillic (fonipa)", "'en-Cyrl-US-fonipa' should display as 'English (United States) / Cyrillic (fonipa)'");
|
||||
todo_is(isc.getDictionaryDisplayName("en-Cyrl-US-fonipa-fonxsamp"), "English (United States) / Cyrillic (fonipa / fonxsamp)", "'en-Cyrl-US-fonipa-fonxsamp' should display as 'English (United States) / Cyrillic (fonipa / fonxsamp)'");
|
||||
is(isc.getDictionaryDisplayName("qaz-Qaaz-QZ-fonipa"), "qaz (QZ) / Qaaz (fonipa)", "'qaz-Qaaz-QZ-fonipa' should display as 'qaz (QZ) / Qaaz (fonipa)'"); // Private use subtags
|
||||
is(isc.getDictionaryDisplayName("qaz-Qaaz-QZ-fonipa-fonxsamp"), "qaz (QZ) / Qaaz (fonipa / fonxsamp)", "'qaz-Qaaz-QZ-fonipa-fonxsamp' should display as 'qaz (QZ) / Qaaz (fonipa / fonxsamp)'"); // Private use subtags
|
||||
|
||||
// Check if display name is available for grandfathered tags.
|
||||
todo_is(isc.getDictionaryDisplayName("en-GB-oed"), "English (United Kingdom) (OED)", "'en-GB-oed' should display as 'English (United Kingdom) (OED)'");
|
||||
},
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user