Bug 1276739 - Switch search to use a JSON based format - NOT READY FOR CHECKIN draft
authorMichael Kaply <mozilla@kaply.com>
Tue, 31 May 2016 13:37:26 -0500
changeset 387777 4b5dfe844846f568bb962f2bd5ac94d160be6954
parent 386783 55922a4a546c9a6b5c6842aeb00b65c10b29bfc2
child 525452 5150bb35e3d5923bd01ad8ffe191f98d39f6a723
push id23073
push usermozilla@kaply.com
push dateThu, 14 Jul 2016 21:07:34 +0000
bugs1276739
milestone50.0a1
Bug 1276739 - Switch search to use a JSON based format - NOT READY FOR CHECKIN MozReview-Commit-ID: 6ipYl60a66U
browser/locales/Makefile.in
browser/locales/en-US/searchplugins/list.txt
browser/locales/jar.mn
browser/locales/moz.build
browser/locales/search/list.json
browser/locales/searchjson.py
browser/locales/searchplugins.py
toolkit/components/search/nsSearchService.js
toolkit/components/search/searchplugins/list.txt
toolkit/components/search/tests/xpcshell/data/list.json
toolkit/components/search/tests/xpcshell/data/searchTest.jar
toolkit/components/search/tests/xpcshell/test_json_cache.js
toolkit/components/search/tests/xpcshell/xpcshell.ini
--- a/browser/locales/Makefile.in
+++ b/browser/locales/Makefile.in
@@ -56,47 +56,41 @@ UNINSTALLER_PACKAGE_HOOK = $(RM) -r $(ST
 
 STUB_HOOK = $(NSINSTALL) -D '$(ABS_DIST)/$(PKG_INST_PATH)'; \
     $(RM) '$(ABS_DIST)/$(PKG_INST_PATH)$(PKG_STUB_BASENAME).exe'; \
     cp ../installer/windows/l10ngen/stub.exe '$(ABS_DIST)/$(PKG_INST_PATH)$(PKG_STUB_BASENAME).exe'; \
     chmod 0755 '$(ABS_DIST)/$(PKG_INST_PATH)$(PKG_STUB_BASENAME).exe'; \
     $(NULL)
 endif
 
-SEARCHPLUGINS_NAMES = $(shell cat $(call MERGE_FILE,/searchplugins/list.txt)) ddg
-ifeq (,$(filter-out en-US ru be kk tr uk zh-CN zh-TW,$(AB_CD)))
-    SEARCHPLUGINS_NAMES := $(subst google,google:hidden,$(SEARCHPLUGINS_NAMES))
-    SEARCHPLUGINS_NAMES += google-nocodes
-endif
-SEARCHPLUGINS_FILENAMES = $(subst :hidden,,$(SEARCHPLUGINS_NAMES))
+SEARCHPLUGINS_FILENAMES := $(shell $(PYTHON) $(srcdir)/searchplugins.py $(srcdir)/search/list.json $(AB_CD))
 SEARCHPLUGINS_PATH := .deps/generated_$(AB_CD)
 SEARCHPLUGINS_TARGET := libs searchplugins
 SEARCHPLUGINS := $(foreach plugin,$(addsuffix .xml,$(SEARCHPLUGINS_FILENAMES)),$(or $(wildcard $(call EN_US_OR_L10N_FILE,searchplugins/$(plugin))),$(warning Missing searchplugin: $(plugin))))
 # Some locale-specific search plugins may have preprocessor directives, but the
 # default en-US ones do not.
 SEARCHPLUGINS_FLAGS := --silence-missing-directive-warnings
 PP_TARGETS += SEARCHPLUGINS
 
-list-txt = $(SEARCHPLUGINS_PATH)/list.txt
-GARBAGE += $(list-txt)
+list-json = $(SEARCHPLUGINS_PATH)/list.json
+GARBAGE += $(list-json)
 
 libs:: searchplugins
 
 # Required for l10n.mk - defines a list of app sub dirs that should
 # be included in langpack xpis.
 DIST_SUBDIRS = $(DIST_SUBDIR)
 
 include $(topsrcdir)/config/rules.mk
 
 include $(topsrcdir)/toolkit/locales/l10n.mk
 
-$(list-txt): $(call mkdir_deps,$(SEARCHPLUGINS_PATH)) $(if $(IS_LANGUAGE_REPACK),FORCE)
-	$(RM) $(list-txt)
-	$(foreach plugin,$(SEARCHPLUGINS_NAMES),printf '$(plugin)\n' >> $(list-txt);)
-searchplugins:: $(list-txt)
+$(list-json): $(call mkdir_deps,$(SEARCHPLUGINS_PATH)) $(if $(IS_LANGUAGE_REPACK),FORCE)
+	$(shell $(PYTHON) $(srcdir)/searchjson.py $(srcdir)/search/list.json $(AB_CD) $(list-json))
+searchplugins:: $(list-json)
 
 $(STAGEDIST): $(DIST)/branding
 
 $(DIST)/branding:
 	$(NSINSTALL) -D $@
 
 DEFINES += -DBOOKMARKS_INCLUDE_DIR=$(dir $(call MERGE_FILE,profile/bookmarks.inc))
 
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -88,21 +88,21 @@
     locale/browser/syncSetup.dtd                (%chrome/browser/syncSetup.dtd)
     locale/browser/syncSetup.properties         (%chrome/browser/syncSetup.properties)
     locale/browser/syncGenericChange.properties         (%chrome/browser/syncGenericChange.properties)
     locale/browser/syncKey.dtd                  (%chrome/browser/syncKey.dtd)
     locale/browser/syncQuota.dtd                (%chrome/browser/syncQuota.dtd)
     locale/browser/syncQuota.properties         (%chrome/browser/syncQuota.properties)
 % resource search-plugins chrome://browser/locale/searchplugins/
 #if BUILD_FASTER
-    locale/browser/searchplugins/list.txt       (%searchplugins/list.txt)
     locale/browser/searchplugins/               (%searchplugins/*.xml)
+    locale/browser/searchplugins/list.json      (search/list.json)
 #else
-    locale/browser/searchplugins/list.txt       (.deps/generated_@AB_CD@/list.txt)
     locale/browser/searchplugins/               (.deps/generated_@AB_CD@/*.xml)
+    locale/browser/searchplugins/list.json      (.deps/generated_@AB_CD@/list.json)
 #endif
 % locale browser-region @AB_CD@ %locale/browser-region/
     locale/browser-region/region.properties        (%chrome/browser-region/region.properties)
 # the following files are browser-specific overrides
     locale/browser/netError.dtd                (%chrome/overrides/netError.dtd)
     locale/browser/appstrings.properties       (%chrome/overrides/appstrings.properties)
     locale/browser/downloads/settingsChange.dtd  (%chrome/overrides/settingsChange.dtd)
 % override chrome://global/locale/netError.dtd chrome://browser/locale/netError.dtd
--- a/browser/locales/moz.build
+++ b/browser/locales/moz.build
@@ -1,7 +1,7 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-JAR_MANIFESTS += ['jar.mn']
\ No newline at end of file
+JAR_MANIFESTS += ['jar.mn']
new file mode 100644
--- /dev/null
+++ b/browser/locales/search/list.json
@@ -0,0 +1,733 @@
+{
+  "default": {
+    "visibleDefaultEngines": [
+      "google", "yahoo", "amazondotcom", "bing", "ddg", "eBay", "twitter", "wikipedia"
+    ]
+  },
+  "locales": {
+    "en-US": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "amazondotcom", "bing", "ddg", "eBay", "twitter", "wikipedia"
+        ]
+      },
+      "US": {
+        "visibleDefaultEngines": [
+          "yahoo", "google-nocodes", "bing", "amazondotcom", "ddg", "eBay", "twitter", "wikipedia"
+        ]
+      },
+      "CA": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-en-CA", "bing", "amazondotcom", "ddg", "eBay", "twitter", "wikipedia"
+        ]
+      }
+    },
+    "ach": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazondotcom", "ddg", "eBay", "twitter", "wikipedia"
+        ]
+      }
+    },
+    "af": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazondotcom", "ddg", "eBay", "wikipedia-af"
+        ]
+      }
+    },
+    "an": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-es", "bing", "wikipedia-an", "ddg", "eBay-es", "twitter"
+        ]
+      }
+    },
+    "ar": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazondotcom", "ddg", "eBay", "wikipedia-ar"
+        ]
+      }
+    },
+    "as": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-in", "amazondotcom", "ddg", "eBay-in", "wikipedia-as"
+        ]
+      }
+    },
+    "ast": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-es", "bing", "diccionariu-alla", "ddg", "eBay-es", "wikipedia-ast"
+        ]
+      }
+    },
+    "az": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "amazondotcom", "azerdict", "bing", "ddg", "eBay", "wikipedia-az", "yandex-az"
+        ]
+      }
+    },
+    "be": {
+      "default": {
+        "visibleDefaultEngines": [
+          "yandex.by", "yahoo", "google", "ddg", "be-x-old.wikipedia.org", "be.wikipedia.org", "ru.wikipedia.org-be", "tut.by"
+        ]
+      }
+    },
+    "bg": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "diribg", "amazondotcom", "ddg", "portalbgdict", "wikipedia-bg"
+        ]
+      }
+    },
+    "bn-BD": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "ddg", "wikipedia-bn"
+        ]
+      }
+    },
+    "bn-IN": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-in", "amazondotcom", "bing", "ddg", "eBay-in", "rediff", "wikipedia-bn"
+        ]
+      }
+    },
+    "br": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-france", "amazon-france", "ddg", "freelang", "klask", "wikipedia-br"
+        ]
+      }
+    },
+    "brx": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-in", "bing", "ddg", "eBay-in", "wikipedia-hi"
+        ]
+      }
+    },
+    "bs": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "ddg", "eBay", "olx", "twitter", "wikipedia-bs"
+        ]
+      }
+    },
+    "ca": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "bing", "diec2", "ddg", "twitter", "wikipedia-ca"
+        ]
+      }
+    },
+    "cak": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-espanol", "bing", "amazondotcom", "ddg", "wikipedia-es"
+        ]
+      }
+    },
+    "cs": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "seznam-cz", "ddg", "heureka-cz", "mapy-cz", "wikipedia-cz"
+        ]
+      }
+    },
+    "cy": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-en-GB", "amazon-en-GB", "ddg", "eBay-en-GB", "palasprint", "termau", "wikipedia-cy"
+        ]
+      }
+    },
+    "da": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "bing", "amazon-co-uk", "ddg", "eBay", "wikipedia-da"
+        ]
+      }
+    },
+    "de": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-de", "amazondotcom-de", "bing", "ddg", "eBay-de", "leo_ende_de", "wikipedia-de"
+        ]
+      }
+    },
+    "dsb": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-de", "bing", "amazondotcom-de", "ddg", "eBay-de", "leo_ende_de", "wikipedia-dsb"
+        ]
+      }
+    },
+    "el": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "amazon-en-GB", "bing", "ddg", "eBay-en-GB", "wikipedia-el"
+        ]
+      }
+    },
+    "en-GB": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-en-GB", "bing", "amazon-en-GB", "chambers-en-GB", "ddg", "eBay-en-GB", "twitter", "wikipedia"
+        ]
+      }
+    },
+    "en-ZA": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "bing", "amazondotcom", "ddg", "twitter", "wikipedia"
+        ]
+      }
+    },
+    "eo": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazondotcom", "ddg", "eBay", "reta-vortaro", "wikipedia-eo"
+        ]
+      }
+    },
+    "es-AR": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-ar", "amazondotcom", "drae", "ddg", "mercadolibre-ar", "wikipedia-es"
+        ]
+      }
+    },
+    "es-CL": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-cl", "bing", "drae", "ddg", "mercadolibre-cl", "wikipedia-es"
+        ]
+      }
+    },
+    "es-ES": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-es", "bing", "drae", "ddg", "eBay-es", "twitter", "wikipedia-es"
+        ]
+      }
+    },
+    "es-MX": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-mx", "bing", "ddg", "mercadolibre-mx", "wikipedia-es"
+        ]
+      }
+    },
+    "et": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "neti-ee", "ddg", "eBay", "osta-ee", "wikipedia-et", "eki-ee"
+        ]
+      }
+    },
+    "eu": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazon-en-GB", "ddg", "eBay-es", "elebila", "wikipedia-eu"
+        ]
+      }
+    },
+    "fa": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "amazondotcom", "bing", "ddg", "wikipedia-fa"
+        ]
+      }
+    },
+    "ff": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-france", "bing", "amazon-france", "ddg", "eBay-france", "cnrtl-tlfi-fr", "wikipedia-fr"
+        ]
+      }
+    },
+    "fi": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-fi", "bing", "bookplus-fi", "ddg", "eBay-fi", "wikipedia-fi"
+        ]
+      }
+    },
+    "fr": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-france", "bing", "amazon-france", "ddg", "eBay-france", "cnrtl-tlfi-fr", "wikipedia-fr"
+        ]
+      }
+    },
+    "fy-NL": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-fy-NL", "bing", "bolcom-fy-NL", "ddg", "marktplaats-fy-NL", "wikipedia-fy-NL"
+        ]
+      }
+    },
+    "ga-IE": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-en-GB", "amazon-en-GB", "ddg", "eBay-en-GB", "tearma", "twitter", "wikipedia-ga-IE"
+        ]
+      }
+    },
+    "gd": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-en-GB", "faclair-beag", "amazon-en-GB", "bbc-alba", "ddg", "wikipedia-gd"
+        ]
+      }
+    },
+    "gl": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-es", "amazon-en-GB", "ddg", "eBay-es", "wikipedia-gl"
+        ]
+      }
+    },
+    "gn": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-es", "bing", "amazondotcom", "ddg", "eBay", "twitter", "wikipedia-gn"
+        ]
+      }
+    },
+    "gu-IN": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-in", "bing", "ddg", "eBay-in", "gujaratilexicon", "wikipedia-gu"
+        ]
+      }
+    },
+    "he": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "ddg", "wikipedia-he", "morfix-dic"
+        ]
+      }
+    },
+    "hi-IN": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-in", "bing", "ddg", "eBay-in", "wikipedia-hi"
+        ]
+      }
+    },
+    "hr": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "amazon-en-GB", "bing", "ddg", "eBay-en-GB", "eudict", "twitter", "wikipedia-hr"
+        ]
+      }
+    },
+    "hsb": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-de", "bing", "amazondotcom-de", "ddg", "eBay-de", "leo_ende_de", "wikipedia-hsb"
+        ]
+      }
+    },
+    "hu": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "ddg", "eBay-hu", "sztaki-en-hu", "vatera", "wikipedia-hu"
+        ]
+      }
+    },
+    "hy-AM": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "amazondotcom", "ddg", "eBay", "list-am", "wikipedia-hy"
+        ]
+      }
+    },
+    "id": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-id", "ddg", "wikipedia-id"
+        ]
+      }
+    },
+    "is": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazondotcom", "ddg", "eBay", "leit-is", "wikipedia-is"
+        ]
+      }
+    },
+    "it": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-it", "bing", "amazon-it", "ddg", "eBay-it", "hoepli", "wikipedia-it"
+        ]
+      }
+    },
+    "ja-JP-mac": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-jp", "bing", "amazon-jp", "rakuten", "yahoo-jp-auctions", "oshiete-goo", "twitter-ja", "wikipedia-ja", "ddg"
+        ]
+      }
+    },
+    "ja": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-jp", "bing", "amazon-jp", "rakuten", "yahoo-jp-auctions", "oshiete-goo", "twitter-ja", "wikipedia-ja", "ddg"
+        ]
+      }
+    },
+    "ka": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazondotcom", "ddg", "eBay", "twitter", "wikipedia-ka"
+        ]
+      }
+    },
+    "kk": {
+      "default": {
+        "visibleDefaultEngines": [
+          "yandex", "google", "ddg", "flip", "kaz-kk", "twitter", "wikipedia-kk"
+        ]
+      }
+    },
+    "km": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazondotcom", "ddg", "eBay", "twitter", "wikipedia-km"
+        ]
+      }
+    },
+    "kn": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-in", "bing", "amazondotcom", "ddg", "kannadastore", "wikipedia-kn"
+        ]
+      }
+    },
+    "ko": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "ddg", "naver-kr", "danawa-kr", "daum-kr", "wikipedia-kr"
+        ]
+      }
+    },
+    "kok": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-in", "bing", "ddg", "eBay-in", "wikipedia-hi"
+        ]
+      }
+    },
+    "ks": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-in", "bing", "ddg", "eBay-in", "wikipedia-hi"
+        ]
+      }
+    },
+    "lij": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-it", "bing", "amazon-it", "ddg", "eBay-it", "paroledigenova-lij", "wikipedia-lij"
+        ]
+      }
+    },
+    "lt": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "wikipedia-lt", "bing", "amazondotcom", "ddg", "eBay", "twitter"
+        ]
+      }
+    },
+    "ltg": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "dict-enlv", "ddg", "salidzinilv", "sslv", "wikipedia-lv"
+        ]
+      }
+    },
+    "lv": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "dict-enlv", "ddg", "salidzinilv", "sslv", "wikipedia-lv"
+        ]
+      }
+    },
+    "mai": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-in", "bing", "ddg", "eBay-in", "twitter", "wikipedia-hi"
+        ]
+      }
+    },
+    "mk": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazondotcom", "ddg", "eBay", "wikipedia-mk"
+        ]
+      }
+    },
+    "ml": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "webdunia", "bing", "ddg", "eBay-in", "rediff", "wikipedia", "wikipedia-ml"
+        ]
+      }
+    },
+    "mr": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-in", "amazondotcom", "ddg", "eBay-in", "rediff", "wikipedia-mr"
+        ]
+      }
+    },
+    "ms": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazondotcom", "ddg", "eBay", "twitter", "wikipedia-ms"
+        ]
+      }
+    },
+    "my": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazondotcom", "ddg", "eBay", "twitter", "wikipedia-my"
+        ]
+      }
+    },
+    "nb-NO": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-NO", "amazon-en-GB", "bing", "ddg", "gulesider-NO", "bok-NO", "qxl-NO", "wikipedia-NO"
+        ]
+      }
+    },
+    "ne-NP": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "ddg", "twitter", "wikipedia-ne"
+        ]
+      }
+    },
+    "nl": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "bing", "bolcom-nl", "ddg", "marktplaats-nl", "wikipedia-nl"
+        ]
+      }
+    },
+    "nn-NO": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "bing", "amazon-en-GB", "ddg", "gulesider-NO", "bok-NO", "qxl-NO", "wikipedia-NN"
+        ]
+      }
+    },
+    "or": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-in", "bing", "amazondotcom", "ddg", "eBay-in", "wikipedia-or"
+        ]
+      }
+    },
+    "pa-IN": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-in", "bing", "ddg", "eBay-in", "wikipedia-pa"
+        ]
+      }
+    },
+    "pl": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "allegro-pl", "ddg", "pwn-pl", "wikipedia-pl", "wolnelektury-pl"
+        ]
+      }
+    },
+    "pt-BR": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-br", "bing", "buscape", "ddg", "mercadolivre", "twitter", "wikipedia-br"
+        ]
+      }
+    },
+    "pt-PT": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "amazon-en-GB", "ddg", "priberam", "sapo", "wikipedia-ptpt"
+        ]
+      }
+    },
+    "rm": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-ch", "bing", "ddg", "leo_ende_de", "pledarigrond", "wikipedia-rm"
+        ]
+      }
+    },
+    "ro": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazondotcom", "ddg", "eBay", "wikipediaro"
+        ]
+      }
+    },
+    "ru": {
+      "default": {
+        "visibleDefaultEngines": [
+          "yandex", "google", "ddg", "ozonru", "priceru", "wikipedia-ru", "mailru"
+        ]
+      }
+    },
+    "sat": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-in", "bing", "wikipedia-hi", "ddg", "eBay-in"
+        ]
+      }
+    },
+    "si": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "amazondotcom", "ddg", "eBay", "wikipedia-si"
+        ]
+      }
+    },
+    "sk": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "azet-sk", "atlas-sk", "ddg", "dunaj-sk", "eBay", "slovnik-sk", "wikipedia-sk", "zoznam-sk"
+        ]
+      }
+    },
+    "sl": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "ceneji", "ddg", "najdi-si", "odpiralni", "twitter", "wikipedia-sl"
+        ]
+      }
+    },
+    "son": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-france", "bing", "amazon-france", "ddg", "eBay-france", "cnrtl-tlfi-fr", "wikipedia-fr"
+        ]
+      }
+    },
+    "sq": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazon-en-GB", "ddg", "eBay", "wikipedia-sq"
+        ]
+      }
+    },
+    "sr": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "amazon-en-GB", "bing", "ddg", "eBay-en-GB", "wikipedia-sr", "pogodak"
+        ]
+      }
+    },
+    "sv-SE": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-sv-SE", "bing", "allaannonser-sv-SE", "ddg", "prisjakt-sv-SE", "tyda-sv-SE", "wikipedia-sv-SE"
+        ]
+      }
+    },
+    "ta": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-in", "ddg", "eBay-in", "wikipedia-ta"
+        ]
+      }
+    },
+    "te": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-in", "amazondotcom", "ddg", "eBay-in", "wikipedia-te", "wiktionary-te"
+        ]
+      }
+    },
+    "th": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "amazondotcom", "bing", "ddg", "eBay", "longdo", "wikipedia-th"
+        ]
+      }
+    },
+    "tr": {
+      "default": {
+        "visibleDefaultEngines": [
+          "yandex-tr", "google", "ddg", "twitter", "wikipedia-tr"
+        ]
+      }
+    },
+    "uk": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yandex", "meta-ua", "ddg", "wikipedia-uk", "metamarket"
+        ]
+      }
+    },
+    "ur": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazondotcom", "ddg", "eBay", "twitter", "wikipedia"
+        ]
+      }
+    },
+    "uz": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazondotcom", "ddg", "eBay", "twitter", "wikipedia-uz"
+        ]
+      }
+    },
+    "vi": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "ddg", "wikipedia-vi", "zing-mp3"
+        ]
+      }
+    },
+    "wo": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazondotcom", "ddg", "eBay", "wikipedia-wo"
+        ]
+      }
+    },
+    "xh": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "bing", "ddg", "wikipedia"
+        ]
+      }
+    },
+    "zh-CN": {
+      "default": {
+        "visibleDefaultEngines": [
+          "baidu", "google", "bing", "ddg", "wikipedia-zh-CN", "amazondotcn"
+        ]
+      }
+    },
+    "zh-TW": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-zh-TW", "ddg", "findbook-zh-TW", "wikipedia-zh-TW", "yahoo-zh-TW-HK", "yahoo-bid-zh-TW", "yahoo-answer-zh-TW"
+        ]
+      }
+    }
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/locales/searchjson.py
@@ -0,0 +1,23 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import sys
+import json
+
+engines = []
+
+locale = sys.argv[2]
+output_file = sys.argv[3]
+
+output = open(output_file, 'w')
+
+with open(sys.argv[1]) as f:
+  searchinfo = json.load(f)
+
+if locale in searchinfo["locales"]:
+  output.write(json.dumps(searchinfo["locales"][locale]))
+else:
+  output.write(json.dumps(searchinfo["default"]))
+
+output.close();
new file mode 100644
--- /dev/null
+++ b/browser/locales/searchplugins.py
@@ -0,0 +1,21 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import sys
+import json
+
+engines = []
+
+locale = sys.argv[2]
+
+with open(sys.argv[1]) as f:
+  searchinfo = json.load(f)
+
+if locale in searchinfo["locales"]:
+  for region in searchinfo["locales"][locale]:
+    engines = list(set(engines)|set(searchinfo["locales"][locale][region]["visibleDefaultEngines"]))
+else:
+  engines = searchinfo["default"]["visibleDefaultEngines"]
+
+print '\n'.join(engines)
--- a/toolkit/components/search/nsSearchService.js
+++ b/toolkit/components/search/nsSearchService.js
@@ -3592,71 +3592,161 @@ SearchService.prototype = {
     fileURI.QueryInterface(Ci.nsIFileURL);
 
     return fileURI.file;
   },
 
   _findJAREngines: function SRCH_SVC_findJAREngines() {
     LOG("_findJAREngines: looking for engines in JARs")
 
-    let chan = makeChannel(APP_SEARCH_PREFIX + "list.txt");
+    let chan = makeChannel(APP_SEARCH_PREFIX + "list.json");
     if (!chan) {
       LOG("_findJAREngines: " + APP_SEARCH_PREFIX + " isn't registered");
       return [];
     }
 
     let uris = [];
 
     let sis = Cc["@mozilla.org/scriptableinputstream;1"].
                 createInstance(Ci.nsIScriptableInputStream);
-    sis.init(chan.open2());
-    this._parseListTxt(sis.read(sis.available()), uris);
+    try {
+      sis.init(chan.open2());
+      this._parseListJSON(sis.read(sis.available()), uris);
+      // parseListJSON will catch its own errors, so we
+      // should only go into this catch if list.json
+      // doesn't exist
+    } catch (e) {
+      chan = makeChannel(APP_SEARCH_PREFIX + "list.txt");
+      sis.init(chan.open2());
+      this._parseListTxt(sis.read(sis.available()), uris);
+    }
     return uris;
   },
 
   /**
    * Loads jar engines asynchronously.
    *
    * @returns {Promise} A promise, resolved successfully if finding jar engines
    * succeeds.
    */
   _asyncFindJAREngines: function SRCH_SVC__asyncFindJAREngines() {
     return Task.spawn(function() {
       LOG("_asyncFindJAREngines: looking for engines in JARs")
 
-      let listURL = APP_SEARCH_PREFIX + "list.txt";
+      let listURL = APP_SEARCH_PREFIX + "list.json";
       let chan = makeChannel(listURL);
       if (!chan) {
         LOG("_asyncFindJAREngines: " + APP_SEARCH_PREFIX + " isn't registered");
         throw new Task.Result([]);
       }
 
       let uris = [];
 
-      // Read list.txt to find the engines we need to load.
+      // Read list.json to find the engines we need to load.
       let deferred = Promise.defer();
       let request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
                       createInstance(Ci.nsIXMLHttpRequest);
       request.overrideMimeType("text/plain");
       request.onload = function(aEvent) {
         deferred.resolve(aEvent.target.responseText);
       };
       request.onerror = function(aEvent) {
         LOG("_asyncFindJAREngines: failed to read " + listURL);
-        deferred.resolve("");
+        // Couldn't find list.json, try list.txt
+        request.onerror = function(aEvent) {
+          LOG("_asyncFindJAREngines: failed to read " + APP_SEARCH_PREFIX + "list.txt");
+          deferred.resolve("");
+        }
+        request.open("GET", NetUtil.newURI(APP_SEARCH_PREFIX + "list.txt").spec, true);
+        request.send();
       };
       request.open("GET", NetUtil.newURI(listURL).spec, true);
-      request.send();
+      // On Fennec, the request fails immediately so we handle
+      // the error in a try/catch
+      try {
+        request.send();
+      } catch(e) {
+        LOG("_asyncFindJAREngines: failed to read " + listURL);
+        // Couldn't find list.json, try list.txt
+        request.open("GET", NetUtil.newURI(APP_SEARCH_PREFIX + "list.txt").spec, true);
+        request.send();
+      }
       let list = yield deferred.promise;
 
-      this._parseListTxt(list, uris);
+      if (request.responseURL.endsWith(".txt")) {
+        this._parseListTxt(list, uris);
+      } else {
+        this._parseListJSON(list, uris);
+      }
       throw new Task.Result(uris);
     }.bind(this));
   },
 
+  _parseListJSON: function SRCH_SVC_parseListJSON(list, uris) {
+    let searchSettings;
+    try {
+      searchSettings = JSON.parse(list);
+    } catch(e) {
+      LOG("failing to parse list.json: " + e);
+      return;
+    }
+
+    let jarNames = new Set();
+    for (let region in searchSettings) {
+      // Artifact builds use the full list.json which parses
+      // slightly differently
+      if (region == "locales") {
+        continue;
+      }
+      for (let engine of searchSettings[region]["visibleDefaultEngines"]) {
+        jarNames.add(engine);
+      }
+    }
+
+    // Check if we have a useable country specific list of visible default engines.
+    let engineNames;
+    let visibleDefaultEngines = this.getVerifiedGlobalAttr("visibleDefaultEngines");
+    if (visibleDefaultEngines) {
+      engineNames = visibleDefaultEngines.split(",");
+      for (let engineName of engineNames) {
+        // If all engineName values are part of jarNames,
+        // then we can use the country specific list, otherwise ignore it.
+        // The visibleDefaultEngines string containing the name of an engine we
+        // don't ship indicates the server is misconfigured to answer requests
+        // from the specific Firefox version we are running, so ignoring the
+        // value altogether is safer.
+        if (!jarNames.has(engineName)) {
+          LOG("_parseListJSON: ignoring visibleDefaultEngines value because " +
+              engineName + " is not in the jar engines we have found");
+          engineNames = null;
+          break;
+        }
+      }
+    }
+
+    // Fallback to building a list based on the regions in the JSON
+    if (!engineNames) {
+      let region;
+      if (Services.prefs.prefHasUserValue("browser.search.region")) {
+        region = Services.prefs.getCharPref("browser.search.region");
+      }
+      if (!region || !(region in searchSettings)) {
+        region = "default";
+      }
+      engineNames = searchSettings[region]["visibleDefaultEngines"];
+    }
+
+    for (let name of engineNames) {
+      uris.push(APP_SEARCH_PREFIX + name + ".xml");
+    }
+
+    // Store this so that it can be used while writing the cache file.
+    this._visibleDefaultEngines = engineNames;
+  },
+
   _parseListTxt: function SRCH_SVC_parseListTxt(list, uris) {
     let names = list.split("\n").filter(n => !!n);
     // This maps the names of our built-in engines to a boolean
     // indicating whether it should be hidden by default.
     let jarNames = new Map();
     for (let name of names) {
       if (name.endsWith(":hidden")) {
         name = name.split(":")[0];
rename from browser/locales/en-US/searchplugins/list.txt
rename to toolkit/components/search/searchplugins/list.txt
new file mode 100644
--- /dev/null
+++ b/toolkit/components/search/tests/xpcshell/data/list.json
@@ -0,0 +1,7 @@
+{
+  "default": {
+    "visibleDefaultEngines": [
+      "engine", "engine-pref", "engine-rel-searchform-purpose", "engine-system-purpose", "engine-chromeicon", "engine-resourceicon"
+    ]
+  }
+}
index 6cce53d1265d0da885a2f21344a22a7405e752a0..484158a01f66a5e02a5fdbedf7b3a51026f83efc
GIT binary patch
literal 1324
zc${^VeLT|%9LIlS8)ZE$G!c1NLfBGGO}MMB<T2A&vWD2M4cUqorY@-@qG_f~dB_R5
zMjI1}O(t<xtR*8e%3~!u5m$Gw`{!P-zTemP^Lc&$_<a6+`?za@bpZg-2C$c2?hD&l
zl}iHyKm-&3^Z+9ultPb+2(xE|1=B+*eqoFgcE^J02mO`+n)fRr{Q2MR<S88h1fB)~
zz&|xQ@594a1(Qhqq_;Bz4B>XcmpdD;T7twOu+1<@$)!C~1IYHGcU-3A%XY2=c^avQ
zylr|D)^^OLBUvOrmBhgxcR=yu!;X@G8>(_OHIi1{C7yp=vf7!)BV#ZSF$&yZ%glX6
zjhz_mE}n6nj>|?M3elU~tUWOf=m%Rcf0nj91NBsmyz%WDb!kt|S5%#lNz0m`8WEGD
z)w<qgPK^(?_*zR8Oc|0Kb)M0-whxX!5`nAXy-P@pdVR<3u{}>9@3<PjEs(w@@Ri!4
z3&*Gudc?evnzEt<cS0x>s!ziG5OK=kN3mnie!~=m*kX(nhg#`3(fIjpd&X8t+;dj_
zzWHF&H9leqzOh(1?IjVFW))l8>c7p)@fD&dk#An8DshqRD>h~hGNV&Rr7UBP;e`%Q
z=fPgb4CKQ3_S;jvn_A~Nj=Y_p9J5z{$Z+v~bHA)7G(EnSBM=?n58-93&Sq}WXJYxU
zjEMk@`9Vq%d&HE06V5v01Pcj-CS8GzlH9A7we@RZFwQU6<`NSVXGIWqS&Ws1i7H!Y
z<%v<BW{x}@8sqhLsSm`?JtR9F{+-#(mdDN1t5yh6*Z0>&&xywtdi$`L>5jx9n^`1b
zU^BW;uFE3r6}xGn24a)%?SR8zipw6iTK1-2OKoGbUpSpg+6WXFC!x&-@Aa8#W~e3~
zUH)rng=*D1pKP{V3cnSVPd~$K?O}KIRWb6koRkSzjvFN?z2-~D>{NGOVhsxW*aJiB
z<mP&H<={j*CKI_<y1Hve7E_L-t4|J%NiWTfca`~5E4_PecQ3kzbyADpE|UHH0y+#K
z9^6oKN1-B69#5R{GracM$kc#l$<H$?dz~LdGmExNTdd~$2i4AT8n~QKyYL1Tb8J4A
z?~%}IL{$d`a#`0M3|T$z6QmbzfwRsH;CoFLH*Ceallk#>$K90r3uq(69#JQCr)-?4
z?995mygtD}g}*@lIHjy9bF;M<nRRWTpF|9u#}L{2Ub(2m@w()a$!g0yyNh*5-vdLq
zjDxJ<$^F6R%e?YFu^r%A=bE~O^@_TQw&7)1y@|u)_46ZN)AXfr&E;5*MR+qym>nu;
zsF<A;yJ*?9_QFzlOHvDWWih;K_(!hTth^fr-2-2vsf~zHz9+eA#3M4mX*tYMMw46v
zedxt{vmQ9b>uIjeCR10X{(Ai<yr-2ZQ&SDldy>fh5%NzU5Rq4}+(F)|iGh@pZ0IKf
zN-7nN0l2T$r7{)a`S7!w#*)=$4Th~Nci0}q6A$^~!<8EPA6VU<gren7WWLvJ2_I=8
z`S^=;`ECfbfLmG|t+`IxV(}!k6qO0Y8B$!DGJjdA<KHP>YL$c10D`xL8zj+UtdkWK
zB;2NOcVj3hJo#rqzooed(xSMmms$5mPMQsJpDRHF7PW2|U2tRhHiofa%h}`T@Vl-t
z9~@u~88U4fiz_5Vdn<JF89nU|08&eEbpm|cK^n%IKY|wm_-_i&e%BwM4Dv6^{)aIi
ScL?-*2=r|Ozj-bA`}a4>iegUy
--- a/toolkit/components/search/tests/xpcshell/test_json_cache.js
+++ b/toolkit/components/search/tests/xpcshell/test_json_cache.js
@@ -50,31 +50,27 @@ function run_test() {
   engineFile.parent.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
 
   // Copy the test engine to the test profile.
   let engineTemplateFile = do_get_file("data/engine.xml");
   engineTemplateFile.copyTo(engineFile.parent, "test-search-engine.xml");
 
   // The list of visibleDefaultEngines needs to match or the cache will be ignored.
   let chan = NetUtil.newChannel({
-    uri: "resource://search-plugins/list.txt",
+    uri: "resource://search-plugins/list.json",
     loadUsingSystemPrincipal: true
   });
   let visibleDefaultEngines = [];
   let sis = Cc["@mozilla.org/scriptableinputstream;1"].
               createInstance(Ci.nsIScriptableInputStream);
   sis.init(chan.open2());
   let list = sis.read(sis.available());
-  let names = list.split("\n").filter(n => !!n);
-  for (let name of names) {
-    if (name.endsWith(":hidden"))
-      continue;
-    visibleDefaultEngines.push(name);
-  }
-  cacheTemplate.visibleDefaultEngines = visibleDefaultEngines;
+  let searchSettings = JSON.parse(list);
+
+  cacheTemplate.visibleDefaultEngines = searchSettings["default"]["visibleDefaultEngines"];
 
   run_next_test();
 }
 
 add_test(function prepare_test_data() {
   OS.File.writeAtomic(OS.Path.join(OS.Constants.Path.profileDir, CACHE_FILENAME),
                       new TextEncoder().encode(JSON.stringify(cacheTemplate)),
                       {compression: "lz4"})
--- a/toolkit/components/search/tests/xpcshell/xpcshell.ini
+++ b/toolkit/components/search/tests/xpcshell/xpcshell.ini
@@ -20,16 +20,17 @@ support-files =
   data/engine-update.xml
   data/engineImages.xml
   data/engine-chromeicon.xml
   data/engine-resourceicon.xml
   data/ico-size-16x16-png.ico
   data/invalid-engine.xml
   data/install.rdf
   data/list.txt
+  data/list.json
   data/langpack-metadata.json
   data/metadata.json
   data/search-metadata.json
   data/search.json
   data/search.sqlite
   data/searchSuggestions.sjs
   data/searchTest.jar