diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e52dded5e..e0abd977b 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -57,6 +57,15 @@
+
+
+
+
= 33) {
- requirePreference(R.string.app_language_key).setVisible(false);
- final Preference newAppLanguagePref =
+ appLanguagePref.setVisible(false);
+ final var newAppLanguagePref =
requirePreference(R.string.app_language_android_13_and_up_key);
newAppLanguagePref.setSummaryProvider(preference -> {
- final Locale customLocale = AppCompatDelegate.getApplicationLocales().get(0);
- if (customLocale != null) {
- return customLocale.getDisplayName();
- }
- return getString(R.string.systems_language);
+ final Locale loc = AppCompatDelegate.getApplicationLocales().get(0);
+ return loc != null ? loc.getDisplayName() : getString(R.string.systems_language);
});
newAppLanguagePref.setOnPreferenceClickListener(preference -> {
final Intent intent = new Intent(Settings.ACTION_APP_LOCALE_SETTINGS)
@@ -55,10 +50,16 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
return true;
});
newAppLanguagePref.setVisible(true);
+ } else {
+ appLanguagePref.setOnPreferenceChangeListener((preference, newValue) -> {
+ final String language = (String) newValue;
+ final Locale locale = Locale.forLanguageTag(language);
+ AppCompatDelegate.setApplicationLocales(LocaleListCompat.create(locale));
+ return true;
+ });
}
- final Preference imageQualityPreference = requirePreference(R.string.image_quality_key);
- imageQualityPreference.setOnPreferenceChangeListener(
+ requirePreference(R.string.image_quality_key).setOnPreferenceChangeListener(
(preference, newValue) -> {
ImageStrategy.setPreferredImageQuality(PreferredImageQuality
.fromPreferenceKey(requireContext(), (String) newValue));
@@ -92,22 +93,10 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
public void onDestroy() {
super.onDestroy();
- final String selectedLanguage =
- defaultPreferences.getString(getString(R.string.app_language_key), "en");
-
- if (!selectedLanguage.equals(initialLanguage)) {
- if (Build.VERSION.SDK_INT < 33) {
- Toast.makeText(
- requireContext(),
- R.string.localization_changes_requires_app_restart,
- Toast.LENGTH_LONG
- ).show();
- }
- final Localization selectedLocalization = org.schabi.newpipe.util.Localization
- .getPreferredLocalization(requireContext());
- final ContentCountry selectedContentCountry = org.schabi.newpipe.util.Localization
- .getPreferredContentCountry(requireContext());
- NewPipe.setupLocalization(selectedLocalization, selectedContentCountry);
- }
+ final Localization selectedLocalization = org.schabi.newpipe.util.Localization
+ .getPreferredLocalization(requireContext());
+ final ContentCountry selectedContentCountry = org.schabi.newpipe.util.Localization
+ .getPreferredContentCountry(requireContext());
+ NewPipe.setupLocalization(selectedLocalization, selectedContentCountry);
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/settings/DownloadSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/DownloadSettingsFragment.java
index ff7811af3..356dcd9b2 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/DownloadSettingsFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/DownloadSettingsFragment.java
@@ -1,7 +1,5 @@
package org.schabi.newpipe.settings;
-import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
-
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
@@ -209,8 +207,6 @@ public class DownloadSettingsFragment extends BasePreferenceFragment {
}
private void requestDownloadPathResult(final ActivityResult result, final String key) {
- assureCorrectAppLanguage(getContext());
-
if (result.getResultCode() != Activity.RESULT_OK) {
return;
}
diff --git a/app/src/main/java/org/schabi/newpipe/settings/SettingsActivity.java b/app/src/main/java/org/schabi/newpipe/settings/SettingsActivity.java
index 0d57ce174..d5089cb7d 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/SettingsActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/SettingsActivity.java
@@ -1,7 +1,5 @@
package org.schabi.newpipe.settings;
-import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
-
import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
@@ -89,7 +87,6 @@ public class SettingsActivity extends AppCompatActivity implements
@Override
protected void onCreate(final Bundle savedInstanceBundle) {
setTheme(ThemeHelper.getSettingsThemeStyle(this));
- assureCorrectAppLanguage(this);
super.onCreate(savedInstanceBundle);
Bridge.restoreInstanceState(this, savedInstanceBundle);
@@ -228,7 +225,6 @@ public class SettingsActivity extends AppCompatActivity implements
// Build search items
final Context searchContext = getApplicationContext();
- assureCorrectAppLanguage(searchContext);
final PreferenceParser parser = new PreferenceParser(searchContext, config);
final PreferenceSearcher searcher = new PreferenceSearcher(config);
diff --git a/app/src/main/java/org/schabi/newpipe/util/ListHelper.java b/app/src/main/java/org/schabi/newpipe/util/ListHelper.java
index 282a88b1e..ea41f3e81 100644
--- a/app/src/main/java/org/schabi/newpipe/util/ListHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/util/ListHelper.java
@@ -322,7 +322,7 @@ public final class ListHelper {
}
// Sort collected streams by name
- return collectedStreams.values().stream().sorted(getAudioTrackNameComparator(context))
+ return collectedStreams.values().stream().sorted(getAudioTrackNameComparator())
.collect(Collectors.toList());
}
@@ -359,7 +359,7 @@ public final class ListHelper {
}
// Sort tracks alphabetically, sort track streams by quality
- final Comparator nameCmp = getAudioTrackNameComparator(context);
+ final Comparator nameCmp = getAudioTrackNameComparator();
final Comparator formatCmp = getAudioFormatComparator(context);
return collectedStreams.values().stream()
@@ -867,12 +867,10 @@ public final class ListHelper {
* Get a {@link Comparator} to compare {@link AudioStream}s by their languages and track types
* for alphabetical sorting.
*
- * @param context app context for localization
* @return Comparator
*/
- private static Comparator getAudioTrackNameComparator(
- @NonNull final Context context) {
- final Locale appLoc = Localization.getAppLocale(context);
+ private static Comparator getAudioTrackNameComparator() {
+ final Locale appLoc = Localization.getAppLocale();
return Comparator.comparing(AudioStream::getAudioLocale, Comparator.nullsLast(
Comparator.comparing(locale -> locale.getDisplayName(appLoc))))
diff --git a/app/src/main/java/org/schabi/newpipe/util/Localization.java b/app/src/main/java/org/schabi/newpipe/util/Localization.java
index 65cfec930..40c7b2a03 100644
--- a/app/src/main/java/org/schabi/newpipe/util/Localization.java
+++ b/app/src/main/java/org/schabi/newpipe/util/Localization.java
@@ -5,14 +5,12 @@ import static org.schabi.newpipe.MainActivity.DEBUG;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
-import android.content.res.Configuration;
import android.content.res.Resources;
import android.icu.text.CompactDecimalFormat;
import android.os.Build;
+import android.text.BidiFormatter;
import android.text.TextUtils;
import android.text.format.DateUtils;
-import android.text.BidiFormatter;
-import android.util.DisplayMetrics;
import android.util.Log;
import androidx.annotation.NonNull;
@@ -43,7 +41,6 @@ import java.time.format.FormatStyle;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
-import java.util.Objects;
import java.util.stream.Collectors;
@@ -120,39 +117,35 @@ public final class Localization {
return getLocaleFromPrefs(context, R.string.content_language_key);
}
- public static Locale getAppLocale(@NonNull final Context context) {
- if (Build.VERSION.SDK_INT >= 33) {
- final Locale customLocale = AppCompatDelegate.getApplicationLocales().get(0);
- return Objects.requireNonNullElseGet(customLocale, Locale::getDefault);
- }
- return getLocaleFromPrefs(context, R.string.app_language_key);
+ public static Locale getAppLocale() {
+ final Locale customLocale = AppCompatDelegate.getApplicationLocales().get(0);
+ return customLocale != null ? customLocale : Locale.getDefault();
}
- public static String localizeNumber(@NonNull final Context context, final long number) {
- return localizeNumber(context, (double) number);
+ public static String localizeNumber(final long number) {
+ return localizeNumber((double) number);
}
- public static String localizeNumber(@NonNull final Context context, final double number) {
- final NumberFormat nf = NumberFormat.getInstance(getAppLocale(context));
+ public static String localizeNumber(final double number) {
+ final NumberFormat nf = NumberFormat.getInstance(getAppLocale());
return nf.format(number);
}
- public static String formatDate(@NonNull final Context context,
- @NonNull final OffsetDateTime offsetDateTime) {
+ public static String formatDate(@NonNull final OffsetDateTime offsetDateTime) {
return DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)
- .withLocale(getAppLocale(context)).format(offsetDateTime
+ .withLocale(getAppLocale()).format(offsetDateTime
.atZoneSameInstant(ZoneId.systemDefault()));
}
@SuppressLint("StringFormatInvalid")
public static String localizeUploadDate(@NonNull final Context context,
@NonNull final OffsetDateTime offsetDateTime) {
- return context.getString(R.string.upload_date_text, formatDate(context, offsetDateTime));
+ return context.getString(R.string.upload_date_text, formatDate(offsetDateTime));
}
public static String localizeViewCount(@NonNull final Context context, final long viewCount) {
return getQuantity(context, R.plurals.views, R.string.no_views, viewCount,
- localizeNumber(context, viewCount));
+ localizeNumber(viewCount));
}
public static String localizeStreamCount(@NonNull final Context context,
@@ -166,7 +159,7 @@ public final class Localization {
return context.getResources().getString(R.string.more_than_100_videos);
default:
return getQuantity(context, R.plurals.videos, R.string.no_videos, streamCount,
- localizeNumber(context, streamCount));
+ localizeNumber(streamCount));
}
}
@@ -187,27 +180,27 @@ public final class Localization {
public static String localizeWatchingCount(@NonNull final Context context,
final long watchingCount) {
return getQuantity(context, R.plurals.watching, R.string.no_one_watching, watchingCount,
- localizeNumber(context, watchingCount));
+ localizeNumber(watchingCount));
}
public static String shortCount(@NonNull final Context context, final long count) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- return CompactDecimalFormat.getInstance(getAppLocale(context),
+ return CompactDecimalFormat.getInstance(getAppLocale(),
CompactDecimalFormat.CompactStyle.SHORT).format(count);
}
final double value = (double) count;
if (count >= 1000000000) {
- return localizeNumber(context, round(value / 1000000000))
+ return localizeNumber(round(value / 1000000000))
+ context.getString(R.string.short_billion);
} else if (count >= 1000000) {
- return localizeNumber(context, round(value / 1000000))
+ return localizeNumber(round(value / 1000000))
+ context.getString(R.string.short_million);
} else if (count >= 1000) {
- return localizeNumber(context, round(value / 1000))
+ return localizeNumber(round(value / 1000))
+ context.getString(R.string.short_thousand);
} else {
- return localizeNumber(context, value);
+ return localizeNumber(value);
}
}
@@ -377,8 +370,8 @@ public final class Localization {
prettyTime.removeUnit(Decade.class);
}
- public static PrettyTime resolvePrettyTime(@NonNull final Context context) {
- return new PrettyTime(getAppLocale(context));
+ public static PrettyTime resolvePrettyTime() {
+ return new PrettyTime(getAppLocale());
}
public static String relativeTime(@NonNull final OffsetDateTime offsetDateTime) {
@@ -410,14 +403,6 @@ public final class Localization {
}
}
- public static void assureCorrectAppLanguage(final Context c) {
- final Resources res = c.getResources();
- final DisplayMetrics dm = res.getDisplayMetrics();
- final Configuration conf = res.getConfiguration();
- conf.setLocale(getAppLocale(c));
- res.updateConfiguration(conf, dm);
- }
-
private static Locale getLocaleFromPrefs(@NonNull final Context context,
@StringRes final int prefKey) {
final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
@@ -453,28 +438,29 @@ public final class Localization {
}
public static void migrateAppLanguageSettingIfNecessary(@NonNull final Context context) {
- // Starting with pull request #12093, NewPipe on Android 13+ exclusively uses Android's
+ // Starting with pull request #12093, NewPipe exclusively uses Android's
// public per-app language APIs to read and set the UI language for NewPipe.
- // If running on Android 13+, the following code will migrate any existing custom
- // app language in SharedPreferences to use the public per-app language APIs instead.
- if (Build.VERSION.SDK_INT >= 33) {
- final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
- final String appLanguageKey = context.getString(R.string.app_language_key);
- final String appLanguageValue = sp.getString(appLanguageKey, null);
- if (appLanguageValue != null) {
+ // The following code will migrate any existing custom app language in SharedPreferences to
+ // use the public per-app language APIs instead.
+ final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
+ final String appLanguageKey = context.getString(R.string.app_language_key);
+ final String appLanguageValue = sp.getString(appLanguageKey, null);
+ if (appLanguageValue != null) {
+ // The app language key is used on Android versions < Tiramisu; for more info, see
+ // ContentSettingsFragment.
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
sp.edit().remove(appLanguageKey).apply();
- final String appLanguageDefaultValue =
- context.getString(R.string.default_localization_key);
- if (!appLanguageValue.equals(appLanguageDefaultValue)) {
- try {
- AppCompatDelegate.setApplicationLocales(
- LocaleListCompat.forLanguageTags(appLanguageValue)
- );
- } catch (final RuntimeException e) {
- Log.e(TAG, "Failed to migrate previous custom app language "
- + "setting to public per-app language APIs"
- );
- }
+ }
+ final String appLanguageDefaultValue =
+ context.getString(R.string.default_localization_key);
+ if (!appLanguageValue.equals(appLanguageDefaultValue)) {
+ try {
+ final var locales = LocaleListCompat.forLanguageTags(appLanguageValue);
+ AppCompatDelegate.setApplicationLocales(locales);
+ } catch (final RuntimeException e) {
+ Log.e(TAG, "Failed to migrate previous custom app language "
+ + "setting to public per-app language APIs"
+ );
}
}
}