---
title: "How do I use a percent sign in Android strings.xml?"
description: "Write `%%` when the string is formatted with arguments through `getString(id, args)` or Compose's `stringResource(id, args)`. A string that is never formatted can keep a plain `%`; add `formatted=\"false\"` when aapt2 warns about multiple non-positional substitutions."
category: android
date: 2026-10-09
canonical: https://localizely.com/i18n-questions/android/how-do-i-use-a-percent-sign-in-android-strings-xml/
---

# How do I use a percent sign in Android strings.xml?

It depends on whether the string is a format string. If you pass arguments to it, write the percent sign as `%%`. If it is never formatted, a plain `%` is fine, and `formatted="false"` tells the resource compiler so.

Android only formats a resource when you pass arguments: `getString(R.string.discount, 20)` and Compose's `stringResource(R.string.discount, 20)` run the text through `String.format()`, where `%` starts a format specifier and `%%` produces a literal percent sign. `getString(R.string.progress_done)` without arguments returns the raw text and does not look at `%` at all.

```xml
<!-- Formatted: getString(R.string.discount, 20) gives "Save 20% today" -->
<string name="discount">Save %1$d%% today</string>

<!-- Never formatted: getString(R.string.progress_done) gives "100% done" -->
<string name="progress_done">100% done</string>
```

The resource compiler checks every translatable string that is not marked `formatted="false"`. When it finds more than one substitution and at least one of them has no position index, it reports `multiple substitutions specified in non-positional format; did you mean to add the formatted="false" attribute?`. A `%` followed by a space or a letter counts as a substitution, so text such as "Save 50% on shoes and 70% on hats" triggers it even though it is not meant to be formatted. The Android Gradle plugin passes `--legacy` to aapt2, so today this is a warning in the build output; the original aapt failed the build on it. For a string that is not a format string, mark it:

```xml
<string name="sale" formatted="false">Save 50% on shoes and 70% on hats</string>
```

For a real format string, fix the string instead: give every placeholder a position (`%1$s`, `%2$d`) and write `%%` for the literal sign. Positions are required as soon as there is more than one placeholder, and they let translators reorder the arguments in languages with a different word order.

Pitfalls:

- `formatted="false"` only silences the compile-time check. If you still call `getString(id, args)` on that string, `String.format()` runs and a lone `%` throws an `IllegalFormatException`.
- Strings marked `translatable="false"` are not checked either, so a broken format string there only fails at runtime.
- Translators sometimes change `%%` back to `%`. Check translated files for it before a release.

Reference: the [Format strings](https://developer.android.com/guide/topics/resources/string-resource) section of the Android string resource guide and the [`java.util.Formatter`](https://docs.oracle.com/javase/8/docs/api/java/util/Formatter.html) syntax.

Source: https://localizely.com/i18n-questions/android/how-do-i-use-a-percent-sign-in-android-strings-xml/
