Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Managing Android Application Resources and Localization

Tech 2

Resource Directory Structure

Android projects organize non-code assets into specific subdirectories within the res/ folder. The build system optimizes these assets, and you access them via unique resource IDs generated in the R class.

DirectoryResource Type
animator/XML files defining property animations.
anim/XML files defining tween animations.
color/XML files defining color state lists.
drawable/Bitmaps (.png, .9.png, .jpg, .gif) or XML drawables (shapes, layers, selectors).
mipmap/Launcher icon assets for different densities.
layout/XML files defining UI structure.
menu/XML files defining application menus (options, context, submenus).
raw/Arbitrary files to be opened as a raw input stream (e.g., audio, video).
values/XML files containing simple values (strings, colors, dimensions, styles). Multiple resources can be defined in one file.
xml/Arbitrary XML configuration files read at runtime.
font/Font files (.ttf, .otf) or XML font family definitions.

Note: Do not place resource files directly into the res/ root directory; it will cause a compilation error.

Configuration Qualifiers

Directory names can be modified with configuration qualifiers to allow the system to load the most appropriate resources based on the current device state. The naming convention follows the pattern: <resources_name>-<config_qualifier>.

ConfigurationQualifier ExamplesDescription
MCC and MNCmcc310
mcc310-mnc004
Mobile Country Code and Mobile Network Code from the SIM card.
Language and Regionen
fr-rCA
b+es+419
Two-letter ISO 639-1 language code, optionally followed by a region code. Android 7.0+ supports BCP 47 tags (e.g., b+es+419).
Layout Directionldrtl
ldltr
ldrtl for right-to-left layouts, ldltr for left-to-right (default).
Smallest Widthsw600dpThe minimum width of the screen available to the layout, regardless of orientation.
Available Widthw720dpThe current minimum available width, changing with orientation.
Available Heighth1024dpThe current minimum available height, changing with orientation.
Screen Sizesmall
normal
large
xlarge
Generalized screen size buckets based on physical dimensions.
Screen Aspectlong
notlong
Widescreen aspect ratio versus non-widescreen.
Screen Shaperound
notround
Circular screens (wearables) versus standard rectangular screens.
Wide Color Gamutwidecg
nowidecg
Display capability for wide color gamuts (P3, AdobeRGB) or standard sRGB.
Dynamic Rangehighdr
lowdr
High Dynamic Range (HDR) versus Standard Dynamic Range.
Orientationport
land
Portrait or landscape orientation.
UI Modecar
desk
television
watch
The device is docked in a car, desk, or presenting on a TV, or is a wearable.
Night Modenight
notnight
Whether night mode is active.
Screen Densityldpi
hdpi
xhdpi
xxhdpi
xxxhdpi
nodpi
Density of the screen. nodpi prevents scaling.
Touchscreennotouch
finger
Absence of touch or primary finger interaction.
Keyboard Availabilitykeysexposed
keyshidden
Visibility status of a physical or software keyboard.
Primary Inputnokeys
qwerty
12key
Type of hardware keyboard available.
Navigationnavexposed
navhidden
Availability of navigation keys.
Navigation Methodnonav
dpad
trackball
Primary non-touch navigation method.
API Versionv21Minimum API level supported by the resource.

Handling Configuration Changes

When configuration changes occur (such as screen rotation), the default behavior is to destroy and recreate the Activity. To persist UI data across these changes efficiently, modern Android development relies on using ViewModel objects.

Localization and Locale Detection

To adapt the application to different languages, developers can retrieve the current system locale via the Context configuration.

Java Implementation

Configuration sysConfig = context.getResources().getConfiguration();
Locale primaryLocale = sysConfig.getLocales().get(0);
String userLocale = primaryLocale.getDisplayName();

Kotlin Implementation

val primaryLocale: Locale = context.resources.configuration.locales[0]
val userLocale: String = primaryLocale.displayName

Testing with Pseudolocales

Pseudolocales allow developers to test UI layouts for potential expansion issues caused by string translations. Enable this in your build.gradle file:

android {
    buildTypes {
        debug {
            pseudoLocalesEnabled true
        }
    }
}

Unicode and Internationalization (ICU)

Starting with Android 7.0 (API level 24), the framework utilizes the android.icu library for comprehensive Unicode and internationalization support. Older versions relying on com.ibm.icu should migrate to the native Android package.

Legacy ClassAndroid ICU Replacement
java.lang.Characterandroid.icu.lang.UCharacter
java.text.BreakIteratorandroid.icu.text.BreakIterator
java.text.DecimalFormatandroid.icu.text.DecimalFormat
java.util.Calendarandroid.icu.util.Calendar
android.text.format.DateFormatandroid.icu.text.DateFormat

Note that android.icu does not automatically respect the user's 12/24-hour preference. You must manually apply the skeleton:

boolean is24Hour = android.text.format.DateFormat.is24HourFormat(context);
String timeSkeleton = is24Hour ? "Hm" : "hm";

android.icu.text.DateFormat formatter = android.icu.text.DateFormat.getInstanceForSkeleton(timeSkeleton, Locale.getDefault());
String resultTime = formatter.format(new Date());
val is24Hour = android.text.format.DateFormat.is24HourFormat(context)
val timeSkeleton = if (is24Hour) "Hm" else "hm"

val formatter = android.icu.text.DateFormat.getInstanceForSkeleton(timeSkeleton, Locale.getDefault())
val resultTime = formatter.format(Date())

Transliteration

Android 10 (API level 29) introduced the Transliterator API. This utility converts text from one script to another (e.g., Latin to Cyrillic). Developers should verify available IDs using Transliterator.getAvailableIDs() before usage, as IDs vary by device manufacturer.

Resource Resolution Strategy

The Android runtime attempts to find the most specific resource match. If an exact match is not found (e.g., requesting es-MX when only es-ES exists), it may fall back to a less specific qualifier. If no match is found, it defaults to the resource set without qualifiers.

To improve matching accuracy, especially for region-agnostic languages, use BCP 47 language tags. For instance, move generic Spanish resources to values-b+es+419 (Latin American Spanish) rather than a specific country code. Furthermore, API 24+ allows querying the user's full preferred language list via LocaleList.getDefault() for more granular control.

Animated Vector Drawables

Historically, creating an animated vector drawable required three separate XML files: a vector drawable, an animator, and an animated-vector XML linking them.

Modern Android tooling allows consolidating these into a single XML file using inline resources via the aapt:attr namespace. This reduces file clutter and simplifies asset management.

Consolidated Example (AVD):

<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:aapt="http://schemas.android.com/aapt">

    <!-- Inline Vector Definition -->
    <aapt:attr name="android:drawable">
        <vector
            android:width="100dp"
            android:height="100dp"
            android:viewportWidth="100"
            android:viewportHeight="100">

            <group
                android:name="scaleGroup"
                android:pivotX="50"
                android:pivotY="50">
                <path
                    android:fillColor="#FF5722"
                    android:pathData="M50,50 L50,20 A30,30 0 1,1 50,80 A30,30 0 1,1 50,20 Z" />
            </group>
        </vector>
    </aapt:attr>

    <!-- Inline Animation Target -->
    <target android:name="scaleGroup">
        <aapt:attr name="android:animation">
            <objectAnimator
                android:duration="2000"
                android:propertyName="scaleX"
                android:valueFrom="1"
                android:valueTo="1.5"
                android:valueType="floatType"
                android:repeatCount="-1"
                android:repeatMode="reverse" />
        </aapt:attr>
    </target>
</animated-vector>

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.