blob: 1544767d53cb02243693a91e86c32b3da288c71b [file] [log] [blame]
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import CoreFoundation
internal func __NSLocaleIsAutoupdating(_ locale: NSLocale) -> Bool {
return false // Auto-updating is only on Darwin
}
internal func __NSLocaleCurrent() -> NSLocale {
return CFLocaleCopyCurrent()._nsObject
}
/**
`Locale` encapsulates information about linguistic, cultural, and technological conventions and standards. Examples of information encapsulated by a locale include the symbol used for the decimal separator in numbers and the way dates are formatted.
Locales are typically used to provide, format, and interpret information about and according to the user’s customs and preferences. They are frequently used in conjunction with formatters. Although you can use many locales, you usually use the one associated with the current user.
*/
public struct Locale : CustomStringConvertible, CustomDebugStringConvertible, Hashable, Equatable, ReferenceConvertible {
public typealias ReferenceType = NSLocale
public typealias LanguageDirection = NSLocale.LanguageDirection
internal var _wrapped : NSLocale
internal var _autoupdating : Bool
/// Returns the user's current locale.
public static var current : Locale {
return Locale(adoptingReference: __NSLocaleCurrent(), autoupdating: false)
}
/// Returns a locale which tracks the user's current preferences.
///
/// If mutated, this Locale will no longer track the user's preferences.
///
/// - note: The autoupdating Locale will only compare equal to another autoupdating Locale.
public static var autoupdatingCurrent : Locale {
// swift-corelibs-foundation does not yet support autoupdating, but we can return the current locale (which will not change).
return Locale(adoptingReference: __NSLocaleCurrent(), autoupdating: true)
}
@available(*, unavailable, message: "Consider using the user's locale or nil instead, depending on use case")
public static var system : Locale { fatalError() }
// MARK: -
//
/// Return a locale with the specified identifier.
public init(identifier: String) {
_wrapped = NSLocale(localeIdentifier: identifier)
_autoupdating = false
}
internal init(reference: NSLocale) {
_wrapped = reference.copy() as! NSLocale
if __NSLocaleIsAutoupdating(reference) {
_autoupdating = true
} else {
_autoupdating = false
}
}
private init(adoptingReference reference: NSLocale, autoupdating: Bool) {
_wrapped = reference
_autoupdating = autoupdating
}
// MARK: -
//
/// Returns a localized string for a specified identifier.
///
/// For example, in the "en" locale, the result for `"es"` is `"Spanish"`.
public func localizedString(forIdentifier identifier: String) -> String? {
return _wrapped.displayName(forKey: .identifier, value: identifier)
}
/// Returns a localized string for a specified language code.
///
/// For example, in the "en" locale, the result for `"es"` is `"Spanish"`.
public func localizedString(forLanguageCode languageCode: String) -> String? {
return _wrapped.displayName(forKey: .languageCode, value: languageCode)
}
/// Returns a localized string for a specified region code.
///
/// For example, in the "en" locale, the result for `"fr"` is `"France"`.
public func localizedString(forRegionCode regionCode: String) -> String? {
return _wrapped.displayName(forKey: .countryCode, value: regionCode)
}
/// Returns a localized string for a specified script code.
///
/// For example, in the "en" locale, the result for `"Hans"` is `"Simplified Han"`.
public func localizedString(forScriptCode scriptCode: String) -> String? {
return _wrapped.displayName(forKey: .scriptCode, value: scriptCode)
}
/// Returns a localized string for a specified variant code.
///
/// For example, in the "en" locale, the result for `"POSIX"` is `"Computer"`.
public func localizedString(forVariantCode variantCode: String) -> String? {
return _wrapped.displayName(forKey: .variantCode, value: variantCode)
}
/// Returns a localized string for a specified `Calendar.Identifier`.
///
/// For example, in the "en" locale, the result for `.buddhist` is `"Buddhist Calendar"`.
public func localizedString(for calendarIdentifier: Calendar.Identifier) -> String? {
// NSLocale doesn't export a constant for this
let result = CFLocaleCopyDisplayNameForPropertyValue(unsafeBitCast(_wrapped, to: CFLocale.self), kCFLocaleCalendarIdentifier, Calendar._toNSCalendarIdentifier(calendarIdentifier).rawValue._cfObject)._swiftObject
return result
}
/// Returns a localized string for a specified ISO 4217 currency code.
///
/// For example, in the "en" locale, the result for `"USD"` is `"US Dollar"`.
/// - seealso: `Locale.isoCurrencyCodes`
public func localizedString(forCurrencyCode currencyCode: String) -> String? {
return _wrapped.displayName(forKey: .currencyCode, value: currencyCode)
}
/// Returns a localized string for a specified ICU collation identifier.
///
/// For example, in the "en" locale, the result for `"phonebook"` is `"Phonebook Sort Order"`.
public func localizedString(forCollationIdentifier collationIdentifier: String) -> String? {
return _wrapped.displayName(forKey: .collationIdentifier, value: collationIdentifier)
}
/// Returns a localized string for a specified ICU collator identifier.
public func localizedString(forCollatorIdentifier collatorIdentifier: String) -> String? {
return _wrapped.displayName(forKey: .collatorIdentifier, value: collatorIdentifier)
}
// MARK: -
//
/// Returns the identifier of the locale.
public var identifier: String {
return _wrapped.localeIdentifier
}
/// Returns the language code of the locale, or nil if has none.
///
/// For example, for the locale "zh-Hant-HK", returns "zh".
public var languageCode: String? {
return _wrapped.object(forKey: .languageCode) as? String
}
/// Returns the region code of the locale, or nil if it has none.
///
/// For example, for the locale "zh-Hant-HK", returns "HK".
public var regionCode: String? {
// n.b. this is called countryCode in ObjC
if let result = _wrapped.object(forKey: .countryCode) as? String {
if result.isEmpty {
return nil
} else {
return result
}
} else {
return nil
}
}
/// Returns the script code of the locale, or nil if has none.
///
/// For example, for the locale "zh-Hant-HK", returns "Hant".
public var scriptCode: String? {
return _wrapped.object(forKey: .scriptCode) as? String
}
/// Returns the variant code for the locale, or nil if it has none.
///
/// For example, for the locale "en_POSIX", returns "POSIX".
public var variantCode: String? {
if let result = _wrapped.object(forKey: .variantCode) as? String {
if result.isEmpty {
return nil
} else {
return result
}
} else {
return nil
}
}
/// Returns the exemplar character set for the locale, or nil if has none.
public var exemplarCharacterSet: CharacterSet? {
return _wrapped.object(forKey: .exemplarCharacterSet) as? CharacterSet
}
/// Returns the calendar for the locale, or the Gregorian calendar as a fallback.
public var calendar: Calendar {
// NSLocale should not return nil here
if let result = _wrapped.object(forKey: .calendar) as? Calendar {
return result
} else {
return Calendar(identifier: .gregorian)
}
}
/// Returns the collation identifier for the locale, or nil if it has none.
///
/// For example, for the locale "en_US@collation=phonebook", returns "phonebook".
public var collationIdentifier: String? {
return _wrapped.object(forKey: .collationIdentifier) as? String
}
/// Returns true if the locale uses the metric system.
///
/// -seealso: MeasurementFormatter
public var usesMetricSystem: Bool {
// NSLocale should not return nil here, but just in case
if let result = _wrapped.object(forKey: .usesMetricSystem) as? Bool {
return result
} else {
return false
}
}
/// Returns the decimal separator of the locale.
///
/// For example, for "en_US", returns ".".
public var decimalSeparator: String? {
return _wrapped.object(forKey: .decimalSeparator) as? String
}
/// Returns the grouping separator of the locale.
///
/// For example, for "en_US", returns ",".
public var groupingSeparator: String? {
return _wrapped.object(forKey: .groupingSeparator) as? String
}
/// Returns the currency symbol of the locale.
///
/// For example, for "zh-Hant-HK", returns "HK$".
public var currencySymbol: String? {
return _wrapped.object(forKey: .currencySymbol) as? String
}
/// Returns the currency code of the locale.
///
/// For example, for "zh-Hant-HK", returns "HKD".
public var currencyCode: String? {
return _wrapped.object(forKey: .currencyCode) as? String
}
/// Returns the collator identifier of the locale.
public var collatorIdentifier: String? {
return _wrapped.object(forKey: .collatorIdentifier) as? String
}
/// Returns the quotation begin delimiter of the locale.
///
/// For example, returns `“` for "en_US", and `「` for "zh-Hant-HK".
public var quotationBeginDelimiter: String? {
return _wrapped.object(forKey: .quotationBeginDelimiterKey) as? String
}
/// Returns the quotation end delimiter of the locale.
///
/// For example, returns `”` for "en_US", and `」` for "zh-Hant-HK".
public var quotationEndDelimiter: String? {
return _wrapped.object(forKey: .quotationEndDelimiterKey) as? String
}
/// Returns the alternate quotation begin delimiter of the locale.
///
/// For example, returns `‘` for "en_US", and `『` for "zh-Hant-HK".
public var alternateQuotationBeginDelimiter: String? {
return _wrapped.object(forKey: .alternateQuotationBeginDelimiterKey) as? String
}
/// Returns the alternate quotation end delimiter of the locale.
///
/// For example, returns `’` for "en_US", and `』` for "zh-Hant-HK".
public var alternateQuotationEndDelimiter: String? {
return _wrapped.object(forKey: .alternateQuotationEndDelimiterKey) as? String
}
// MARK: -
//
/// Returns a list of available `Locale` identifiers.
public static var availableIdentifiers: [String] {
return NSLocale.availableLocaleIdentifiers
}
/// Returns a list of available `Locale` language codes.
public static var isoLanguageCodes: [String] {
return NSLocale.isoLanguageCodes
}
/// Returns a list of available `Locale` region codes.
public static var isoRegionCodes: [String] {
// This was renamed from Obj-C
return NSLocale.isoCountryCodes
}
/// Returns a list of available `Locale` currency codes.
public static var isoCurrencyCodes: [String] {
return NSLocale.isoCurrencyCodes
}
/// Returns a list of common `Locale` currency codes.
public static var commonISOCurrencyCodes: [String] {
return NSLocale.commonISOCurrencyCodes
}
/// Returns a list of the user's preferred languages.
///
/// - note: `Bundle` is responsible for determining the language that your application will run in, based on the result of this API and combined with the languages your application supports.
/// - seealso: `Bundle.preferredLocalizations(from:)`
/// - seealso: `Bundle.preferredLocalizations(from:forPreferences:)`
public static var preferredLanguages: [String] {
return NSLocale.preferredLanguages
}
/// Returns a dictionary that splits an identifier into its component pieces.
public static func components(fromIdentifier string: String) -> [String : String] {
return NSLocale.components(fromLocaleIdentifier: string)
}
/// Constructs an identifier from a dictionary of components.
public static func identifier(fromComponents components: [String : String]) -> String {
return NSLocale.localeIdentifier(fromComponents: components)
}
/// Returns a canonical identifier from the given string.
public static func canonicalIdentifier(from string: String) -> String {
return NSLocale.canonicalLocaleIdentifier(from: string)
}
/// Returns a canonical language identifier from the given string.
public static func canonicalLanguageIdentifier(from string: String) -> String {
return NSLocale.canonicalLanguageIdentifier(from: string)
}
/// Returns the `Locale` identifier from a given Windows locale code, or nil if it could not be converted.
public static func identifier(fromWindowsLocaleCode code: Int) -> String? {
return NSLocale.localeIdentifier(fromWindowsLocaleCode: UInt32(code))
}
/// Returns the Windows locale code from a given identifier, or nil if it could not be converted.
public static func windowsLocaleCode(fromIdentifier identifier: String) -> Int? {
let result = NSLocale.windowsLocaleCode(fromLocaleIdentifier: identifier)
if result == 0 {
return nil
} else {
return Int(result)
}
}
/// Returns the character direction for a specified language code.
public static func characterDirection(forLanguage isoLangCode: String) -> Locale.LanguageDirection {
return NSLocale.characterDirection(forLanguage: isoLangCode)
}
/// Returns the line direction for a specified language code.
public static func lineDirection(forLanguage isoLangCode: String) -> Locale.LanguageDirection {
return NSLocale.lineDirection(forLanguage: isoLangCode)
}
// MARK: -
@available(*, unavailable, renamed: "init(identifier:)")
public init(localeIdentifier: String) { fatalError() }
@available(*, unavailable, renamed: "identifier")
public var localeIdentifier: String { fatalError() }
@available(*, unavailable, renamed: "localizedString(forIdentifier:)")
public func localizedString(forLocaleIdentifier localeIdentifier: String) -> String { fatalError() }
@available(*, unavailable, renamed: "availableIdentifiers")
public static var availableLocaleIdentifiers: [String] { fatalError() }
@available(*, unavailable, renamed: "components(fromIdentifier:)")
public static func components(fromLocaleIdentifier string: String) -> [String : String] { fatalError() }
@available(*, unavailable, renamed: "identifier(fromComponents:)")
public static func localeIdentifier(fromComponents dict: [String : String]) -> String { fatalError() }
@available(*, unavailable, renamed: "canonicalIdentifier(from:)")
public static func canonicalLocaleIdentifier(from string: String) -> String { fatalError() }
@available(*, unavailable, renamed: "identifier(fromWindowsLocaleCode:)")
public static func localeIdentifier(fromWindowsLocaleCode lcid: UInt32) -> String? { fatalError() }
@available(*, unavailable, renamed: "windowsLocaleCode(fromIdentifier:)")
public static func windowsLocaleCode(fromLocaleIdentifier localeIdentifier: String) -> UInt32 { fatalError() }
@available(*, unavailable, message: "use regionCode instead")
public var countryCode: String { fatalError() }
@available(*, unavailable, message: "use localizedString(forRegionCode:) instead")
public func localizedString(forCountryCode countryCode: String) -> String { fatalError() }
@available(*, unavailable, renamed: "isoRegionCodes")
public static var isoCountryCodes: [String] { fatalError() }
// MARK: -
//
public var description: String {
return _wrapped.description
}
public var debugDescription : String {
return _wrapped.debugDescription
}
public var hashValue : Int {
if _autoupdating {
return 1
} else {
return _wrapped.hash
}
}
public static func ==(lhs: Locale, rhs: Locale) -> Bool {
if lhs._autoupdating || rhs._autoupdating {
return lhs._autoupdating == rhs._autoupdating
} else {
return lhs._wrapped.isEqual(rhs._wrapped)
}
}
}
extension Locale : _ObjectTypeBridgeable {
public static func _isBridgedToObjectiveC() -> Bool {
return true
}
@_semantics("convertToObjectiveC")
public func _bridgeToObjectiveC() -> NSLocale {
return _wrapped
}
public static func _forceBridgeFromObjectiveC(_ input: NSLocale, result: inout Locale?) {
if !_conditionallyBridgeFromObjectiveC(input, result: &result) {
fatalError("Unable to bridge \(NSLocale.self) to \(self)")
}
}
public static func _conditionallyBridgeFromObjectiveC(_ input: NSLocale, result: inout Locale?) -> Bool {
result = Locale(reference: input)
return true
}
public static func _unconditionallyBridgeFromObjectiveC(_ source: NSLocale?) -> Locale {
var result: Locale? = nil
_forceBridgeFromObjectiveC(source!, result: &result)
return result!
}
}
extension Locale : Codable {
private enum CodingKeys : Int, CodingKey {
case identifier
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let identifier = try container.decode(String.self, forKey: .identifier)
self.init(identifier: identifier)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.identifier, forKey: .identifier)
}
}