Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions frontend/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { client, currentUserVar } from './client'
import canada from './theme/canada'
import { UserVarProvider, useUserVar } from './utilities/userState'
import { REFRESH_TOKENS } from './graphql/mutations'
import { activate, defaultLocale } from './utilities/i18n.config'
import { activate, defaultLocale, getStoredLocale } from './utilities/i18n.config'
import { IS_LOGIN_REQUIRED } from './graphql/queries'
import { TourProvider } from './userOnboarding/contexts/TourContext'

Expand Down Expand Up @@ -98,7 +98,8 @@ const I18nApp = () => {

const setUpApp = async () => {
await activate(
['en', 'fr'].includes(window.env?.APP_DEFAULT_LANGUAGE) ? window.env?.APP_DEFAULT_LANGUAGE : defaultLocale,
getStoredLocale() ??
(['en', 'fr'].includes(window.env?.APP_DEFAULT_LANGUAGE) ? window.env?.APP_DEFAULT_LANGUAGE : defaultLocale),
)

const root = createRoot(document.getElementById('root'))
Expand Down
32 changes: 32 additions & 0 deletions frontend/src/utilities/__tests__/i18nPersistence.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { i18n } from '@lingui/core'

import { activate, getStoredLocale } from '../i18n.config'

describe('locale persistence', () => {
beforeEach(() => {
window.localStorage.clear()
})

it('returns null when nothing was stored', () => {
expect(getStoredLocale()).toBeNull()
})

it('returns the stored locale', () => {
window.localStorage.setItem('locale', 'fr')
expect(getStoredLocale()).toEqual('fr')
})

it('ignores an invalid stored value', () => {
window.localStorage.setItem('locale', 'de')
expect(getStoredLocale()).toBeNull()
})

it('persists the activated locale for the next tab', async () => {
await activate('fr')
expect(i18n.locale).toEqual('fr')
expect(window.localStorage.getItem('locale')).toEqual('fr')

await activate('en')
expect(window.localStorage.getItem('locale')).toEqual('en')
})
})
18 changes: 18 additions & 0 deletions frontend/src/utilities/i18n.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ export const locales = {
fr: 'Français',
}

const LOCALE_STORAGE_KEY = 'locale'

export function getStoredLocale() {
try {
const stored = window.localStorage.getItem(LOCALE_STORAGE_KEY)
return ['en', 'fr'].includes(stored) ? stored : null
} catch (e) {
return null
}
}

export async function activate(locale) {
let catalog
try {
Expand All @@ -22,6 +33,13 @@ export async function activate(locale) {

i18n.load(locale, catalog.messages)
i18n.activate(locale)

try {
window.localStorage.setItem(LOCALE_STORAGE_KEY, locale)
} catch (e) {
// storage unavailable (e.g. private mode) — app still works,
// the choice just won't survive to the next tab.
}
}

let defaultLanguage
Expand Down