1 | import lcid from 'lcid';
|
2 | import {exec, execSync} from './exec.js';
|
3 |
|
4 | const defaultOptions = {spawn: true};
|
5 | const defaultLocale = 'en-US';
|
6 |
|
7 | async function getStdOut(command, args) {
|
8 | return (await exec(command, args)).stdout;
|
9 | }
|
10 |
|
11 | function getStdOutSync(command, args) {
|
12 | return execSync(command, args);
|
13 | }
|
14 |
|
15 | function getEnvLocale(env = process.env) {
|
16 | return env.LC_ALL || env.LC_MESSAGES || env.LANG || env.LANGUAGE;
|
17 | }
|
18 |
|
19 | function parseLocale(string) {
|
20 | const env = {};
|
21 | for (const definition of string.split('\n')) {
|
22 | const [key, value] = definition.split('=');
|
23 | env[key] = value.replace(/^"|"$/g, '');
|
24 | }
|
25 |
|
26 | return getEnvLocale(env);
|
27 | }
|
28 |
|
29 | function getLocale(string) {
|
30 | return (string && string.replace(/[.:].*/, ''));
|
31 | }
|
32 |
|
33 | async function getLocales() {
|
34 | return getStdOut('locale', ['-a']);
|
35 | }
|
36 |
|
37 | function getLocalesSync() {
|
38 | return getStdOutSync('locale', ['-a']);
|
39 | }
|
40 |
|
41 | function getSupportedLocale(locale, locales = '') {
|
42 | return locales.includes(locale) ? locale : defaultLocale;
|
43 | }
|
44 |
|
45 | async function getAppleLocale() {
|
46 | const results = await Promise.all([
|
47 | getStdOut('defaults', ['read', '-globalDomain', 'AppleLocale']),
|
48 | getLocales(),
|
49 | ]);
|
50 |
|
51 | return getSupportedLocale(results[0], results[1]);
|
52 | }
|
53 |
|
54 | function getAppleLocaleSync() {
|
55 | return getSupportedLocale(
|
56 | getStdOutSync('defaults', ['read', '-globalDomain', 'AppleLocale']),
|
57 | getLocalesSync(),
|
58 | );
|
59 | }
|
60 |
|
61 | async function getUnixLocale() {
|
62 | return getLocale(parseLocale(await getStdOut('locale')));
|
63 | }
|
64 |
|
65 | function getUnixLocaleSync() {
|
66 | return getLocale(parseLocale(getStdOutSync('locale')));
|
67 | }
|
68 |
|
69 | async function getWinLocale() {
|
70 | const stdout = await getStdOut('wmic', ['os', 'get', 'locale']);
|
71 | const lcidCode = Number.parseInt(stdout.replace('Locale', ''), 16);
|
72 |
|
73 | return lcid.from(lcidCode);
|
74 | }
|
75 |
|
76 | function getWinLocaleSync() {
|
77 | const stdout = getStdOutSync('wmic', ['os', 'get', 'locale']);
|
78 | const lcidCode = Number.parseInt(stdout.replace('Locale', ''), 16);
|
79 |
|
80 | return lcid.from(lcidCode);
|
81 | }
|
82 |
|
83 | function normalise(input) {
|
84 | return input.replace(/_/, '-');
|
85 | }
|
86 |
|
87 | const cache = new Map();
|
88 |
|
89 | export async function osLocale(options = defaultOptions) {
|
90 | if (cache.has(options.spawn)) {
|
91 | return cache.get(options.spawn);
|
92 | }
|
93 |
|
94 | let locale;
|
95 |
|
96 | try {
|
97 | const envLocale = getEnvLocale();
|
98 |
|
99 | if (envLocale || options.spawn === false) {
|
100 | locale = getLocale(envLocale);
|
101 | } else if (process.platform === 'win32') {
|
102 | locale = await getWinLocale();
|
103 | } else if (process.platform === 'darwin') {
|
104 | locale = await getAppleLocale();
|
105 | } else {
|
106 | locale = await getUnixLocale();
|
107 | }
|
108 | } catch {}
|
109 |
|
110 | const normalised = normalise(locale || defaultLocale);
|
111 | cache.set(options.spawn, normalised);
|
112 | return normalised;
|
113 | }
|
114 |
|
115 | export function osLocaleSync(options = defaultOptions) {
|
116 | if (cache.has(options.spawn)) {
|
117 | return cache.get(options.spawn);
|
118 | }
|
119 |
|
120 | let locale;
|
121 | try {
|
122 | const envLocale = getEnvLocale();
|
123 |
|
124 | if (envLocale || options.spawn === false) {
|
125 | locale = getLocale(envLocale);
|
126 | } else if (process.platform === 'win32') {
|
127 | locale = getWinLocaleSync();
|
128 | } else if (process.platform === 'darwin') {
|
129 | locale = getAppleLocaleSync();
|
130 | } else {
|
131 | locale = getUnixLocaleSync();
|
132 | }
|
133 | } catch {}
|
134 |
|
135 | const normalised = normalise(locale || defaultLocale);
|
136 | cache.set(options.spawn, normalised);
|
137 | return normalised;
|
138 | }
|