Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support per-app language preferences #12093

Open
wants to merge 10 commits into
base: dev
Choose a base branch
from

Conversation

mileskrell
Copy link
Contributor

@mileskrell mileskrell commented Mar 12, 2025

What is it?

  • Bugfix (user facing)
  • Feature (user facing)
  • Codebase improvement (dev facing)
  • Meta improvement to the project (dev facing)

Description of the changes in your PR

Enables automatic per-app language support.

On Android 13+, the preference in Settings -> Content shows any locale that has been set by the user through Android's per-app language settings. When tapped, it opens NewPipe's per-app language settings screen.

Also added a method to migrate any existing app language preference from SharedPreferences to the Android per-app language settings when we run the app on Android 13+.

Before/After Screenshots/Screen Record

  • Before:
  • After:
per-app.language.settings.integrated.with.existing.ui.without.toast.mp4

APK testing

The APK can be found by going to the "Checks" tab below the title. On the left pane, click on "CI", scroll down to "artifacts" and click "app" to download the zip file which contains the debug APK of this PR. You can find more info and a video demonstration on this wiki page.

Due diligence

@github-actions github-actions bot added the size/small PRs with less than 50 changed lines label Mar 12, 2025
@TobiGr
Copy link
Contributor

TobiGr commented Mar 12, 2025

I'll paste my comment from #10994 here:

NewPipe has an in-app language chooser (settings > content > app language). This one conflicts with the language chosen in the Android app settings when a language is set. The language chosen inside the app is used. Everything works fine when the "system default" option is chosen. Not sure if this is an unwanted behaviour in terms of accessibility.

Is it possible to check whether the per-app language is set? If it is, we might want to disable the in-app setting and display a hint that the per-app language preference is used instead.

@mileskrell
Copy link
Contributor Author

thanks @TobiGr! I looked briefly for an existing in-app language picker but didn't check in the "content" settings.

Yeah, I'll need to make some more changes so they don't conflict. I should be able to keep the in-app language picker and migrate it to use the new APIs.

@mileskrell mileskrell marked this pull request as draft March 12, 2025 20:41
@TobiGr
Copy link
Contributor

TobiGr commented Mar 12, 2025

@Stypox @AudricV Should these changes be done on the dev branch or the refactor branch?

@Stypox
Copy link
Member

Stypox commented Mar 13, 2025

If it's just a matter of hiding the settings screen language toggle and showing a message instead, in case the language has been changed from outside, then it's ok on the dev branch. If it involves heavy changes to the way the app sets the language then it's better on the refactor branch. Thanks @mileskrell !

@github-actions github-actions bot added size/medium PRs with less than 250 changed lines and removed size/small PRs with less than 50 changed lines labels Mar 16, 2025
@mileskrell mileskrell marked this pull request as ready for review March 16, 2025 02:46
Comment on lines +16 to +21
<Preference
android:key="@string/app_language_android_13_and_up_key"
android:title="@string/app_language_title"
app:isPreferenceVisible="false"
app:singleLineTitle="false"
app:iconSpaceReserved="false" />
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a separate Preference for the Android 13+ behavior only because for some reason when I set an OnPreferenceClickListener on the existing preference that returns true (indicating "the click was handled"), it still opens the existing dialog.

@mileskrell
Copy link
Contributor Author

@TobiGr @Stypox I've updated this PR so it doesn't conflict with the existing in-app language picker. Let me know what you think!

@ShareASmile ShareASmile added the feature request Issue is related to a feature in the app label Mar 16, 2025
Copy link
Contributor

@TobiGr TobiGr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. There is still a toast displayed that the language change is going to take effect with the next start of the app when changing the language on SDK 33+ which is obviously false.

Comment on lines 128 to 150

if (Build.VERSION.SDK_INT >= 33) {
ensureAppLanguagePreferenceIsMigrated(prefs);
}
}

private void ensureAppLanguagePreferenceIsMigrated(final SharedPreferences prefs) {
final String appLanguageDefaultValue = getString(R.string.default_localization_key);
final String appLanguageKey = getString(R.string.app_language_key);
final String appLanguageCurrentValue = prefs.getString(appLanguageKey, null);
if (appLanguageCurrentValue != null) {
// Migrate to Android per-app language settings
prefs.edit().remove(appLanguageKey).apply();
if (!appLanguageCurrentValue.equals(appLanguageDefaultValue)) {
try {
AppCompatDelegate.setApplicationLocales(
LocaleListCompat.forLanguageTags(appLanguageCurrentValue)
);
} catch (final RuntimeException e) {
Log.e(TAG, "Error migrating to Android 13+ per-app language settings");
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That looks like it should be moved and converted to a Migration in org.schabi.newpipe.settings.SettingMigrations.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My only concern is that if we convert this to a Migration, my understanding is that it will only run once. So in theory, the following scenario is possible:

  1. Someone running NewPipe on Android <13 sets a custom app language
  2. They update to the new version of NewPipe, where this migration is run but doesn't do anything because they're on Android <13
  3. They update to Android 13+
  4. Their custom app language pref isn't used (because it's running the Android 13+ code path) and it's not migrated from their old preference (because there's nothing triggering the migration to run again)

I recognize this will probably be a pretty rare scenario, just wanted to flag it. But whether or not we make it a Migration, I do recognize that this code belongs somewhere outside of the Application subclass for sure.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've moved it to a Migration. If we want to prevent the hypothetical app language setting loss I described above, maybe we could add a new migrations file for "migrations that should always be run on app startup because they depend on the current Android version".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mmmh you are right, this shouldn't be a migration as it needs to run every time the app notices it has been updated to Android 13+ from a lower Android version. What do you think @TobiGr?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you are right. My bad. I'd move it to initSettings in NewPipeSettings then. Does that make sense @Stypox ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

@mileskrell
Copy link
Contributor Author

mileskrell commented Mar 16, 2025

My bad, totally forgot to fix the toast!

So prior to this PR, we've been showing this toast whenever the app language, content language, or content country is changed. But are we sure that changes to content language/country have ever required a restart? When building from the latest commit on dev, after I set the content language, I'm shown the toast. But if I then open a video that has an audio track for the new content language, that audio track is automatically used without having to restart first:

content.language.changing.without.restart.mp4

If changes to the content language and country are reflected without having to restart, then the only situation where we need to show the toast is when app language is changed on a device running Android <13. Let me know if that sounds correct!

@mileskrell
Copy link
Contributor Author

mileskrell commented Mar 17, 2025

If changes to the content language and country are reflected without having to restart, then the only situation where we need to show the toast is when app language is changed on a device running Android <13. Let me know if that sounds correct!

The most recent commit I pushed assumes this is the case, but we can revert it if not.

Video showing new behavior (no toast when changing only content language):

dont.show.toast.when.changing.content.language.or.country.mp4

@mileskrell mileskrell requested a review from TobiGr March 20, 2025 04:33
Copy link
Member

@Stypox Stypox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code looks good to me, thank you! I have a comment here that could possibly be solved in a separate PR if you prefer. Also, see my comment about the migration.

Also, could you take a video of the updated code on pre-Android-13, so we can see if it still works as expected there?

Comment on lines +100 to +103
androidResources {
generateLocaleConfig = true
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we don't pay attention to new languages being added from Weblate, this might lead to half-translated being proposed to the user. Currently the list of languages is manually kept in settings_keys.xml, so when new languages are added through Weblate they don't automatically appear in the app menu. However, I'm fine with switching to the new behavior, as it would avoid work to keep the language list up to date. Is it possible to access the locale config from within the app, so we can delete the list of languages in settings_keys.xml and use the autogenerated locale config even for the pre-Android-13 language picker?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found LocaleManager#getOverrideLocaleConfig but it sounds like that method is only to get a LocaleConfig that's already been set with setOverrideLocaleConfig(). As far as I can tell, we would have to manually generate a LocaleConfig instead of using the auto-generated one if we wanted to use it for this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could find the data under app/build/generated/res/localeConfig/debug/xml/_generated_res_locale_config.xml after running the build, with this data inside:

<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
    <locale android:name="en-US"/>
    <locale android:name="ace"/>
    ...

So in theory the data is there, but in practice I think we better not access it by manually opening the xml since it's not officially supported. So yeah let's keep the previous behavior.

@mileskrell
Copy link
Contributor Author

Also, could you take a video of the updated code on pre-Android-13, so we can see if it still works as expected there?

@Stypox I tried it on an emulator running Android 12 and it seems fine:

changing.language.on.android.12.mp4

@Stypox
Copy link
Member

Stypox commented Mar 24, 2025

Thank you! I tested to import an export from a previous version of NewPipe into this PR's build on Android 13 and unfortunately it did not work: the app language remained the one that was there previously before importing settings. This is the database I imported (it should set the language to italian): NewPipeData-20250324_172806.zip

@mileskrell
Copy link
Contributor Author

thanks for catching that and for sharing the settings export @Stypox!

It turns out AppCompatDelegate.setApplicationLocales wasn't working - I missed the part of the documentation that says

Note: This API should always be called after Activity.onCreate(), apart from any exceptions explicitly mentioned in this documentation.

I've moved the migration method to Localization.migrateAppLanguageSettingIfNecessary and I'm calling it at the end of MainActivity.onCreate. Here's a video of the working migration:

fixed.migration.mp4

@mileskrell mileskrell requested a review from Stypox March 27, 2025 23:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request Issue is related to a feature in the app size/medium PRs with less than 250 changed lines
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants