import Combine import Foundation @MainActor final class LocalizationStore: ObservableObject { @Published private(set) var localeCode: String private let bundle: Bundle private static let supportedLocaleCodes = ["en", "sv"] private static let fallbackLocaleCode = "en" init(bundle: Bundle = .main, localeCode: String = Locale.preferredLanguages.first.map { String($0.prefix(2)) } ?? "en") { self.bundle = bundle self.localeCode = Self.normalize(localeCode) } func setLocale(_ localeCode: String) { self.localeCode = Self.normalize(localeCode) } func string(for key: String) -> String { string(for: key, localeCode: localeCode) } func string(for key: String, localeCode: String) -> String { guard let localizedBundle = localizedBundle(for: localeCode) else { return fallbackString(for: key, localeCode: localeCode) } let value = localizedBundle.localizedString(forKey: key, value: nil, table: nil) if value == key { return fallbackString(for: key, localeCode: localeCode) } return value } func localeName(for targetLocaleCode: String, displayLocaleCode: String? = nil) -> String { let key = Self.normalize(targetLocaleCode) == "sv" ? "locale_swedish" : "locale_english" return string(for: key, localeCode: displayLocaleCode ?? localeCode) } private func fallbackString(for key: String, localeCode: String) -> String { guard localeCode != Self.fallbackLocaleCode else { return key } return string(for: key, localeCode: Self.fallbackLocaleCode) } private func localizedBundle(for localeCode: String) -> Bundle? { guard let path = bundle.path(forResource: localeCode, ofType: "lproj") else { return nil } return Bundle(path: path) } private static func normalize(_ localeCode: String) -> String { guard supportedLocaleCodes.contains(localeCode) else { return fallbackLocaleCode } return localeCode } }