2
0
mirror of https://github.com/TeamNewPipe/NewPipe synced 2025-08-22 10:09:39 +00:00

Enable per-app language preferences for Android < 13

This commit is contained in:
Isira Seneviratne 2025-07-19 19:14:38 +05:30
parent 0db859e225
commit 893a227ab1
23 changed files with 85 additions and 145 deletions

View File

@ -57,6 +57,15 @@
</intent-filter>
</receiver>
<service
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
android:enabled="false"
android:exported="false">
<meta-data
android:name="autoStoreLocales"
android:value="true" />
</service>
<service
android:name=".player.PlayerService"
android:exported="true"

View File

@ -102,7 +102,7 @@ public class App extends Application {
NewPipe.init(getDownloader(),
Localization.getPreferredLocalization(this),
Localization.getPreferredContentCountry(this));
Localization.initPrettyTime(Localization.resolvePrettyTime(getApplicationContext()));
Localization.initPrettyTime(Localization.resolvePrettyTime());
BridgeStateSaverInitializer.init(this);
StateSaver.init(this);

View File

@ -20,8 +20,6 @@
package org.schabi.newpipe;
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@ -142,6 +140,7 @@ public class MainActivity extends AppCompatActivity {
+ "savedInstanceState = [" + savedInstanceState + "]");
}
Localization.migrateAppLanguageSettingIfNecessary(getApplicationContext());
ThemeHelper.setDayNightMode(this);
ThemeHelper.setTheme(this, ServiceHelper.getSelectedServiceId(this));
@ -158,7 +157,6 @@ public class MainActivity extends AppCompatActivity {
}
}
assureCorrectAppLanguage(this);
super.onCreate(savedInstanceState);
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
sharedPrefEditor = sharedPreferences.edit();
@ -197,7 +195,6 @@ public class MainActivity extends AppCompatActivity {
UpdateSettingsFragment.askForConsentToUpdateChecks(this);
}
Localization.migrateAppLanguageSettingIfNecessary(getApplicationContext());
SettingMigrations.showUserInfoIfPresent(this);
}
@ -504,9 +501,8 @@ public class MainActivity extends AppCompatActivity {
@Override
protected void onResume() {
assureCorrectAppLanguage(this);
// Change the date format to match the selected language on resume
Localization.initPrettyTime(Localization.resolvePrettyTime(getApplicationContext()));
Localization.initPrettyTime(Localization.resolvePrettyTime());
super.onResume();
// Close drawer on return, and don't show animation,

View File

@ -84,7 +84,6 @@ import org.schabi.newpipe.util.ChannelTabHelper;
import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.DeviceUtils;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.PermissionHelper;
import org.schabi.newpipe.util.ThemeHelper;
@ -132,7 +131,6 @@ public class RouterActivity extends AppCompatActivity {
ThemeHelper.setDayNightMode(this);
setTheme(ThemeHelper.isLightThemeSelected(this)
? R.style.RouterActivityThemeLight : R.style.RouterActivityThemeDark);
Localization.assureCorrectAppLanguage(this);
// Pass-through touch events to background activities
// so that our transparent window won't lock UI in the mean time

View File

@ -16,14 +16,12 @@ import org.schabi.newpipe.BuildConfig
import org.schabi.newpipe.R
import org.schabi.newpipe.databinding.ActivityAboutBinding
import org.schabi.newpipe.databinding.FragmentAboutBinding
import org.schabi.newpipe.util.Localization
import org.schabi.newpipe.util.ThemeHelper
import org.schabi.newpipe.util.external_communication.ShareUtils
class AboutActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
Localization.assureCorrectAppLanguage(this)
super.onCreate(savedInstanceState)
ThemeHelper.setTheme(this)
title = getString(R.string.title_activity_about)

View File

@ -19,7 +19,6 @@ import org.schabi.newpipe.R
import org.schabi.newpipe.databinding.FragmentLicensesBinding
import org.schabi.newpipe.databinding.ItemSoftwareComponentBinding
import org.schabi.newpipe.ktx.parcelableArrayList
import org.schabi.newpipe.util.Localization
import org.schabi.newpipe.util.external_communication.ShareUtils
/**
@ -100,7 +99,6 @@ class LicenseFragment : Fragment() {
val webView = WebView(context)
webView.loadData(webViewData, "text/html; charset=UTF-8", "base64")
Localization.assureCorrectAppLanguage(context)
val builder = AlertDialog.Builder(requireContext())
.setTitle(softwareComponent.name)
.setView(webView)

View File

@ -20,8 +20,6 @@ import org.schabi.newpipe.views.FocusOverlayView;
import us.shandian.giga.service.DownloadManagerService;
import us.shandian.giga.ui.fragment.MissionsFragment;
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
public class DownloadActivity extends AppCompatActivity {
private static final String MISSIONS_FRAGMENT_TAG = "fragment_tag";
@ -33,7 +31,6 @@ public class DownloadActivity extends AppCompatActivity {
i.setClass(this, DownloadManagerService.class);
startService(i);
assureCorrectAppLanguage(this);
ThemeHelper.setTheme(this);
super.onCreate(savedInstanceState);

View File

@ -2,7 +2,6 @@ package org.schabi.newpipe.download;
import static org.schabi.newpipe.extractor.stream.DeliveryMethod.PROGRESSIVE_HTTP;
import static org.schabi.newpipe.util.ListHelper.getStreamsOfSpecifiedDelivery;
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
import android.app.Activity;
import android.content.ComponentName;
@ -751,7 +750,6 @@ public class DownloadDialog extends DialogFragment
}
private void showFailedDialog(@StringRes final int msg) {
assureCorrectAppLanguage(requireContext());
new AlertDialog.Builder(context)
.setTitle(R.string.general_error)
.setMessage(msg)

View File

@ -1,7 +1,5 @@
package org.schabi.newpipe.error;
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
@ -79,7 +77,6 @@ public class ErrorActivity extends AppCompatActivity {
@Override
protected void onCreate(final Bundle savedInstanceState) {
assureCorrectAppLanguage(this);
super.onCreate(savedInstanceState);
ThemeHelper.setDayNightMode(this);
@ -306,7 +303,7 @@ public class ErrorActivity extends AppCompatActivity {
}
private String getAppLanguage() {
return Localization.getAppLocale(getApplicationContext()).toString();
return Localization.getAppLocale().toString();
}
private String getOsString() {

View File

@ -93,7 +93,7 @@ public class DescriptionFragment extends BaseDescriptionFragment {
if (streamInfo.getLanguageInfo() != null) {
addMetadataItem(inflater, layout, false, R.string.metadata_language,
streamInfo.getLanguageInfo().getDisplayLanguage(getAppLocale(getContext())));
streamInfo.getLanguageInfo().getDisplayLanguage(getAppLocale()));
}
addMetadataItem(inflater, layout, true, R.string.metadata_support,

View File

@ -81,9 +81,7 @@ public class ChannelAboutFragment extends BaseDescriptionFragment {
if (channelInfo.getSubscriberCount() != UNKNOWN_SUBSCRIBER_COUNT) {
addMetadataItem(inflater, layout, false, R.string.metadata_subscribers,
Localization.localizeNumber(
requireContext(),
channelInfo.getSubscriberCount()));
Localization.localizeNumber(channelInfo.getSubscriberCount()));
}
addImagesMetadataItem(inflater, layout, R.string.metadata_avatars,

View File

@ -1,7 +1,5 @@
package org.schabi.newpipe.local.subscription;
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
import android.app.Dialog;
import android.content.Intent;
import android.os.Bundle;
@ -35,7 +33,6 @@ public class ImportConfirmationDialog extends DialogFragment {
@NonNull
@Override
public Dialog onCreateDialog(@Nullable final Bundle savedInstanceState) {
assureCorrectAppLanguage(getContext());
return new AlertDialog.Builder(requireContext())
.setMessage(R.string.import_network_expensive_warning)
.setCancelable(true)

View File

@ -2,7 +2,6 @@ package org.schabi.newpipe.player;
import static org.schabi.newpipe.QueueItemMenuUtil.openPopupMenu;
import static org.schabi.newpipe.player.helper.PlayerHelper.formatSpeed;
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
import android.content.ComponentName;
import android.content.Intent;
@ -84,7 +83,6 @@ public final class PlayQueueActivity extends AppCompatActivity
@Override
protected void onCreate(final Bundle savedInstanceState) {
assureCorrectAppLanguage(this);
super.onCreate(savedInstanceState);
ThemeHelper.setTheme(this, ServiceHelper.getSelectedServiceId(this));

View File

@ -44,7 +44,6 @@ import static org.schabi.newpipe.player.notification.NotificationConstants.ACTIO
import static org.schabi.newpipe.player.notification.NotificationConstants.ACTION_SHUFFLE;
import static org.schabi.newpipe.util.ListHelper.getPopupResolutionIndex;
import static org.schabi.newpipe.util.ListHelper.getResolutionIndex;
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import android.content.BroadcastReceiver;
@ -88,8 +87,8 @@ import org.schabi.newpipe.databinding.PlayerBinding;
import org.schabi.newpipe.error.ErrorInfo;
import org.schabi.newpipe.error.ErrorUtil;
import org.schabi.newpipe.error.UserAction;
import org.schabi.newpipe.extractor.stream.AudioStream;
import org.schabi.newpipe.extractor.Image;
import org.schabi.newpipe.extractor.stream.AudioStream;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.extractor.stream.VideoStream;
@ -120,9 +119,9 @@ import org.schabi.newpipe.player.ui.VideoPlayerUi;
import org.schabi.newpipe.util.DependentPreferenceHelper;
import org.schabi.newpipe.util.ListHelper;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.image.PicassoHelper;
import org.schabi.newpipe.util.SerializedCache;
import org.schabi.newpipe.util.StreamTypeUtil;
import org.schabi.newpipe.util.image.PicassoHelper;
import java.util.List;
import java.util.Optional;
@ -753,7 +752,6 @@ public final class Player implements PlaybackListener, Listener {
toggleShuffleModeEnabled();
break;
case Intent.ACTION_CONFIGURATION_CHANGED:
assureCorrectAppLanguage(service);
if (DEBUG) {
Log.d(TAG, "ACTION_CONFIGURATION_CHANGED received");
}

View File

@ -19,8 +19,6 @@
package org.schabi.newpipe.player;
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
@ -91,7 +89,6 @@ public final class PlayerService extends MediaBrowserServiceCompat {
if (DEBUG) {
Log.d(TAG, "onCreate() called");
}
assureCorrectAppLanguage(this);
ThemeHelper.setTheme(this);
mediaBrowserImpl = new MediaBrowserImpl(this, this::notifyChildrenChanged);

View File

@ -2,7 +2,6 @@ package org.schabi.newpipe.player.helper;
import static org.schabi.newpipe.ktx.ViewUtils.animateRotation;
import static org.schabi.newpipe.player.Player.DEBUG;
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
import static org.schabi.newpipe.util.ThemeHelper.resolveDrawable;
import android.app.Dialog;
@ -145,7 +144,6 @@ public class PlaybackParameterDialog extends DialogFragment {
@NonNull
@Override
public Dialog onCreateDialog(@Nullable final Bundle savedInstanceState) {
assureCorrectAppLanguage(getContext());
Bridge.restoreInstanceState(this, savedInstanceState);
binding = DialogPlaybackParameterBinding.inflate(getLayoutInflater());

View File

@ -6,6 +6,7 @@ import android.os.Bundle
import android.os.ResultReceiver
import android.support.v4.media.session.PlaybackStateCompat
import android.util.Log
import androidx.core.content.ContextCompat
import androidx.core.net.toUri
import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector.PlaybackPreparer
@ -109,14 +110,14 @@ class MediaBrowserPlaybackPreparer(
//region Errors
private fun onUnsupportedError() {
setMediaSessionError.accept(
context.getString(R.string.content_not_supported),
ContextCompat.getString(context, R.string.content_not_supported),
PlaybackStateCompat.ERROR_CODE_NOT_SUPPORTED
)
}
private fun onPrepareError() {
setMediaSessionError.accept(
context.getString(R.string.error_snackbar_message),
ContextCompat.getString(context, R.string.error_snackbar_message),
PlaybackStateCompat.ERROR_CODE_APP_ERROR
)
}

View File

@ -1,7 +1,6 @@
package org.schabi.newpipe.settings;
import static org.schabi.newpipe.extractor.utils.Utils.isBlank;
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
import android.app.Activity;
import android.app.AlertDialog;
@ -126,7 +125,6 @@ public class BackupRestoreSettingsFragment extends BasePreferenceFragment {
}
private void requestExportPathResult(final ActivityResult result) {
assureCorrectAppLanguage(requireContext());
if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) {
// will be saved only on success
final Uri lastExportDataUri = result.getData().getData();
@ -139,7 +137,6 @@ public class BackupRestoreSettingsFragment extends BasePreferenceFragment {
}
private void requestImportPathResult(final ActivityResult result) {
assureCorrectAppLanguage(requireContext());
if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) {
// will be saved only on success
final Uri lastImportDataUri = result.getData().getData();

View File

@ -10,6 +10,7 @@ import android.util.Log;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.os.LocaleListCompat;
import androidx.preference.Preference;
import org.schabi.newpipe.DownloaderImpl;
@ -27,26 +28,20 @@ import java.util.Locale;
public class ContentSettingsFragment extends BasePreferenceFragment {
private String youtubeRestrictedModeEnabledKey;
private String initialLanguage;
@Override
public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) {
youtubeRestrictedModeEnabledKey = getString(R.string.youtube_restricted_mode_enabled);
addPreferencesFromResourceRegistry();
initialLanguage = defaultPreferences.getString(getString(R.string.app_language_key), "en");
final var appLanguagePref = requirePreference(R.string.app_language_key);
if (Build.VERSION.SDK_INT >= 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);
}
}
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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<AudioStream> nameCmp = getAudioTrackNameComparator(context);
final Comparator<AudioStream> nameCmp = getAudioTrackNameComparator();
final Comparator<AudioStream> 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<AudioStream> getAudioTrackNameComparator(
@NonNull final Context context) {
final Locale appLoc = Localization.getAppLocale(context);
private static Comparator<AudioStream> getAudioTrackNameComparator() {
final Locale appLoc = Localization.getAppLocale();
return Comparator.comparing(AudioStream::getAudioLocale, Comparator.nullsLast(
Comparator.comparing(locale -> locale.getDisplayName(appLoc))))

View File

@ -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) {
public static Locale getAppLocale() {
final Locale customLocale = AppCompatDelegate.getApplicationLocales().get(0);
return Objects.requireNonNullElseGet(customLocale, Locale::getDefault);
}
return getLocaleFromPrefs(context, R.string.app_language_key);
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,23 +438,25 @@ 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) {
// 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)
);
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"
@ -478,5 +465,4 @@ public final class Localization {
}
}
}
}
}