diff --git a/Sources/SkipUI/SkipUI/Environment/EnvironmentValues.swift b/Sources/SkipUI/SkipUI/Environment/EnvironmentValues.swift index 0dc44bf7..3537e961 100644 --- a/Sources/SkipUI/SkipUI/Environment/EnvironmentValues.swift +++ b/Sources/SkipUI/SkipUI/Environment/EnvironmentValues.swift @@ -479,8 +479,12 @@ extension EnvironmentValues { } public var locale: Locale { - get { Locale(LocalConfiguration.current.locales[0]) } + get { builtinValue(key: "_locale", defaultValue: { nil }) as! Locale? ?? Locale(LocalConfiguration.current.locales[0]) } set { + // Presentations compose in their own Android window, where Compose re-provides + // `LocalConfiguration` from the platform. Track the override in our own composition + // local as well so that it survives into sheets, covers, alerts, and popups. + setBuiltinValue(key: "_locale", value: newValue, defaultValue: { nil }) let action: @Composable () -> Void = { // Requires a @Composable context to copy LocalConfiguration.current let configuration = Configuration(LocalConfiguration.current) diff --git a/Tests/SkipUITests/SkipUITests.swift b/Tests/SkipUITests/SkipUITests.swift index 03fcdb89..49b35f65 100644 --- a/Tests/SkipUITests/SkipUITests.swift +++ b/Tests/SkipUITests/SkipUITests.swift @@ -633,6 +633,33 @@ final class SkipUITests: SkipUITestCase { } } + func testSheetInheritsLocaleFromPresenter() throws { + #if !SKIP + throw XCTSkip("sheet content composes in a separate Android window") + #else + try testUI(view: { + SheetLocaleTestView() + .environment(\.locale, Locale(identifier: "fr")) + .accessibilityIdentifier("test-view") + }, eval: { rule in + rule.waitForIdle() + rule.onAllNodesWithTag("sheet-text").onFirst().assert(hasTextExactly("Terminé")) + }) + #endif + } + + struct SheetLocaleTestView: View { + @State var isPresented = true + + var body: some View { + Text(verbatim: "Sheet Host") + .sheet(isPresented: $isPresented) { + Text("Done", bundle: .module) + .accessibilityIdentifier("sheet-text") + } + } + } + // look up a localized string in the current bundle using the given language func localizedBundle(_ lang: String) throws -> Bundle { try XCTUnwrap(Bundle(url: XCTUnwrap(Bundle.module.url(forResource: "Localizable", withExtension: "strings", subdirectory: nil, localization: lang)).deletingLastPathComponent()))