Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManageMisc.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManageMisc.cpp	(revision 68238)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManageMisc.cpp	(revision 68239)
@@ -1337,4 +1337,6 @@
     Bstr bstrDetectedFlavor;
     CHECK_ERROR2_RET(hrc, ptrUnattended, COMGETTER(DetectedOSFlavor)(bstrDetectedFlavor.asOutParam()), RTEXITCODE_FAILURE);
+    Bstr bstrDetectedLanguages;
+    CHECK_ERROR2_RET(hrc, ptrUnattended, COMGETTER(DetectedOSLanguages)(bstrDetectedLanguages.asOutParam()), RTEXITCODE_FAILURE);
     Bstr bstrDetectedHints;
     CHECK_ERROR2_RET(hrc, ptrUnattended, COMGETTER(DetectedOSHints)(bstrDetectedHints.asOutParam()), RTEXITCODE_FAILURE);
@@ -1343,19 +1345,23 @@
                  "OSVersion=\"%ls\"\n"
                  "OSFlavor=\"%ls\"\n"
+                 "OSLanguages=\"%ls\"\n"
                  "OSHints=\"%ls\"\n",
                  bstrDetectedOSTypeId.raw(),
                  bstrDetectedVersion.raw(),
                  bstrDetectedFlavor.raw(),
+                 bstrDetectedLanguages.raw(),
                  bstrDetectedHints.raw());
     else
     {
         RTMsgInfo("Detected '%s' to be:\n", szIsoPath);
-        RTPrintf("    OS TypeId  = %ls\n"
-                 "    OS Version = %ls\n"
-                 "    OS Flavor  = %ls\n"
-                 "    OS Hints   = %ls\n",
+        RTPrintf("    OS TypeId    = %ls\n"
+                 "    OS Version   = %ls\n"
+                 "    OS Flavor    = %ls\n"
+                 "    OS Languages = %ls\n"
+                 "    OS Hints     = %ls\n",
                  bstrDetectedOSTypeId.raw(),
                  bstrDetectedVersion.raw(),
                  bstrDetectedFlavor.raw(),
+                 bstrDetectedLanguages.raw(),
                  bstrDetectedHints.raw());
     }
@@ -1398,5 +1404,5 @@
         { "--validation-kit-iso",               'K', RTGETOPT_REQ_STRING },
         { "--locale",                           'l', RTGETOPT_REQ_STRING },
-        { "--country",                          'L', RTGETOPT_REQ_STRING },
+        { "--country",                          'Y', RTGETOPT_REQ_STRING },
         { "--time-zone",                        'z', RTGETOPT_REQ_STRING },
         { "--proxy",                            'y', RTGETOPT_REQ_STRING },
@@ -1411,4 +1417,5 @@
         { "--post-install-command",             'P', RTGETOPT_REQ_STRING },
         { "--extra-install-kernel-parameters",  'I', RTGETOPT_REQ_STRING },
+        { "--language",                         'L', RTGETOPT_REQ_STRING },
         // start vm related options:
         { "--session-type",                     'S', RTGETOPT_REQ_STRING },
@@ -1497,5 +1504,5 @@
                 break;
 
-            case 'L':   // --country
+            case 'Y':   // --country
                 CHECK_ERROR2_RET(hrc, ptrUnattended, COMSETTER(Country)(Bstr(ValueUnion.psz).raw()), RTEXITCODE_FAILURE);
                 break;
@@ -1552,4 +1559,8 @@
             case 'I':   // --extra-install-kernel-parameters
                 CHECK_ERROR2_RET(hrc, ptrUnattended, COMSETTER(ExtraInstallKernelParameters)(Bstr(ValueUnion.psz).raw()), RTEXITCODE_FAILURE);
+                break;
+
+            case 'L':   // --language
+                CHECK_ERROR2_RET(hrc, ptrUnattended, COMSETTER(Language)(Bstr(ValueUnion.psz).raw()), RTEXITCODE_FAILURE);
                 break;
 
@@ -1678,7 +1689,9 @@
     SHOW_STR_ATTR(PostInstallCommand,            "postInstallCommand");
     SHOW_STR_ATTR(ExtraInstallKernelParameters,  "extraInstallKernelParameters");
+    SHOW_STR_ATTR(Language,                      "language");
     SHOW_STR_ATTR(DetectedOSTypeId,              "detectedOSTypeId");
     SHOW_STR_ATTR(DetectedOSVersion,             "detectedOSVersion");
     SHOW_STR_ATTR(DetectedOSFlavor,              "detectedOSFlavor");
+    SHOW_STR_ATTR(DetectedOSLanguages,           "detectedOSLanguages");
     SHOW_STR_ATTR(DetectedOSHints,               "detectedOSHints");
 
Index: /trunk/src/VBox/Main/UnattendedTemplates/win_nt6_unattended.xml
===================================================================
--- /trunk/src/VBox/Main/UnattendedTemplates/win_nt6_unattended.xml	(revision 68238)
+++ /trunk/src/VBox/Main/UnattendedTemplates/win_nt6_unattended.xml	(revision 68239)
@@ -8,8 +8,11 @@
             publicKeyToken="31bf3856ad364e35" language="neutral"
             versionScope="nonSxS">
-            <InputLocale>@@VBOX_INSERT_DASH_LOCALE@@</InputLocale>
+            <InputLocale>en-US</InputLocale>
             <SystemLocale>@@VBOX_INSERT_DASH_LOCALE@@</SystemLocale>
-            <UILanguage>@@VBOX_INSERT_DASH_LOCALE@@</UILanguage>
             <UserLocale>@@VBOX_INSERT_DASH_LOCALE@@</UserLocale>
+            <!-- UILanguage must match the installation media language.  Stuff like de-CH does not work for
+                 example de_windows_7_enterprise_with_sp1_x64_dvd_u_677649.iso.  However, stupidly we cannot
+                 omit this element (kudos to brilliant minds at MS).  -->
+            <UILanguage>@@VBOX_INSERT_LANGUAGE@@</UILanguage>
         </component>
 
Index: /trunk/src/VBox/Main/idl/VirtualBox.xidl
===================================================================
--- /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 68238)
+++ /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 68239)
@@ -3778,5 +3778,5 @@
   <interface
     name="IUnattended" extends="$unknown"
-    uuid="3107e9fd-7b3a-4008-91de-24273f605a8e"
+    uuid="6f89464f-7193-426c-a41f-522e8f537fa0"
     wsmap="managed"
     reservedMethods="4" reservedAttributes="16"
@@ -3923,4 +3923,23 @@
     </attribute>
 
+    <attribute name="language" type="wstring">
+      <desc>
+        This is more or less a Windows specific setting for choosing the UI language
+        setting of the installer.
+
+        The value should be from the list availble via <link to="IUnattended::detectedOSLanguages"/>.
+        The typical format is {language-code}-{COUNTRY} but windows may also use
+        {16-bit code}:{32-bit code} or insert another component between the language
+        and country codes.  We consider the format guest OS specific.
+
+        Note that it is crucial that this is correctly specified for Windows
+        installations.  If an unsupported value is given the installer will ask
+        for an installation language and wait for user input.  Best to leave it
+        to the default value.
+
+        The default is the first one from <link to="IUnattended::detectedOSLanguages"/>.
+      </desc>
+    </attribute>
+
     <attribute name="country" type="wstring">
       <desc>
@@ -4067,4 +4086,17 @@
     </attribute>
 
+    <attribute name="detectedOSLanguages" type="wstring" readonly="yes">
+      <desc>
+        The space separated list of (Windows) installation UI languages we detected (lang.ini).
+
+        The language specifier format is specific to the guest OS.  They are
+        used to set <link to="IUnattended::language"/>.
+
+        Set by <link to="IUnattended::detectIsoOS"/> or <link to="IUnattended::prepare"/>.
+
+        Partially implemented.
+      </desc>
+    </attribute>
+
     <attribute name="detectedOSHints" type="wstring" readonly="yes">
       <desc>
@@ -4082,7 +4114,8 @@
         Detects the OS on the ISO given by <link to="IUnattended::isoPath"/> and sets
         <link to="IUnattended::detectedOSTypeId"/>, <link to="IUnattended::detectedOSVersion"/>
-        <link to="IUnattended::detectedOSFlavor"/>, and <link to="IUnattended::detectedOSHints"/>.
-
-        Not yet implemented.
+        <link to="IUnattended::detectedOSFlavor"/>, <link to="IUnattended::detectedOSLanguages"/>,
+        and <link to="IUnattended::detectedOSHints"/>.
+
+        Not really yet implemented.
       </desc>
     </method>
Index: /trunk/src/VBox/Main/include/UnattendedImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/UnattendedImpl.h	(revision 68238)
+++ /trunk/src/VBox/Main/include/UnattendedImpl.h	(revision 68239)
@@ -60,4 +60,5 @@
     PCRTTIMEZONEINFO i_getTimeZoneInfo() const;
     Utf8Str const &i_getLocale() const;
+    Utf8Str const &i_getLanguage() const;
     Utf8Str const &i_getCountry() const;
     bool           i_isMinimalInstallation() const;
@@ -100,4 +101,5 @@
     PCRTTIMEZONEINFO mpTimeZoneInfo;
     Utf8Str         mStrLocale;
+    Utf8Str         mStrLanguage;           /**< (only relevant for windows at the moment) */
     Utf8Str         mStrCountry;
     RTCList<RTCString, RTCString *> mPackageSelectionAdjustments;
@@ -110,7 +112,10 @@
     Utf8Str         mStrPostInstallCommand;
     Utf8Str         mStrExtraInstallKernelParameters;
+
+    bool            mfDoneDetectIsoOS;         /**< Set by detectIsoOS(), cleared by setIsoPath(). */
     Utf8Str         mStrDetectedOSTypeId;
     Utf8Str         mStrDetectedOSVersion;
     Utf8Str         mStrDetectedOSFlavor;
+    RTCList<RTCString, RTCString *> mDetectedOSLanguages; /**< (only relevant for windows at the moment) */
     Utf8Str         mStrDetectedOSHints;
     /** @} */
@@ -166,4 +171,6 @@
     HRESULT getLocale(com::Utf8Str &aLocale);
     HRESULT setLocale(const com::Utf8Str &aLocale);
+    HRESULT getLanguage(com::Utf8Str &aLanguage);
+    HRESULT setLanguage(const com::Utf8Str &aLanguage);
     HRESULT getCountry(com::Utf8Str &aCountry);
     HRESULT setCountry(const com::Utf8Str &aCountry);
@@ -190,4 +197,5 @@
     HRESULT getDetectedOSTypeId(com::Utf8Str &aDetectedOSTypeId);
     HRESULT getDetectedOSVersion(com::Utf8Str &aDetectedOSVersion);
+    HRESULT getDetectedOSLanguages(com::Utf8Str &aDetectedOSLanguages);
     HRESULT getDetectedOSFlavor(com::Utf8Str &aDetectedOSFlavor);
     HRESULT getDetectedOSHints(com::Utf8Str &aDetectedOSHints);
Index: /trunk/src/VBox/Main/src-server/UnattendedImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/UnattendedImpl.cpp	(revision 68238)
+++ /trunk/src/VBox/Main/src-server/UnattendedImpl.cpp	(revision 68239)
@@ -151,5 +151,5 @@
 Unattended::Unattended()
     : mhThreadReconfigureVM(NIL_RTNATIVETHREAD), mfRtcUseUtc(false), mfGuestOs64Bit(false)
-    , mpInstaller(NULL), mpTimeZoneInfo(NULL), mfIsDefaultAuxiliaryBasePath(true)
+    , mpInstaller(NULL), mpTimeZoneInfo(NULL), mfIsDefaultAuxiliaryBasePath(true), mfDoneDetectIsoOS(false)
 { }
 
@@ -231,4 +231,76 @@
 HRESULT Unattended::detectIsoOS()
 {
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    /*
+     * Just fake up some windows installation media locale (for <UILanguage>).
+     * Note! The translation here isn't perfect.  Feel free to send us a patch.
+     */
+    /** @todo Looks like we can get this from sources/lang.ini as well as
+     *        sources/??-* and boot/??-*.  Will require UDF reader. */
+    char        szTmp[16];
+    const char *pszFilename = RTPathFilename(mStrIsoPath.c_str());
+    if (   pszFilename
+        && RT_C_IS_ALPHA(pszFilename[0])
+        && RT_C_IS_ALPHA(pszFilename[1])
+        && (pszFilename[2] == '-' || pszFilename[2] == '_') )
+    {
+        szTmp[0] = RT_C_TO_LOWER(pszFilename[0]);
+        szTmp[1] = RT_C_TO_LOWER(pszFilename[1]);
+        szTmp[2] = '-';
+        if (szTmp[0] == 'e' && szTmp[1] == 'n')
+            strcpy(&szTmp[3], "US");
+        else if (szTmp[0] == 'a' && szTmp[1] == 'r')
+            strcpy(&szTmp[3], "SA");
+        else if (szTmp[0] == 'd' && szTmp[1] == 'a')
+            strcpy(&szTmp[3], "DK");
+        else if (szTmp[0] == 'e' && szTmp[1] == 't')
+            strcpy(&szTmp[3], "EE");
+        else if (szTmp[0] == 'e' && szTmp[1] == 'l')
+            strcpy(&szTmp[3], "GR");
+        else if (szTmp[0] == 'h' && szTmp[1] == 'e')
+            strcpy(&szTmp[3], "IL");
+        else if (szTmp[0] == 'j' && szTmp[1] == 'a')
+            strcpy(&szTmp[3], "JP");
+        else if (szTmp[0] == 's' && szTmp[1] == 'v')
+            strcpy(&szTmp[3], "SE");
+        else if (szTmp[0] == 'u' && szTmp[1] == 'k')
+            strcpy(&szTmp[3], "UA");
+        else if (szTmp[0] == 'c' && szTmp[1] == 's')
+            strcpy(szTmp, "cs-CZ");
+        else if (szTmp[0] == 'n' && szTmp[1] == 'o')
+            strcpy(szTmp, "nb-NO");
+        else if (szTmp[0] == 'p' && szTmp[1] == 'p')
+            strcpy(szTmp, "pt-PT");
+        else if (szTmp[0] == 'p' && szTmp[1] == 't')
+            strcpy(szTmp, "pt-BR");
+        else if (szTmp[0] == 'c' && szTmp[1] == 'n')
+            strcpy(szTmp, "zh-CN");
+        else if (szTmp[0] == 'h' && szTmp[1] == 'k')
+            strcpy(szTmp, "zh-HK");
+        else if (szTmp[0] == 't' && szTmp[1] == 'w')
+            strcpy(szTmp, "zh-TW");
+        else if (szTmp[0] == 's' && szTmp[1] == 'r')
+            strcpy(szTmp, "sr-Latn-CS"); /* hmm */
+        else
+        {
+            szTmp[3] = RT_C_TO_UPPER(pszFilename[0]);
+            szTmp[4] = RT_C_TO_UPPER(pszFilename[1]);
+            szTmp[5] = '\0';
+        }
+    }
+    else
+        strcpy(szTmp, "en-US");
+    try
+    {
+        mDetectedOSLanguages.clear();
+        mDetectedOSLanguages.append(szTmp);
+    }
+    catch (std::bad_alloc)
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    /** @todo implement actual detection logic. */
     return E_NOTIMPL;
 }
@@ -319,4 +391,14 @@
 
     /*
+     * Do media detection if it haven't been done yet.
+     */
+    if (!mfDoneDetectIsoOS)
+    {
+        hrc = detectIsoOS();
+        if (FAILED(hrc) && hrc != E_NOTIMPL)
+            return hrc;
+    }
+
+    /*
      * Do some default property stuff and check other properties.
      */
@@ -334,4 +416,12 @@
                 mStrLocale = "en_US";
             Assert(RTLOCALE_IS_LANGUAGE2_UNDERSCORE_COUNTRY2(mStrLocale));
+        }
+
+        if (mStrLanguage.isEmpty())
+        {
+            if (mDetectedOSLanguages.size() > 0)
+                mStrLanguage = mDetectedOSLanguages[0];
+            else
+                mStrLanguage.assign(mStrLocale).findReplace('_', '-');
         }
 
@@ -1053,5 +1143,6 @@
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
-    mStrIsoPath = isoPath;
+    mStrIsoPath       = isoPath;
+    mfDoneDetectIsoOS = false;
     return S_OK;
 }
@@ -1216,4 +1307,19 @@
     }
     return setError(E_INVALIDARG, tr("Expected two lower cased letters, an underscore, and two upper cased letters"));
+}
+
+HRESULT Unattended::getLanguage(com::Utf8Str &aLanguage)
+{
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+    aLanguage = mStrLanguage;
+    return S_OK;
+}
+
+HRESULT Unattended::setLanguage(const com::Utf8Str &aLanguage)
+{
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+    AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
+    mStrLanguage = aLanguage;
+    return S_OK;
 }
 
@@ -1528,4 +1634,11 @@
 }
 
+HRESULT Unattended::getDetectedOSLanguages(com::Utf8Str &aDetectedOSLanguages)
+{
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+    aDetectedOSLanguages = RTCString::join(mDetectedOSLanguages, " ");
+    return S_OK;
+}
+
 HRESULT Unattended::getDetectedOSHints(com::Utf8Str &aDetectedOSHints)
 {
@@ -1608,4 +1721,10 @@
     Assert(isReadLockedOnCurrentThread());
     return mStrLocale;
+}
+
+Utf8Str const &Unattended::i_getLanguage() const
+{
+    Assert(isReadLockedOnCurrentThread());
+    return mStrLanguage;
 }
 
Index: /trunk/src/VBox/Main/src-server/UnattendedScript.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/UnattendedScript.cpp	(revision 68238)
+++ /trunk/src/VBox/Main/src-server/UnattendedScript.cpp	(revision 68239)
@@ -565,4 +565,6 @@
         rValue.replace(2, 1, "-");
     }
+    else if (IS_PLACEHOLDER_MATCH("LANGUAGE"))
+        rValue = mpUnattended->i_getLanguage();
     else if (IS_PLACEHOLDER_MATCH("COUNTRY"))
         rValue = mpUnattended->i_getCountry();
