web-dev-qa-db-fra.com

localisation des fichiers d'actifs

J'ai plusieurs fichiers html dans le dossier assets. Comment puis-je les localiser? Est-ce que ma seule option est de mettre du code dur pour choisir le bon fichier en fonction des paramètres régionaux?

50
mishkin

Ce n'est pas pris en charge directement, mais voici ce que j'ai fait ...

Séparez vos fichiers en groupes par code de pays (comme ce que vous feriez pour des fichiers de ressources normaux), puis créez une chaîne localisée dans chacun de vos fichiers string.xml localisés appelée quelque chose comme "prefix" (où préfixe serait "en" pour l'anglais par exemple).

Ensuite, lorsque vous créez les noms de fichiers de vos ressources, utilisez simplement quelque chose comme getString("prefix") + "-" + "<name-of-asset->.

Au moins une variation de ce qui précède devrait fonctionner pour vous.

57
Andrew White

Si vous souhaitez localiser un fichier HTML, vous pouvez simplement le placer sous res/raw- <language> /filename.html (où <language> = en, es, fr, it, etc.) puis accédez-y à partir de votre code avec l'ID de ressource R.raw.filename. Le framework choisira le bon fichier en fonction des paramètres régionaux.

31
PJ_Finnegan

Placez vos fichiers dans le dossier des ressources avec le suffixe local. Définissez une ressource de chaîne "myLocalizedFileName" pour chaque fichier et obtenez le nom de fichier via R.string.myLocalizedFileName.

Exemple:

Structure des dossiers:

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

Ressources de chaîne pour chaque langue dans res/values ​​/ strings.xml:

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

Appels WebView:

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

Placer des fichiers dans le dossier raw-LOCALE choisira automatiquement le bon emplacement, mais si vous chargez ces fichiers dans les chemins webView seront rompus après l'obscurcissement à l'aide de Proguard.

Proguard Breaks Android WebView, pourquoi?

Ensuite, la seule solution consiste à utiliser le dossier des ressources et à utiliser file-LOCALE et à récupérer les bons fichiers.

2
jogo

Essayer de localiser avec assets-ja ne fonctionnera pas, car ce ne sont malheureusement pas des fichiers de ressources. La meilleure option consiste à localiser par programme, avec les paramètres régionaux appropriés. Alternativement, le contenu d'un fichier HTML est simplement du texte brut. S'il correspond à votre projet, vous pouvez essayer de stocker cette chaîne en tant qu'entrée dans le strings.xml (ou votre propre myHtmlText.xml?) fichier d'un nouveau values-ja dossier, par exemple.

1
SK9

Une alternative à l'utilisation d'un fichier par code de pays (comme décrit dans Andrew White's et PJ_Finnegan's réponses) est de définir le HTML une seule fois (par exemple dans les assets dossier) et utilisez @string ID, comme ceci

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

Après avoir chargé l'actif dans une chaîne, vous pouvez transmettre son contenu à 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());
}

La bonne chose à propos de cette approche est que vous devez spécifier la structure du HTML une seule fois et utiliser mécanisme de localisation d'Android . De plus, il permet de référencer récursivement des chaînes dans strings.xml, ce qui n'est pas pris en charge par Context.getResources() . Par exemple:

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

L'inconvénient est que l'analyse est effectuée au moment de l'exécution, donc la spécification d'un HTML dédié pour chaque langue a de meilleures performances lorsqu'elle est utilisée dans l'application.

Pour un exemple qui utilise ce code pour convertir le HTML d'un fichier d'actif en un "stylable" CharSequence (en utilisant TagHandler de Kuitsi ) qui peut être affiché dans un TextView voir TextUtil .

1
schnatterer