forked from swiftlang/swift-corelibs-foundation
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLocale.swift
485 lines (400 loc) · 18.6 KB
/
Locale.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
//===----------------------------------------------------------------------===//
//
// 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)
}
}