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