I have several html files in assets folder. How can I localize them? Is my only option to put some hardcode to pick the right file based on locale?
-
1I need to use assets because embedded images in html won't work from raw resources. If it is a simple html, raw is the way to go. here is tutorial for people who might be curious how to read html from raw monocube.com/2011/02/08/android-tutorial-html-file-in-webview – mishkin Sep 25 '14 at 03:04
6 Answers
This isn't supported directly but here is what I have done...
Separate your files into groups by country code (like what you would do for normal resource files) and then create a localized string in each of your localized string.xml files called something like "prefix" (where prefix would be "en" for English for example).
Then when you build your asset filenames simple use something like getString("prefix") + "-" + "<name-of-asset->
.
At least some variation of the above should work for you.

- 52,720
- 19
- 113
- 137
-
16thanks! improving your idea a bit, I can use Locale.getLanguage().substring(0, 2).toLowerCase() to get that prefix so I do not need to add prefix var to string.xml – mishkin Mar 25 '11 at 03:04
-
10Note that `getLanguage().substring(0, 2)` is not a versitle method in android because `zh-rTW` (taiwanese a.k.a traditional chinese. `zh` is simplified chinese) cannot be handled. – Youngjae Dec 22 '13 at 11:39
-
3Excellent solution. I'm using a variation of this to put things under assets/en/..., assets/es/..., etc. A nice thing is that if you have the prefix defined in your strings.xml, you know the directory will exist in assets (so long as you make the dir each time you add a new localized version of strings.xml). I'm using this to localize not only html but some other assets too. – mkasberg Jun 29 '15 at 00:19
-
2I use Locale.getDefault().getLanguage() to get prefix since Locale.getLanguage() is not working. – Plugie Jan 26 '17 at 04:25
-
+1 to mkasberg, this solution assures that the files you are using in your assets dir always corresponds to the strings.xml file you are using. – Lyck Mar 28 '18 at 22:51
Put your files into the assets folder with local suffix. Define a String resource 'myLocalizedFileName' for every file and get the filename via R.string.myLocalizedFileName.
Example:
Folder structure:
assets/
assets/help.html
assets/help_de.htlm
String resources for every language in res/values/strings.xml:
<resource>
<string name=helpFile>help.html</string>
</resource>
WebView calling:
public class HelpActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
...
findViewById(R.id.helpWebView)
.loadUrl("file:///android_asset/"
+ getString(R.string.helpFile));
}
}

- 1,431
- 1
- 18
- 15
-
-
-
1@Shadow first its help_de.html and Secondly, this is how it will work open Translations Editor in Default Value you have help.html and in de language, you just have to write help_de.html. That's it.It is working for you. – Waheed Akhtar Jul 26 '17 at 02:13
-
But what about use raw resources holder, and then you don't need handle localization stuff https://developer.android.com/reference/android/content/res/Resources.html#openRawResource(int) – user1221256 Mar 23 '18 at 08:26
If you want to localize a HTML file you can simply put it under res/raw-<language>/filename.html (where <language>=en, es, fr, it, etc.) then access it from your code with the resource ID R.raw.filename. The framework will pick the right file according to the locale.

- 1,981
- 1
- 20
- 17
-
1see my comment above about embedded images in HTML - that's why I could not use resources – mishkin Sep 25 '14 at 03:05
-
1
-
Works great for txt files as well... getResources().openRawResource(R.raw.filename) – Veener Feb 28 '17 at 16:00
An alternative to using one file per country code (as described in Andrew White's and PJ_Finnegan's answers) is to define the HTML only once (e.g. in the assets
folder) and use @string
IDs in it, like so
<html>
<body>
<p>@string/message_text</p>
</body>
</html>
After loading the asset into a string you could pass its content to 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());
}
The nice thing about this approach is that you have to specify the structure of the HTML only once and use android's localization mechanism. In addition, it allows recursively referencing strings in strings.xml, which is not supported by Context.getResources()
. For example:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="message_text">Some string @string/another_one.</string>
</resources>
The downside is that the parsing is done at runtime, so specifying a dedicated HTML for each language has a better performance when used within the app.
For an example that uses this code to convert HTML from an asset file to a "stylable" CharSequence
(using Kuitsi's TagHandler) that can be displayed in a TextView
see TextUtil
.

- 1
- 1

- 7,525
- 7
- 61
- 80
Putting files in raw-LOCALE folder will automatically pick the right location, but if you load those files in webView paths will be broken after obfuscation using Proguard.
Proguard Breaks Android WebView, Why?
Then the only solution is to use assets folder and use file-LOCALE and pick up right files.
Trying to localize with assets-ja
will not work, because sadly these aren't resource files. The best option is to localize programmatically, with the right locale. Alternatively, the content of a HTML file is just plain text. If it fits with your project you can try storing this string as an entry in the strings.xml
(or your own myHtmlText.xml
?) file of a new values-ja
folder, for example.

- 30,811
- 34
- 116
- 155
-
4I need to use assets because embedded images in html won't work from raw. but you are right if it is a simple html, raw is the way to go. here is tutorial for people who might be curious how to read html from raw http://www.monocube.com/2011/02/08/android-tutorial-html-file-in-webview/ – mishkin Mar 25 '11 at 03:07