1use objc::{msg_send, sel, sel_impl};
2
3use crate::{
4 object,
5 objective_c_runtime::{
6 id,
7 macros::interface_impl,
8 nil,
9 traits::{FromId, PNSObject},
10 },
11 utils::to_bool,
12};
13
14use super::{
15 NSArray, NSCharacterSet, NSCoder, NSDictionary, NSLocaleKey, NSNotificationName, NSString,
16};
17
18#[repr(usize)]
20#[derive(Debug)]
21pub enum LanguageDirection {
22 Unknown = 0,
24 LeftToRight = 1,
26 RightToLeft = 2,
28 TopToBottom = 3,
30 BottomToTop = 4,
32}
33
34object! {
35 unsafe pub struct NSLocale;
37}
38
39#[interface_impl(NSObject)]
40impl NSLocale {
41 #[method]
46 pub fn locale_with_locale_identifier(string: &NSString) -> Self
47 where
48 Self: Sized + FromId,
49 {
50 unsafe {
51 let ptr = msg_send![Self::m_class(), localeWithLocaleIdentifier: string.m_self()];
52 FromId::from_id(ptr)
53 }
54 }
55
56 #[method]
58 pub fn init_with_locale_identifier(&mut self, locale_identifier: &NSString) -> Self
59 where
60 Self: Sized + FromId,
61 {
62 unsafe {
63 let ptr =
64 msg_send![self.m_self(), initWithLocaleIdentifier: locale_identifier.m_self()];
65 FromId::from_id(ptr)
66 }
67 }
68
69 #[method]
71 pub fn init_with_coder(&mut self, coder: &NSCoder) -> Self
72 where
73 Self: Sized + FromId,
74 {
75 unsafe { Self::from_id(msg_send![self.m_self(), initWithCoder: coder.m_self()]) }
76 }
77
78 #[property]
83 pub fn autoupdating_current_locale() -> NSLocale {
84 unsafe { NSLocale::from_id(msg_send![Self::m_class(), autoupdatingCurrentLocale]) }
85 }
86
87 #[property]
89 pub fn current_locale() -> NSLocale {
90 unsafe { NSLocale::from_id(msg_send![Self::m_class(), currentLocale]) }
91 }
92
93 #[property]
95 pub fn system_locale() -> NSLocale {
96 unsafe { NSLocale::from_id(msg_send![Self::m_class(), systemLocale]) }
97 }
98
99 #[property]
104 pub fn available_locale_identifiers() -> NSArray<NSString> {
105 unsafe { NSArray::from_id(msg_send![Self::m_class(), availableLocaleIdentifiers]) }
106 }
107
108 #[property]
110 pub fn iso_country_codes() -> NSArray<NSString> {
111 unsafe { NSArray::from_id(msg_send![Self::m_class(), ISOCountryCodes]) }
112 }
113
114 #[property]
116 pub fn iso_language_codes() -> NSArray<NSString> {
117 unsafe { NSArray::from_id(msg_send![Self::m_class(), ISOLanguageCodes]) }
118 }
119
120 #[property]
122 pub fn iso_currency_codes() -> NSArray<NSString> {
123 unsafe { NSArray::from_id(msg_send![Self::m_class(), ISOCurrencyCodes]) }
124 }
125
126 #[property]
128 pub fn common_isocurrency_codes() -> NSArray<NSString> {
129 unsafe { NSArray::from_id(msg_send![Self::m_class(), commonISOCurrencyCodes]) }
130 }
131
132 #[method]
137 pub fn canonical_locale_identifier_from_string(string: &NSString) -> NSString {
138 unsafe {
139 NSString::from_id(msg_send![
140 Self::m_class(),
141 canonicalLocaleIdentifierFromString: string.m_self()
142 ])
143 }
144 }
145
146 #[method]
148 pub fn components_from_locale_identifier(
149 string: &NSString,
150 ) -> NSDictionary<NSString, NSString> {
151 unsafe {
152 NSDictionary::from_id(msg_send![
153 Self::m_class(),
154 componentsFromLocaleIdentifier: string.m_self()
155 ])
156 }
157 }
158
159 #[method]
161 pub fn locale_identifier_from_components(dict: &NSDictionary<NSString, NSString>) -> NSString {
162 unsafe {
163 NSString::from_id(msg_send![
164 Self::m_class(),
165 localeIdentifierFromComponents: dict.m_self()
166 ])
167 }
168 }
169
170 #[method]
172 pub fn canonical_language_identifier_from_string(string: &NSString) -> NSString {
173 unsafe {
174 NSString::from_id(msg_send![
175 Self::m_class(),
176 canonicalLanguageIdentifierFromString: string.m_self()
177 ])
178 }
179 }
180
181 #[method]
183 pub fn locale_identifier_from_windows_locale_code(lcid: u32) -> Option<NSString> {
184 unsafe {
185 let ptr = msg_send![Self::m_class(), localeIdentifierFromWindowsLocaleCode: lcid];
186
187 if ptr != nil {
188 Some(NSString::from_id(ptr))
189 } else {
190 None
191 }
192 }
193 }
194
195 #[method]
197 pub fn windows_locale_code_from_locale_identifier(locale_identifier: &NSString) -> u32 {
198 unsafe {
199 msg_send![
200 Self::m_class(),
201 windowsLocaleCodeFromLocaleIdentifier: locale_identifier.m_self()
202 ]
203 }
204 }
205
206 #[property]
211 pub fn locale_identifier(&self) -> NSString {
212 unsafe { NSString::from_id(msg_send![self.m_self(), localeIdentifier]) }
213 }
214
215 #[property]
217 pub fn country_code(&self) -> Option<NSString> {
218 unsafe {
219 let ptr = msg_send![self.m_self(), countryCode];
220
221 if ptr != nil {
222 Some(NSString::from_id(ptr))
223 } else {
224 None
225 }
226 }
227 }
228
229 #[property]
231 pub fn language_code(&self) -> NSString {
232 unsafe { NSString::from_id(msg_send![self.m_self(), languageCode]) }
233 }
234
235 #[property]
237 pub fn script_code(&self) -> Option<NSString> {
238 unsafe {
239 let ptr = msg_send![self.m_self(), scriptCode];
240
241 if ptr != nil {
242 Some(NSString::from_id(ptr))
243 } else {
244 None
245 }
246 }
247 }
248
249 #[property]
251 pub fn variant_code(&self) -> Option<NSString> {
252 unsafe {
253 let ptr = msg_send![self.m_self(), variantCode];
254
255 if ptr != nil {
256 Some(NSString::from_id(ptr))
257 } else {
258 None
259 }
260 }
261 }
262
263 #[property]
265 pub fn exemplar_character_set(&self) -> NSCharacterSet {
266 unsafe { NSCharacterSet::from_id(msg_send![self.m_self(), exemplarCharacterSet]) }
267 }
268
269 #[property]
271 pub fn collation_identifier(&self) -> Option<NSString> {
272 unsafe {
273 let ptr = msg_send![self.m_self(), collationIdentifier];
274
275 if ptr != nil {
276 Some(NSString::from_id(ptr))
277 } else {
278 None
279 }
280 }
281 }
282
283 #[property]
285 pub fn collator_identifier(&self) -> NSString {
286 unsafe { NSString::from_id(msg_send![self.m_self(), collatorIdentifier]) }
287 }
288
289 #[property]
291 pub fn uses_metric_system(&self) -> bool {
292 unsafe { to_bool(msg_send![self.m_self(), usesMetricSystem]) }
293 }
294
295 #[property]
297 pub fn decimal_separator(&self) -> NSString {
298 unsafe { NSString::from_id(msg_send![self.m_self(), decimalSeparator]) }
299 }
300
301 #[property]
303 pub fn grouping_separator(&self) -> NSString {
304 unsafe { NSString::from_id(msg_send![self.m_self(), groupingSeparator]) }
305 }
306
307 #[property]
309 pub fn currency_code(&self) -> Option<NSString> {
310 unsafe {
311 let ptr = msg_send![self.m_self(), currencyCode];
312
313 if ptr != nil {
314 Some(NSString::from_id(ptr))
315 } else {
316 None
317 }
318 }
319 }
320
321 #[property]
323 pub fn currency_symbol(&self) -> NSString {
324 unsafe { NSString::from_id(msg_send![self.m_self(), currencySymbol]) }
325 }
326
327 #[property]
329 pub fn calendar_identifier(&self) -> NSString {
330 unsafe { NSString::from_id(msg_send![self.m_self(), calendarIdentifier]) }
331 }
332
333 #[property]
335 pub fn quotation_begin_delimiter(&self) -> NSString {
336 unsafe { NSString::from_id(msg_send![self.m_self(), quotationBeginDelimiter]) }
337 }
338
339 #[property]
341 pub fn quotation_end_delimiter(&self) -> NSString {
342 unsafe { NSString::from_id(msg_send![self.m_self(), quotationEndDelimiter]) }
343 }
344
345 #[property]
347 pub fn alternate_quotation_begin_delimiter(&self) -> NSString {
348 unsafe { NSString::from_id(msg_send![self.m_self(), alternateQuotationBeginDelimiter]) }
349 }
350
351 #[property]
353 pub fn alternate_quotation_end_delimiter(&self) -> NSString {
354 unsafe { NSString::from_id(msg_send![self.m_self(), alternateQuotationEndDelimiter]) }
355 }
356
357 #[method]
362 pub fn localized_string_for_locale_identifier(&self, locale_identifier: &NSString) -> NSString {
363 unsafe {
364 NSString::from_id(msg_send![
365 self.m_self(),
366 localizedStringForLocaleIdentifier: locale_identifier.m_self()
367 ])
368 }
369 }
370
371 #[method]
373 pub fn localized_string_for_country_code(&self, country_code: &NSString) -> Option<NSString> {
374 unsafe {
375 let ptr = msg_send![
376 self.m_self(),
377 localizedStringForCountryCode: country_code.m_self()
378 ];
379
380 if ptr != nil {
381 Some(NSString::from_id(ptr))
382 } else {
383 None
384 }
385 }
386 }
387
388 #[method]
390 pub fn localized_string_for_language_code(&self, language_code: &NSString) -> Option<NSString> {
391 unsafe {
392 let ptr =
393 msg_send![self.m_self(), localizedStringForLanguageCode: language_code.m_self()];
394
395 if ptr != nil {
396 Some(NSString::from_id(ptr))
397 } else {
398 None
399 }
400 }
401 }
402
403 #[method]
405 pub fn localized_string_for_script_code(&self, script_code: &NSString) -> Option<NSString> {
406 unsafe {
407 let ptr = msg_send![self.m_self(), localizedStringForScriptCode: script_code.m_self()];
408
409 if ptr != nil {
410 Some(NSString::from_id(ptr))
411 } else {
412 None
413 }
414 }
415 }
416 #[method]
418 pub fn localized_string_for_variant_code(&self, variant_code: &NSString) -> Option<NSString> {
419 unsafe {
420 let ptr =
421 msg_send![self.m_self(), localizedStringForVariantCode: variant_code.m_self()];
422
423 if ptr != nil {
424 Some(NSString::from_id(ptr))
425 } else {
426 None
427 }
428 }
429 }
430 #[method]
432 pub fn localized_string_for_collation_identifier(
433 &self,
434 collation_identifier: &NSString,
435 ) -> Option<NSString> {
436 unsafe {
437 let ptr = msg_send![
438 self.m_self(),
439 localizedStringForCollationIdentifier: collation_identifier.m_self()
440 ];
441
442 if ptr != nil {
443 Some(NSString::from_id(ptr))
444 } else {
445 None
446 }
447 }
448 }
449 #[method]
451 pub fn localized_string_for_collator_identifier(
452 &self,
453 collator_identifier: &NSString,
454 ) -> Option<NSString> {
455 unsafe {
456 let ptr = msg_send![
457 self.m_self(),
458 localizedStringForCollatorIdentifier: collator_identifier
459 ];
460
461 if ptr != nil {
462 Some(NSString::from_id(ptr))
463 } else {
464 None
465 }
466 }
467 }
468 #[method]
470 pub fn localized_string_for_currency_code(&self, currency_code: &NSString) -> Option<NSString> {
471 unsafe {
472 let ptr =
473 msg_send![self.m_self(), localizedStringForCurrencyCode: currency_code.m_self()];
474
475 if ptr != nil {
476 Some(NSString::from_id(ptr))
477 } else {
478 None
479 }
480 }
481 }
482 #[method]
484 pub fn localized_string_for_calendar_identifier(
485 &self,
486 calendar_identifier: &NSString,
487 ) -> Option<NSString> {
488 unsafe {
489 let ptr = msg_send![
490 self.m_self(),
491 localizedStringForCalendarIdentifier: calendar_identifier.m_self()
492 ];
493
494 if ptr != nil {
495 Some(NSString::from_id(ptr))
496 } else {
497 None
498 }
499 }
500 }
501 #[method]
506 pub fn object_for_key(&self, key: NSLocaleKey) -> Option<id> {
507 unsafe {
508 let obj: id = msg_send![self.m_self(), objectForKey: key];
509 if obj == nil {
510 None
511 } else {
512 Some(obj)
513 }
514 }
515 }
516
517 #[method]
519 pub fn display_name_for_key_value(
520 &self,
521 key: NSLocaleKey,
522 value: &NSString,
523 ) -> Option<NSString> {
524 unsafe {
525 let obj: id = msg_send![self.m_self(), displayNameForKey: key value: value.m_self()];
526 if obj == nil {
527 None
528 } else {
529 Some(NSString::from_id(obj))
530 }
531 }
532 }
533
534 #[property]
539 pub fn preferred_languages() -> NSArray<NSString> {
540 unsafe { NSArray::from_id(msg_send![Self::m_class(), preferredLanguages]) }
541 }
542
543 #[method]
548 pub fn character_direction_for_language(iso_language_code: NSString) -> LanguageDirection {
549 unsafe {
550 msg_send![
551 Self::m_class(),
552 characterDirectionForLanguage: iso_language_code
553 ]
554 }
555 }
556
557 #[method]
559 pub fn line_direction_for_language(iso_language_code: NSString) -> LanguageDirection {
560 unsafe { msg_send![Self::m_class(), lineDirectionForLanguage: iso_language_code] }
561 }
562}
563
564extern "C" {
565 pub static NSCurrentLocaleDidChangeNotification: NSNotificationName;
567}
568
569#[cfg(test)]
570mod tests {
571 use super::NSLocale;
572
573 use crate::{
574 foundation::NSString,
575 objective_c_runtime::{nil, traits::PNSObject},
576 };
577
578 #[test]
579 fn test_current_locale() {
580 let locale = NSLocale::current_locale();
581 assert!(locale.m_self() != nil)
582 }
583
584 #[test]
585 fn test_init_with_locale_identifier() {
586 let ident = NSLocale::current_locale().locale_identifier();
587
588 assert!(
589 NSLocale::m_alloc()
590 .init_with_locale_identifier(&ident)
591 .locale_identifier()
592 == NSLocale::current_locale().locale_identifier()
593 );
594
595 assert!(
596 NSLocale::m_alloc()
597 .init_with_locale_identifier(&ident)
598 .locale_identifier()
599 == NSLocale::current_locale().locale_identifier()
600 );
601
602 assert!(
603 NSLocale::m_alloc()
604 .init_with_locale_identifier(&ident)
605 .locale_identifier()
606 == NSLocale::current_locale().locale_identifier()
607 );
608 }
609
610 #[test]
611 fn test_locale_with_locale_identifier() {
612 let ident = NSLocale::current_locale().locale_identifier();
613
614 assert!(
615 NSLocale::locale_with_locale_identifier(&ident).locale_identifier()
616 == NSLocale::current_locale().locale_identifier()
617 );
618
619 assert!(
620 NSLocale::locale_with_locale_identifier(&ident).locale_identifier()
621 == NSLocale::current_locale().locale_identifier()
622 );
623
624 assert!(
625 NSLocale::locale_with_locale_identifier(&ident).locale_identifier()
626 == NSLocale::current_locale().locale_identifier()
627 );
628 }
629
630 #[test]
631 fn test_country_less_locale() {
632 let name: NSString = "zh-Hans".into();
633 assert!(NSLocale::locale_with_locale_identifier(&name)
634 .country_code()
635 .is_none());
636 }
637
638 #[test]
639 fn test_properties() {
640 let en = NSLocale::locale_with_locale_identifier(&"en-US".into());
641 assert_eq!(en.alternate_quotation_begin_delimiter(), "‘");
642 assert_eq!(en.alternate_quotation_end_delimiter(), "’");
643 assert!(en.collation_identifier().is_none());
644 assert_eq!(en.collator_identifier(), "en-US");
645 assert_eq!(en.country_code(), Some("US".into()));
646 assert_eq!(en.currency_code(), Some("USD".into()));
647 assert_eq!(en.currency_symbol(), "$");
648 assert_eq!(en.decimal_separator(), ".");
649 assert_eq!(en.grouping_separator(), ",");
650 assert_eq!(en.language_code(), "en");
651 assert_eq!(en.locale_identifier(), "en-US");
652 assert_eq!(en.quotation_begin_delimiter(), "“");
653 assert_eq!(en.quotation_end_delimiter(), "”");
654 }
655}