Modules/businessdev.ALbuild.Containers/Private/Set-BcContainerLanguage.ps1

function Set-BcContainerLanguage {
    <#
    .SYNOPSIS
        Makes a culture available and the default UI language of a Business Central container.
 
    .DESCRIPTION
        1. Installs Microsoft's language app for <Language> (Install-BcContainerLanguageApp). Without it the
           culture is not available in the client, whatever the server settings say. A language app that
           cannot be found or installed throws.
        2. Sets the server instance's language settings:
             - DefaultLanguage = <Language>
             - SupportedLanguages = the pinned list (default: <Language> plus en-US). Must include the
                                    DefaultLanguage. A browser requesting a supported language gets that
                                    language, so a client that sends en-US sees English; pin
                                    -SupportedLanguages <Language> alone to force <Language> for every browser.
        Neither key is dynamically updatable, so the instance is restarted (via Set-BcContainerServerConfig).
 
    .PARAMETER Name
        Container name.
 
    .PARAMETER Language
        The culture name to make the default UI language, e.g. 'de-DE'.
 
    .PARAMETER SupportedLanguages
        Optional ';'-separated culture list to pin. Default = <Language>;en-US. Must contain <Language>.
 
    .PARAMETER ServerInstance
        BC server instance inside the container. Default 'BC'.
 
    .PARAMETER DockerExecutable
        The Docker executable to use (default 'docker').
 
    .OUTPUTS
        PSCustomObject with Language, SupportedLanguages and LanguageApp.
    #>

    [CmdletBinding(SupportsShouldProcess)]
    [OutputType([PSCustomObject])]
    param(
        [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [Alias('ContainerName')] [string] $Name,
        [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $Language,
        [string] $SupportedLanguages,
        [string] $ServerInstance = 'BC',
        [string] $DockerExecutable = 'docker'
    )

    $supported = if ($PSBoundParameters.ContainsKey('SupportedLanguages') -and $SupportedLanguages) { $SupportedLanguages }
    elseif ($Language -eq 'en-US') { 'en-US' }
    else { "$Language;en-US" }
    $supportedList = @($supported -split ';' | ForEach-Object { $_.Trim() } | Where-Object { $_ })
    if ($supportedList -notcontains $Language) {
        throw "SupportedLanguages '$supported' must include the default language '$Language'."
    }

    if (-not $PSCmdlet.ShouldProcess($Name, "Install the language app for '$Language', set DefaultLanguage='$Language', SupportedLanguages='$supported' (restarts the instance)")) {
        return [PSCustomObject]@{ Language = $Language; SupportedLanguages = $supported; LanguageApp = $null }
    }

    # en-US is built into every container; every other culture needs its language app.
    $languageApp = $null
    if ($Language -ne 'en-US') {
        $languageApp = Install-BcContainerLanguageApp -Name $Name -Language $Language -ServerInstance $ServerInstance -DockerExecutable $DockerExecutable -Confirm:$false
    }

    # Apply in a SAFE ORDER: DefaultLanguage first (accepted while SupportedLanguages is still empty = all
    # installed), then narrow SupportedLanguages (now DefaultLanguage is already <lang>, so BC's invariant
    # "DefaultLanguage must be in SupportedLanguages" holds). Passing both in one hashtable applies them in
    # arbitrary order and can hit the invalid intermediate state (DefaultLanguage=en-US not in
    # SupportedLanguages=de-DE) - the reported failure. -NoRestart on the first so only one restart happens.
    Set-BcContainerServerConfig -Name $Name -ServerInstance $ServerInstance -DockerExecutable $DockerExecutable -NoRestart -Settings @{ DefaultLanguage = $Language }
    Set-BcContainerServerConfig -Name $Name -ServerInstance $ServerInstance -DockerExecutable $DockerExecutable -Settings @{ SupportedLanguages = $supported }
    Write-ALbuildLog -Level Success "Set container '$Name' UI language to '$Language' (supported: $supported)."
    return [PSCustomObject]@{ Language = $Language; SupportedLanguages = $supported; LanguageApp = $languageApp }
}