web-dev-qa-db-ja.com

Android:現在のロケールを変更せずに特定のロケールで文字列を取得する方法

使用例:ユーザーに表示されるエラーメッセージのロギング。

ただし、ユーザーのデバイスのロケールに依存するメッセージをログに残したくない場合があります。一方、(技術的な)ログ記録のためだけにユーザーのデバイスのロケールを変更する必要はありません。これは達成できますか?私はここでstackoverflowでいくつかの潜在的な解決策を見つけました:

ただし、これらの結果、デバイスのロケールが変更されます(次の構成が変更されるまで)。

とにかく、私の現在の回避策はそうです:

public String getStringInDefaultLocale(int resId) {
    Resources currentResources = getResources();
    AssetManager assets = currentResources.getAssets();
    DisplayMetrics metrics = currentResources.getDisplayMetrics();
    Configuration config = new Configuration(
            currentResources.getConfiguration());
    config.locale = DEFAULT_LOCALE;
    /*
     * Note: This (temporiarily) changes the devices locale! TODO find a
     * better way to get the string in the specific locale
     */
    Resources defaultLocaleResources = new Resources(assets, metrics,
            config);
    String string = defaultLocaleResources.getString(resId);
    // Restore device-specific locale
    new Resources(assets, metrics, currentResources.getConfiguration());
    return string;
}

正直なところ、私はこのアプローチがまったく好きではありません。これは効率的ではなく、同時実行性などについて考えると、「間違った」ロケールで何らかのビューが表示される可能性があります。

だから-アイデアは?たぶんこれは、標準のJavaのように、 ResourceBundle sを使用して実現できますか?

36
schnatterer

これはAPI +17に使用できます

@NonNull
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public static String getStringByLocal(Activity context, int id, String locale) {
    Configuration configuration = new Configuration(context.getResources().getConfiguration());
    configuration.setLocale(new Locale(locale));
    return context.createConfigurationContext(configuration).getResources().getString(id);
}

更新(1):古いバージョンをサポートする方法。

@NonNull
public static String getStringByLocal(Activity context, int resId, String locale) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
        return getStringByLocalPlus17(context, resId, locale);
    else
        return getStringByLocalBefore17(context, resId, locale);
}

@NonNull
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private static String getStringByLocalPlus17(Activity context, int resId, String locale) {
    Configuration configuration = new Configuration(context.getResources().getConfiguration());
    configuration.setLocale(new Locale(locale));
    return context.createConfigurationContext(configuration).getResources().getString(resId);
}

private static String getStringByLocalBefore17(Context context,int resId, String language) {
    Resources currentResources = context.getResources();
    AssetManager assets = currentResources.getAssets();
    DisplayMetrics metrics = currentResources.getDisplayMetrics();
    Configuration config = new Configuration(currentResources.getConfiguration());
    Locale locale = new Locale(language);
    Locale.setDefault(locale);
    config.locale = locale;
/*
 * Note: This (temporarily) changes the devices locale! TODO find a
 * better way to get the string in the specific locale
 */
    Resources defaultLocaleResources = new Resources(assets, metrics, config);
    String string = defaultLocaleResources.getString(resId);
    // Restore device-specific locale
    new Resources(assets, metrics, currentResources.getConfiguration());
    return string;
}

更新(2):この記事を確認

29
Khaled Lela

アプリの起動時に実行されるMapのように、グローバルクラス内のApplicationにデフォルトロケールのすべての文字列を保存できます。

public class DualLocaleApplication extends Application {

    private static Map<Integer, String> defaultLocaleString;

    public void onCreate() {
        super.onCreate();
        Resources currentResources = getResources();
        AssetManager assets = currentResources.getAssets();
        DisplayMetrics metrics = currentResources.getDisplayMetrics();
        Configuration config = new Configuration(
                currentResources.getConfiguration());
        config.locale = Locale.ENGLISH;
        new Resources(assets, metrics, config);
        defaultLocaleString = new HashMap<Integer, String>();
        Class<?> stringResources = R.string.class;
        for (Field field : stringResources.getFields()) {
            String packageName = getPackageName();
            int resId = getResources().getIdentifier(field.getName(), "string", packageName);
            defaultLocaleString.put(resId, getString(resId));
        }
        // Restore device-specific locale
        new Resources(assets, metrics, currentResources.getConfiguration());
    }

    public static String getStringInDefaultLocale(int resId) {
        return defaultLocaleString.get(resId);
    }

}

このソリューションは最適ではありませんが、同時実行性の問題は発生しません。

4
Juan Sánchez

API +17の場合、これを使用できます。

public static String getDefaultString(Context context, @StringRes int stringId){
    Resources resources = context.getResources();
    Configuration configuration = new Configuration(resources.getConfiguration());
    Locale defaultLocale = new Locale("en");
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        LocaleList localeList = new LocaleList(defaultLocale);
        configuration.setLocales(localeList);
        return context.createConfigurationContext(configuration).getString(stringId);
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1){
        configuration.setLocale(defaultLocale);
        return context.createConfigurationContext(configuration).getString(stringId);
    }
    return context.getString(stringId);
}
0
Djek-Grif