Index: src/wp-admin/admin-header.php
===================================================================
--- src/wp-admin/admin-header.php	(revision 32993)
+++ src/wp-admin/admin-header.php	(working copy)
@@ -157,7 +157,8 @@
 $admin_body_class .= ' branch-' . str_replace( array( '.', ',' ), '-', floatval( $wp_version ) );
 $admin_body_class .= ' version-' . str_replace( '.', '-', preg_replace( '/^([.0-9]+).*/', '$1', $wp_version ) );
 $admin_body_class .= ' admin-color-' . sanitize_html_class( get_user_option( 'admin_color' ), 'fresh' );
-$admin_body_class .= ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
+$language_code = wp_get_html_language_code();
+$admin_body_class .= ' locale-' . strtolower( $language_code );
 
 if ( wp_is_mobile() )
 	$admin_body_class .= ' mobile';
Index: src/wp-admin/customize.php
===================================================================
--- src/wp-admin/customize.php	(revision 32993)
+++ src/wp-admin/customize.php	(working copy)
@@ -87,8 +87,10 @@
 if ( is_rtl() ) {
 	$body_class .= ' rtl';
 }
-$body_class .= ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
 
+$language_code = wp_get_html_language_code();
+$body_class .= ' locale-' . strtolower( $language_code );
+
 if ( $wp_customize->is_theme_active() ) {
 	$document_title_tmpl = _x( 'Customize: %s', 'Placeholder is the document title from the preview' );
 } else {
Index: src/wp-admin/includes/class-wp-press-this.php
===================================================================
--- src/wp-admin/includes/class-wp-press-this.php	(revision 32993)
+++ src/wp-admin/includes/class-wp-press-this.php	(working copy)
@@ -1298,7 +1298,8 @@
 	$admin_body_class .= ' branch-' . str_replace( array( '.', ',' ), '-', floatval( $wp_version ) );
 	$admin_body_class .= ' version-' . str_replace( '.', '-', preg_replace( '/^([.0-9]+).*/', '$1', $wp_version ) );
 	$admin_body_class .= ' admin-color-' . sanitize_html_class( get_user_option( 'admin_color' ), 'fresh' );
-	$admin_body_class .= ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
+	$language_code = wp_get_html_language_code();
+	$admin_body_class .= ' locale-' . strtolower( $language_code );
 
 	/** This filter is documented in wp-admin/admin-header.php */
 	$admin_body_classes = apply_filters( 'admin_body_class', '' );
Index: src/wp-admin/includes/template.php
===================================================================
--- src/wp-admin/includes/template.php	(revision 32993)
+++ src/wp-admin/includes/template.php	(working copy)
@@ -1647,7 +1647,8 @@
 /** This action is documented in wp-admin/admin-header.php */
 do_action( 'admin_head' );
 
-$admin_body_class .= ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
+$language_code = wp_get_html_language_code();
+$admin_body_class .= ' locale-' . strtolower( $language_code );
 
 if ( is_rtl() )
 	$admin_body_class .= ' rtl';
Index: src/wp-includes/class-wp-editor.php
===================================================================
--- src/wp-includes/class-wp-editor.php	(revision 32993)
+++ src/wp-includes/class-wp-editor.php	(working copy)
@@ -655,7 +655,8 @@
 				}
 			}
 
-			$body_class .= ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
+			$language_code = wp_get_html_language_code();
+			$body_class .= ' locale-' . strtolower( $language_code );
 
 			if ( !empty($set['tinymce']['body_class']) ) {
 				$body_class .= ' ' . $set['tinymce']['body_class'];
Index: src/wp-includes/formatting.php
===================================================================
--- src/wp-includes/formatting.php	(revision 32993)
+++ src/wp-includes/formatting.php	(working copy)
@@ -1138,7 +1138,7 @@
 		// Used for locale-specific rules
 		$locale = get_locale();
 
-		if ( 'de_DE' == $locale ) {
+		if ( 'de_DE' == $locale || 'de_DE_formal' == $locale ) {
 			$chars[ chr(195).chr(132) ] = 'Ae';
 			$chars[ chr(195).chr(164) ] = 'ae';
 			$chars[ chr(195).chr(150) ] = 'Oe';
Index: src/wp-includes/general-template.php
===================================================================
--- src/wp-includes/general-template.php	(revision 32993)
+++ src/wp-includes/general-template.php	(working copy)
@@ -665,8 +665,7 @@
 			$output = $wp_version;
 			break;
 		case 'language':
-			$output = get_locale();
-			$output = str_replace('_', '-', $output);
+			$output = wp_get_html_language_code();
 			break;
 		case 'text_direction':
 			_deprecated_argument( __FUNCTION__, '2.2', sprintf(
Index: src/wp-includes/l10n.php
===================================================================
--- src/wp-includes/l10n.php	(revision 32993)
+++ src/wp-includes/l10n.php	(working copy)
@@ -820,7 +820,7 @@
 		if ( substr( $file, -3 ) !== '.po' ) {
 			continue;
 		}
-		if ( ! preg_match( '/(?:(.+)-)?([A-Za-z_]{2,6}).po/', $file, $match ) ) {
+		if ( ! preg_match( '/(?:(.+)-)?([a-z]{2,3}(?:_[A-Z]{2})?(?:_[a-z]+)?).po/', $file, $match ) ) {
 			continue;
 		}
 		if ( ! in_array( substr( $file, 0, -3 ) . '.mo', $files ) )  {
@@ -859,6 +859,27 @@
 }
 
 /**
+ * Extract the language code from a locale.
+ *
+ * @since 4.3.0
+ *
+ * @param string $locale Optional. Locale to parse.
+ * @return string Language code.
+ */
+function wp_get_html_language_code( $locale = '' ) {
+	if ( ! $locale ) {
+		$locale = get_locale();
+	}
+
+	preg_match( '/^([a-z]{2,3}(_[A-Z]{2})?)/', $locale, $matches );
+	if ( ! empty( $matches[1] ) ) {
+		return str_replace( '_', '-', $matches[1] );
+	}
+
+	return '';
+}
+
+/**
  * Language selector.
  *
  * @since 4.0.0
Index: src/wp-login.php
===================================================================
--- src/wp-login.php	(revision 32993)
+++ src/wp-login.php	(working copy)
@@ -133,7 +133,8 @@
 		if ( 'success' ===  $interim_login )
 			$classes[] = 'interim-login-success';
 	}
-	$classes[] =' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
+	$language_code = wp_get_html_language_code();
+	$classes[] =' locale-' . strtolower( $language_code );
 
 	/**
 	 * Filter the login page body classes.
Index: tests/phpunit/tests/l10n.php
===================================================================
--- tests/phpunit/tests/l10n.php	(revision 32993)
+++ tests/phpunit/tests/l10n.php	(working copy)
@@ -16,4 +16,20 @@
 		$this->assertTrue( unload_textdomain( 'wp-tests-domain' ) );
 		$this->assertFalse( is_textdomain_loaded( 'wp-tests-domain' ) );
 	}
+
+	/**
+	 * @dataProvider locales
+	 */
+	function test_wp_get_html_language_code( $locale, $expected ) {
+		$this->assertEquals( $expected, wp_get_html_language_code( $locale ) );
+	}
+
+	function locales() {
+		return array(
+			'ar'           => 'ar',
+			'de_DE'        => 'de-DE',
+			'de_DE_formal' => 'de-DE',
+			'oci'          => 'oci',
+		);
+	}
 }
