Bug 1276739 - Switch search to use a JSON based format. r?florian draft
authorMichael Kaply <mozilla@kaply.com>
Tue, 31 May 2016 13:37:26 -0500
changeset 412243 db0950fd96c3c475669e4be4b5ace05675437ff4
parent 412242 dc0b1953a7f1b649309a5a370c3b0f845578a45b
child 530908 ce3f7b1efd8d3833f5837c1a5f33a9452def9e88
push id29089
push usermozilla@kaply.com
push dateFri, 09 Sep 2016 16:26:05 +0000
reviewersflorian
bugs1276739
milestone51.0a1
Bug 1276739 - Switch search to use a JSON based format. r?florian MozReview-Commit-ID: 9xy3UPoRCmW
browser/locales/Makefile.in
browser/locales/en-US/searchplugins/list.txt
browser/locales/jar.mn
browser/locales/search/list.json
browser/locales/searchjson.py
browser/locales/searchplugins.py
toolkit/components/search/nsSearchService.js
toolkit/components/search/tests/xpcshell/data/list.json
toolkit/components/search/tests/xpcshell/data/list.txt
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))
 
deleted file mode 100644
--- a/browser/locales/en-US/searchplugins/list.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-amazondotcom
-bing
-google
-twitter
-wikipedia
-yahoo
-yahoo-en-CA:hidden
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -85,21 +85,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
new file mode 100644
--- /dev/null
+++ b/browser/locales/search/list.json
@@ -0,0 +1,733 @@
+{
+  "default": {
+    "visibleDefaultEngines": [
+      "google", "yahoo", "amazondotcom", "bing", "ddg", "twitter", "wikipedia"
+    ]
+  },
+  "locales": {
+    "en-US": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "amazondotcom", "bing", "ddg", "twitter", "wikipedia"
+        ]
+      },
+      "US": {
+        "visibleDefaultEngines": [
+          "yahoo", "google-nocodes", "bing", "amazondotcom", "ddg", "twitter", "wikipedia"
+        ]
+      },
+      "CA": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-en-CA", "bing", "amazondotcom", "ddg", "twitter", "wikipedia"
+        ]
+      }
+    },
+    "ach": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazondotcom", "ddg", "twitter", "wikipedia"
+        ]
+      }
+    },
+    "af": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazondotcom", "ddg", "wikipedia-af"
+        ]
+      }
+    },
+    "an": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-es", "bing", "wikipedia-an", "ddg", "twitter"
+        ]
+      }
+    },
+    "ar": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazondotcom", "ddg", "wikipedia-ar"
+        ]
+      }
+    },
+    "as": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-in", "amazondotcom", "ddg", "wikipedia-as"
+        ]
+      }
+    },
+    "ast": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-es", "bing", "diccionariu-alla", "ddg", "wikipedia-ast"
+        ]
+      }
+    },
+    "az": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "amazondotcom", "azerdict", "bing", "ddg", "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", "rediff", "wikipedia-bn"
+        ]
+      }
+    },
+    "br": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-france", "amazon-france", "ddg", "freelang", "klask", "wikipedia-br"
+        ]
+      }
+    },
+    "brx": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-in", "bing", "ddg", "wikipedia-hi"
+        ]
+      }
+    },
+    "bs": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "ddg", "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", "palasprint", "termau", "wikipedia-cy"
+        ]
+      }
+    },
+    "da": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "bing", "amazon-co-uk", "ddg", "wikipedia-da"
+        ]
+      }
+    },
+    "de": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-de", "amazondotcom-de", "bing", "ddg", "leo_ende_de", "wikipedia-de"
+        ]
+      }
+    },
+    "dsb": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-de", "bing", "amazondotcom-de", "ddg", "leo_ende_de", "wikipedia-dsb"
+        ]
+      }
+    },
+    "el": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "amazon-en-GB", "bing", "ddg", "wikipedia-el"
+        ]
+      }
+    },
+    "en-GB": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-en-GB", "bing", "amazon-en-GB", "chambers-en-GB", "ddg", "twitter", "wikipedia"
+        ]
+      }
+    },
+    "en-ZA": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "bing", "amazondotcom", "ddg", "twitter", "wikipedia"
+        ]
+      }
+    },
+    "eo": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazondotcom", "ddg", "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", "twitter", "wikipedia-es"
+        ]
+      }
+    },
+    "es-MX": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-mx", "bing", "ddg", "mercadolibre-mx", "wikipedia-es"
+        ]
+      }
+    },
+    "et": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "neti-ee", "ddg", "osta-ee", "wikipedia-et", "eki-ee"
+        ]
+      }
+    },
+    "eu": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazon-en-GB", "ddg", "elebila", "wikipedia-eu"
+        ]
+      }
+    },
+    "fa": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "amazondotcom", "bing", "ddg", "wikipedia-fa"
+        ]
+      }
+    },
+    "ff": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-france", "bing", "amazon-france", "ddg", "cnrtl-tlfi-fr", "wikipedia-fr"
+        ]
+      }
+    },
+    "fi": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-fi", "bing", "bookplus-fi", "ddg", "wikipedia-fi"
+        ]
+      }
+    },
+    "fr": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-france", "bing", "amazon-france", "ddg", "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", "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", "wikipedia-gl"
+        ]
+      }
+    },
+    "gn": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-es", "bing", "amazondotcom", "ddg", "twitter", "wikipedia-gn"
+        ]
+      }
+    },
+    "gu-IN": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-in", "bing", "ddg", "gujaratilexicon", "wikipedia-gu"
+        ]
+      }
+    },
+    "he": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "ddg", "wikipedia-he", "morfix-dic"
+        ]
+      }
+    },
+    "hi-IN": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-in", "bing", "ddg", "wikipedia-hi"
+        ]
+      }
+    },
+    "hr": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "amazon-en-GB", "bing", "ddg", "eudict", "twitter", "wikipedia-hr"
+        ]
+      }
+    },
+    "hsb": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-de", "bing", "amazondotcom-de", "ddg", "leo_ende_de", "wikipedia-hsb"
+        ]
+      }
+    },
+    "hu": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "ddg", "sztaki-en-hu", "vatera", "wikipedia-hu"
+        ]
+      }
+    },
+    "hy-AM": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "amazondotcom", "ddg", "list-am", "wikipedia-hy"
+        ]
+      }
+    },
+    "id": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-id", "ddg", "wikipedia-id"
+        ]
+      }
+    },
+    "is": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazondotcom", "ddg", "leit-is", "wikipedia-is"
+        ]
+      }
+    },
+    "it": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-it", "bing", "amazon-it", "ddg", "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", "twitter", "wikipedia-ka"
+        ]
+      }
+    },
+    "kk": {
+      "default": {
+        "visibleDefaultEngines": [
+          "yandex", "google", "ddg", "flip", "kaz-kk", "twitter", "wikipedia-kk"
+        ]
+      }
+    },
+    "km": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazondotcom", "ddg", "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", "wikipedia-hi"
+        ]
+      }
+    },
+    "ks": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-in", "bing", "ddg", "wikipedia-hi"
+        ]
+      }
+    },
+    "lij": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-it", "bing", "amazon-it", "ddg", "paroledigenova-lij", "wikipedia-lij"
+        ]
+      }
+    },
+    "lt": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "wikipedia-lt", "bing", "amazondotcom", "ddg", "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", "twitter", "wikipedia-hi"
+        ]
+      }
+    },
+    "mk": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazondotcom", "ddg", "wikipedia-mk"
+        ]
+      }
+    },
+    "ml": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "webdunia", "bing", "ddg", "rediff", "wikipedia", "wikipedia-ml"
+        ]
+      }
+    },
+    "mr": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-in", "amazondotcom", "ddg", "rediff", "wikipedia-mr"
+        ]
+      }
+    },
+    "ms": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazondotcom", "ddg", "twitter", "wikipedia-ms"
+        ]
+      }
+    },
+    "my": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazondotcom", "ddg", "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", "wikipedia-or"
+        ]
+      }
+    },
+    "pa-IN": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-in", "bing", "ddg", "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", "wikipediaro"
+        ]
+      }
+    },
+    "ru": {
+      "default": {
+        "visibleDefaultEngines": [
+          "yandex", "google", "ddg", "ozonru", "priceru", "wikipedia-ru", "mailru"
+        ]
+      }
+    },
+    "sat": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-in", "bing", "wikipedia-hi", "ddg"
+        ]
+      }
+    },
+    "si": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "amazondotcom", "ddg", "wikipedia-si"
+        ]
+      }
+    },
+    "sk": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "azet-sk", "atlas-sk", "ddg", "dunaj-sk", "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", "cnrtl-tlfi-fr", "wikipedia-fr"
+        ]
+      }
+    },
+    "sq": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazon-en-GB", "ddg", "wikipedia-sq"
+        ]
+      }
+    },
+    "sr": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "amazon-en-GB", "bing", "ddg", "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", "wikipedia-ta"
+        ]
+      }
+    },
+    "te": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo-in", "amazondotcom", "ddg", "wikipedia-te", "wiktionary-te"
+        ]
+      }
+    },
+    "th": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "amazondotcom", "bing", "ddg", "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", "twitter", "wikipedia"
+        ]
+      }
+    },
+    "uz": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazondotcom", "ddg", "twitter", "wikipedia-uz"
+        ]
+      }
+    },
+    "vi": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "ddg", "wikipedia-vi", "zing-mp3"
+        ]
+      }
+    },
+    "wo": {
+      "default": {
+        "visibleDefaultEngines": [
+          "google", "yahoo", "bing", "amazondotcom", "ddg", "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
@@ -3588,71 +3588,152 @@ 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();
       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 (!("visibleDefaultEngines" in searchSettings[region])) {
+        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 || !engineNames.length) {
+      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];
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"
+    ]
+  }
+}
deleted file mode 100644
--- a/toolkit/components/search/tests/xpcshell/data/list.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-engine
-engine-pref
-engine-rel-searchform-purpose
-engine-system-purpose
-engine-chromeicon
-engine-resourceicon
index 6cce53d1265d0da885a2f21344a22a7405e752a0..8bfbe6f215c364ad1cd9dc1f9581bd825238d99f
GIT binary patch
literal 1249
zc$^FHW@Zs#U|`^2m=U1qY5LV6Takr<VGSz-gD8UxLvlt@er~FMacW{waz;pMafx15
zVo_)aCj)c;`Agvwfw;7Sn}Lz#D<cB~*ck2)X=x9W7#jaE`1-S{95}9UIAG4Kh$(Xd
zCj`%$H#2;VywstS2V%<q1y$G!Ob;tCHrP~?nv#$p$heA+VHWcuONqGU-)_yd-uZQ<
zZ9o>kFmtm>o2BQ{muYItrafb;65VN;;2drn^XhhQ=8H?7>YMqbIkxOw|2W8I<0p>m
zmpoRAq(AqZK4-7!Im7H4?}*y1zE7)`egC_+aJCxj{)$_1_RgPf=A4Yp$(%kp#Q*HY
zdqy`i)!TpUy*aCE;lj0!UypVPY8U;zx6z#YUQgH7I|V7(nx_koMSP6jf99&ld*9zb
zl|Ht&#yALyM{~}<cg<S#^}4WmtF}ZesL%4cduYMV*5Lm0emgDg7kEs1e$;TC`tQn^
zJQ+LlpA*U-yG;8bZq<ISe6z;q_(v7rE<8@~JL3M&ruF!yynfqHZ{u#gayvOI+Vi)o
zbo#V=)mxXH-I;v1CuHH&pjGWDzIUJf_PP1%dn#}6jdd0COQ(AqH_P9-^CKa<r0VbA
zr?16yJZ~?ZP}7rqZ<)#6DX*Wd{5)%Oby@gy_q%UD&-+-g@R?+A-20oq`|R%=iqQIc
z?5*(T-{tl1?_9C}KXd()=_#G3kJQ8m|7esIRF{pbd1vh$F3ZW*_Qo|~jz_`~Pq#EL
zuPiwmCy}~&yho)J%m4C8cF5HKk3AAzA=~fKerU-aziAA$!c&>g1m9b>=HIfpzil3T
ze0O`NkJIa_Ggs@+&ENj--|5zyoN2ofyU)ETS#@pBrPv<@?|l|7xDfC^{7;q6dgF9|
zzdQNs)AmNquD!*#^&h)dcbv8BfBVIY4prULNH`@UeQ@X5d%K=}-n9JIj6KgeP9|7S
z{QD%~so2{j;ZEzqKgXx;eRb>ZewK54mdI~9RdILul)DpCUj;vl(0+gG)R)b3ZhpAk
z_TJl$MRkRY$o5zNeweSk8EG~7X>p_Xr)?klA0E)S)EoDDV&3;ped|I>KfIkSx!uZU
z^8D}TQhl>3FN&@-o4ES0f&QM4i?$TJYWbP{-qfe|xb4pp$2YnYyNu>{t@&hKAI>G6
zS@3Jg@;MVNBxJVj`+D|WX}Vqhjg<w@v%WtKe_y`E<DPNe-JL3i#@}`ymD$W%ceY;r
zpJhSdyR?8WJ_#zatL9Xnn)){@rZGU*SZR`ub$-Q`J39{uF+Is;Oe*a0ICWA-@8W5#
zbLW|lU%d5o=fj9c8DBRqXkgIykI$dGc~;}>rmzj7mR4)7+{{T_v$Ae#=*y35UVcvV
z>wm;4_<%Q+W3HHyw!W^WwsAgVcZL1yWov@klQT6>Pt&P1GYr&r*_pkFsrllWtCx2)
z?wmc*vrjVIQjsy0(_l|2%f%N<*|e8jIiO+akoHK+SRsvRCy%$3t-%==ZN~^jRSr3B
z17n6wtmP6Hbsf&}t(owq;dsfJ8O~;VCraKeSyGYGdPKSH;hG!;=7@$33>qtrF+E~r
t2=HcPl4HhI;z%&Sz>-D~iKF~sg_J*NWlw-ND;r1?BM?Rd=>irI4*<dzPN)C?
--- 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
@@ -19,17 +19,17 @@ support-files =
   data/engine-system-purpose.xml
   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