2013-07-21 25 views
23

使用例:ユーザーに表示されるエラーメッセージを記録します。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を使用して達成できますか?

+0

こんにちは、あなたはどんな解決策を得たのですか?私もほとんど同じユースケースを持っています。 – Nitish

+0

いいえ、私はまだ質問 – schnatterer

+0

に記載された回避策を使用していますが、ロギング目的に特定の英語ベースの文字列を使用しない理由は何ですか。 R.string.dev_error_clicking_button_b。他の言語に翻訳していない場合は、デフォルトでこれを取得します。 –

答えて

10

あなたは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):Check this article

+0

これは現在のロケールを変更せずに確認できます。ついに解決!少なくともAPI 17+の場合 – schnatterer

+0

@schnatterer古いバージョンをサポートするようにビルドバージョンを確認することができます。if(Build.VERSION.SDK_INT> = Build.VERSION_CODES.JELLY_BEAN_MR1) getStringByLocal(context、resId、locale); else return getStringByLocalBefore17(context、resId、locale); ' –

3

あなたはアプリを起動したときに実行されることApplicationのように、グローバルクラスの内部Mapでデフォルトロケールのすべての文字列を保存することができます:

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); 
    } 

} 

このソリューションは最適ではありませんが、あなたはしません並行性に問題があります。

+0

別の回避策を提案してくれてありがとう!これはトレードオフです:並行性の問題とメモリ使用量の増加とアプリケーションの起動の遅れに対する対称性の問題はありません。しかし、私の特定のユースケースでは、ほとんどの場合リソースを必要としません(エラー/例外のログのみ)。だからマップを作成し、最初にメモリに保存しておくと、ここではあまりにも多くの労力がかかるようです。 – schnatterer

+1

これらのエラー/例外に対して実際に使用している文字列リソースの数によって異なります。サブセットが小さい場合は、おそらくあなたはそれで暮らすことができます。別のアプローチ(アプローチDを回避する)は、一時的にこれらのリソースをtmpファイルに保存し、必要に応じてそれらにアクセスすることです。このアプローチでは余分なメモリを使用する必要はなく、ニーズに合わせることができます。 –

+0

回避策を見つけるのは本当に創造的です! +1);あなたの努力に感謝 - しかし、私はまだ誰かが解決策ではない解決策を提示してほしいと思っています – schnatterer

-2

これを試してみてください:

Configuration conf = getResources().getConfiguration(); 
    conf.locale = new Locale("ar"); // locale I used here is Arabic 

    Resources resources = new Resources(getAssets(), getResources().getDisplayMetrics(), conf); 
    /* get localized string */ 
    String appName = resources.getString(R.string.app_name); 
+0

何かが見つからないのでしょうか、あなたのアプローチと質問の違いはありませんか? getResources()、getResources()、getResources()。getConfiguration())。getString(R.string.app_name); '文字列はアラビア語で表示されます。以前は言語が違っていた!私は、次のユースケースの解決策を探しています:あなたのデバイスは中国語ですが、ログはデフォルトの(例えば英語)メッセージを出力するはずです。 – schnatterer

+2

'new resources'を呼び出すことは' AssetManager'の設定を変更することに注意してください。これは後で無関係なコードセクションで問題を引き起こします。この[質問](http://stackoverflow.com/questions/18984397/android-is-taking-wrong-layout-on-inflating-view)と[answer](http://stackoverflow.com/a/20522668)を参照してください。/262789)を参照してください。 – Benjamin

0

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); 
} 
関連する問題