Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion src/Compiler/Interactive/fsi.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1068,8 +1068,41 @@ type internal FsiCommandLineOptions(fsi: FsiEvaluationSessionHostConfig, argv: s
(fun args ->
let scriptFile = args[0]
let scriptArgs = List.tail args

// Filter out and process preferreduilang from script args
let isPreferredUiLangArg (arg: string) =
arg.StartsWith("--preferreduilang:", StringComparison.OrdinalIgnoreCase)
|| arg.StartsWith("/preferreduilang:", StringComparison.OrdinalIgnoreCase)

let rec filterScriptArgs (args: string list) =
match args with
| [] -> []
| (arg: string) :: rest when isPreferredUiLangArg arg ->
// Extract culture and set it
let colonIndex = arg.IndexOf(':')

if colonIndex >= 0 && colonIndex < arg.Length - 1 then
let culture = arg.Substring(colonIndex + 1)

try
// Validate culture first by creating CultureInfo
let cultureInfo = CultureInfo(culture)
// Only set if valid
tcConfigB.preferredUiLang <- Some culture
Thread.CurrentThread.CurrentUICulture <- cultureInfo
with
| :? CultureNotFoundException
| :? ArgumentException ->
// Ignore invalid culture, just don't set it
()

filterScriptArgs rest
| arg :: rest -> arg :: filterScriptArgs rest

let filteredScriptArgs = filterScriptArgs scriptArgs

inputFilesAcc <- inputFilesAcc @ [ (scriptFile, true) ] (* record script.fsx for evaluation *)
List.iter recordExplicitArg scriptArgs (* record rest of line as explicit arguments *)
List.iter recordExplicitArg filteredScriptArgs (* record rest of line as explicit arguments *)
tcConfigB.noFeedback <- true (* "quiet", no banners responses etc *)
interact <- false (* --exec, exit after eval *)
[] (* no arguments passed on, all consumed here *)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@
<Compile Include="Interop\Literals.fs" />
<Compile Include="Scripting\Interactive.fs" />
<Compile Include="Scripting\TypeCheckOnlyTests.fs" />
<Compile Include="Scripting\PreferredUiLangTests.fs" />
<Compile Include="TypeChecks\TypeRelations.fs" />
<Compile Include="TypeChecks\SeqTypeCheckTests.fs" />
<Compile Include="TypeChecks\CheckDeclarationsTests.fs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.

namespace Scripting

open Xunit
open System
open System.IO
open FSharp.Test
open FSharp.Test.CompilerAssertHelpers
open FSharp.Compiler.Interactive.Shell
open FSharp.Compiler.Diagnostics

module ``PreferredUiLang tests`` =

[<Fact>]
let ``preferreduilang switch before script is consumed from CommandLineArgs``() =
let scriptContent = """
printfn "Args: %A" fsi.CommandLineArgs
if fsi.CommandLineArgs.Length <> 2 then exit 1
if fsi.CommandLineArgs.[0] <> __SOURCE_FILE__ then exit 1
if fsi.CommandLineArgs.[1] <> "arg1" then exit 1
exit 0
"""
let tmpFile = Path.GetTempFileName() + ".fsx"
try
File.WriteAllText(tmpFile, scriptContent)
let errors, _, _ =
CompilerAssert.RunScriptWithOptionsAndReturnResult
[| "--preferreduilang:es-ES"; tmpFile; "arg1" |]
""

// Should succeed (exit 0)
Assert.True((errors: ResizeArray<string>).Count = 0, sprintf "Expected no errors, got: %A" errors)
finally
if File.Exists(tmpFile) then File.Delete(tmpFile)

[<Fact>]
let ``preferreduilang switch after script is consumed from CommandLineArgs``() =
let scriptContent = """
printfn "Args: %A" fsi.CommandLineArgs
if fsi.CommandLineArgs.Length <> 2 then exit 1
if fsi.CommandLineArgs.[0] <> __SOURCE_FILE__ then exit 1
if fsi.CommandLineArgs.[1] <> "arg1" then exit 1
exit 0
"""
let tmpFile = Path.GetTempFileName() + ".fsx"
try
File.WriteAllText(tmpFile, scriptContent)
let errors, _, _ =
CompilerAssert.RunScriptWithOptionsAndReturnResult
[| tmpFile; "--preferreduilang:es-ES"; "arg1" |]
""

// Should succeed (exit 0)
Assert.True((errors: ResizeArray<string>).Count = 0, sprintf "Expected no errors, got: %A" errors)
finally
if File.Exists(tmpFile) then File.Delete(tmpFile)

[<Fact>]
let ``preferreduilang with slash form is consumed from CommandLineArgs``() =
let scriptContent = """
printfn "Args: %A" fsi.CommandLineArgs
if fsi.CommandLineArgs.Length <> 2 then exit 1
if fsi.CommandLineArgs.[0] <> __SOURCE_FILE__ then exit 1
if fsi.CommandLineArgs.[1] <> "arg1" then exit 1
exit 0
"""
let tmpFile = Path.GetTempFileName() + ".fsx"
try
File.WriteAllText(tmpFile, scriptContent)
let errors, _, _ =
CompilerAssert.RunScriptWithOptionsAndReturnResult
[| tmpFile; "/preferreduilang:de-DE"; "arg1" |]
""

// Should succeed (exit 0)
Assert.True((errors: ResizeArray<string>).Count = 0, sprintf "Expected no errors, got: %A" errors)
finally
if File.Exists(tmpFile) then File.Delete(tmpFile)

[<Fact>]
let ``preferreduilang sets CurrentUICulture correctly``() =
let scriptContent = """
let culture = System.Threading.Thread.CurrentThread.CurrentUICulture.Name
printfn "Culture: %s" culture
if not (culture.StartsWith("fr-FR")) then
printfn "Expected culture starting with fr-FR, got: %s" culture
exit 1
exit 0
"""
let tmpFile = Path.GetTempFileName() + ".fsx"
try
File.WriteAllText(tmpFile, scriptContent)
let errors, _, _ =
CompilerAssert.RunScriptWithOptionsAndReturnResult
[| "--preferreduilang:fr-FR"; tmpFile |]
""

// Should succeed (exit 0)
Assert.True((errors: ResizeArray<string>).Count = 0, sprintf "Expected no errors, got: %A" errors)
finally
if File.Exists(tmpFile) then File.Delete(tmpFile)

[<Fact>]
let ``preferreduilang after script also sets culture``() =
let scriptContent = """
let culture = System.Threading.Thread.CurrentThread.CurrentUICulture.Name
printfn "Culture: %s" culture
if not (culture.StartsWith("ja-JP")) then
printfn "Expected culture starting with ja-JP, got: %s" culture
exit 1
exit 0
"""
let tmpFile = Path.GetTempFileName() + ".fsx"
try
File.WriteAllText(tmpFile, scriptContent)
let errors, _, _ =
CompilerAssert.RunScriptWithOptionsAndReturnResult
[| tmpFile; "--preferreduilang:ja-JP" |]
""

// Should succeed (exit 0)
Assert.True((errors: ResizeArray<string>).Count = 0, sprintf "Expected no errors, got: %A" errors)
finally
if File.Exists(tmpFile) then File.Delete(tmpFile)

[<Fact>]
let ``invalid culture in preferreduilang is ignored gracefully``() =
let scriptContent = """
printfn "Args: %A" fsi.CommandLineArgs
if fsi.CommandLineArgs.Length <> 2 then exit 1
if fsi.CommandLineArgs.[0] <> __SOURCE_FILE__ then exit 1
if fsi.CommandLineArgs.[1] <> "arg1" then exit 1
exit 0
"""
let tmpFile = Path.GetTempFileName() + ".fsx"
try
File.WriteAllText(tmpFile, scriptContent)
let errors, _, _ =
CompilerAssert.RunScriptWithOptionsAndReturnResult
[| tmpFile; "--preferreduilang:invalid-culture-xyz"; "arg1" |]
""

// Should succeed - invalid culture is ignored, but switch is still consumed
Assert.True((errors: ResizeArray<string>).Count = 0, sprintf "Expected no errors, got: %A" errors)
finally
if File.Exists(tmpFile) then File.Delete(tmpFile)
Loading