34

At one point in one of my Android apps I need to load strings of a specific language. For example:

 values:    <string name="txt_help">Help</string>
 values-de: <string name="txt_help">Hilfe</string>
 values-fr: <string name="txt_help">Aider</string>

Now I need the default (values) text.

Is there a way to load the key "txt_help" with a given language "en"? I can't find a method where I can set a locale as an additional parameter.

Or can I create a new ResourceManager with a given locale and read the String through this resource object?

Many thanks in advance. hjw

5
  • Maybe this helps you: developer.android.com/resources/tutorials/localization/… Commented Mar 9, 2011 at 11:24
  • 1
    Thanks, but this is not what I'm looking for. Our apps are localized already but at one single part we want to read the strings from the default strings.xml even if there are localized strings available. Commented Mar 10, 2011 at 16:03
  • 1
    Have you tried creating a new Resources object providing it a Configuration with the locale field set to the Locale that you want? Commented Jun 17, 2011 at 0:01
  • Can you please, show us your manifest. In particular the uses-sdk / target-sdk part. I got the same issue with <uses-sdk android:minSdkVersion="8" /> running on 4.x. Commented Mar 26, 2014 at 11:25
  • Bug Report: Please START IT. code.google.com/p/android/issues/detail?id=67672 Commented Mar 26, 2014 at 11:29

2 Answers 2

47
+50

Looking in the documentation, this looks promising:

Resources standardResources = context.getResources();
AssetManager assets = standardResources.getAssets();
DisplayMetrics metrics = standardResources.getDisplayMetrics();
Configuration config = new Configuration(standardResources.getConfiguration());
config.locale = Locale.US;
Resources defaultResources = new Resources(assets, metrics, config);

In other words, create a new Resources object configured to a standard locale.

Sign up to request clarification or add additional context in comments.

7 Comments

Very close... what's weird is that the Resources defaultResources = new Resources(assets, metrics, config); line seems to change something so that after that's called, getResources() returns the new locale that I custom set here... any clue why that would happen? I guess I can always just re-set config.locale back to the original; but I don't understand how creating a new Resources object could cause my standard getResources() to change.
@GendoIkari: It looks like you're right. The problem is that a Resources object internally pushes its configuration (including the locale) down to the underlying AssetManager object, so it's the AssetManager underlying both Resources objects that is getting changed. Unfortunately, there doesn't seem to be any documented way to clone or create a new AssetManager, just to retrieve the existing AssetManager. So it looks like we're stuck with changing the configuration before fetching the resource and then changing it back after.
Interesting... thanks. I messed with the code a little so that now I just call the new Resources(assets, metrics, config); constructor; not need to even set it to a variable. I just set the config; call the constructor; get my strings; then set the config back and call the constructor again. It works. Thanks again!
@GendoIkari: For that matter, you can just call updateConfiguration on the existing Resources object.
@Anomie: You'd think so... just tested it; and got some extremely weird behavior. When I use new Resources(assets, metrics, config); to set the config; it works. When I use res.updateConfiguration(config, metrics); the app freezes... doesn't crash; just goes dim; after which I can hit "back" but then all the displays are drawn incorrectly.
|
1

From my own question and taking reference from this answer and this answer, I came up with the following custom class solution:

package com.my.package.localisation;

import android.content.Context;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.support.annotation.NonNull;
import android.util.DisplayMetrics;

import java.util.Formatter;
import java.util.Locale;

/**
 * Class to manage fetching {@link Resources} for a specific {@link Locale}. API levels less
 * than {@link Build.VERSION_CODES#JELLY_BEAN_MR1} require an ugly implementation.
 * <p/>
 * Subclass extends {@link Resources} in case of further functionality requirements.
 */
public class MyResources {

    private final Context mContext;
    private final AssetManager assetManager;
    private final DisplayMetrics metrics;
    private final Configuration configuration;
    private final Locale targetLocale;
    private final Locale defaultLocale;

    public MyResources(@NonNull final Context mContext, @NonNull final Locale defaultLocale,
                         @NonNull final Locale targetLocale) {

        this.mContext = mContext;
        final Resources resources = this.mContext.getResources();
        this.assetManager = resources.getAssets();
        this.metrics = resources.getDisplayMetrics();
        this.configuration = new Configuration(resources.getConfiguration());
        this.targetLocale = targetLocale;
        this.defaultLocale = defaultLocale;
    }

    public String[] getStringArray(final int resourceId) {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            configuration.setLocale(targetLocale);
            return mContext.createConfigurationContext(configuration).getResources().getStringArray(resourceId);
        } else {
            configuration.locale = targetLocale;
            final String[] resourceArray = new ResourceManager(assetManager, metrics, configuration).getStringArray(resourceId);
            configuration.locale = defaultLocale; // reset
            new ResourceManager(assetManager, metrics, configuration); // reset
            return resourceArray;
        }
    }

    public String getString(final int resourceId) {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            configuration.setLocale(targetLocale);
            return mContext.createConfigurationContext(configuration).getResources().getString(resourceId);
        } else {
            configuration.locale = targetLocale;
            final String resource = new ResourceManager(assetManager, metrics, configuration).getString(resourceId);
            configuration.locale = defaultLocale; // reset
            new ResourceManager(assetManager, metrics, configuration); // reset
            return resource;
        }
    }

    private final class ResourceManager extends Resources {
        public ResourceManager(final AssetManager assets, final DisplayMetrics metrics, final Configuration config) {
            super(assets, metrics, config);
        }

        /**
         * Return the string array associated with a particular resource ID.
         *
         * @param id The desired resource identifier, as generated by the aapt
         *           tool. This integer encodes the package, type, and resource
         *           entry. The value 0 is an invalid identifier.
         * @return The string array associated with the resource.
         * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
         */
        @Override
        public String[] getStringArray(final int id) throws NotFoundException {
            return super.getStringArray(id);
        }

        /**
         * Return the string value associated with a particular resource ID,
         * substituting the format arguments as defined in {@link Formatter}
         * and {@link String#format}. It will be stripped of any styled text
         * information.
         * {@more}
         *
         * @param id         The desired resource identifier, as generated by the aapt
         *                   tool. This integer encodes the package, type, and resource
         *                   entry. The value 0 is an invalid identifier.
         * @param formatArgs The format arguments that will be used for substitution.
         * @return String The string data associated with the resource,
         * stripped of styled text information.
         * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
         */
        @NonNull
        @Override
        public String getString(final int id, final Object... formatArgs) throws NotFoundException {
            return super.getString(id, formatArgs);
        }

        /**
         * Return the string value associated with a particular resource ID.  It
         * will be stripped of any styled text information.
         * {@more}
         *
         * @param id The desired resource identifier, as generated by the aapt
         *           tool. This integer encodes the package, type, and resource
         *           entry. The value 0 is an invalid identifier.
         * @return String The string data associated with the resource,
         * stripped of styled text information.
         * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
         */
        @NonNull
        @Override
        public String getString(final int id) throws NotFoundException {
            return super.getString(id);
        }
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.