native_windows_gui2/winnls/
locale.rs1use super::*;
2use crate::NwgError;
3use crate::win32::base_helper::{from_utf16, to_utf16};
4use std::{mem, ptr};
5use winapi::um::winnls::{
6 GetLocaleInfoEx, GetSystemDefaultLocaleName, GetUserDefaultLocaleName, LCTYPE,
7};
8use winapi::um::winnt::{LOCALE_NAME_MAX_LENGTH, LPWSTR};
9
10#[derive(Clone)]
27pub struct Locale {
28 name: String,
29 name_buffer: Vec<u16>,
30}
31
32impl Locale {
33 pub fn new(name: String) -> Result<Locale, NwgError> {
35 let name_buffer = to_utf16(&name);
36 match Locale::locale_valid(&name_buffer) {
37 true => Ok(Locale { name, name_buffer }),
38 false => Err(NwgError::bad_locale("Locale name is not valid")),
39 }
40 }
41
42 pub fn from_str<'a>(name: &'a str) -> Result<Locale, NwgError> {
44 let name_buffer = to_utf16(name);
45 match Locale::locale_valid(&name_buffer) {
46 true => Ok(Locale {
47 name: name.to_string(),
48 name_buffer,
49 }),
50 false => Err(NwgError::bad_locale("Locale name is not valid")),
51 }
52 }
53
54 pub fn all() -> Vec<String> {
56 use crate::win32::base_helper::from_wide_ptr;
57 use winapi::shared::minwindef::{BOOL, DWORD, LPARAM};
58 use winapi::um::winnls::EnumSystemLocalesEx;
59
60 extern "system" fn enum_locales(locale: LPWSTR, _flags: DWORD, p: LPARAM) -> BOOL {
61 let locales: *mut Vec<String> = p as *mut Vec<String>;
62 unsafe { (&mut *locales).push(from_wide_ptr(locale, None)) };
63 1
64 }
65
66 unsafe {
67 let mut locales: Vec<String> = Vec::with_capacity(10);
68 EnumSystemLocalesEx(
69 Some(enum_locales),
70 1,
71 &mut locales as *mut Vec<String> as LPARAM,
72 ptr::null_mut(),
73 );
74 locales
75 }
76 }
77
78 pub fn user() -> Locale {
80 let mut name_buffer: Vec<u16> = Vec::with_capacity(LOCALE_NAME_MAX_LENGTH);
81 unsafe {
82 name_buffer.set_len(LOCALE_NAME_MAX_LENGTH);
83 GetUserDefaultLocaleName(name_buffer.as_mut_ptr(), LOCALE_NAME_MAX_LENGTH as i32);
84 }
85
86 Locale {
87 name: from_utf16(&name_buffer),
88 name_buffer,
89 }
90 }
91
92 pub fn system() -> Locale {
94 let mut name_buffer: Vec<u16> = Vec::with_capacity(LOCALE_NAME_MAX_LENGTH);
95 unsafe {
96 name_buffer.set_len(LOCALE_NAME_MAX_LENGTH);
97 GetSystemDefaultLocaleName(name_buffer.as_mut_ptr(), LOCALE_NAME_MAX_LENGTH as i32);
98 }
99
100 Locale {
101 name: from_utf16(&name_buffer),
102 name_buffer,
103 }
104 }
105
106 pub fn name(&self) -> &str {
108 &self.name
109 }
110
111 pub fn display_name(&self) -> String {
113 self.get_locale_info_string(0x00000002)
114 }
115
116 pub fn english_display_name(&self) -> String {
118 self.get_locale_info_string(0x00000072)
119 }
120
121 pub fn native_display_name(&self) -> String {
123 self.get_locale_info_string(0x00000072)
124 }
125
126 pub fn country_name(&self) -> String {
128 self.get_locale_info_string(0x00000006)
129 }
130
131 pub fn english_country_name(&self) -> String {
133 self.get_locale_info_string(0x00001002)
134 }
135
136 pub fn native_country_name(&self) -> String {
138 self.get_locale_info_string(0x00000008)
139 }
140
141 pub fn dialing_code(&self) -> i32 {
143 self.get_locale_info_int(0x00000005)
144 }
145
146 pub fn list_separator(&self) -> String {
148 self.get_locale_info_string(0x0000000C)
149 }
150
151 pub fn measurement_system(&self) -> MeasurementSystem {
153 match self.get_locale_info_int(0x0000000D) {
154 0 => MeasurementSystem::Metric,
155 _ => MeasurementSystem::Imperial,
156 }
157 }
158
159 pub fn decimal_separator(&self) -> String {
161 self.get_locale_info_string(0x0000000E)
162 }
163
164 pub fn thousand_separator(&self) -> String {
166 self.get_locale_info_string(0x0000000F)
167 }
168
169 pub fn digit_grouping(&self) -> String {
171 self.get_locale_info_string(0x00000010)
172 }
173
174 pub fn fractional_digit(&self) -> i32 {
176 self.get_locale_info_int(0x00000011)
177 }
178
179 pub fn leading_zeros(&self) -> i32 {
181 self.get_locale_info_int(0x00000012)
182 }
183
184 pub fn negative_number_mode(&self) -> NegativeNumberMode {
186 match self.get_locale_info_int(0x00001010) {
187 0 => NegativeNumberMode::Mode0,
188 1 => NegativeNumberMode::Mode1,
189 2 => NegativeNumberMode::Mode2,
190 3 => NegativeNumberMode::Mode3,
191 4 => NegativeNumberMode::Mode4,
192 _ => NegativeNumberMode::Mode1,
193 }
194 }
195
196 pub fn native_digits(&self) -> String {
198 self.get_locale_info_string(0x00000013)
199 }
200
201 pub fn currency_symbol(&self) -> String {
203 self.get_locale_info_string(0x00000014)
204 }
205
206 pub fn intl_monetary_symbol(&self) -> String {
208 self.get_locale_info_string(0x00000015)
209 }
210
211 pub fn monetary_decimal_separator(&self) -> String {
213 self.get_locale_info_string(0x00000016)
214 }
215
216 pub fn monetary_thousand_separator(&self) -> String {
218 self.get_locale_info_string(0x00000017)
219 }
220
221 pub fn monetary_digit_grouping(&self) -> String {
223 self.get_locale_info_string(0x00000018)
224 }
225
226 pub fn monetary_fractional_digit(&self) -> i32 {
228 self.get_locale_info_int(0x00000019)
229 }
230
231 pub fn currency_mode(&self) -> PositiveCurrency {
233 match self.get_locale_info_int(0x0000001B) {
234 0 => PositiveCurrency::Mode0,
235 1 => PositiveCurrency::Mode1,
236 2 => PositiveCurrency::Mode2,
237 3 => PositiveCurrency::Mode3,
238 _ => PositiveCurrency::Mode1,
239 }
240 }
241
242 pub fn negative_currency_mode(&self) -> NegativeCurrency {
244 let id = self.get_locale_info_int(0x00001009) as u32;
245 match id <= 15 {
246 true => unsafe { mem::transmute(id) },
247 false => NegativeCurrency::Mode1,
248 }
249 }
250
251 pub fn short_date(&self) -> String {
253 self.get_locale_info_string(0x0000001F)
254 }
255
256 pub fn long_date(&self) -> String {
258 self.get_locale_info_string(0x00000020)
259 }
260
261 pub fn time(&self) -> String {
263 self.get_locale_info_string(0x00001003)
264 }
265
266 pub fn am(&self) -> String {
268 self.get_locale_info_string(0x00000028)
269 }
270
271 pub fn pm(&self) -> String {
273 self.get_locale_info_string(0x00000029)
274 }
275
276 pub fn calendar(&self) -> Calendar {
278 let id = self.get_locale_info_int(0x00001009) as u32;
279 match id <= 23 {
280 true => unsafe { mem::transmute(id) },
281 false => Calendar::Gregorian,
282 }
283 }
284
285 pub fn calendar2(&self) -> Calendar {
287 let id = self.get_locale_info_int(0x0000100B) as u32;
288 match id <= 23 {
289 true => unsafe { mem::transmute(id) },
290 false => Calendar::Gregorian,
291 }
292 }
293
294 pub fn first_day_of_week(&self) -> i32 {
296 self.get_locale_info_int(0x0000100C)
297 }
298
299 pub fn first_day_of_year(&self) -> FirstDayOfYear {
301 match self.get_locale_info_int(0x0000100D) {
302 0 => FirstDayOfYear::Mode0,
303 1 => FirstDayOfYear::Mode1,
304 2 => FirstDayOfYear::Mode2,
305 _ => FirstDayOfYear::Mode0,
306 }
307 }
308
309 pub fn iso_lang_name(&self) -> String {
311 self.get_locale_info_string(0x00000059)
312 }
313
314 pub fn iso_country_name(&self) -> String {
316 self.get_locale_info_string(0x0000005A)
317 }
318
319 pub fn currency_name(&self) -> String {
321 self.get_locale_info_string(0x00001007)
322 }
323
324 pub fn native_currency_name(&self) -> String {
326 self.get_locale_info_string(0x00001008)
327 }
328
329 pub fn month_name(&self, month_index: u32) -> String {
339 match month_index {
340 1 => self.get_locale_info_string(0x00000038),
341 2 => self.get_locale_info_string(0x00000039),
342 3 => self.get_locale_info_string(0x0000003A),
343 4 => self.get_locale_info_string(0x0000003B),
344 5 => self.get_locale_info_string(0x0000003C),
345 6 => self.get_locale_info_string(0x0000003D),
346 7 => self.get_locale_info_string(0x0000003E),
347 8 => self.get_locale_info_string(0x0000003F),
348 9 => self.get_locale_info_string(0x00000040),
349 10 => self.get_locale_info_string(0x00000041),
350 11 => self.get_locale_info_string(0x00000042),
351 12 => self.get_locale_info_string(0x00000043),
352 13 => self.get_locale_info_string(0x0000100E),
353 x => panic!("{} is not a valid month index", x),
354 }
355 }
356
357 pub fn month_name_abv(&self, month_index: u32) -> String {
367 match month_index {
368 1 => self.get_locale_info_string(0x00000044),
369 2 => self.get_locale_info_string(0x00000045),
370 3 => self.get_locale_info_string(0x00000046),
371 4 => self.get_locale_info_string(0x00000047),
372 5 => self.get_locale_info_string(0x00000048),
373 6 => self.get_locale_info_string(0x00000049),
374 7 => self.get_locale_info_string(0x0000004A),
375 8 => self.get_locale_info_string(0x0000004B),
376 9 => self.get_locale_info_string(0x0000004C),
377 10 => self.get_locale_info_string(0x0000004D),
378 11 => self.get_locale_info_string(0x0000004E),
379 12 => self.get_locale_info_string(0x0000004F),
380 13 => self.get_locale_info_string(0x0000100F),
381 x => panic!("{} is not a valid month index", x),
382 }
383 }
384
385 pub fn day_name(&self, day_index: u32) -> String {
395 match day_index {
396 1 => self.get_locale_info_string(0x0000002A),
397 2 => self.get_locale_info_string(0x0000002B),
398 3 => self.get_locale_info_string(0x0000002C),
399 4 => self.get_locale_info_string(0x0000002D),
400 5 => self.get_locale_info_string(0x0000002E),
401 6 => self.get_locale_info_string(0x0000002F),
402 7 => self.get_locale_info_string(0x00000030),
403 x => panic!("{} is not a valid day index", x),
404 }
405 }
406
407 pub fn day_name_abv(&self, day_index: u32) -> String {
417 match day_index {
418 1 => self.get_locale_info_string(0x00000031),
419 2 => self.get_locale_info_string(0x00000032),
420 3 => self.get_locale_info_string(0x00000033),
421 4 => self.get_locale_info_string(0x00000034),
422 5 => self.get_locale_info_string(0x00000035),
423 6 => self.get_locale_info_string(0x00000036),
424 7 => self.get_locale_info_string(0x00000037),
425 x => panic!("{} is not a valid day index", x),
426 }
427 }
428
429 fn get_locale_info_string(&self, info: LCTYPE) -> String {
430 unsafe {
431 let buffer_size =
432 GetLocaleInfoEx(self.name_buffer.as_ptr(), info, ptr::null_mut(), 0) as usize;
433 let mut buffer: Vec<u16> = Vec::with_capacity(buffer_size);
434 buffer.set_len(buffer_size);
435
436 GetLocaleInfoEx(
437 self.name_buffer.as_ptr(),
438 info,
439 buffer.as_mut_ptr(),
440 buffer_size as i32,
441 );
442
443 from_utf16(&buffer)
444 }
445 }
446
447 fn get_locale_info_int(&self, info: LCTYPE) -> i32 {
448 let mut out = 0i32;
449 let return_number = 0x20000000;
450
451 unsafe {
452 let out_ptr = &mut out as *mut i32 as *mut u16;
453 GetLocaleInfoEx(
454 self.name_buffer.as_ptr(),
455 info | return_number,
456 out_ptr,
457 mem::size_of::<i32>() as i32,
458 );
459 }
460
461 out
462 }
463
464 fn locale_valid(buffer: &[u16]) -> bool {
465 use winapi::um::winnls::IsValidLocaleName;
466 unsafe { IsValidLocaleName(buffer.as_ptr()) != 0 }
467 }
468}
469
470use std::fmt;
471
472impl fmt::Debug for Locale {
473 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
474 write!(f, "Locale {{ name: {}, }}", self.name)
475 }
476}
477
478impl fmt::Display for Locale {
479 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
480 write!(f, "{}", self.name)
481 }
482}