Skip to content

Commit d4557e1

Browse files
committed
feat: add setLanguage and setLocale for web worker use cases
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
1 parent d7961cc commit d4557e1

8 files changed

Lines changed: 77 additions & 32 deletions

File tree

lib/globals.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* SPDX-License-Identifier: GPL-3.0-or-later
44
*/
55

6-
/* eslint-disable no-var, camelcase */
6+
/* eslint-disable camelcase */
77

88
import type { PluralFunction, Translations } from './registry.ts'
99

lib/locale.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,22 @@ export function getCanonicalLocale(): string {
1818
return getLocale().replaceAll(/_/g, '-')
1919
}
2020

21+
/**
22+
* Set the current user's language (locally).
23+
* This is to be used only for e.g. usage within web workers etc.
24+
*
25+
* @param locale - The new language code
26+
* @since 3.4.0
27+
*/
28+
export function setLocale(locale: string): void {
29+
globalThis._nc_l10n_locale = locale
30+
31+
// also for browsers set the DOM
32+
if (typeof document !== 'undefined') {
33+
document.documentElement.dataset.locale = locale
34+
}
35+
}
36+
2137
/**
2238
* Returns the user's language
2339
*/
@@ -27,8 +43,10 @@ export function getLanguage(): string {
2743

2844
/**
2945
* Set the current user's language (locally).
46+
* This is to be used only for e.g. usage within web workers etc.
3047
*
3148
* @param lang - The new language code
49+
* @since 3.4.0
3250
*/
3351
export function setLanguage(lang: string): void {
3452
globalThis._nc_l10n_language = lang

tests/gettext.test.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66
import { po } from 'gettext-parser'
77
import { beforeEach, describe, expect, it, vi } from 'vitest'
88
import { getGettextBuilder } from '../lib/gettext.ts'
9-
10-
const setLanguage = (lang: string) => { globalThis._nc_l10n_language = lang }
9+
import { setLanguage } from '../lib/locale.ts'
1110

1211
describe('gettext', () => {
1312
beforeEach(() => {

tests/is-rtl.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
*/
55

66
import { beforeEach, describe, expect, it } from 'vitest'
7-
import { isRTL } from '../lib/locale'
8-
9-
const setLanguage = (lang: string) => { globalThis._nc_l10n_language = lang }
7+
import { isRTL, setLanguage } from '../lib/locale.ts'
108

119
describe('isRTL', () => {
12-
beforeEach(() => { globalThis._nc_l10n_locale = 'en' })
10+
beforeEach(() => {
11+
globalThis._nc_l10n_locale = 'en'
12+
})
1313

1414
it('falls back to English which is LTR', () => {
1515
// Expect fallback which is English = LTR

tests/loadTranslations.test.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,13 @@ import type { SetupServerApi } from 'msw/node'
88
import { http, HttpResponse } from 'msw'
99
import { setupServer } from 'msw/node'
1010
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'
11+
import { setLanguage } from '../lib/locale.ts'
1112
import { loadTranslations, register, translate, unregister } from '../lib/translation.ts'
1213

1314
vi.mock('@nextcloud/router', () => ({
1415
generateFilePath: (app: string, type: string, path: string) => `http://localhost/${app}/${type}/${path}`,
1516
}))
1617

17-
/**
18-
* Mock the langauge
19-
*
20-
* @param lang - The language to mock
21-
*/
22-
function setLanguage(lang: string): void {
23-
globalThis._nc_l10n_language = lang
24-
}
25-
2618
const requestHandlers = [
2719
http.get('http://localhost/myapp/l10n/de.json', () => HttpResponse.json({
2820
translations: {

tests/locale.test.ts

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,47 +9,75 @@ beforeEach(() => vi.resetModules())
99

1010
describe('getLanguage', () => {
1111
it('returns the set language as it is', async () => {
12-
setLanguage('de-DE')
12+
mockLanguage('de-DE')
1313
expect(await getLanguage()).toEqual('de-DE')
1414
})
1515

1616
it('returns the navigator language if no language is set', async () => {
1717
const spy = vi.spyOn(navigator, 'language', 'get')
1818
spy.mockImplementationOnce(() => 'ar-EG')
1919

20-
setLanguage(undefined)
20+
mockLanguage(undefined)
2121
expect(await getLanguage()).toEqual('ar-EG')
2222
expect(spy).toHaveBeenCalledOnce()
2323
})
2424
})
2525

26+
describe('setLanguage', () => {
27+
it('does set the global state', async () => {
28+
mockLanguage('de')
29+
await setLanguage('ar')
30+
expect(globalThis._nc_l10n_language).toBe('ar')
31+
})
32+
33+
it.skipIf(typeof globalThis.document === 'undefined')('does set the DOM attribute', async () => {
34+
mockLanguage('de')
35+
await setLanguage('ar')
36+
expect(document.documentElement.lang).toBe('ar')
37+
})
38+
})
39+
2640
describe('getLocale', () => {
2741
it('returns the set locale as it is with underscore', async () => {
28-
setLocale('de_DE')
42+
mockLocale('de_DE')
2943
expect(await getLocale()).toEqual('de_DE')
3044
})
3145

3246
it('returns the environment locale with underscore if no locale is set', async () => {
33-
setLocale(undefined)
47+
mockLocale(undefined)
3448
expect(await getLocale()).toEqual(process.env.LANG?.replaceAll('-', '_').split('.')[0])
3549
})
3650
})
3751

52+
describe('setLocale', () => {
53+
it('does set the global state', async () => {
54+
mockLocale('de_DE')
55+
await setLocale('ar')
56+
expect(globalThis._nc_l10n_locale).toBe('ar')
57+
})
58+
59+
it.skipIf(typeof globalThis.document === 'undefined')('does set the DOM attribute', async () => {
60+
mockLocale('de_DE')
61+
await setLocale('ar')
62+
expect(document.documentElement.dataset.locale).toBe('ar')
63+
})
64+
})
65+
3866
describe('getCanonicalLocale', () => {
3967
it('returns the set locale with hyphen', async () => {
40-
setLocale('de_DE')
68+
mockLocale('de_DE')
4169
expect(await getCanonicalLocale()).toEqual('de-DE')
4270
})
4371

4472
it('returns the set locale with multiple hyphen', async () => {
45-
setLocale('az_Cyrl_AZ')
73+
mockLocale('az_Cyrl_AZ')
4674
expect(await getCanonicalLocale()).toEqual('az-Cyrl-AZ')
4775
})
4876

4977
it('returns the environment locale with hyphen if no locale is set', async () => {
5078
expect(process.env.LANG).toBeTruthy()
5179

52-
setLocale(undefined)
80+
mockLocale(undefined)
5381
expect(await getCanonicalLocale()).toEqual(process.env.LANG!.split('.')[0])
5482
})
5583
})
@@ -69,11 +97,24 @@ async function getLanguage() {
6997
return getLanguage()
7098
}
7199

72-
function setLanguage(lang?: string) {
100+
async function setLocale(locale: string) {
101+
const { setLocale } = await import('../lib/locale.ts')
102+
return setLocale(locale)
103+
}
104+
105+
async function setLanguage(language: string) {
106+
const { setLanguage } = await import('../lib/locale.ts')
107+
return setLanguage(language)
108+
}
109+
110+
function mockLanguage(lang?: string) {
73111
// @ts-expect-error - Mocking global state
74112
globalThis._nc_l10n_language = lang
75113
}
76-
function setLocale(locale?: string) {
114+
function mockLocale(locale?: string) {
77115
// @ts-expect-error - Mocking global state
78116
globalThis._nc_l10n_locale = locale
117+
if (typeof globalThis.document !== 'undefined') {
118+
delete globalThis.document.documentElement.dataset.locale
119+
}
79120
}

tests/time.test.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@
44
*/
55

66
import { beforeAll, beforeEach, describe, expect, it, test, vi } from 'vitest'
7+
import { setLanguage } from '../lib/locale.ts'
78
import { formatRelativeTime } from '../lib/time.ts'
89

9-
const setLanguage = (lang: string) => { globalThis._nc_l10n_language = lang }
10-
1110
describe('time - formatRelativeTime', () => {
1211
beforeAll(() => {
1312
vi.useFakeTimers({ now: new Date('2025-01-01T00:00:00Z') })

tests/translation.test.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33
* SPDX-License-Identifier: GPL-3.0-or-later
44
*/
55

6-
import type { NextcloudWindowWithRegistry } from '../lib/registry.ts'
7-
86
import { beforeAll, beforeEach, describe, expect, it } from 'vitest'
7+
import { setLanguage, setLocale } from '../lib/locale.ts'
98
import {
109
getPlural,
1110
n,
@@ -16,9 +15,6 @@ import {
1615
unregister,
1716
} from '../lib/translation.ts'
1817

19-
const setLocale = (locale: string) => { globalThis._nc_l10n_locale = locale }
20-
const setLanguage = (lang: string) => { globalThis._nc_l10n_language = lang }
21-
2218
describe('translate', () => {
2319
const mockWindowDE = () => {
2420
globalThis._oc_l10n_registry_translations = {

0 commit comments

Comments
 (0)