Load localized strings at runtime

Here is a possible solution if you want to load localized text resources on a TextView in Android.

Problem:

You may need to extend your app flexibility to be able to load localized texts at runtime from a web server for example. That would be to be able to add new localizations (for new countries) without having to release a new update.

Solution:

One possible solution would be to:
1. Set a sort of naming conventions for your localized resources(text) like naming the key to something like: en_my_text, ro_my_text, de_my_text…
2. Load the text resources from the webserver and save those into a SharedPreferences file using the naming convention from above
3. Create a custom TextView and a custom attribute for the text view that will be used to set in XML the key for your localized text
4. Use the value from the custom attribute to load the translation on the TextView when Android loads your TextView

Simple sample

The xml attribute:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- Define our custom attributes to be used on the TextView or where we need -->
    <declare-styleable name="LocalizationAttributes">
        <attr name="locText" format="string" />
    </declare-styleable>
</resources>

 

You can save that under res -> values -> attributes.xml

The TextView custom class:

/**
 * A simple TextView that has the ability to fetch a custom attribute (locText in our case) if is set into the xml
 * and use it as key to load a localized resource from the SharedPreferences (assuming that the localization was saved there at runtime)
 *
 * @author catalinprata
 */
public class LocalizedTextView extends TextView {

    public LocalizedTextView(Context context) {
        super(context);
        init(null, 0);
    }

    public LocalizedTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(attrs, 0);
    }

    public LocalizedTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(attrs, defStyle);
    }

    private void init(AttributeSet attrs, int defStyle) {

        // Load attributes
        final TypedArray typedArray = getContext().obtainStyledAttributes(
                attrs, R.styleable.LocalizationAttributes, defStyle, 0);

        // get the locText value that might be set in the xml
        String localizedString = typedArray.getString(
                R.styleable.LocalizationAttributes_locText);

        typedArray.recycle();

        if (localizedString != null) {

            setLocalizedText(localizedString);

        }

    }

    /**
     * Sets the text to the text being saved into SharedPreferences with the given key
     */
    public void setLocalizedText(String key) {

        SharedPreferences settings = getContext().getSharedPreferences("localization_strings_file", 0);

        // fetch the localized string with the given key (that is set in XML)
        // and set it to the text view, or set an empty String
        setText(settings.getString(key, ""));

    }

}

I uploaded the source project here for you.


 

Homework:

As an exercise and also improvement, you could create a new attribute called language that could store the language prefix in strings. This way you can remove the string you added in the xml and replace it with just the key for the resource.
After that you could fetch the value of that in your custom TextView and append the language prefix attribute value to the key attribute value to form the final key that you use to load the resource from the SharedPreferences.

This way you have to write only one string resource under the strings.xml file.

Cheers!

 

 

 

 

 

 

Exit mobile version