Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reference String Resource in custom XML Resource

In the assets folder of my Android App Project I am storing custom XML files which describe actions in my game. Since they are a little more complex, they can not be directly written as Android Resources.

Update: I am storing my custom (complex) XML files in the res/xml folder now.

Simple Example:

<dialog>
    <npc>1</npc>
    <text>Hello! How are you?</text>
</dialog>

What I want is to use the convenient advantages of Android String resources for language localisation. In the example above, I want to save Hello! How are you? in my res/values/strings.xml and then reference this somehow like this:

<text>@string/dialog_1_text</text>

I do not want to create different language res/xml folders where I copy all xml files and translate them completely. I only want parts of it to be translated. Easily by referencing a String resource.

Update 2: I have now found out that the XMLParser that you get from Resource.getXml() has a method called getAttributeResourceValue() which converts an attribute like randomAtt="@string/random_string" automatically to an actual Resource ID.
However, in the XML file, there still is no clear dependency and there is no preview for the string or a warning when you put in an invalid resource. But - since there even is a method for that - I strongly believe that it is possible to let the validator only allow string resources in some custom attributes.

like image 966
Tobias Baumeister Avatar asked Dec 25 '22 08:12

Tobias Baumeister


1 Answers

Okay, so after a lot of research in the past two hours, I finally found a very well working solution. I have seen a few threads which ask very similar questions - that's why I am sure this answer might help some programmers in the future.

Requirements:
The requirements for my task were the following: Referencing String Resources in a custom XML file with my own schema, stored in the res/xml directory. The XML Validator of Android Studio should automatically detect it as a String resource, print a warning when it is invalid - and preview the actual String when it is a valid resource. Also it should be as performant as possible.

Solution:
And this is how I solved it:
Instead of putting the string resource between the tags, I had to put them as an attribute. No big deal in my case.
And for the validator to recognize them as String resource, I had to call these attributes text from the android namespace: Update: I found out that you can call the attribute whatever you like, and it is not necessary to include the android namespace.

<main>
    <nested>
        <test myText="@string/lorem_ipsum_100"/>
    </nested>
</main>

(Your custom XML may look as whatever you like/need! This is just an example - it works with unlimited nested tags and your own defined schema.)

I didn't think this was gonna work - but it actually does quite well! Whenever I hit Build project, it prints out a warning when I used an invalid String resource.
And not only that, it also previews it as desired: String preview in Android Studio

(Note: This screenshot was made before I noticed that you can call the attribute whatever you want/need. There is no need to call it explicitely android:text. Android Studio will automatically recognize it as a string resource, as long as you put @string/....)

Now last but not least, to let your Java code interpret the resource correctly, you have to do this:

XmlResourceParser parser = getResources().getXml(R.xml.tutorial_welcome_dialog);
try {
    while (parser.next() != XmlPullParser.END_DOCUMENT) {
        if (parser.getEventType() == XmlPullParser.START_TAG && parser.getName().equals("test")) {
            String s;
            for (int i = 0; i < parser.getAttributeCount(); i++) {
                if (parser.getAttributeName(i).equals("text"))
                    s = getResources().getString(parser.getAttributeResourceValue(i, -1));
            }
        }

    }
} catch (Exception e) {
    e.printStackTrace();
}

Performance note: As far as I can see, this solution is also super performant, since android pre-parses the @string/... automatically into Resource IDs.

like image 95
Tobias Baumeister Avatar answered Jan 06 '23 03:01

Tobias Baumeister