jenkins-bot has submitted this change and it was merged.

Change subject: Fix article language picker for Chinese
......................................................................


Fix article language picker for Chinese

- Replace article language picker entry for Chinese with Simplified and 
Traditional Chinese entries.
- Decouple language from WikipediaApp.
- Decouple static app language support from app language state.
- Consider site in accept-language headers.
- Fix and refactor LanguageVariantTests.
- Misc refactoring.

Bug: T99965
Change-Id: I362e23ac2383d6ee81daf29d103ee8cc48c04bfd
---
M wikipedia-it/src/main/java/org/wikipedia/test/LanguageVariantTests.java
M wikipedia-it/src/main/java/org/wikipedia/test/TestDummyActivity.java
M wikipedia/res/layout/item_language_list_entry.xml
M wikipedia/src/main/java/org/wikipedia/Site.java
M wikipedia/src/main/java/org/wikipedia/Utils.java
M wikipedia/src/main/java/org/wikipedia/WikipediaApp.java
M wikipedia/src/main/java/org/wikipedia/editing/EditPreviewFragment.java
M wikipedia/src/main/java/org/wikipedia/editing/EditSectionActivity.java
M 
wikipedia/src/main/java/org/wikipedia/editing/summaries/EditSummaryHandler.java
A 
wikipedia/src/main/java/org/wikipedia/interlanguage/AppLanguageLookUpTable.java
A wikipedia/src/main/java/org/wikipedia/interlanguage/AppLanguageState.java
M wikipedia/src/main/java/org/wikipedia/interlanguage/LangLinksActivity.java
M wikipedia/src/main/java/org/wikipedia/page/JsonPageLoadStrategy.java
M wikipedia/src/main/java/org/wikipedia/page/PageActivity.java
M wikipedia/src/main/java/org/wikipedia/page/PageTitle.java
M wikipedia/src/main/java/org/wikipedia/page/gallery/GalleryActivity.java
M 
wikipedia/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewContents.java
M wikipedia/src/main/java/org/wikipedia/search/SearchResultsFragment.java
M wikipedia/src/main/java/org/wikipedia/settings/LanguagePreference.java
A wikipedia/src/main/java/org/wikipedia/settings/PreferenceUtil.java
M wikipedia/src/main/java/org/wikipedia/settings/SettingsActivityGB.java
M wikipedia/src/main/java/org/wikipedia/settings/SettingsFragment.java
M wikipedia/src/main/java/org/wikipedia/staticdata/MainPageNameData.java
M wikipedia/src/main/java/org/wikipedia/util/ShareUtils.java
A wikipedia/src/main/java/org/wikipedia/util/StringUtil.java
M wikipedia/src/main/java/org/wikipedia/widgets/WidgetProviderFeaturedPage.java
26 files changed, 667 insertions(+), 342 deletions(-)

Approvals:
  BearND: Looks good to me, approved
  jenkins-bot: Verified



diff --git 
a/wikipedia-it/src/main/java/org/wikipedia/test/LanguageVariantTests.java 
b/wikipedia-it/src/main/java/org/wikipedia/test/LanguageVariantTests.java
index 54526d7..011d4c7 100644
--- a/wikipedia-it/src/main/java/org/wikipedia/test/LanguageVariantTests.java
+++ b/wikipedia-it/src/main/java/org/wikipedia/test/LanguageVariantTests.java
@@ -1,47 +1,78 @@
 package org.wikipedia.test;
 
-import android.content.Intent;
-import android.test.ActivityUnitTestCase;
+import android.test.InstrumentationTestCase;
+import android.test.UiThreadTest;
+
+import org.wikipedia.Site;
 import org.wikipedia.WikipediaApp;
+import org.wikipedia.interlanguage.AppLanguageLookUpTable;
 
 import java.util.Locale;
 
-public class LanguageVariantTests extends 
ActivityUnitTestCase<TestDummyActivity> {
+public class LanguageVariantTests extends InstrumentationTestCase {
+    private Locale defaultLocale;
+    private String appLanguage;
 
-    private WikipediaApp app;
+    /** Ensure that the more specific dialect is first in the list. */
+    @UiThreadTest
+    public void testDefaultLocaleAndAcceptLanguageAgree() throws Throwable {
+        preserveAppState();
 
-    public LanguageVariantTests() {
-        super(TestDummyActivity.class);
+        testDefaultLocaleAndAcceptLanguageAgree("zh,zh-hant;q=0.8", "zh",
+                Locale.TRADITIONAL_CHINESE);
+        testDefaultLocaleAndAcceptLanguageAgree("zh,zh-hans;q=0.8", "zh",
+                Locale.SIMPLIFIED_CHINESE);
+        testDefaultLocaleAndAcceptLanguageAgree("zh,en;q=0.8", "zh", 
Locale.US);
+        testDefaultLocaleAndAcceptLanguageAgree("zh,en;q=0.8", "zh", 
Locale.ENGLISH);
+        testDefaultLocaleAndAcceptLanguageAgree("en,zh-hans;q=0.8", "en",
+                Locale.SIMPLIFIED_CHINESE);
+        testDefaultLocaleAndAcceptLanguageAgree("test,zh-hans;q=0.8", "test",
+                Locale.SIMPLIFIED_CHINESE);
+        
testDefaultLocaleAndAcceptLanguageAgree("es,zh-hans;q=0.9,zh-hant;q=0.8",
+                AppLanguageLookUpTable.SIMPLIFIED_CHINESE_LANGUAGE_CODE,
+                Locale.TRADITIONAL_CHINESE, Site.forLanguage("es"));
+        testDefaultLocaleAndAcceptLanguageAgree("zh-hant",
+                AppLanguageLookUpTable.TRADITIONAL_CHINESE_LANGUAGE_CODE,
+                Locale.TRADITIONAL_CHINESE);
+
+        restoreAppState();
     }
 
-    /**
-     * Ensure that the more specific dialect is first in the list
-     * TODO: once Chinese is updated, update tests for more languages
-     */
-    public void testDefaultLocaleAndAcceptLanguageAgree() throws Throwable {
-        startActivity(new Intent(), null, null);
+    private void testDefaultLocaleAndAcceptLanguageAgree(String expected, 
String appLanguage,
+            Locale systemLocale) {
+        testDefaultLocaleAndAcceptLanguageAgree(expected, appLanguage, 
systemLocale, null);
+    }
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                app = (WikipediaApp) 
getInstrumentation().getTargetContext().getApplicationContext();
-                Locale originalLocale = Locale.getDefault();
+    private void testDefaultLocaleAndAcceptLanguageAgree(String expected,
+             String appLanguage, Locale systemLocale, Site site) {
+        WikipediaApp.getInstance().setAppLanguageCode(appLanguage);
+        Locale.setDefault(systemLocale);
+        assertEquals(expected, 
WikipediaApp.getInstance().getAcceptLanguage(site));
+    }
 
-                cover("zh-tw,zh;q=0.9", "zh", Locale.TRADITIONAL_CHINESE);
-                cover("zh-cn,zh;q=0.9", "zh", Locale.SIMPLIFIED_CHINESE);
-                cover("zh,en-us;q=0.9,en;q=0.8", "zh", Locale.US);
-                cover("zh,en;q=0.9", "zh", Locale.ENGLISH);
-                cover("en,zh-cn;q=0.9,zh;q=0.8", "en", 
Locale.SIMPLIFIED_CHINESE);
-                cover("test,zh-cn;q=0.9,zh;q=0.8", "test", 
Locale.SIMPLIFIED_CHINESE);
+    private void preserveAppState() {
+        preserveDefaultLocale();
+        preserveAppLanguage();
+    }
 
-                Locale.setDefault(originalLocale);
-            }
+    private void restoreAppState() {
+        restoreAppLanguage();
+        restoreDefaultLocale();
+    }
 
-            private void cover(String expected, String primaryLanguage, Locale 
locale) {
-                app.setLanguage(primaryLanguage);
-                Locale.setDefault(locale);
-                assertEquals(expected, app.getAcceptLanguage());
-            }
-        });
+    private void preserveAppLanguage() {
+        appLanguage = WikipediaApp.getInstance().getAppLanguageCode();
+    }
+
+    private void restoreAppLanguage() {
+        WikipediaApp.getInstance().setAppLanguageCode(appLanguage);
+    }
+
+    private void preserveDefaultLocale() {
+        defaultLocale = Locale.getDefault();
+    }
+
+    private void restoreDefaultLocale() {
+        Locale.setDefault(defaultLocale);
     }
 }
diff --git 
a/wikipedia-it/src/main/java/org/wikipedia/test/TestDummyActivity.java 
b/wikipedia-it/src/main/java/org/wikipedia/test/TestDummyActivity.java
index f9cd631..e176241 100644
--- a/wikipedia-it/src/main/java/org/wikipedia/test/TestDummyActivity.java
+++ b/wikipedia-it/src/main/java/org/wikipedia/test/TestDummyActivity.java
@@ -1,7 +1,6 @@
 package org.wikipedia.test;
 
 import android.app.Activity;
-import android.os.Bundle;
 
 /**
  * Dummy activity that does nothing and is happy about it.
@@ -9,7 +8,4 @@
  * Used to do things on the UI thread in unit tests.
  */
 public class TestDummyActivity extends Activity {
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-    }
 }
\ No newline at end of file
diff --git a/wikipedia/res/layout/item_language_list_entry.xml 
b/wikipedia/res/layout/item_language_list_entry.xml
index dd453dd..c798947 100644
--- a/wikipedia/res/layout/item_language_list_entry.xml
+++ b/wikipedia/res/layout/item_language_list_entry.xml
@@ -12,7 +12,7 @@
               android:background="@drawable/selectable_item_background"
               >
     <TextView
-            android:id="@+id/language_local_name"
+            android:id="@+id/localized_language_name"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:textAppearance="?android:attr/textAppearanceMedium"
@@ -20,7 +20,7 @@
             tools:text="Sample language local name"
             />
     <TextView
-            android:id="@+id/article_local_name"
+            android:id="@+id/article_title"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:textAppearance="?android:attr/textAppearanceSmall"
diff --git a/wikipedia/src/main/java/org/wikipedia/Site.java 
b/wikipedia/src/main/java/org/wikipedia/Site.java
index 1a8c6a9..f2c58bc 100644
--- a/wikipedia/src/main/java/org/wikipedia/Site.java
+++ b/wikipedia/src/main/java/org/wikipedia/Site.java
@@ -5,7 +5,10 @@
 import android.os.Parcelable;
 import android.text.TextUtils;
 
+import org.wikipedia.interlanguage.AppLanguageLookUpTable;
 import org.wikipedia.page.PageTitle;
+
+import java.util.Locale;
 
 /**
  * Represents a particular wiki.
@@ -13,15 +16,15 @@
 public class Site implements Parcelable {
     private final String domain;
 
-    private final String language;
+    private final String languageCode;
 
     public Site(String domain) {
         this(domain, urlToLanguage(domain));
     }
 
-    public Site(String domain, String language) {
+    public Site(String domain, String languageCode) {
         this.domain = urlToDesktopSite(domain);
-        this.language = language;
+        this.languageCode = languageCode;
     }
 
     public Site(Parcel in) {
@@ -31,7 +34,7 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(domain);
-        dest.writeString(language);
+        dest.writeString(languageCode);
     }
 
     public String getScriptPath(String script) {
@@ -85,7 +88,7 @@
         if (domain != null ? !domain.equals(site.domain) : site.domain != 
null) {
             return false;
         }
-        return !(language != null ? !language.equals(site.language) : 
site.language != null);
+        return !(languageCode != null ? 
!languageCode.equals(site.languageCode) : site.languageCode != null);
 
     }
 
@@ -93,7 +96,7 @@
     @Override
     public int hashCode() {
         int result = domain != null ? domain.hashCode() : 0;
-        result = 31 * result + (language != null ? language.hashCode() : 0);
+        result = 31 * result + (languageCode != null ? languageCode.hashCode() 
: 0);
         return result;
     }
 
@@ -102,7 +105,7 @@
     public String toString() {
         return "Site{"
                 + "domain='" + domain + '\''
-                + ", language='" + language + '\''
+                + ", languageCode='" + languageCode + '\''
                 + '}';
     }
 
@@ -136,8 +139,8 @@
         return titleForInternalLink(path);
     }
 
-    public String getLanguage() {
-        return language;
+    public String getLanguageCode() {
+        return languageCode;
     }
 
     public static Site forLanguage(String language) {
@@ -167,9 +170,9 @@
 
     private static String languageToWikiSubdomain(String language) {
         switch (language) {
-            case "zh-hans":
-            case "zh-hant":
-                return "zh";
+            case AppLanguageLookUpTable.SIMPLIFIED_CHINESE_LANGUAGE_CODE:
+            case AppLanguageLookUpTable.TRADITIONAL_CHINESE_LANGUAGE_CODE:
+                return Locale.CHINA.getLanguage();
             default:
                 return language;
         }
diff --git a/wikipedia/src/main/java/org/wikipedia/Utils.java 
b/wikipedia/src/main/java/org/wikipedia/Utils.java
index 1fe8bf1..7363e41 100644
--- a/wikipedia/src/main/java/org/wikipedia/Utils.java
+++ b/wikipedia/src/main/java/org/wikipedia/Utils.java
@@ -336,7 +336,7 @@
      * @return dbname for given site object
      */
     public static String getDBNameForSite(Site site) {
-        return site.getLanguage() + "wiki";
+        return site.getLanguageCode() + "wiki";
     }
 
     public static void handleExternalLink(final Context context, final Uri 
uri) {
diff --git a/wikipedia/src/main/java/org/wikipedia/WikipediaApp.java 
b/wikipedia/src/main/java/org/wikipedia/WikipediaApp.java
index d654350..8b9b2d6 100644
--- a/wikipedia/src/main/java/org/wikipedia/WikipediaApp.java
+++ b/wikipedia/src/main/java/org/wikipedia/WikipediaApp.java
@@ -10,10 +10,11 @@
 import android.preference.PreferenceManager;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
-import android.text.TextUtils;
 import android.view.Window;
 import android.webkit.WebView;
+
 import com.squareup.otto.Bus;
+
 import org.acra.ACRA;
 import org.acra.ReportingInteractionMode;
 import org.acra.annotation.ReportsCrashes;
@@ -29,6 +30,7 @@
 import org.wikipedia.events.ThemeChangeEvent;
 import org.wikipedia.history.HistoryEntry;
 import org.wikipedia.history.HistoryEntryPersister;
+import org.wikipedia.interlanguage.AppLanguageState;
 import org.wikipedia.login.UserInfoStorage;
 import org.wikipedia.migration.PerformMigrationsTask;
 import org.wikipedia.networking.MccMncStateHandler;
@@ -42,9 +44,7 @@
 import org.wikipedia.settings.PrefKeys;
 import org.wikipedia.util.ApiUtil;
 import org.wikipedia.zero.WikipediaZeroHandler;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
+
 import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
@@ -60,13 +60,6 @@
         mailTo = "mobile-android-wikipedia-cras...@wikimedia.org")
 public class WikipediaApp extends Application {
     private static final String HTTPS_PROTOCOL = "https";
-    private static final String FALLBACK_LANGUAGE = "en"; // Must exist in 
preference_language_keys.
-    private static final String HONG_KONG_COUNTRY_CODE = "HK";
-    private static final String MACAU_COUNTRY_CODE = "MO";
-    private static final String SIMPLIFIED_CHINESE_LANGUAGE = "zh-hans";
-    private static final String TRADITIONAL_CHINESE_LANGUAGE = "zh-hant";
-    private static final List<String> TRADITIONAL_CHINESE_COUNTRY_CODES = 
Arrays.asList(
-            Locale.TAIWAN.getCountry(), HONG_KONG_COUNTRY_CODE, 
MACAU_COUNTRY_CODE);
 
     private float screenDensity;
     public float getScreenDensity() {
@@ -110,6 +103,8 @@
 
     public static final int PREFERRED_THUMB_SIZE = 96;
 
+    private AppLanguageState appLanguageState;
+
     /**
      * Returns a constant that tells whether this app is a production release,
      * a beta release, or an alpha (continuous integration) release.
@@ -123,26 +118,6 @@
         return releaseType == RELEASE_PROD;
     }
 
-    // Language codes for all supported languages in fixed order.
-    @Nullable
-    private List<String> supportedLanguages;
-
-    // English names for all supported languages in fixed order.
-    @Nullable
-    private String[] supportedLanguageCanonicalNames;
-
-    // Native names for all supported languages in fixed order.
-    @Nullable
-    private String[] supportedLanguageLocalNames;
-
-    // Language codes that have been explicitly chosen by the user in most 
recently used order.
-    @Nullable
-    private List<String> mruLanguages;
-
-    // The primary language code used by the app when the page language is 
unspecified. Null is a
-    // special value that indicates the system language should used.
-    @Nullable
-    private String language;
 
     private SessionFunnel sessionFunnel;
     public SessionFunnel getSessionFunnel() {
@@ -214,6 +189,8 @@
         this.prefs = PreferenceManager.getDefaultSharedPreferences(this);
         PrefKeys.initPreferenceKeys(resources);
 
+        appLanguageState = new AppLanguageState(this);
+
         sessionFunnel = new SessionFunnel(this);
 
         // Enable debugging on the webview
@@ -248,15 +225,25 @@
         return userAgent;
     }
 
+    @NonNull
+    public String getAcceptLanguage() {
+        return getAcceptLanguage(null);
+    }
+
     /**
      * @return the value that should go in the Accept-Language header.
      */
-    public String getAcceptLanguage() {
-        String acceptLanguage = getLanguage();
+    @NonNull
+    public String getAcceptLanguage(@Nullable Site site) {
+        /*Nonnull*/ String siteLanguageCode = site == null ? "" : 
site.getLanguageCode();
+        /*Nonnull*/ String appLanguageCode = isSystemLanguageEnabled() ? "" : 
getAppLanguageCode();
+        /*Nonnull*/ String systemLanguageCode = getSystemLanguageCode();
+        final float appLanguageQuality = .9f;
+        final float systemLanguageQuality = .8f;
 
-        if (getSystemLanguage() != null && 
!getLanguage().equals(getSystemLanguage())) {
-            acceptLanguage += "," + getSystemLanguage() + ";q=0.9";
-        }
+        String acceptLanguage = siteLanguageCode;
+        acceptLanguage = appendToAcceptLanguage(acceptLanguage, 
appLanguageCode, appLanguageQuality);
+        acceptLanguage = appendToAcceptLanguage(acceptLanguage, 
systemLanguageCode, systemLanguageQuality);
 
         return acceptLanguage;
     }
@@ -271,7 +258,7 @@
         if (isEventLoggingEnabled()) {
             customHeaders.put("X-WMF-UUID", getAppInstallID());
         }
-        String acceptLanguage = getAcceptLanguage();
+        String acceptLanguage = getAcceptLanguage(site);
 
         customHeaders.put("Accept-Language", acceptLanguage);
 
@@ -303,7 +290,7 @@
      */
     public Site getPrimarySite() {
         if (primarySite == null) {
-            primarySite = Site.forLanguage(getLanguage());
+            primarySite = Site.forLanguage(getAppOrSystemLanguageCode());
         }
 
         return primarySite;
@@ -318,40 +305,61 @@
         return getAPIForSite(getPrimarySite());
     }
 
-    public Locale getLocale() {
-        return new Locale(getLanguage());
+    public String getAppLanguageCode() {
+        return appLanguageState.getAppLanguageCode();
     }
 
-    public String getDisplayLanguage() {
-        return isSystemLanguageEnabled()
-                ? getString(R.string.preference_system_language_summary)
-                : 
getLocalNameForSupportedLanguage(findSupportedLanguageIndex());
+    public String getSystemLanguageCode() {
+        return appLanguageState.getSystemLanguageCode();
     }
 
-    /** In general, this value should not be cached as it may change outside 
the app. */
-    public String getLanguage() {
-        return isSystemLanguageEnabled() ? getSystemLanguage() : language;
+    public String getAppOrSystemLanguageCode() {
+        return appLanguageState.getAppOrSystemLanguageCode();
     }
 
-    public String getLanguageKey() {
-        if (language == null) {
-            language = prefs.getString(PrefKeys.getContentLanguageKey(), null);
-        }
-        return language;
-    }
-
-    public void setSystemLanguage() {
-        setLanguage(null);
-    }
-
-    public void setLanguage(String language) {
-        this.language = language;
-        prefs.edit().putString(PrefKeys.getContentLanguageKey(), 
language).apply();
+    public void setAppLanguageCode(String code) {
+        appLanguageState.setAppLanguageCode(code);
         resetSite();
     }
 
     public boolean isSystemLanguageEnabled() {
-        return getLanguageKey() == null;
+        return appLanguageState.isSystemLanguageEnabled();
+    }
+
+    public void setSystemLanguageEnabled() {
+        appLanguageState.setSystemLanguageEnabled();
+    }
+
+    public String getAppLanguageLocalizedName() {
+        return appLanguageState.getAppLanguageLocalizedName();
+    }
+
+    public Locale getAppLocale() {
+        return appLanguageState.getAppLocale();
+    }
+
+    @NonNull
+    public List<String> getMruLanguageCodes() {
+        return appLanguageState.getMruLanguageCodes();
+    }
+
+    @NonNull
+    public List<String> getAppMruLanguageCodes() {
+        return appLanguageState.getAppMruLanguageCodes();
+    }
+
+    public void setMruLanguageCode(@Nullable String code) {
+        appLanguageState.setMruLanguageCode(code);
+    }
+
+    @Nullable
+    public String getAppLanguageLocalizedName(String code) {
+        return appLanguageState.getAppLanguageLocalizedName(code);
+    }
+
+    @Nullable
+    public String getAppLanguageCanonicalName(String code) {
+        return appLanguageState.getAppLanguageCanonicalName(code);
     }
 
     private DBOpenHelper dbOpenHelper;
@@ -384,31 +392,6 @@
         return persisters.get(cls.getCanonicalName());
     }
 
-    public int findSupportedLanguageIndex() {
-        return findSupportedLanguageIndex(getLanguageKey());
-    }
-
-    public int findSupportedLanguageIndex(String language) {
-        int index = getSupportedLanguages().indexOf(language);
-        if (index == -1) {
-            // FIXME: Instrument this with EL to find out what is happening on 
places where there is a lang we can't find
-            // In the meantime, just fall back to en. See 
https://bugzilla.wikimedia.org/show_bug.cgi?id=66140
-            return findSupportedLanguageIndex(FALLBACK_LANGUAGE);
-        }
-        return index;
-    }
-
-    private boolean isSupportedLanguage(String language) {
-       return getSupportedLanguages().contains(language);
-    }
-
-    /** @return Immutable list. */
-    public List<String> getSupportedLanguages() {
-        if (supportedLanguages == null) {
-            supportedLanguages = 
Arrays.asList(getResources().getStringArray(R.array.preference_language_keys));
-        }
-        return supportedLanguages;
-    }
 
     private RemoteConfig remoteConfig;
     public RemoteConfig getRemoteConfig() {
@@ -416,20 +399,6 @@
             remoteConfig = new RemoteConfig(prefs);
         }
         return remoteConfig;
-    }
-
-    public String getCanonicalNameForSupportedLanguage(int index) {
-        if (supportedLanguageCanonicalNames == null) {
-            supportedLanguageCanonicalNames = 
getResources().getStringArray(R.array.preference_language_canonical_names);
-        }
-        return supportedLanguageCanonicalNames[index];
-    }
-
-    public String getLocalNameForSupportedLanguage(int index) {
-        if (supportedLanguageLocalNames == null) {
-            supportedLanguageLocalNames = 
getResources().getStringArray(R.array.preference_language_local_names);
-        }
-        return supportedLanguageLocalNames[index];
     }
 
     private EditTokenStorage editTokenStorage;
@@ -614,78 +583,27 @@
         return prefs.getBoolean(PrefKeys.getEventLoggingEnabled(), true);
     }
 
-    /** @return All support languages in MRU order. */
-    public List<String> getAllMruLanguages() {
-        List<String> languages = new ArrayList<>(getSupportedLanguages());
-        int addIndex = 0;
-        for (String langCode : getMruLanguages()) {
-            if (languages.contains(langCode)) {
-                languages.remove(langCode);
-                languages.add(addIndex++, langCode);
-            }
-        }
-        return languages;
-    }
-
-    public List<String> getMruLanguages() {
-        if (mruLanguages == null) {
-            mruLanguages = unmarshalMruLanguages();
-        }
-        return mruLanguages;
-    }
-
-    public void setMruLanguage(String language) {
-        List<String> languages = getMruLanguages();
-        languages.remove(language);
-        languages.add(0, language);
-        prefs.edit().putString(PrefKeys.getLanguageMru(), 
listToCsv(languages)).apply();
-    }
-
     public boolean showImages() {
         return prefs.getBoolean(PrefKeys.getShowImages(), true);
-    }
-
-    private List<String> unmarshalMruLanguages() {
-        String nullString = String.valueOf((Object) null);
-        String csv = prefs.getString(PrefKeys.getLanguageMru(), nullString);
-
-        List<String> list = new ArrayList<>(csvToList(csv));
-
-        // Null value is used to indicate that system language should be used.
-        Collections.replaceAll(list, nullString, null);
-
-        return list;
-    }
-
-    private String listToCsv(List<String> list) {
-        return TextUtils.join(",", list);
-    }
-
-    /** @return Immutable list. */
-    private List<String> csvToList(String csv) {
-        return Arrays.asList(csv.split(","));
     }
 
     public void resetSite() {
         primarySite = null;
     }
 
-    @NonNull
-    public String getSystemLanguage() {
-        String lang = 
Utils.langCodeToWikiLang(Locale.getDefault().getLanguage());
-        return isSupportedLanguage(lang) ? lang : convertSystemLanguage(lang);
-    }
-
-    @NonNull
-    private String convertSystemLanguage(String language) {
-        if (Locale.CHINA.getLanguage().equals(language)) {
-            return 
isTraditionalChinesePredominantInCountry(Locale.getDefault().getCountry())
-                    ? TRADITIONAL_CHINESE_LANGUAGE : 
SIMPLIFIED_CHINESE_LANGUAGE;
+    @NonNull private String appendToAcceptLanguage(@NonNull String 
acceptLanguage,
+            @NonNull String languageCode, float quality) {
+        // If accept-language already contains the language, just return 
accept-language.
+        if (acceptLanguage.contains(languageCode)) {
+            return acceptLanguage;
         }
-        return FALLBACK_LANGUAGE;
-    }
 
-    private boolean isTraditionalChinesePredominantInCountry(String country) {
-        return TRADITIONAL_CHINESE_COUNTRY_CODES.contains(country);
+        // If accept-language is empty, don't append. Just return the language.
+        if (acceptLanguage.isEmpty()) {
+            return languageCode;
+        }
+
+        // Accept-language is nonempty, append the language.
+        return String.format("%s,%s;q=%.1f", acceptLanguage, languageCode, 
quality);
     }
 }
diff --git 
a/wikipedia/src/main/java/org/wikipedia/editing/EditPreviewFragment.java 
b/wikipedia/src/main/java/org/wikipedia/editing/EditPreviewFragment.java
index 48400ca..ae9ab91 100644
--- a/wikipedia/src/main/java/org/wikipedia/editing/EditPreviewFragment.java
+++ b/wikipedia/src/main/java/org/wikipedia/editing/EditPreviewFragment.java
@@ -81,7 +81,7 @@
         AssetManager assets = oldResources.getAssets();
         DisplayMetrics metrics = oldResources.getDisplayMetrics();
         Locale oldLocale = oldResources.getConfiguration().locale;
-        Locale newLocale = WikipediaApp.getInstance().getLocale();
+        Locale newLocale = WikipediaApp.getInstance().getAppLocale();
         Configuration config = new 
Configuration(oldResources.getConfiguration());
         Resources tempResources = getResources();
         if (!oldLocale.getLanguage().equals(newLocale.getLanguage())) {
@@ -171,7 +171,7 @@
         if (!isWebViewSetup) {
             isWebViewSetup = true;
             
bridge.injectStyleBundle(StyleBundle.getAvailableBundle(StyleBundle.BUNDLE_PREVIEW));
-            
Utils.setupDirectionality(parentActivity.getPageTitle().getSite().getLanguage(),
 Locale.getDefault().getLanguage(), bridge);
+            
Utils.setupDirectionality(parentActivity.getPageTitle().getSite().getLanguageCode(),
 Locale.getDefault().getLanguage(), bridge);
             if (WikipediaApp.getInstance().getCurrentTheme() == 
WikipediaApp.THEME_DARK) {
                 new NightModeHandler(bridge).turnOn(false);
             }
diff --git 
a/wikipedia/src/main/java/org/wikipedia/editing/EditSectionActivity.java 
b/wikipedia/src/main/java/org/wikipedia/editing/EditSectionActivity.java
index c2174d6..d2ca9f6 100644
--- a/wikipedia/src/main/java/org/wikipedia/editing/EditSectionActivity.java
+++ b/wikipedia/src/main/java/org/wikipedia/editing/EditSectionActivity.java
@@ -167,7 +167,7 @@
         });
 
 
-        Utils.setTextDirection(sectionText, title.getSite().getLanguage());
+        Utils.setTextDirection(sectionText, title.getSite().getLanguageCode());
 
         fetchSectionText();
 
diff --git 
a/wikipedia/src/main/java/org/wikipedia/editing/summaries/EditSummaryHandler.java
 
b/wikipedia/src/main/java/org/wikipedia/editing/summaries/EditSummaryHandler.java
index 066631a..5eed3a9 100644
--- 
a/wikipedia/src/main/java/org/wikipedia/editing/summaries/EditSummaryHandler.java
+++ 
b/wikipedia/src/main/java/org/wikipedia/editing/summaries/EditSummaryHandler.java
@@ -66,7 +66,7 @@
             }
         });
 
-        Utils.setTextDirection(summaryEdit, title.getSite().getLanguage());
+        Utils.setTextDirection(summaryEdit, title.getSite().getLanguageCode());
     }
 
     public void show() {
diff --git 
a/wikipedia/src/main/java/org/wikipedia/interlanguage/AppLanguageLookUpTable.java
 
b/wikipedia/src/main/java/org/wikipedia/interlanguage/AppLanguageLookUpTable.java
new file mode 100644
index 0000000..7155935
--- /dev/null
+++ 
b/wikipedia/src/main/java/org/wikipedia/interlanguage/AppLanguageLookUpTable.java
@@ -0,0 +1,83 @@
+package org.wikipedia.interlanguage;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.wikipedia.R;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/** Immutable look up table for all app supported languages. All article 
languages may not be
+  * present in this table as it is statically bundled with the app. */
+public class AppLanguageLookUpTable {
+    public static final String SIMPLIFIED_CHINESE_LANGUAGE_CODE = "zh-hans";
+    public static final String TRADITIONAL_CHINESE_LANGUAGE_CODE = "zh-hant";
+    public static final String FALLBACK_LANGUAGE_CODE = "en"; // Must exist in 
preference_language_keys.
+
+    // Immutable language codes for all app supported languages in fixed order.
+    @NonNull
+    private final List<String> codes;
+
+    // Immutable English names for all app supported languages in fixed order.
+    @NonNull
+    private final List<String> canonicalNames;
+
+    // Immutable native names for all app supported languages in fixed order.
+    @NonNull
+    private final List<String> localizedNames;
+
+    public AppLanguageLookUpTable(@NonNull Context context) {
+        codes = getStringList(context, R.array.preference_language_keys); // 
The codes are the keys.
+        canonicalNames = getStringList(context, 
R.array.preference_language_canonical_names);
+        localizedNames = getStringList(context, 
R.array.preference_language_local_names);
+    }
+
+    /** @return Nonnull immutable list. */
+    @NonNull
+    public List<String> getCodes() {
+        return codes;
+    }
+
+    @Nullable
+    public String getCanonicalName(String code) {
+        return defaultIndex(canonicalNames, indexOfCode(code), null);
+    }
+
+    @Nullable
+    public String getLocalizedName(String code) {
+        return defaultIndex(localizedNames, indexOfCode(code), null);
+    }
+
+    public boolean isSupportedCode(String code) {
+        return getCodes().contains(code);
+    }
+
+    private <T> T defaultIndex(List<T> list, int index, T defaultValue) {
+        return inBounds(list, index) ? list.get(index) : defaultValue;
+    }
+
+    /**
+     * Searches #codes for the specified language code and returns the index 
for use in
+     * #canonicalNames and #localizedNames.
+     *
+     * @param code The language code to search for.
+     * @return The index of the language code or -1 if the code is not 
supported.
+     */
+    private int indexOfCode(String code) {
+        return getCodes().indexOf(code);
+    }
+
+    /** @return Nonnull immutable list. */
+    @NonNull
+    private List<String> getStringList(Context context, int id) {
+        String[] array = context.getResources().getStringArray(id);
+        return array == null ? Collections.<String>emptyList() : 
Arrays.asList(array);
+    }
+
+    private boolean inBounds(List<?> list, int index) {
+        return index >= 0 && index < list.size();
+    }
+}
diff --git 
a/wikipedia/src/main/java/org/wikipedia/interlanguage/AppLanguageState.java 
b/wikipedia/src/main/java/org/wikipedia/interlanguage/AppLanguageState.java
new file mode 100644
index 0000000..35fc461
--- /dev/null
+++ b/wikipedia/src/main/java/org/wikipedia/interlanguage/AppLanguageState.java
@@ -0,0 +1,187 @@
+package org.wikipedia.interlanguage;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+
+import org.wikipedia.R;
+import org.wikipedia.Utils;
+import org.wikipedia.settings.PreferenceUtil;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+
+import static org.wikipedia.util.StringUtil.defaultIfNull;
+import static org.wikipedia.util.StringUtil.emptyIfNull;
+
+/** Language lookup and state management for the application language and most 
recently used article
+ * and application languages. */
+public class AppLanguageState {
+    public static final String SYSTEM_LANGUAGE_CODE = null;
+    private static final String HONG_KONG_COUNTRY_CODE = "HK";
+    private static final String MACAU_COUNTRY_CODE = "MO";
+    private static final List<String> TRADITIONAL_CHINESE_COUNTRY_CODES = 
Arrays.asList(
+            Locale.TAIWAN.getCountry(), HONG_KONG_COUNTRY_CODE, 
MACAU_COUNTRY_CODE);
+
+    @NonNull
+    private final Context context;
+
+    @NonNull
+    private final AppLanguageLookUpTable appLanguageLookUpTable;
+
+    // The language code used by the app when the article language is 
unspecified. It's possible for
+    // this code to be unsupported if the languages supported changes. Null is 
a special value that
+    // indicates the system language should used.
+    @Nullable
+    private String appLanguageCode;
+
+    // Language codes that have been explicitly chosen by the user in most 
recently used order. This
+    // list includes both app and article languages.
+    @NonNull
+    private final List<String> mruLanguageCodes;
+
+    public AppLanguageState(@NonNull Context context) {
+        this.context = context;
+        appLanguageLookUpTable = new AppLanguageLookUpTable(context);
+        appLanguageCode = PreferenceUtil.getAppLanguageCode();
+        mruLanguageCodes = unmarshalMruLanguageCodes();
+    }
+
+    @Nullable
+    public String getAppLanguageCode() {
+        return appLanguageCode;
+    }
+
+    @NonNull
+    public String getAppOrSystemLanguageCode() {
+        return isSystemLanguageEnabled() ? getSystemLanguageCode() : 
appLanguageCode;
+    }
+
+    public void setAppLanguageCode(@Nullable String code) {
+        appLanguageCode = code;
+        PreferenceUtil.setAppLanguageCode(code);
+    }
+
+    public boolean isSystemLanguageEnabled() {
+        return 
emptyIfNull(getAppLanguageCode()).equals(emptyIfNull(SYSTEM_LANGUAGE_CODE));
+    }
+
+    public void setSystemLanguageEnabled() {
+        setAppLanguageCode(SYSTEM_LANGUAGE_CODE);
+    }
+
+    @NonNull
+    public String getSystemLanguageCode() {
+        String lang = 
Utils.langCodeToWikiLang(Locale.getDefault().getLanguage());
+        return appLanguageLookUpTable.isSupportedCode(lang) ? lang : 
convertSystemLanguageCode(lang);
+    }
+
+    public Locale getAppLocale() {
+        return isSystemLanguageEnabled() ? Locale.getDefault() : new 
Locale(getAppLanguageCode());
+    }
+
+    /** Note: returned codes may include languages offered by articles but not 
the app. */
+    @NonNull
+    public List<String> getMruLanguageCodes() {
+        return mruLanguageCodes;
+    }
+
+    public void setMruLanguageCode(@Nullable String code) {
+        List<String> codes = getMruLanguageCodes();
+        codes.remove(code);
+        codes.add(0, code);
+        PreferenceUtil.setMruLanguageCodes(listToCsv(codes));
+    }
+
+    /** @return All app supported languages in MRU order. */
+    public List<String> getAppMruLanguageCodes() {
+        List<String> codes = new 
ArrayList<>(appLanguageLookUpTable.getCodes());
+        int insertIndex = 0;
+        for (String code : getMruLanguageCodes()) {
+            if (codes.contains(code)) {
+                codes.remove(code);
+                codes.add(insertIndex, code);
+                ++insertIndex;
+            }
+        }
+        return codes;
+    }
+
+    @Nullable
+    public String getAppLanguageCanonicalName() {
+        return isSystemLanguageEnabled()
+                ? getString(R.string.preference_system_language_summary)
+                : getAppLanguageCanonicalName(getAppLanguageCode());
+    }
+
+    /** @return English name if app language is supported. */
+    @Nullable
+    public String getAppLanguageCanonicalName(String code) {
+        return appLanguageLookUpTable.getCanonicalName(code);
+    }
+
+    @Nullable
+    public String getAppLanguageLocalizedName() {
+        return isSystemLanguageEnabled()
+                ? getString(R.string.preference_system_language_summary)
+                : getAppLanguageLocalizedName(getAppLanguageCode());
+    }
+
+    /** @return Native name if app language is supported. */
+    @Nullable
+    public String getAppLanguageLocalizedName(String code) {
+        return appLanguageLookUpTable.getLocalizedName(code);
+    }
+
+    @NonNull
+    private String convertSystemLanguageCode(@NonNull String code) {
+        // If the user configures Android for Chinese (zh) we have no way to 
know the intended
+        // dialect. We guess based on country. If the guess is incorrect, the 
user must explicitly
+        // choose the dialect in the app settings.
+        if (Locale.CHINA.getLanguage().equals(code)) {
+            return 
isTraditionalChinesePredominantInCountry(Locale.getDefault().getCountry())
+                    ? AppLanguageLookUpTable.TRADITIONAL_CHINESE_LANGUAGE_CODE
+                    : AppLanguageLookUpTable.SIMPLIFIED_CHINESE_LANGUAGE_CODE;
+        }
+
+        return AppLanguageLookUpTable.FALLBACK_LANGUAGE_CODE;
+    }
+
+    private boolean isTraditionalChinesePredominantInCountry(@Nullable String 
country) {
+        return TRADITIONAL_CHINESE_COUNTRY_CODES.contains(country);
+    }
+
+    @NonNull
+    private List<String> unmarshalMruLanguageCodes() {
+        // Null value is used to indicate that system language should be used.
+        String systemLanguageCodeString = String.valueOf(SYSTEM_LANGUAGE_CODE);
+
+        String csv = defaultIfNull(PreferenceUtil.getMruLanguageCodes(), 
systemLanguageCodeString);
+
+        List<String> list = new ArrayList<>(csvToList(csv));
+
+        Collections.replaceAll(list, systemLanguageCodeString, 
SYSTEM_LANGUAGE_CODE);
+
+        return list;
+    }
+
+    @NonNull
+    private String listToCsv(@NonNull List<String> list) {
+        return TextUtils.join(",", list);
+    }
+
+    /** @return Nonnull immutable list. */
+    @NonNull
+    private List<String> csvToList(@NonNull String csv) {
+        return Arrays.asList(csv.split(","));
+    }
+
+    @Nullable
+    private String getString(int id, @Nullable Object... formatArgs) {
+        return context.getString(id, formatArgs);
+    }
+}
\ No newline at end of file
diff --git 
a/wikipedia/src/main/java/org/wikipedia/interlanguage/LangLinksActivity.java 
b/wikipedia/src/main/java/org/wikipedia/interlanguage/LangLinksActivity.java
index 23d0fb8..c7b05e1 100644
--- a/wikipedia/src/main/java/org/wikipedia/interlanguage/LangLinksActivity.java
+++ b/wikipedia/src/main/java/org/wikipedia/interlanguage/LangLinksActivity.java
@@ -21,6 +21,12 @@
 import org.wikipedia.page.PageTitle;
 
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Locale;
+
+import static org.wikipedia.util.StringUtil.emptyIfNull;
 
 public class LangLinksActivity extends ThemedActionBarActivity {
     public static final int ACTIVITY_RESULT_LANGLINK_SELECT = 1;
@@ -28,7 +34,11 @@
     public static final String ACTION_LANGLINKS_FOR_TITLE = 
"org.wikipedia.langlinks_for_title";
     public static final String EXTRA_PAGETITLE = "org.wikipedia.pagetitle";
 
-    private ArrayList<PageTitle> langLinks;
+    private static final String LANGUAGE_ENTRIES_BUNDLE_KEY = 
"languageEntries";
+
+    private static final String GOTHIC_LANGUAGE_CODE = "got";
+
+    private ArrayList<PageTitle> languageEntries;
     private PageTitle title;
 
     private WikipediaApp app;
@@ -42,7 +52,7 @@
 
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        app = (WikipediaApp)getApplicationContext();
+        app = WikipediaApp.getInstance();
 
         setContentView(R.layout.activity_langlinks);
 
@@ -61,8 +71,8 @@
 
         title = getIntent().getParcelableExtra(EXTRA_PAGETITLE);
 
-        if (savedInstanceState != null && 
savedInstanceState.containsKey("langlinks")) {
-            langLinks = savedInstanceState.getParcelableArrayList("langlinks");
+        if (savedInstanceState != null && 
savedInstanceState.containsKey(LANGUAGE_ENTRIES_BUNDLE_KEY)) {
+            languageEntries = 
savedInstanceState.getParcelableArrayList(LANGUAGE_ENTRIES_BUNDLE_KEY);
         }
 
         fetchLangLinks();
@@ -79,13 +89,13 @@
             @Override
             public void onItemClick(AdapterView<?> parent, View view, int 
position, long id) {
                 PageTitle langLink = (PageTitle) 
parent.getAdapter().getItem(position);
-                app.setMruLanguage(langLink.getSite().getLanguage());
+                app.setMruLanguageCode(langLink.getSite().getLanguageCode());
                 HistoryEntry historyEntry = new HistoryEntry(langLink, 
HistoryEntry.SOURCE_LANGUAGE_LINK);
-                Intent intent = new Intent();
-                intent.setClass(LangLinksActivity.this, PageActivity.class);
-                intent.setAction(PageActivity.ACTION_PAGE_FOR_TITLE);
-                intent.putExtra(PageActivity.EXTRA_PAGETITLE, langLink);
-                intent.putExtra(PageActivity.EXTRA_HISTORYENTRY, historyEntry);
+                Intent intent = new Intent()
+                        .setClass(LangLinksActivity.this, PageActivity.class)
+                        .setAction(PageActivity.ACTION_PAGE_FOR_TITLE)
+                        .putExtra(PageActivity.EXTRA_PAGETITLE, langLink)
+                        .putExtra(PageActivity.EXTRA_HISTORYENTRY, 
historyEntry);
                 setResult(ACTIVITY_RESULT_LANGLINK_SELECT, intent);
                 Utils.hideSoftKeyboard(LangLinksActivity.this);
                 finish();
@@ -127,53 +137,38 @@
                 finish();
                 return true;
             default:
-                throw new RuntimeException("WAT");
+                throw new RuntimeException("item=" + item);
         }
     }
 
     @Override
     protected void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
-        if (langLinks != null) {
-           outState.putParcelableArrayList("langlinks", langLinks);
+        if (languageEntries != null) {
+           outState.putParcelableArrayList(LANGUAGE_ENTRIES_BUNDLE_KEY, 
languageEntries);
         }
     }
 
     private void displayLangLinks() {
-        if (langLinks.size() == 0) {
+        if (languageEntries.size() == 0) {
             ViewAnimations.crossFade(langLinksProgress, langLinksEmpty);
         } else {
-            langLinksList.setAdapter(new LangLinksAdapter(langLinks, app));
+            langLinksList.setAdapter(new LangLinksAdapter(languageEntries, 
app));
             ViewAnimations.crossFade(langLinksProgress, langLinksContainer);
         }
     }
 
+
     private void fetchLangLinks() {
-        if (langLinks == null) {
+        if (languageEntries == null) {
             new LangLinksFetchTask(this, title) {
                 @Override
                 public void onFinish(ArrayList<PageTitle> result) {
-                    langLinks = result;
+                    languageEntries = result;
 
-                    // Rearrange language list based on the mru list
-                    int addIndex = 0;
-                    for (String language : app.getMruLanguages()) {
-                        for (int i = 0; i < result.size(); i++) {
-                            if 
(langLinks.get(i).getSite().getLanguage().equals(language)) {
-                                PageTitle preferredLink = langLinks.remove(i);
-                                langLinks.add(addIndex++, preferredLink);
-                                break;
-                            }
-                        }
-                    }
+                    updateLanguageEntriesSupported(languageEntries);
+                    sortLanguageEntriesByMru(languageEntries);
 
-                    // Also get rid of goddamn 'got', since that just 
segfaults android everywhere
-                    for (int i = 0; i < result.size(); i++) {
-                        if 
(langLinks.get(i).getSite().getLanguage().equals("got")) {
-                            langLinks.remove(i);
-                            break;
-                        }
-                    }
                     displayLangLinks();
                 }
 
@@ -185,6 +180,38 @@
                     // Also happens in {@link PageViewFragment}
                     langLinksError.setVisibility(View.VISIBLE);
                 }
+
+                private void updateLanguageEntriesSupported(List<PageTitle> 
languageEntries) {
+                    for (ListIterator<PageTitle> it = 
languageEntries.listIterator(); it.hasNext();) {
+                        PageTitle link = it.next();
+                        String languageCode = link.getSite().getLanguageCode();
+
+                        if (GOTHIC_LANGUAGE_CODE.equals(languageCode)) {
+                            // Remove Gothic since it causes Android to 
segfault.
+                            it.remove();
+                        } else if 
(Locale.CHINESE.getLanguage().equals(languageCode)) {
+                            // Replace Chinese with Simplified and Traditional 
dialects.
+                            it.remove();
+                            for (String dialect : 
Arrays.asList(AppLanguageLookUpTable.SIMPLIFIED_CHINESE_LANGUAGE_CODE,
+                                    
AppLanguageLookUpTable.TRADITIONAL_CHINESE_LANGUAGE_CODE)) {
+                                it.add(new PageTitle(link.getText(), 
Site.forLanguage(dialect)));
+                            }
+                        }
+                    }
+                }
+
+                private void sortLanguageEntriesByMru(List<PageTitle> entries) 
{
+                    int addIndex = 0;
+                    for (String language : app.getMruLanguageCodes()) {
+                        for (int i = 0; i < entries.size(); i++) {
+                            if 
(entries.get(i).getSite().getLanguageCode().equals(language)) {
+                                PageTitle entry = entries.remove(i);
+                                entries.add(addIndex++, entry);
+                                break;
+                            }
+                        }
+                    }
+                }
             }.execute();
         } else {
             displayLangLinks();
@@ -192,38 +219,39 @@
     }
 
     private static final class LangLinksAdapter extends BaseAdapter {
-        private final ArrayList<PageTitle> origLangLinks;
-        private final ArrayList<PageTitle> langLinks;
+        private final List<PageTitle> originalLanguageEntries;
+        private final List<PageTitle> languageEntries;
         private final WikipediaApp app;
 
-        private LangLinksAdapter(ArrayList<PageTitle> langLinks, WikipediaApp 
app) {
-            this.origLangLinks = langLinks;
-            this.langLinks = new ArrayList<>(origLangLinks);
+        private LangLinksAdapter(List<PageTitle> languageEntries, WikipediaApp 
app) {
+            this.originalLanguageEntries = languageEntries;
+            this.languageEntries = new ArrayList<>(originalLanguageEntries);
             this.app = app;
         }
 
         public void setFilterText(String filter) {
-            this.langLinks.clear();
+            languageEntries.clear();
             filter = filter.toLowerCase();
-            for (PageTitle l: origLangLinks) {
-                int langIndex = 
app.findSupportedLanguageIndex(l.getSite().getLanguage());
-                String canonicalLang = 
app.getCanonicalNameForSupportedLanguage(langIndex);
-                String localLang = 
app.getLocalNameForSupportedLanguage(langIndex);
-                if (canonicalLang.toLowerCase().contains(filter)
-                        || localLang.toLowerCase().contains(filter)) {
-                    this.langLinks.add(l);
+            for (PageTitle entry : originalLanguageEntries) {
+                String languageCode = entry.getSite().getLanguageCode();
+                String canonicalName = 
emptyIfNull(app.getAppLanguageCanonicalName(languageCode));
+                String localizedName = 
emptyIfNull(app.getAppLanguageLocalizedName(languageCode));
+                if (canonicalName.toLowerCase().contains(filter)
+                        || localizedName.toLowerCase().contains(filter)) {
+                    languageEntries.add(entry);
                 }
             }
             notifyDataSetInvalidated();
         }
+
         @Override
         public int getCount() {
-            return langLinks.size();
+            return languageEntries.size();
         }
 
         @Override
-        public Object getItem(int position) {
-            return langLinks.get(position);
+        public PageTitle getItem(int position) {
+            return languageEntries.get(position);
         }
 
         @Override
@@ -237,16 +265,18 @@
                 convertView = 
LayoutInflater.from(parent.getContext()).inflate(R.layout.item_language_list_entry,
 parent, false);
             }
 
-            PageTitle langLink = (PageTitle) getItem(position);
-            String language = langLink.getSite().getLanguage();
-            int langIndex = app.findSupportedLanguageIndex(language);
-            String localName = app.getLocalNameForSupportedLanguage(langIndex);
+            PageTitle item = getItem(position);
+            String languageCode = item.getSite().getLanguageCode();
+            String localizedLanguageName = 
app.getAppLanguageLocalizedName(languageCode);
+            if (localizedLanguageName == null && 
languageCode.equals(Locale.CHINA.getLanguage())) {
+                localizedLanguageName = 
Locale.CHINA.getDisplayName(Locale.CHINA);
+            }
 
-            TextView langLocalNameText = (TextView) 
convertView.findViewById(R.id.language_local_name);
-            TextView articleLocalNameText = (TextView) 
convertView.findViewById(R.id.article_local_name);
+            TextView localizedLanguageNameTextView = (TextView) 
convertView.findViewById(R.id.localized_language_name);
+            TextView articleTitleTextView = (TextView) 
convertView.findViewById(R.id.article_title);
 
-            langLocalNameText.setText(localName);
-            articleLocalNameText.setText(langLink.getText());
+            localizedLanguageNameTextView.setText(localizedLanguageName);
+            articleTitleTextView.setText(item.getText());
 
             return convertView;
         }
diff --git 
a/wikipedia/src/main/java/org/wikipedia/page/JsonPageLoadStrategy.java 
b/wikipedia/src/main/java/org/wikipedia/page/JsonPageLoadStrategy.java
index ea3a22e..6bd0c89 100644
--- a/wikipedia/src/main/java/org/wikipedia/page/JsonPageLoadStrategy.java
+++ b/wikipedia/src/main/java/org/wikipedia/page/JsonPageLoadStrategy.java
@@ -343,7 +343,7 @@
         // replaced (normalized)
         sectionTargetFromTitle = model.getTitle().getFragment();
 
-        Utils.setupDirectionality(model.getTitle().getSite().getLanguage(), 
Locale.getDefault().getLanguage(),
+        
Utils.setupDirectionality(model.getTitle().getSite().getLanguageCode(), 
Locale.getDefault().getLanguage(),
                 bridge);
 
         // hide the native top and bottom components...
@@ -526,13 +526,13 @@
             leadSectionPayload.put("string_table_close", 
activity.getString(R.string.table_close));
             leadSectionPayload.put("string_expand_refs", 
activity.getString(R.string.expand_refs));
             leadSectionPayload.put("isBeta", app.getReleaseType() != 
WikipediaApp.RELEASE_PROD);
-            leadSectionPayload.put("siteLanguage", 
model.getTitle().getSite().getLanguage());
+            leadSectionPayload.put("siteLanguage", 
model.getTitle().getSite().getLanguageCode());
             leadSectionPayload.put("isMainPage", page.isMainPage());
             leadSectionPayload.put("apiLevel", Build.VERSION.SDK_INT);
             bridge.sendMessage("displayLeadSection", leadSectionPayload);
             Log.d(TAG, "Sent message 'displayLeadSection' for page: " + 
page.getDisplayTitle());
 
-            Utils.setupDirectionality(model.getTitle().getSite().getLanguage(),
+            
Utils.setupDirectionality(model.getTitle().getSite().getLanguageCode(),
                     Locale.getDefault().getLanguage(), bridge);
 
             // Hide edit pencils if anon editing is disabled by remote 
killswitch or if this is a file page
diff --git a/wikipedia/src/main/java/org/wikipedia/page/PageActivity.java 
b/wikipedia/src/main/java/org/wikipedia/page/PageActivity.java
index 3482450..5b6653e 100644
--- a/wikipedia/src/main/java/org/wikipedia/page/PageActivity.java
+++ b/wikipedia/src/main/java/org/wikipedia/page/PageActivity.java
@@ -66,7 +66,7 @@
     public static final String EXTRA_SEARCH_FROM_WIDGET = "searchFromWidget";
     public static final String EXTRA_FEATURED_ARTICLE_FROM_WIDGET = 
"featuredArticleFromWidget";
     private static final String ZERO_ON_NOTICE_PRESENTED = 
"org.wikipedia.zero.zeroOnNoticePresented";
-    private static final String LANGUAGE_BUNDLE_KEY = "language";
+    private static final String LANGUAGE_CODE_BUNDLE_KEY = "language";
     private static final String PLAIN_TEXT_MIME_TYPE = "text/plain";
 
     private static final String KEY_LAST_FRAGMENT = "lastFragment";
@@ -210,8 +210,8 @@
             if (savedInstanceState.getBoolean("isSearching")) {
                 searchFragment.openSearch();
             }
-            String language = 
savedInstanceState.getString(LANGUAGE_BUNDLE_KEY);
-            languageChanged = 
!emptyIfNull(language).equals(emptyIfNull(app.getLanguage()));
+            String language = 
savedInstanceState.getString(LANGUAGE_CODE_BUNDLE_KEY);
+            languageChanged = 
!app.getAppOrSystemLanguageCode().equals(language);
         } else if (themeChanged) {
             // we've changed themes!
             pausedStateOfZero = 
getIntent().getExtras().getBoolean("pausedStateOfZero");
@@ -604,7 +604,7 @@
      * @param allowStateLoss Whether to allow state loss.
      */
     public void displayMainPage(boolean allowStateLoss) {
-        PageTitle title = new 
PageTitle(MainPageNameData.valueFor(app.getLanguage()), app.getPrimarySite());
+        PageTitle title = new 
PageTitle(MainPageNameData.valueFor(app.getAppOrSystemLanguageCode()), 
app.getPrimarySite());
         HistoryEntry historyEntry = new HistoryEntry(title, 
HistoryEntry.SOURCE_MAIN_PAGE);
         displayNewPage(title, historyEntry, allowStateLoss);
     }
@@ -804,7 +804,7 @@
             outState.putBoolean("themeChooserShowing", 
themeChooser.isShowing());
         }
         outState.putBoolean("isSearching", isSearching());
-        outState.putString(LANGUAGE_BUNDLE_KEY, app.getLanguage());
+        outState.putString(LANGUAGE_CODE_BUNDLE_KEY, app.getAppLanguageCode());
     }
 
     @Override
@@ -874,11 +874,6 @@
         // ActionMode in non-WebView components (History, Saved Pages, or Find 
In Page) must call
         // setTag().
         return mode.getTag() != null;
-    }
-
-    // TODO: Replace with Apache Commons Lang StringUtils.defaultString().
-    private String emptyIfNull(String value) {
-        return value == null ? "" : value;
     }
 
     private void registerBus() {
diff --git a/wikipedia/src/main/java/org/wikipedia/page/PageTitle.java 
b/wikipedia/src/main/java/org/wikipedia/page/PageTitle.java
index 8b921dc..b2f6412 100644
--- a/wikipedia/src/main/java/org/wikipedia/page/PageTitle.java
+++ b/wikipedia/src/main/java/org/wikipedia/page/PageTitle.java
@@ -76,7 +76,7 @@
         // FIXME: Does not handle mainspace articles with a colon in the title 
well at all
         if (TextUtils.isEmpty(text)) {
             // If empty, this refers to the main page.
-            text = MainPageNameData.valueFor(site.getLanguage());
+            text = MainPageNameData.valueFor(site.getLanguageCode());
         }
 
         String[] fragParts = text.split("#", -1);
@@ -252,7 +252,7 @@
      */
     public boolean isFilePage() {
         if (isFilePage == null) {
-            String filePageAlias = 
FileAliasData.valueFor(getSite().getLanguage());
+            String filePageAlias = 
FileAliasData.valueFor(getSite().getLanguageCode());
             isFilePage = getNamespace() != null
                     && filePageAlias != null // If langcode, for some reason, 
isn't in FileAlias
                     && filePageAlias.equals(getNamespace());
@@ -269,7 +269,7 @@
      */
     public boolean isSpecial() {
         if (isSpecial == null) {
-            String specialPageAlias = 
SpecialAliasData.valueFor(getSite().getLanguage());
+            String specialPageAlias = 
SpecialAliasData.valueFor(getSite().getLanguageCode());
             isSpecial = getNamespace() != null
                     && specialPageAlias != null // If langcode, for some 
reason, isn't in SpecialPageAlias
                     && specialPageAlias.equals(getNamespace());
diff --git 
a/wikipedia/src/main/java/org/wikipedia/page/gallery/GalleryActivity.java 
b/wikipedia/src/main/java/org/wikipedia/page/gallery/GalleryActivity.java
index 928070a..867b0b7 100644
--- a/wikipedia/src/main/java/org/wikipedia/page/gallery/GalleryActivity.java
+++ b/wikipedia/src/main/java/org/wikipedia/page/gallery/GalleryActivity.java
@@ -18,7 +18,6 @@
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
-import android.os.Parcelable;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentPagerAdapter;
 import android.support.v4.app.FragmentTransaction;
@@ -347,7 +346,7 @@
         Intent intent = new Intent();
         intent.setClass(GalleryActivity.this, PageActivity.class);
         intent.setAction(PageActivity.ACTION_PAGE_FOR_TITLE);
-        intent.putExtra(PageActivity.EXTRA_PAGETITLE, (Parcelable) 
resultTitle);
+        intent.putExtra(PageActivity.EXTRA_PAGETITLE, resultTitle);
         intent.putExtra(PageActivity.EXTRA_HISTORYENTRY, historyEntry);
         setResult(ACTIVITY_RESULT_FILEPAGE_SELECT, intent);
         finish();
diff --git 
a/wikipedia/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewContents.java
 
b/wikipedia/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewContents.java
index 58449f6..25165ef 100755
--- 
a/wikipedia/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewContents.java
+++ 
b/wikipedia/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewContents.java
@@ -86,7 +86,7 @@
      */
     public static List<String> getSentences(String text, Site site) {
         List<String> sentenceList = new ArrayList<>();
-        BreakIterator iterator = BreakIterator.getSentenceInstance(new 
Locale(site.getLanguage()));
+        BreakIterator iterator = BreakIterator.getSentenceInstance(new 
Locale(site.getLanguageCode()));
         // feed the text into the iterator, with line breaks removed:
         text = text.replaceAll("(\r|\n)", "");
         iterator.setText(text);
diff --git 
a/wikipedia/src/main/java/org/wikipedia/search/SearchResultsFragment.java 
b/wikipedia/src/main/java/org/wikipedia/search/SearchResultsFragment.java
index 7af8fff..b1b91b1 100644
--- a/wikipedia/src/main/java/org/wikipedia/search/SearchResultsFragment.java
+++ b/wikipedia/src/main/java/org/wikipedia/search/SearchResultsFragment.java
@@ -167,7 +167,7 @@
             return;
         }
 
-        List<PageTitle> cacheResult = searchResultsCache.get(app.getLanguage() 
+ "-" + term);
+        List<PageTitle> cacheResult = 
searchResultsCache.get(app.getAppOrSystemLanguageCode() + "-" + term);
         if (cacheResult != null) {
             displayResults(cacheResult);
             return;
@@ -226,7 +226,7 @@
                 displayResults(pageTitles);
 
                 // title search special:
-                searchResultsCache.put(app.getLanguage() + "-" + searchTerm, 
pageTitles);
+                searchResultsCache.put(app.getAppOrSystemLanguageCode() + "-" 
+ searchTerm, pageTitles);
                 curSearchTask = null;
 
                 final String suggestion = results.getSuggestion();
diff --git 
a/wikipedia/src/main/java/org/wikipedia/settings/LanguagePreference.java 
b/wikipedia/src/main/java/org/wikipedia/settings/LanguagePreference.java
index 79654f8..096b035 100644
--- a/wikipedia/src/main/java/org/wikipedia/settings/LanguagePreference.java
+++ b/wikipedia/src/main/java/org/wikipedia/settings/LanguagePreference.java
@@ -23,6 +23,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import static org.wikipedia.util.StringUtil.emptyIfNull;
+
 public class LanguagePreference extends DialogPreference {
     private static final float LIST_DISABLED_ALPHA = .5f;
     private static final float LIST_ENABLED_ALPHA = 1;
@@ -31,16 +33,20 @@
     private EditText languagesFilter;
     private ListView languagesList;
 
-    private final List<String> languages;
+    @NonNull
+    private final List<String> languageCodes;
+
+    @NonNull
     private final WikipediaApp app;
 
     public LanguagePreference(Context context, AttributeSet attrs) {
         super(context, attrs);
         setPersistent(false);
         setDialogLayoutResource(R.layout.dialog_preference_languages);
-        app = (WikipediaApp) context.getApplicationContext();
 
-        languages = app.getAllMruLanguages();
+        app = WikipediaApp.getInstance();
+
+        languageCodes = app.getAppMruLanguageCodes();
 
         updateSummary();
 
@@ -79,17 +85,17 @@
             @Override
             public void onItemClick(AdapterView<?> adapterView, View view, int 
i, long l) {
                 String lang = (String) languagesList.getAdapter().getItem(i);
-                app.setLanguage(lang);
-                app.setMruLanguage(lang);
+                app.setAppLanguageCode(lang);
+                app.setMruLanguageCode(lang);
                 updateSummary();
                 closeDialog();
             }
         });
 
-        languagesList.setAdapter(new LanguagesAdapter(languages, app));
+        languagesList.setAdapter(new LanguagesAdapter(languageCodes, app));
 
         if (!app.isSystemLanguageEnabled()) {
-            int selectedLanguageIndex = 
languages.indexOf(app.getLanguageKey());
+            int selectedLanguageIndex = 
languageCodes.indexOf(app.getAppLanguageCode());
             languagesList.setItemChecked(selectedLanguageIndex, true);
         }
 
@@ -110,7 +116,7 @@
     }
 
     private void updateSummary() {
-        setSummary(app.getDisplayLanguage());
+        setSummary(app.getAppLanguageLocalizedName());
     }
 
     private void setSystemLanguageEnabled(boolean enabled) {
@@ -121,7 +127,7 @@
 
         if (enabled) {
             languagesList.clearChoices();
-            app.setSystemLanguage();
+            app.setSystemLanguageEnabled();
         }
     }
 
@@ -135,27 +141,30 @@
     }
 
     private static final class LanguagesAdapter extends BaseAdapter {
-        private final List<String> originalLanguages;
-        private final List<String> languages;
+        @NonNull
+        private final List<String> originalLanguageCodes;
+        @NonNull
+        private final List<String> languageCodes;
+
+        @NonNull
         private final WikipediaApp app;
 
-        private LanguagesAdapter(List<String> languages, WikipediaApp app) {
-            this.originalLanguages = languages;
-            this.languages = new ArrayList<>(languages);
+        private LanguagesAdapter(@NonNull List<String> languageCodes, @NonNull 
WikipediaApp app) {
+            originalLanguageCodes = languageCodes;
+            this.languageCodes = new ArrayList<>(originalLanguageCodes);
             this.app = app;
         }
 
         public void setFilterText(String filter) {
-            this.languages.clear();
+            this.languageCodes.clear();
             filter = filter.toLowerCase();
-            for (String language: originalLanguages) {
-                int index = app.findSupportedLanguageIndex(language);
-                String canonicalLang = 
app.getCanonicalNameForSupportedLanguage(index);
-                String localLang = app.getLocalNameForSupportedLanguage(index);
-                if (language != null && language.contains(filter)
-                        || canonicalLang.toLowerCase().contains(filter)
-                        || localLang.toLowerCase().contains(filter)) {
-                    this.languages.add(language);
+            for (String code : originalLanguageCodes) {
+                String localizedName = 
emptyIfNull(app.getAppLanguageLocalizedName(code));
+                String canonicalName = 
emptyIfNull(app.getAppLanguageCanonicalName(code));
+                if (code != null && code.contains(filter)
+                        || localizedName.toLowerCase().contains(filter)
+                        || canonicalName.toLowerCase().contains(filter)) {
+                    this.languageCodes.add(code);
                 }
             }
             notifyDataSetInvalidated();
@@ -163,12 +172,12 @@
 
         @Override
         public int getCount() {
-            return languages.size();
+            return languageCodes.size();
         }
 
         @Override
-        public Object getItem(int position) {
-            return languages.get(position);
+        public String getItem(int position) {
+            return languageCodes.get(position);
         }
 
         @Override
@@ -182,15 +191,13 @@
                 convertView = 
LayoutInflater.from(parent.getContext()).inflate(R.layout.simple_list_item_activated_2,
 parent, false);
             }
 
-            TextView localNameText = (TextView) 
convertView.findViewById(android.R.id.text1);
-            TextView nameText = (TextView) 
convertView.findViewById(android.R.id.text2);
+            TextView localizedNameTextView = (TextView) 
convertView.findViewById(android.R.id.text1);
+            TextView canonicalNameTextView = (TextView) 
convertView.findViewById(android.R.id.text2);
 
-            String wikiCode = (String) getItem(position);
+            String languageCode = getItem(position);
 
-            int langIndex = app.findSupportedLanguageIndex(wikiCode);
-
-            
localNameText.setText(app.getLocalNameForSupportedLanguage(langIndex));
-            
nameText.setText(app.getCanonicalNameForSupportedLanguage(langIndex));
+            
localizedNameTextView.setText(app.getAppLanguageLocalizedName(languageCode));
+            
canonicalNameTextView.setText(app.getAppLanguageCanonicalName(languageCode));
 
             return convertView;
         }
diff --git a/wikipedia/src/main/java/org/wikipedia/settings/PreferenceUtil.java 
b/wikipedia/src/main/java/org/wikipedia/settings/PreferenceUtil.java
new file mode 100644
index 0000000..4ec0825
--- /dev/null
+++ b/wikipedia/src/main/java/org/wikipedia/settings/PreferenceUtil.java
@@ -0,0 +1,47 @@
+package org.wikipedia.settings;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.support.annotation.Nullable;
+
+import org.wikipedia.WikipediaApp;
+
+public final class PreferenceUtil {
+    public static SharedPreferences getPreferences() {
+        return PreferenceManager.getDefaultSharedPreferences(getContext());
+    }
+
+    @Nullable
+    public static String getAppLanguageCode() {
+        return getString(PrefKeys.getContentLanguageKey(), null);
+    }
+
+    public static void setAppLanguageCode(String code) {
+        setString(PrefKeys.getContentLanguageKey(), code);
+    }
+
+    @Nullable
+    public static String getMruLanguageCodes() {
+        return getString(PrefKeys.getLanguageMru(), null);
+    }
+
+    public static void setMruLanguageCodes(String csv) {
+        setString(PrefKeys.getLanguageMru(), csv);
+    }
+
+    private static String getString(String key, String defaultValue) {
+        return getPreferences().getString(key, defaultValue);
+    }
+
+    private static void setString(String key, String value) {
+        getPreferences().edit().putString(key, value).apply();
+    }
+
+    private static Context getContext() {
+        return WikipediaApp.getInstance();
+    }
+
+    private PreferenceUtil() {
+    }
+}
\ No newline at end of file
diff --git 
a/wikipedia/src/main/java/org/wikipedia/settings/SettingsActivityGB.java 
b/wikipedia/src/main/java/org/wikipedia/settings/SettingsActivityGB.java
index 90c310e..96a5686 100644
--- a/wikipedia/src/main/java/org/wikipedia/settings/SettingsActivityGB.java
+++ b/wikipedia/src/main/java/org/wikipedia/settings/SettingsActivityGB.java
@@ -88,7 +88,7 @@
     public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, 
String key) {
         if (key.equals(PrefKeys.getContentLanguageKey())) {
             LanguagePreference pref = (LanguagePreference) 
findPreference(PrefKeys.getContentLanguageKey());
-            pref.setSummary(WikipediaApp.getInstance().getDisplayLanguage());
+            
pref.setSummary(WikipediaApp.getInstance().getAppLanguageLocalizedName());
             setResult(SettingsActivity.ACTIVITY_RESULT_LANGUAGE_CHANGED);
         }
     }
diff --git 
a/wikipedia/src/main/java/org/wikipedia/settings/SettingsFragment.java 
b/wikipedia/src/main/java/org/wikipedia/settings/SettingsFragment.java
index 5cf9d55..9952cb4 100644
--- a/wikipedia/src/main/java/org/wikipedia/settings/SettingsFragment.java
+++ b/wikipedia/src/main/java/org/wikipedia/settings/SettingsFragment.java
@@ -72,7 +72,7 @@
     public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, 
String key) {
         if (key.equals(PrefKeys.getContentLanguageKey())) {
             LanguagePreference pref = (LanguagePreference) 
findPreference(PrefKeys.getContentLanguageKey());
-            pref.setSummary(WikipediaApp.getInstance().getDisplayLanguage());
+            
pref.setSummary(WikipediaApp.getInstance().getAppLanguageLocalizedName());
             
getActivity().setResult(SettingsActivity.ACTIVITY_RESULT_LANGUAGE_CHANGED);
         }
     }
diff --git 
a/wikipedia/src/main/java/org/wikipedia/staticdata/MainPageNameData.java 
b/wikipedia/src/main/java/org/wikipedia/staticdata/MainPageNameData.java
index 65a1807..2f046f3 100644
--- a/wikipedia/src/main/java/org/wikipedia/staticdata/MainPageNameData.java
+++ b/wikipedia/src/main/java/org/wikipedia/staticdata/MainPageNameData.java
@@ -3,6 +3,8 @@
    TO HAVE YOUR CHANGES OVERWRITTEN */
 package org.wikipedia.staticdata;
 
+import org.wikipedia.interlanguage.AppLanguageLookUpTable;
+
 import java.util.*;
 
 public final class MainPageNameData {
@@ -28,8 +30,8 @@
         DATA_MAP.put("ja", "メインページ");
         DATA_MAP.put("pt", "Wikipedia:Página principal");
         DATA_MAP.put("zh", "Wikipedia:首页");
-        DATA_MAP.put("zh-hans", "Wikipedia:首页");
-        DATA_MAP.put("zh-hant", "Wikipedia:首頁");
+        DATA_MAP.put(AppLanguageLookUpTable.SIMPLIFIED_CHINESE_LANGUAGE_CODE, 
"Wikipedia:首页");
+        DATA_MAP.put(AppLanguageLookUpTable.TRADITIONAL_CHINESE_LANGUAGE_CODE, 
"Wikipedia:首頁");
         DATA_MAP.put("uk", "Головна сторінка");
         DATA_MAP.put("ca", "Portada");
         DATA_MAP.put("fa", "صفحهٔ اصلی");
@@ -312,7 +314,7 @@
         if (DATA_MAP.containsKey(key)) {
             return DATA_MAP.get(key);
         }
-        return DATA_MAP.get("en");
+        return DATA_MAP.get(AppLanguageLookUpTable.FALLBACK_LANGUAGE_CODE);
     }
 
     private MainPageNameData() {
diff --git a/wikipedia/src/main/java/org/wikipedia/util/ShareUtils.java 
b/wikipedia/src/main/java/org/wikipedia/util/ShareUtils.java
index 1aa04ac..3201dac 100644
--- a/wikipedia/src/main/java/org/wikipedia/util/ShareUtils.java
+++ b/wikipedia/src/main/java/org/wikipedia/util/ShareUtils.java
@@ -21,6 +21,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import static org.wikipedia.util.StringUtil.emptyIfNull;
+
 public final class ShareUtils {
     public static final String APP_PACKAGE_REGEX = "org\\.wikipedia.*";
 
@@ -207,10 +209,5 @@
 
     private static String getPackageName(ResolveInfo intentActivity) {
         return intentActivity.activityInfo.packageName;
-    }
-
-    // TODO: Replace with Apache Commons Lang StringUtils.defaultString().
-    private static String emptyIfNull(String value) {
-        return value == null ? "" : value;
     }
 }
diff --git a/wikipedia/src/main/java/org/wikipedia/util/StringUtil.java 
b/wikipedia/src/main/java/org/wikipedia/util/StringUtil.java
new file mode 100644
index 0000000..259011d
--- /dev/null
+++ b/wikipedia/src/main/java/org/wikipedia/util/StringUtil.java
@@ -0,0 +1,30 @@
+package org.wikipedia.util;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+// TODO: Replace with Apache Commons Lang StringUtils.
+public final class StringUtil {
+    @NonNull
+    public static String emptyIfNull(@Nullable String value) {
+        return defaultIfNull(value, "");
+    }
+
+    @NonNull
+    public static CharSequence emptyIfNull(@Nullable CharSequence value) {
+        return defaultIfNull(value, "");
+    }
+
+    @Nullable
+    public static String defaultIfNull(@Nullable String value, @Nullable 
String defaultValue) {
+        return value == null ? defaultValue : value;
+    }
+
+    @Nullable
+    public static CharSequence defaultIfNull(@Nullable CharSequence value,
+            @Nullable CharSequence defaultValue) {
+        return value == null ? defaultValue : value;
+    }
+
+    private StringUtil() { }
+}
\ No newline at end of file
diff --git 
a/wikipedia/src/main/java/org/wikipedia/widgets/WidgetProviderFeaturedPage.java 
b/wikipedia/src/main/java/org/wikipedia/widgets/WidgetProviderFeaturedPage.java
index eb6a5cb..5c8eddd 100644
--- 
a/wikipedia/src/main/java/org/wikipedia/widgets/WidgetProviderFeaturedPage.java
+++ 
b/wikipedia/src/main/java/org/wikipedia/widgets/WidgetProviderFeaturedPage.java
@@ -94,7 +94,7 @@
 
     private class FetchMainPageTask extends SectionsFetchTask {
         public FetchMainPageTask(Context context) {
-            super(context, new 
PageTitle(MainPageNameData.valueFor(WikipediaApp.getInstance().getLanguage()),
+            super(context, new 
PageTitle(MainPageNameData.valueFor(WikipediaApp.getInstance().getAppOrSystemLanguageCode()),
                     WikipediaApp.getInstance().getPrimarySite()), "all");
         }
 

-- 
To view, visit https://gerrit.wikimedia.org/r/217306
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I362e23ac2383d6ee81daf29d103ee8cc48c04bfd
Gerrit-PatchSet: 4
Gerrit-Project: apps/android/wikipedia
Gerrit-Branch: master
Gerrit-Owner: Niedzielski <sniedziel...@wikimedia.org>
Gerrit-Reviewer: BearND <bsitzm...@wikimedia.org>
Gerrit-Reviewer: Brion VIBBER <br...@wikimedia.org>
Gerrit-Reviewer: Dbrant <dbr...@wikimedia.org>
Gerrit-Reviewer: Mholloway <mhollo...@wikimedia.org>
Gerrit-Reviewer: Niedzielski <sniedziel...@wikimedia.org>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to