web-dev-qa-db-ja.com

アセットファイルのローカライズ

アセットフォルダーにいくつかのhtmlファイルがあります。どうすればローカライズできますか?ロケールに基づいて適切なファイルを選択するためのハードコードを配置する唯一のオプションはありますか?

50
mishkin

これは直接サポートされていませんが、これが私が行ったことです...

国コードでファイルをグループに分け(通常のリソースファイルの場合と同じように)、ローカライズされたstring.xmlファイルのそれぞれにローカライズされた文字列を作成します。例えば)。

次に、アセットのファイル名を作成するときに、getString("prefix") + "-" + "<name-of-asset->のようなものを使用します。

上記の少なくともいくつかのバリエーションはあなたのために働くはずです。

57
Andrew White

HTMLファイルをローカライズしたい場合は、単純にres/raw- <language> /filename.html(ここで<language> = en、es、fr、itなど)に配置できます。コードからリソースID R.raw.filenameでアクセスします。フレームワークは、ロケールに応じて適切なファイルを選択します。

31
PJ_Finnegan

ローカルサフィックスが付いたアセットフォルダにファイルを配置します。すべてのファイルに対して文字列リソース「myLocalizedFileName」を定義し、R.string.myLocalizedFileNameを介してファイル名を取得します。

例:

フォルダー構造:

assets/
assets/help.html
assets/help_de.htlm

Res/values/strings.xmlのすべての言語の文字列リソース:

<resource>
  <string name=helpFile>help.html</string>
</resource>

WebView呼び出し:

public class HelpActivity extends AppCompatActivity {
  protected void onCreate(Bundle savedInstanceState) {
    ...
    findViewById(R.id.helpWebView)
      .loadUrl("file:///Android_asset/" 
         + getString(R.string.helpFile));
  }
}

Raw-LOCALEフォルダーにファイルを置くと、適切な場所が自動的に選択されますが、それらのファイルをwebViewパスにロードすると、Proguardを使用して難読化した後に壊れます。

Proguard Breaks Android WebView、なぜ?

次に、唯一の解決策は、assetsフォルダーを使用し、file-LOCALEを使用して正しいファイルを取得することです。

2
jogo

残念ながらこれらはリソースファイルではないため、assets-jaでローカライズしようとしても機能しません。最適なオプションは、適切なロケールを使用してプログラムでローカライズすることです。または、HTMLファイルのコンテンツはプレーンテキストです。プロジェクトに適合する場合は、この文字列をエントリとして、たとえば、新しいstrings.xmlフォルダのmyHtmlText.xml(または独自のvalues-ja?)ファイルに保存してみてください。

1
SK9

国コードごとに1つのファイルを使用する代わりの方法( Andrew White's および PJ_Finnegan's 回答で説明)は、HTMLを1回だけ定義することです(例:assetsフォルダ)、その中で_@string_ IDを使用します。

_<html>
<body>
    <p>@string/message_text</p>
</body>
</html>
_

アセットを文字列に読み込んだ後、その内容をreplaceResourceStrings()に渡すことができます。

_/**
 * Regex that matches a resource string such as <code>@string/a-b_c1</code>.
 */
private static final String REGEX_RESOURCE_STRING = "@string/([A-Za-z0-9-_]*)";

/** Name of the resource type "string" as in <code>@string/...</code> */
private static final String DEF_TYPE_STRING = "string";

/**
 * Recursively replaces resources such as <code>@string/abc</code> with
 * their localized values from the app's resource strings (e.g.
 * <code>strings.xml</code>) within a <code>source</code> string.
 * 
 * Also works recursively, that is, when a resource contains another
 * resource that contains another resource, etc.
 * 
 * @param source
 * @return <code>source</code> with replaced resources (if they exist)
 */
public static String replaceResourceStrings(Context context, String source) {
    // Recursively resolve strings
    Pattern p = Pattern.compile(REGEX_RESOURCE_STRING);
    Matcher m = p.matcher(source);
    StringBuffer sb = new StringBuffer();
    while (m.find()) {
        String stringFromResources = getStringByName(context, m.group(1));
        if (stringFromResources == null) {
            Log.w(Constants.LOG,
                    "No String resource found for ID \"" + m.group(1)
                            + "\" while inserting resources");
            /*
             * No need to try to load from defaults, Android is trying that
             * for us. If we're here, the resource does not exist. Just
             * return its ID.
             */
            stringFromResources = m.group(1);
        }
        m.appendReplacement(sb, // Recurse
                replaceResourceStrings(context, stringFromResources));
    }
    m.appendTail(sb);
    return sb.toString();
}

/**
 * Returns the string value of a string resource (e.g. defined in
 * <code>values.xml</code>).
 * 
 * @param name
 * @return the value of the string resource or <code>null</code> if no
 *         resource found for id
 */
public static String getStringByName(Context context, String name) {
    int resourceId = getResourceId(context, DEF_TYPE_STRING, name);
    if (resourceId != 0) {
        return context.getString(resourceId);
    } else {
        return null;
    }
}

/**
 * Finds the numeric id of a string resource (e.g. defined in
 * <code>values.xml</code>).
 * 
 * @param defType
 *            Optional default resource type to find, if "type/" is not
 *            included in the name. Can be null to require an explicit type.
 * 
 * @param name
 *            the name of the desired resource
 * @return the associated resource identifier. Returns 0 if no such resource
 *         was found. (0 is not a valid resource ID.)
 */
private static int getResourceId(Context context, String defType,
        String name) {
    return context.getResources().getIdentifier(name, defType,
            context.getPackageName());
}
_

このアプローチの良い点は、HTMLの構造を一度だけ指定し、 Androidのローカリゼーションメカニズム を使用する必要があることです。さらに、strings.xmlで文字列を再帰的に参照できます。これは Context.getResources() ではサポートされていません。例えば:

_<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="message_text">Some string @string/another_one.</string>
</resources>
_

欠点は、解析が実行時に行われるため、各言語に専用のHTMLを指定すると、アプリ内で使用したときにパフォーマンスが向上することです。

このコードを使用してHTMLをアセットファイルから "スタイル可能な" CharSequenceに変換する例(_ KuitsiのTagHandler を使用)は、TextViewに表示できます。 TextUtil

1
schnatterer