Skip to content

Commit 756327d

Browse files
authored
Merge pull request #12093 from mileskrell/mileskrell/support-per-app-language-preferences
Support per-app language preferences
2 parents 5840d3a + 205466c commit 756327d

7 files changed

Lines changed: 90 additions & 16 deletions

File tree

app/build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ android {
9797
androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
9898
}
9999

100+
androidResources {
101+
generateLocaleConfig = true
102+
}
103+
100104
buildFeatures {
101105
viewBinding true
102106
buildConfig true

app/src/main/java/org/schabi/newpipe/MainActivity.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,8 @@ protected void onCreate(final Bundle savedInstanceState) {
190190
&& ReleaseVersionUtil.INSTANCE.isReleaseApk()) {
191191
UpdateSettingsFragment.askForConsentToUpdateChecks(this);
192192
}
193+
194+
Localization.migrateAppLanguageSettingIfNecessary(getApplicationContext());
193195
}
194196

195197
@Override

app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
package org.schabi.newpipe.settings;
22

33
import android.content.Context;
4+
import android.content.Intent;
5+
import android.net.Uri;
6+
import android.os.Build;
47
import android.os.Bundle;
8+
import android.provider.Settings;
59
import android.util.Log;
610
import android.widget.Toast;
711

12+
import androidx.appcompat.app.AppCompatDelegate;
813
import androidx.preference.Preference;
914

1015
import org.schabi.newpipe.DownloaderImpl;
@@ -17,12 +22,11 @@
1722
import org.schabi.newpipe.util.image.PreferredImageQuality;
1823

1924
import java.io.IOException;
25+
import java.util.Locale;
2026

2127
public class ContentSettingsFragment extends BasePreferenceFragment {
2228
private String youtubeRestrictedModeEnabledKey;
2329

24-
private Localization initialSelectedLocalization;
25-
private ContentCountry initialSelectedContentCountry;
2630
private String initialLanguage;
2731

2832
@Override
@@ -31,12 +35,28 @@ public void onCreatePreferences(final Bundle savedInstanceState, final String ro
3135

3236
addPreferencesFromResourceRegistry();
3337

34-
initialSelectedLocalization = org.schabi.newpipe.util.Localization
35-
.getPreferredLocalization(requireContext());
36-
initialSelectedContentCountry = org.schabi.newpipe.util.Localization
37-
.getPreferredContentCountry(requireContext());
3838
initialLanguage = defaultPreferences.getString(getString(R.string.app_language_key), "en");
3939

40+
if (Build.VERSION.SDK_INT >= 33) {
41+
requirePreference(R.string.app_language_key).setVisible(false);
42+
final Preference newAppLanguagePref =
43+
requirePreference(R.string.app_language_android_13_and_up_key);
44+
newAppLanguagePref.setSummaryProvider(preference -> {
45+
final Locale customLocale = AppCompatDelegate.getApplicationLocales().get(0);
46+
if (customLocale != null) {
47+
return customLocale.getDisplayName();
48+
}
49+
return getString(R.string.systems_language);
50+
});
51+
newAppLanguagePref.setOnPreferenceClickListener(preference -> {
52+
final Intent intent = new Intent(Settings.ACTION_APP_LOCALE_SETTINGS)
53+
.setData(Uri.fromParts("package", requireContext().getPackageName(), null));
54+
startActivity(intent);
55+
return true;
56+
});
57+
newAppLanguagePref.setVisible(true);
58+
}
59+
4060
final Preference imageQualityPreference = requirePreference(R.string.image_quality_key);
4161
imageQualityPreference.setOnPreferenceChangeListener(
4262
(preference, newValue) -> {
@@ -72,19 +92,21 @@ public boolean onPreferenceTreeClick(final Preference preference) {
7292
public void onDestroy() {
7393
super.onDestroy();
7494

75-
final Localization selectedLocalization = org.schabi.newpipe.util.Localization
76-
.getPreferredLocalization(requireContext());
77-
final ContentCountry selectedContentCountry = org.schabi.newpipe.util.Localization
78-
.getPreferredContentCountry(requireContext());
7995
final String selectedLanguage =
8096
defaultPreferences.getString(getString(R.string.app_language_key), "en");
8197

82-
if (!selectedLocalization.equals(initialSelectedLocalization)
83-
|| !selectedContentCountry.equals(initialSelectedContentCountry)
84-
|| !selectedLanguage.equals(initialLanguage)) {
85-
Toast.makeText(requireContext(), R.string.localization_changes_requires_app_restart,
86-
Toast.LENGTH_LONG).show();
87-
98+
if (!selectedLanguage.equals(initialLanguage)) {
99+
if (Build.VERSION.SDK_INT < 33) {
100+
Toast.makeText(
101+
requireContext(),
102+
R.string.localization_changes_requires_app_restart,
103+
Toast.LENGTH_LONG
104+
).show();
105+
}
106+
final Localization selectedLocalization = org.schabi.newpipe.util.Localization
107+
.getPreferredLocalization(requireContext());
108+
final ContentCountry selectedContentCountry = org.schabi.newpipe.util.Localization
109+
.getPreferredContentCountry(requireContext());
88110
NewPipe.setupLocalization(selectedLocalization, selectedContentCountry);
89111
}
90112
}

app/src/main/java/org/schabi/newpipe/util/Localization.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,15 @@
1212
import android.text.TextUtils;
1313
import android.text.format.DateUtils;
1414
import android.util.DisplayMetrics;
15+
import android.util.Log;
1516

1617
import androidx.annotation.NonNull;
1718
import androidx.annotation.Nullable;
1819
import androidx.annotation.PluralsRes;
1920
import androidx.annotation.StringRes;
21+
import androidx.appcompat.app.AppCompatDelegate;
2022
import androidx.core.math.MathUtils;
23+
import androidx.core.os.LocaleListCompat;
2124
import androidx.preference.PreferenceManager;
2225

2326
import org.ocpsoft.prettytime.PrettyTime;
@@ -39,6 +42,7 @@
3942
import java.util.Arrays;
4043
import java.util.List;
4144
import java.util.Locale;
45+
import java.util.Objects;
4246
import java.util.stream.Collectors;
4347

4448

@@ -63,6 +67,7 @@
6367
*/
6468

6569
public final class Localization {
70+
private static final String TAG = Localization.class.toString();
6671
public static final String DOT_SEPARATOR = " • ";
6772
private static PrettyTime prettyTime;
6873

@@ -101,6 +106,10 @@ public static Locale getPreferredLocale(@NonNull final Context context) {
101106
}
102107

103108
public static Locale getAppLocale(@NonNull final Context context) {
109+
if (Build.VERSION.SDK_INT >= 33) {
110+
final Locale customLocale = AppCompatDelegate.getApplicationLocales().get(0);
111+
return Objects.requireNonNullElseGet(customLocale, Locale::getDefault);
112+
}
104113
return getLocaleFromPrefs(context, R.string.app_language_key);
105114
}
106115

@@ -427,4 +436,32 @@ private static String getQuantity(@NonNull final Context context,
427436
final int safeCount = (int) MathUtils.clamp(count, Integer.MIN_VALUE, Integer.MAX_VALUE);
428437
return context.getResources().getQuantityString(pluralId, safeCount, formattedCount);
429438
}
439+
440+
public static void migrateAppLanguageSettingIfNecessary(@NonNull final Context context) {
441+
// Starting with pull request #12093, NewPipe on Android 13+ exclusively uses Android's
442+
// public per-app language APIs to read and set the UI language for NewPipe.
443+
// If running on Android 13+, the following code will migrate any existing custom
444+
// app language in SharedPreferences to use the public per-app language APIs instead.
445+
if (Build.VERSION.SDK_INT >= 33) {
446+
final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
447+
final String appLanguageKey = context.getString(R.string.app_language_key);
448+
final String appLanguageValue = sp.getString(appLanguageKey, null);
449+
if (appLanguageValue != null) {
450+
sp.edit().remove(appLanguageKey).apply();
451+
final String appLanguageDefaultValue =
452+
context.getString(R.string.default_localization_key);
453+
if (!appLanguageValue.equals(appLanguageDefaultValue)) {
454+
try {
455+
AppCompatDelegate.setApplicationLocales(
456+
LocaleListCompat.forLanguageTags(appLanguageValue)
457+
);
458+
} catch (final RuntimeException e) {
459+
Log.e(TAG, "Failed to migrate previous custom app language "
460+
+ "setting to public per-app language APIs"
461+
);
462+
}
463+
}
464+
}
465+
}
466+
}
430467
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
unqualifiedResLocale=en-US

app/src/main/res/values/settings_keys.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,7 @@
353353
<string name="playback_skip_silence_key">playback_skip_silence_key</string>
354354

355355
<string name="app_language_key">app_language_key</string>
356+
<string name="app_language_android_13_and_up_key">app_language_android_13_and_up_key</string>
356357

357358
<string name="feed_update_threshold_key">feed_update_threshold_key</string>
358359
<string name="feed_update_threshold_default_value">300</string>

app/src/main/res/xml/content_settings.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@
1313
app:iconSpaceReserved="false"
1414
app:useSimpleSummaryProvider="true" />
1515

16+
<Preference
17+
android:key="@string/app_language_android_13_and_up_key"
18+
android:title="@string/app_language_title"
19+
app:isPreferenceVisible="false"
20+
app:singleLineTitle="false"
21+
app:iconSpaceReserved="false" />
22+
1623
<ListPreference
1724
android:defaultValue="@string/default_localization_key"
1825
android:entries="@array/language_names"

0 commit comments

Comments
 (0)