mirror of
https://github.com/OliveTin/OliveTin
synced 2026-09-27 04:05:44 +00:00
fix: make lazy locale selection race-safe
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -188,7 +188,7 @@ import { connectEventStreamIfNeeded } from '../../js/websocket.js'
|
||||
import { DashboardSquare01Icon } from '@hugeicons/core-free-icons'
|
||||
import logoUrl from '../../OliveTinLogo.png'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { activateLocale, resolveBrowserLocale } from './i18n.js'
|
||||
import { ensureLocaleMessages, resolveBrowserLocale } from './i18n.js'
|
||||
import { searchIndexItems, clearSearchIndex, indexSystemNavigation, indexSearchHints, indexRootDashboardEntries } from './stores/searchIndex.js'
|
||||
import { applyThemeStyles } from './utils/themeLoader.js'
|
||||
const { t } = useI18n()
|
||||
@@ -220,6 +220,7 @@ const browserLanguages = ref([])
|
||||
const initialLanguagePreference = typeof window !== 'undefined' ? localStorage.getItem('olivetin-language') : null
|
||||
const languagePreference = ref(initialLanguagePreference || 'auto')
|
||||
const selectedLanguage = ref(languagePreference.value)
|
||||
let latestLanguageChange = 0
|
||||
|
||||
const themeDialog = ref(null)
|
||||
const availableThemes = ref([])
|
||||
@@ -499,14 +500,24 @@ async function changeLanguage () {
|
||||
return
|
||||
}
|
||||
|
||||
if (selectedLanguage.value === 'auto') {
|
||||
const languageChange = ++latestLanguageChange
|
||||
const requestedPreference = selectedLanguage.value
|
||||
const requestedLocale = requestedPreference === 'auto' ? resolveBrowserLocale() : requestedPreference
|
||||
|
||||
await ensureLocaleMessages(window.i18n, requestedLocale)
|
||||
|
||||
if (languageChange !== latestLanguageChange) {
|
||||
return
|
||||
}
|
||||
|
||||
window.i18n.locale.value = requestedLocale
|
||||
|
||||
if (requestedPreference === 'auto') {
|
||||
localStorage.removeItem('olivetin-language')
|
||||
languagePreference.value = 'auto'
|
||||
await activateLocale(window.i18n, resolveBrowserLocale())
|
||||
} else {
|
||||
await activateLocale(window.i18n, selectedLanguage.value)
|
||||
localStorage.setItem('olivetin-language', selectedLanguage.value)
|
||||
languagePreference.value = selectedLanguage.value
|
||||
localStorage.setItem('olivetin-language', requestedPreference)
|
||||
languagePreference.value = requestedPreference
|
||||
}
|
||||
|
||||
// Update navigation with new translations
|
||||
|
||||
@@ -46,10 +46,8 @@ export async function loadInitialMessages (locale) {
|
||||
return Object.fromEntries(loadedMessages)
|
||||
}
|
||||
|
||||
export async function activateLocale (i18n, locale) {
|
||||
export async function ensureLocaleMessages (i18n, locale) {
|
||||
if (!i18n.availableLocales.includes(locale)) {
|
||||
i18n.setLocaleMessage(locale, await loadLocaleMessages(locale))
|
||||
}
|
||||
|
||||
i18n.locale.value = locale
|
||||
}
|
||||
|
||||
@@ -7,11 +7,15 @@ export function selectBrowserLocale (availableLocales, browserLanguages) {
|
||||
return exact
|
||||
}
|
||||
|
||||
const language = lowerCandidate.split('-')[0]
|
||||
const prefix = availableLocales.find(locale => locale.toLowerCase().startsWith(`${language}-`))
|
||||
const parts = lowerCandidate.split('-')
|
||||
|
||||
if (prefix) {
|
||||
return prefix
|
||||
for (let length = parts.length - 1; length > 0; length--) {
|
||||
const prefix = `${parts.slice(0, length).join('-')}-`
|
||||
const match = availableLocales.find(locale => locale.toLowerCase().startsWith(prefix))
|
||||
|
||||
if (match) {
|
||||
return match
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,10 @@ test('selectBrowserLocale falls back to a matching language', () => {
|
||||
assert.equal(selectBrowserLocale(availableLocales, ['de-AT']), 'de-DE')
|
||||
})
|
||||
|
||||
test('selectBrowserLocale preserves script subtags during fallback', () => {
|
||||
assert.equal(selectBrowserLocale(availableLocales, ['zh-Hant-HK']), 'zh-Hant-TW')
|
||||
})
|
||||
|
||||
test('selectBrowserLocale uses English when no locale matches', () => {
|
||||
assert.equal(selectBrowserLocale(availableLocales, ['fr-FR']), 'en')
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user