// Auteur : Simon-Pierre Boucher — contact@spboucher.ai // Formatage à la québécoise : dollars CAD fr_CA, m², distances. import Foundation enum Fmt { private static let cadFormatter: NumberFormatter = { let f = NumberFormatter() f.numberStyle = .currency f.locale = Locale(identifier: "fr_CA") f.maximumFractionDigits = 0 return f }() private static let numFormatter: NumberFormatter = { let f = NumberFormatter() f.numberStyle = .decimal f.locale = Locale(identifier: "fr_CA") f.maximumFractionDigits = 0 return f }() /// « 833 800 $ » static func cad(_ value: Double?) -> String { guard let value, value.isFinite else { return "—" } return cadFormatter.string(from: NSNumber(value: value.rounded())) ?? "—" } /// « +34 000 $ » / « −83 700 $ » — ajustements du moteur, signe explicite. static func signedCad(_ value: Double) -> String { let s = cad(abs(value)) if abs(value) < 0.5 { return "±0 $" } return (value >= 0 ? "+" : "−") + s } /// « 195 m² » static func m2(_ value: Double?) -> String { guard let value, value.isFinite else { return "—" } return (numFormatter.string(from: NSNumber(value: value.rounded())) ?? "—") + " m²" } static func num(_ value: Double?) -> String { guard let value, value.isFinite else { return "—" } return numFormatter.string(from: NSNumber(value: value.rounded())) ?? "—" } /// « 850 m » ou « 2,4 km » static func distance(_ meters: Double) -> String { if meters < 1000 { return "\(Int(meters.rounded())) m" } return String(format: "%.1f km", locale: Locale(identifier: "fr_CA"), meters / 1000) } /// « 2026-04 » → « avril 2026 » static func monthYear(_ isoDate: String) -> String { let input = DateFormatter() input.dateFormat = "yyyy-MM-dd" input.locale = Locale(identifier: "en_US_POSIX") guard let d = input.date(from: isoDate) else { return isoDate } let output = DateFormatter() output.dateFormat = "MMMM yyyy" output.locale = Locale(identifier: "fr_CA") return output.string(from: d) } /// « 12,3 % » static func pct(_ value: Double?, decimals: Int = 1) -> String { guard let value, value.isFinite else { return "—" } return String(format: "%.\(decimals)f %%", locale: Locale(identifier: "fr_CA"), value) } }