Skip to content

Commit

Permalink
lib: add navigator.language & navigator.languages
Browse files Browse the repository at this point in the history
  • Loading branch information
Uzlopak committed Oct 30, 2023
1 parent 14af167 commit fed4162
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 1 deletion.
44 changes: 44 additions & 0 deletions doc/api/globals.md
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,50 @@ logical processors available to the current Node.js instance.
console.log(`This process is running on ${navigator.hardwareConcurrency} logical processors`);
```

### `navigator.language`

<!-- YAML
added: REPLACEME
-->

* {string}

The `navigator.language` read-only property returns a string representing the
preferred language of the Node.js instance.

The value is representing the language version as defined in RFC <5646>.

You can override the value of `navigator.language` by setting the
`LC_ALL` environment variable.

For example:
```sh
LC_ALL=fr-FR node -p "console.log(navigator.language)"
```

The fallback value on builds without ICU is `'en-US'`.

```js
console.log(`The preferred language of the Node.js instance has the tag '${navigator.language}'`);
```

### `navigator.languages`

<!-- YAML
added: REPLACEME
-->

* {Array<string>}

The `navigator.languages` read-only property returns an array of strings
representing the preferred languages of the Node.js instance.
By default it contains only the value of `navigator.language`.
The fallback value on builds without ICU is `['en-US']`.

```js
console.log(`The preferred languages are '${navigator.language}'`);
```

### `navigator.userAgent`

<!-- YAML
Expand Down
24 changes: 24 additions & 0 deletions lib/internal/navigator.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@

const {
ObjectDefineProperties,
ObjectFreeze,
globalThis,
Symbol,
} = primordials;

const {
Intl,
} = globalThis;

const {
ERR_ILLEGAL_CONSTRUCTOR,
} = require('internal/errors').codes;
Expand All @@ -24,6 +30,8 @@ class Navigator {
// Private properties are used to avoid brand validations.
#availableParallelism;
#userAgent = `Node.js/${nodeVersion.slice(1, nodeVersion.indexOf('.'))}`;
#language = Intl?.Collator().resolvedOptions().locale || 'en-US';
#languages = ObjectFreeze([this.#language]);

constructor() {
if (arguments[0] === kInitialize) {
Expand All @@ -40,6 +48,20 @@ class Navigator {
return this.#availableParallelism;
}

/**
* @return {string}
*/
get language() {
return this.#language;
}

/**
* @return {Array<string>}
*/
get languages() {
return this.#languages;
}

/**
* @return {string}
*/
Expand All @@ -50,6 +72,8 @@ class Navigator {

ObjectDefineProperties(Navigator.prototype, {
hardwareConcurrency: kEnumerableProperty,
language: kEnumerableProperty,
languages: kEnumerableProperty,
userAgent: kEnumerableProperty,
});

Expand Down
44 changes: 43 additions & 1 deletion test/parallel/test-navigator.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
'use strict';

require('../common');
const common = require('../common');
const assert = require('assert');
const { execFile } = require('child_process');

const is = {
number: (value, key) => {
Expand All @@ -15,3 +16,44 @@ is.number(navigator.hardwareConcurrency, 'hardwareConcurrency');
assert.ok(navigator.hardwareConcurrency > 0);
assert.strictEqual(typeof navigator.userAgent, 'string');
assert.match(navigator.userAgent, /^Node\.js\/\d+$/);

assert.strictEqual(typeof navigator.language, 'string');
assert.strictEqual(navigator.language, 'en-US');

assert.ok(Array.isArray(navigator.languages));
assert.strictEqual(navigator.languages.length, 1);
assert.strictEqual(typeof navigator.languages[0], 'string');

assert.throws(() => {
navigator.languages[0] = 'foo';
}, new TypeError("Cannot assign to read only property '0' of object '[object Array]'"));
assert.notStrictEqual(navigator.languages[0], 'foo');
assert.strictEqual(navigator.languages[0], 'en-US');

Object.defineProperty(navigator, 'language', { value: 'de-DE' });
assert.strictEqual(navigator.language, 'de-DE');
assert.strictEqual(navigator.languages.length, 1);
assert.strictEqual(navigator.languages[0], 'en-US');


if (common.hasIntl) {
{
const env = { ...process.env, LC_ALL: 'fr-FR' };
execFile(
process.execPath,
['-p', 'process.exit(navigator.language === "fr-FR" ? 0 : 1)'],
{ env },
common.mustSucceed()
);
}

{
const env = { ...process.env, LC_ALL: 'fr-FR' };
execFile(
process.execPath,
['-p', 'process.exit(navigator.languages[0] === "fr-FR" ? 0 : 1)'],
{ env },
common.mustSucceed()
);
}
}

0 comments on commit fed4162

Please sign in to comment.