I implemented some string resources for english and romanian. Switching the locale works fine for text fields, but the titles for the drawer items doesnt change when language is changed.
I have the following configuration:
Setting the locale to "ro" in MainActivity
private fun setDefaultLocale(lang: String) {
val config = android.content.res.Configuration(resources.configuration)
val locale = Locale(lang)
Locale.setDefault(locale)
config.setLocale(locale)
config.setLayoutDirection(locale)
resources.updateConfiguration(config, resources.displayMetrics)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
setDefaultLocale("ro")
.....
}
Menu resources:
<group android:checkableBehavior="single">
<item
android:icon="#drawable/ic_baseline_home_24"
android:id="#+id/home"
android:title="#string/menu_home" />
<item
android:icon="#drawable/ic_baseline_wallpaper_24"
android:id="#+id/news"
android:title="#string/menu_news" />
<item
android:icon="#drawable/ic_jungle"
android:id="#+id/jungleTimer"
android:title="#string/menu_timer" />
<item
android:icon="#drawable/ic_damage"
android:id="#+id/builds"
android:title="#string/menu_builds" />
<item
android:icon="#drawable/ic_baseline_settings_24"
android:id="#+id/settings"
android:title="#string/menu_settings" />
<item
android:icon="#drawable/ic_baseline_info_24"
android:id="#+id/about"
android:title="#string/menu_about" />
<item
android:icon="#drawable/ic_feedback"
android:id="#+id/feedback"
android:title="#string/menu_feedback" />
<item
android:icon="#drawable/ic_favorite"
android:id="#+id/rateapp"
android:title="#string/menu_rate" />
</group>
Default string xml file:
/* Menu translations */
<string name="menu_home">Home</string>
<string name="menu_news">News</string>
<string name="menu_timer">Jungle Timers</string>
<string name="menu_builds">Guides</string>
<string name="menu_settings">Settings</string>
<string name="menu_about">About</string>
<string name="menu_feedback">Feedback</string>
<string name="menu_rate">Rate the app</string>
Romanian strings xml file
/* Menu translations */
<string name="menu_home">Acasă</string>
<string name="menu_news">Noutăți</string>
<string name="menu_timer">Cronometru Junglă</string>
<string name="menu_builds">Ghid Campioni</string>
<string name="menu_settings">Setări</string>
<string name="menu_about">Despre</string>
<string name="menu_feedback">Feedback</string>
<string name="menu_rate">Dă-ne o notă</string>
Updating configuration will not restart your activity, so Drawer will not know that you changed locale on the device thus not changing the texts.
If you change your language in system settings it should work.
I propose recreating the activity after you change your configuration programmatically, for example with activity?.recreate() method
Related
How to change text and background color in a PreferenceScreen inflated by PreferenceFragmentCompat?
Tried How to change the text color of PreferenceCategory/PreferenceScreen but the solution works in a Preference Activity and not in PreferenceFragmentCompat.
Also tried using the layout tag in the preference screen as per How to change text color of preference category in Android? but doesn't save preference.
class FragmentSettings: PreferenceFragmentCompat() {
private lateinit var viewModel: SharedViewModel
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.root_preferences)
val application = requireNotNull(this.activity).application
val dataBase = DataBase.getInstance(application)
val repo = Repo(dataBase!!)
viewModel = ViewModelProvider(this,
SharedViewModelFactory(
dataBase
)
).get(SharedViewModel::class.java)
(activity as MainActivity).supportActionBar?.title = "Settings"
}
This is the code in my settingsPreference.xml.
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="#color/colorExtra"
android:backgroundTint="#color/colorExtra">
<PreferenceCategory android:layout="#layout/pref_title" app:title="#string/location_header">
<SwitchPreferenceCompat
android:background="#color/colorExtra"
android:backgroundTint="#color/colorExtra"
app:defaultValue="true"
android:layout= "#layout/switch_pref_item"
app:disableDependentsState="true"
app:key="USE_DEVICE_LOCATION"
app:summary="Allow the app to get your location"
app:title="#string/your_location_title" />
<EditTextPreference
android:background="#color/colorExtra"
android:backgroundTint="#color/colorExtra"
app:dependency="USE_DEVICE_LOCATION"
app:key="setLocation"
android:layout="#layout/set_location_pref"
app:title="#string/set_location_title"
app:useSimpleSummaryProvider="true" />
</PreferenceCategory>
</PreferenceScreen>
This should be done via styles, and follows the same procedure used to style any layout. It is not done via the preferences xml.
Make an xml style that is a child of Theme.AppCompat. Then you can override the colors for android:windowBackground and android:textColor. You can apply this style to the activity in the manifest.
For example, in styles.xml:
<color name="preferencesTextColor">$ff0000</color>
<color name="preferencesBackgroundColor">#202020</color>
<style name="MyPreferencesTheme" parent="Theme.AppCompat">
<item name="android:textColor">#color/preferencesTextColor</item>
<item name="android:windowBackground">#color/preferencesBackgroundColor</item>
</style>
Then in the manifest, apply the theme to the activity:
<activity android:name="MyPreferencesActivity"
android:theme="#style/MyPreferencesTheme"
android:label="#string/myPreferenceActivityLabel" />
I have the following error:
From menu:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:appcompat="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/menu_item_new"
android:title="#string/menu_item_new"
appcompat:showAsAction="always"></item>
<item
android:id="#+id/menu_item_save"
android:title="#string/menu_item_save"
appcompat:showAsAction="always"></item>
<item
android:id="#+id/menu_item_delete"
android:title="#string/menu_item_delete"
appcompat:showAsAction="always"></item>
<item
android:id="#+id/menu_item_rate"
android:title="#string/menu_item_rate"></item>
<item
android:id="#+id/menu_item_website"
android:title="#string/menu_item_website"></item>
<item
android:id="#+id/menu_item_report"
android:title="#string/menu_item_report"></item>
</menu>
Even though all those strings do in fact exist:
<string name="menu_item_new">New</string>
<string name="menu_item_save">Save</string>
<string name="menu_item_delete">Cancel</string>
<string name="menu_item_rate">Rate on Google Play</string>
<string name="menu_item_website">Website</string>
<string name="menu_item_report">Report a Bug</string>
I have attempted to simply re-write the code as well as clean and rebuild, yet the error persists.
How can this be resolved?
resources tag is missing from strings.xml file.
Android couldn't locate the string resource.
Make following changes:
<resources>
<string name="menu_item_new">New</string>
<string name="menu_item_save">Save</string>
<string name="menu_item_delete">Cancel</string>
<string name="menu_item_rate">Rate on Google Play</string>
<string name="menu_item_website">Website</string>
<string name="menu_item_report">Report a Bug</string>
</resources>
I followed all the instructions for setting default preference values step by step but does not work.
1º I set the default values:
<PreferenceCategory android:title="#string/settings_game" >
<ListPreference
android:defaultValue="1.5"
android:entries="#array/intervale_count"
android:entryValues="#array/intervale_count_values"
android:key="interval"
android:title="#string/interval" />
<ListPreference
android:defaultValue="#string/mode_normal"
android:entries="#array/mode_game"
android:entryValues="#array/mode_game_values"
android:key="mode"
android:title="#string/mode" />
</PreferenceCategory>
<PreferenceCategory android:title="#string/settings_sound" >
<ListPreference
android:defaultValue="#string/stone"
android:entries="#array/time_sounds"
android:entryValues="#array/time_sounds_values"
android:key="time_sounds"
android:title="#string/sounds_stones" />
<ListPreference
android:defaultValue="#string/vuvucela"
android:entries="#array/gong_sounds"
android:entryValues="#array/gong_sounds_values"
android:key="gong_sounds"
android:title="#string/sounds_gong" />
</PreferenceCategory>
2º I get the preferences in my MainActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
SP = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
}
But when I open the preference view no preferences are selected, the strings of I declare in the android:defaultValue is the SAME as one of the options Ihave in the array of data in android:entries.
Note: I try to change to true the boolean in
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
but that still does not work.
I've also tried to uninstall and delete the data of the app but that still does not work.
Edit: the array values
<string-array name="intervale_count">
<item>1</item>
<item>1.3</item>
<item>1.5</item>
<item>1.7</item>
<item>2</item>
</string-array>
<string-array name="intervale_count_values">
<item>1000</item>
<item>1300</item>
<item>1500</item>
<item>1700</item>
<item>2000</item>
</string-array>
<string-array name="mode_game">
<item>#string/mode_normal</item>
<item>#string/mode_extension</item>
<item>#string/mode_infinite</item>
</string-array>
<string-array name="mode_game_values">
<item>100</item>
<item>50</item>
<item>1000</item>
</string-array>
<string-array name="time_sounds">
<item>#string/alan</item>
<item>#string/cash_reg</item>
<item>#string/censure</item>
<item>#string/crow</item>
<item>#string/doh</item>
<item>#string/fb_noti</item>
<item>#string/achievement</item>
<item>#string/metal_gear</item>
<item>#string/duck</item>
<item>#string/pan</item>
<item>#string/drum</item>
<item>#string/stone</item>
</string-array>
<string-array name="time_sounds_values">
<item>2131099648</item> <!-- Alan -->
<item>2131099649</item> <!-- Registradora -->
<item>2131099650</item> <!-- Censura -->
<item>2131099651</item> <!-- Cuervo -->
<item>2131099652</item> <!-- DOh -->
<item>2131099653</item> <!-- FB -->
<item>2131099655</item> <!-- logro -->
<item>2131099656</item> <!--metal gear -->
<item>2131099657</item> <!-- pato -->
<item>2131099658</item><!-- sarten -->
<item>2131099660</item> <!-- tambor -->
<item>2131099659</item><!-- stone -->
</string-array>
<string-array name="gong_sounds">
<item>#string/gong</item>
<item>#string/vuvucela</item>
</string-array>
<string-array name="gong_sounds_values">
<item>2131099654</item> <!-- Gong -->
<item>2131099661</item> <!-- Vuvucela -->
</string-array>
The defaultValue attribute for a ListPreference needs to be a value, not the entry text. In other words, it should be an element in the array you pass to android:entryValues, not an element in the array you pass to android:entries.
For example, your gong sounds preference should use android:defaultValue="2131099661" instead of android:defaultValue="#string/vuvucela"
If it doesn't work, try to wipe the app data from the emulator/device and then reinstall the app. After I did that in my project and followed Tanis hints, it worked like a charm.
I found that there are following statement in package/apps/UnifiedEmail package in android source code:
<add-resource name="RecipientEditTextViewStyle" type="style" />
What does this "add-resource" element mean?
The source code: https://github.com/CyanogenMod/android_packages_apps_UnifiedEmail/blob/cm-11.0/res/values/attrs.xml
<resources>
<string name="app1_name">MyAppName</string>
</resources>
is the same thing as
<resources>
<add-resource type="string" name="app1_name">MyAppName</add-resource>
</resources>
so
<add-resource name="RecipientEditTextViewStyle" type="style" />
is the same thing as
<style name = "RecipientEditTextViewStyle"/>
For instance, the default button has the following dependencies between its states and background images:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_window_focused="false" android:state_enabled="true"
android:drawable="#drawable/btn_default_normal" />
<item android:state_window_focused="false" android:state_enabled="false"
android:drawable="#drawable/btn_default_normal_disable" />
<item android:state_pressed="true"
android:drawable="#drawable/btn_default_pressed" />
<item android:state_focused="true" android:state_enabled="true"
android:drawable="#drawable/btn_default_selected" />
<item android:state_enabled="true"
android:drawable="#drawable/btn_default_normal" />
<item android:state_focused="true"
android:drawable="#drawable/btn_default_normal_disable_focused" />
<item
android:drawable="#drawable/btn_default_normal_disable" />
</selector>
How can I define my own custom state (smth like android:state_custom), so then I could use it to dynamically change my button visual appearance?
The solution indicated by #(Ted Hopp) works, but needs a little correction: in the selector, the item states need an "app:" prefix, otherwise the inflater won't recognise the namespace correctly, and will fail silently; at least this is what happens to me.
Allow me to report here the whole solution, with some more details:
First, create file "res/values/attrs.xml":
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="food">
<attr name="state_fried" format="boolean" />
<attr name="state_baked" format="boolean" />
</declare-styleable>
</resources>
Then define your custom class. For instance, it may be a class "FoodButton", derived from class "Button". You will have to implement a constructor; implement this one, which seems to be the one used by the inflater:
public FoodButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
On top of the derived class:
private static final int[] STATE_FRIED = {R.attr.state_fried};
private static final int[] STATE_BAKED = {R.attr.state_baked};
Also, your state variables:
private boolean mIsFried = false;
private boolean mIsBaked = false;
And a couple of setters:
public void setFried(boolean isFried) {mIsFried = isFried;}
public void setBaked(boolean isBaked) {mIsBaked = isBaked;}
Then override function "onCreateDrawableState":
#Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 2);
if (mIsFried) {
mergeDrawableStates(drawableState, STATE_FRIED);
}
if (mIsBaked) {
mergeDrawableStates(drawableState, STATE_BAKED);
}
return drawableState;
}
Finally, the most delicate piece of this puzzle; the selector defining the StateListDrawable that you will use as a background for your widget. This is file "res/drawable/food_button.xml":
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.mydomain.mypackage">
<item
app:state_baked="true"
app:state_fried="false"
android:drawable="#drawable/item_baked" />
<item
app:state_baked="false"
app:state_fried="true"
android:drawable="#drawable/item_fried" />
<item
app:state_baked="true"
app:state_fried="true"
android:drawable="#drawable/item_overcooked" />
<item
app:state_baked="false"
app:state_fried="false"
android:drawable="#drawable/item_raw" />
</selector>
Notice the "app:" prefix, whereas with standard android states you would have used prefix "android:". The XML namespace is crucial for a correct interpretation by the inflater and depends on the type of project in which you are adding attributes. If it is an application, replace com.mydomain.mypackage with the actual package name of your application (application name excluded). If it is a library you must use "http://schemas.android.com/apk/res-auto" (and be using Tools R17 or later) or you will get runtime errors.
A couple of notes:
It seems you don't need to call the "refreshDrawableState" function, at least the solution works well as is, in my case
In order to use your custom class in a layout xml file, you will have to specify the fully qualified name (e.g. com.mydomain.mypackage.FoodButton)
You can as weel mix-up standard states (e.g. android:pressed, android:enabled, android:selected) with custom states, in order to represent more complicated state combinations
This thread shows how to add custom states to buttons and the like. (If you can't see the new Google groups in your browser, there's a copy of the thread here.)
Please do not forget to call refreshDrawableState within UI thread:
mHandler.post(new Runnable() {
#Override
public void run() {
refreshDrawableState();
}
});
It took lot of my time to figure out why my button is not changing its state even though everything looks right.