---
title: "Should I use en_US or en-US?"
description: "Use `en-US`. The hyphen is the BCP 47 form used by HTML `lang`, hreflang, `Accept-Language`, JavaScript `Intl` and Apple language IDs. The underscore `en_US` is the POSIX locale form that Java `Locale.toString()`, gettext and Android `values-en-rUS` use, so convert at those boundaries."
category: general
date: 2026-10-09
canonical: https://localizely.com/i18n-questions/general/should-i-use-en-us-with-underscore-or-en-us-with-hyphen/
---

# Should I use en_US or en-US?

Use `en-US`. The hyphen is the separator defined by BCP 47 ([RFC 5646](https://www.rfc-editor.org/rfc/rfc5646)), and that is the format expected by HTML `lang`, `hreflang`, the `Accept-Language` and `Content-Language` headers, the JavaScript `Intl` API, Apple language IDs (`en-GB.lproj`) and Flutter's `Locale.toLanguageTag()`.

The underscore comes from a different world. POSIX locale names have the form `language[_territory][.codeset][@modifier]`, for example `en_US.UTF-8`, and that convention carried over into tooling built on C locales: gettext names catalogs after `ll_CC` locale names such as `pt_BR`, Java's `Locale.toString()` prints `en_US`, and Android resource folders use their own variant, `values-en-rUS`. Apple keeps both: a language ID is `en-GB` (hyphen) while a locale ID for formatting conventions is `en_GB` (underscore).

So each form is correct in its own context. The practical rule: store and transmit BCP 47 tags everywhere you control (database columns, API payloads, config files, file names you choose yourself) and convert at the platform boundary. In Java the conversion is built in:

```java
Locale locale = Locale.forLanguageTag("en-US");
locale.toString();      // "en_US"  (debugging and legacy format)
locale.toLanguageTag(); // "en-US"  (BCP 47, for interchange)
```

The [Java docs](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Locale.html) describe `toString()` as a debugging and backward-compatibility format and point to `toLanguageTag()` for interchange. Flutter has the same pair: `Locale.toString()` gives `en_US` and `toLanguageTag()` gives `en-US`.

Casing is a convention rather than a rule: language subtags lowercase (`en`), script subtags title case (`Hant`), region subtags uppercase (`US`). RFC 5646 states that tags are case-insensitive, so `en-us` means the same as `en-US`, but file systems, string-keyed lookups and other developers often are case-sensitive. Normalize once (`Locale.forLanguageTag` does this for you) and write tags the conventional way.

Pitfalls:

- Comparing tags with plain string equality without normalizing case or separator, so `en_us` never matches `en-US`.
- Sending `en_US` in `Accept-Language` or `hreflang`; it is not a well-formed BCP 47 tag, so strict parsers reject or ignore it.
- Mixing both forms in file names (`messages_en_US.properties` next to `app-en-US.json`) and then writing the conversion in three places instead of one.

Source: https://localizely.com/i18n-questions/general/should-i-use-en-us-with-underscore-or-en-us-with-hyphen/
