diff --git a/documentation/docs/help/en/Advanced preferences.md b/documentation/docs/help/en/Advanced preferences.md index d20c220431..759141cd53 100644 --- a/documentation/docs/help/en/Advanced preferences.md +++ b/documentation/docs/help/en/Advanced preferences.md @@ -72,9 +72,9 @@ Select the theme to use. _Follow system_ will follow the setting in the system p Show the menu buttons at the bottom of the screen. Default: _on_. You need to restart the app for changes to this setting to take effect. -### Disable translations +### App language -Use English for the user interface. Google does not provide a supported way to switch languages for individual apps, as a result this setting relies on multiple workarounds that may, or may not, work on your device. Preset translations can be disabled in the preset configurations. +Select a language for the user interface that is different from the device default. On devices running Android 13 and later the app language can be changed in the system settings too. Preset translations can be disabled in the preset configurations. ### Max. number of inline values diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 8eec6a49c2..bfc272de4f 100755 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -311,6 +311,17 @@ android:configChanges="orientation|screenSize|keyboardHidden|density|screenLayout|uiMode|fontScale" android:foregroundServiceType="location" android:label="TrackerService" /> + + + + + + { + Log.d(DEBUG_TAG, "onPreferenceChange appLocale " + newValue); + LocaleListCompat newDefaultList = LocaleListCompat.forLanguageTags((String) newValue); + Locale newDefault = newDefaultList.get(0); + AppCompatDelegate.setApplicationLocales(newDefaultList); + preference.setSummary(newDefault.getDisplayName(newDefault)); + return true; + }; + appLocalePref.setOnPreferenceChangeListener(p); + } + /** * Setup the possible camera apps for selection * @@ -134,23 +174,5 @@ private void setOnPreferenceClickListeners() { return true; }); } - - Preference disableTranslationsPref = getPreferenceScreen().findPreference(r.getString(R.string.config_disableTranslations_key)); - if (disableTranslationsPref != null) { - disableTranslationsPref.setOnPreferenceClickListener(preference -> { - LocaleAwareCompatActivity lac = ((LocaleAwareCompatActivity) getActivity()); - String savedLocaleKey = lac.getString(R.string.config_savedLocale_key); - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(lac); - if (((CheckBoxPreference) disableTranslationsPref).isChecked()) { - if (!prefs.contains(savedLocaleKey)) { - prefs.edit().putString(savedLocaleKey, LocaleUtils.toLanguageTag(Locale.getDefault())).commit(); - } - lac.updateLocale(Locale.ENGLISH); - } else { - lac.updateLocale(LocaleUtils.forLanguageTag(prefs.getString(savedLocaleKey, Locale.ENGLISH.toString()))); - } - return true; - }); - } } } diff --git a/src/main/java/de/blau/android/prefs/VespucciURLActivity.java b/src/main/java/de/blau/android/prefs/VespucciURLActivity.java index 32bb6c29d6..74a53cb9fe 100644 --- a/src/main/java/de/blau/android/prefs/VespucciURLActivity.java +++ b/src/main/java/de/blau/android/prefs/VespucciURLActivity.java @@ -4,8 +4,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import com.zeugmasolutions.localehelper.LocaleAwareCompatActivity; - import android.content.Intent; import android.net.Uri; import android.os.Bundle; @@ -19,6 +17,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; import de.blau.android.Authorize; import de.blau.android.R; import de.blau.android.net.OAuthHelper; @@ -41,7 +40,7 @@ * @author Simon * */ -public class VespucciURLActivity extends LocaleAwareCompatActivity implements OnClickListener { +public class VespucciURLActivity extends AppCompatActivity implements OnClickListener { private static final String DEBUG_TAG = VespucciURLActivity.class.getSimpleName(); private static final int REQUEST_PRESETEDIT = 0; diff --git a/src/main/java/de/blau/android/propertyeditor/PropertyEditorActivity.java b/src/main/java/de/blau/android/propertyeditor/PropertyEditorActivity.java index a7ebe8e37b..d96aa0407b 100644 --- a/src/main/java/de/blau/android/propertyeditor/PropertyEditorActivity.java +++ b/src/main/java/de/blau/android/propertyeditor/PropertyEditorActivity.java @@ -6,8 +6,6 @@ import org.acra.ACRA; -import com.zeugmasolutions.localehelper.LocaleAwareCompatActivity; - import android.app.Activity; import android.content.Intent; import android.content.res.Configuration; @@ -17,6 +15,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; @@ -45,7 +44,7 @@ * @author simon */ public class PropertyEditorActivity & Serializable, L extends List & Serializable, T extends List> & Serializable> - extends LocaleAwareCompatActivity implements ControlListener { + extends AppCompatActivity implements ControlListener { private static final String DEBUG_TAG = PropertyEditorActivity.class.getSimpleName(); diff --git a/src/main/java/de/blau/android/util/ConfigurationChangeAwareActivity.java b/src/main/java/de/blau/android/util/ConfigurationChangeAwareActivity.java index 5ed42a9ee3..3e67af70cf 100644 --- a/src/main/java/de/blau/android/util/ConfigurationChangeAwareActivity.java +++ b/src/main/java/de/blau/android/util/ConfigurationChangeAwareActivity.java @@ -1,13 +1,12 @@ package de.blau.android.util; -import com.zeugmasolutions.localehelper.LocaleAwareCompatActivity; - import android.content.res.Configuration; import android.util.Log; +import androidx.appcompat.app.AppCompatActivity; import de.blau.android.App; -public abstract class ConfigurationChangeAwareActivity extends LocaleAwareCompatActivity { - +public abstract class ConfigurationChangeAwareActivity extends AppCompatActivity { + private static final String DEBUG_TAG = ConfigurationChangeAwareActivity.class.getSimpleName(); @Override @@ -20,6 +19,6 @@ public void onConfigurationChanged(Configuration newConfig) { Log.d(DEBUG_TAG, "recreating activity " + this.getClass().getCanonicalName()); recreate(); } - Util.clearCaches(this, oldConfig, newConfig); + Util.clearCaches(this, oldConfig, newConfig); } } diff --git a/src/main/java/de/blau/android/util/LocaleUtils.java b/src/main/java/de/blau/android/util/LocaleUtils.java index 3febc19c8f..8c327bc4dc 100644 --- a/src/main/java/de/blau/android/util/LocaleUtils.java +++ b/src/main/java/de/blau/android/util/LocaleUtils.java @@ -1,15 +1,28 @@ package de.blau.android.util; +import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; +import java.util.List; import java.util.Locale; import java.util.Set; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import android.app.LocaleConfig; +import android.content.Context; import android.os.Build; +import android.util.Log; import androidx.annotation.NonNull; +import androidx.core.os.LocaleListCompat; +import de.blau.android.R; public final class LocaleUtils { + private static final String DEBUG_TAG = LocaleUtils.class.getSimpleName(); + // list of languages that use Latin script from https://gist.github.com/phil-brown/8056700 private static Set latin = new HashSet<>(Arrays.asList("aa", "ace", "ach", "ada", "af", "agq", "ak", "ale", "amo", "an", "arn", "arp", "arw", "asa", "ast", "ay", "az", "bal", "ban", "bas", "bbc", "bem", "bez", "bi", "bik", "bin", "bku", "bla", "bm", "bqv", "br", "bs", "buc", "bug", "bya", "ca", @@ -171,4 +184,32 @@ public static Locale forLanguageTag(@NonNull String languageTag) { public static boolean usesLatinScript(@NonNull Locale locale) { return latin.contains(locale.getLanguage()); } + + /** + * Get a list of supported locales for the app + * + * For devices prior to Android 13 this reads and parses locales_config.xml directly, note that since we are using + * automatic generation of the file it has a different name. + * + * @param context an Android Context + * @return a LocaleListCompat + */ + public static LocaleListCompat getSupportedLocales(@NonNull Context context) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + return LocaleListCompat.wrap(new LocaleConfig(context).getSupportedLocales()); + } + List locales = new ArrayList<>(); + try { + XmlPullParser parser = context.getResources().getXml(R.xml._generated_res_locale_config); + while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { + if (parser.getEventType() == XmlPullParser.START_TAG && "locale".equals(parser.getName())) { + locales.add(parser.getAttributeValue(0)); + } + parser.next(); + } + } catch (XmlPullParserException | IOException e) { + Log.e(DEBUG_TAG, "Error reading locales_config " + e.getMessage()); + } + return LocaleListCompat.forLanguageTags(String.join(",", locales)); + } } diff --git a/src/main/res/resources.properties b/src/main/res/resources.properties new file mode 100644 index 0000000000..d5a3ddc92a --- /dev/null +++ b/src/main/res/resources.properties @@ -0,0 +1 @@ +unqualifiedResLocale=en-US \ No newline at end of file diff --git a/src/main/res/values/prefkeys.xml b/src/main/res/values/prefkeys.xml index 75ade909f7..e1ce79bc66 100644 --- a/src/main/res/values/prefkeys.xml +++ b/src/main/res/values/prefkeys.xml @@ -89,8 +89,7 @@ useBarometricHeight useUrlForFeedback preferRemovableStorage - disableTranslations - savedLocale + appLocale nameCap indexMediaStore wayNodeDragging diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 3b5d130d60..d32bfd30eb 100755 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -1174,8 +1174,8 @@ Select app styling. Enable split action bar Show the menu buttons at the bottom of the screen. Requires starting Vespucci again, and Android 4.0 or later. - Disable translations - Use English for the user interface + App language + Select non-standard app language Max. number of inline values Maximum number of inline values displayed in tag form. %1$d values diff --git a/src/main/res/xml-v19/advancedpreferences.xml b/src/main/res/xml-v19/advancedpreferences.xml index 3f3bf4443f..3f6a12bd6e 100644 --- a/src/main/res/xml-v19/advancedpreferences.xml +++ b/src/main/res/xml-v19/advancedpreferences.xml @@ -97,11 +97,11 @@ android:key="@string/config_splitActionBarEnabled_key" android:summary="@string/config_splitActionBarEnabled_summary" android:title="@string/config_splitActionBarEnabled_title" /> - + - + - + - +