mirror of
https://github.com/navidrome/navidrome.git
synced 2026-10-31 15:37:51 +01:00
The language selector now shows how complete each translation is, so users can see at a glance which languages are lagging behind English. The native API's translation resource gained a termCount field holding the number of non-empty terms in each language file; the UI divides that by the term count of the bundled English file to get the percentage. The percentage is wrapped in a Unicode left-to-right isolate, otherwise it renders as "(%61)" beside right-to-left names such as Arabic and Persian. Sorting runs on the plain language name, before the percentage is appended. This also fixes prepareLanguage() mutating the bundled English translations: for the English locale it received the shared en object and aliased albumSong and playlistTrack onto it, growing en by 94 keys at runtime. That inflated the denominator and made every language read about 14 points low. The aliases now go on the merged copy instead.
67 lines
2.1 KiB
JavaScript
67 lines
2.1 KiB
JavaScript
import polyglotI18nProvider from 'ra-i18n-polyglot'
|
|
import deepmerge from 'deepmerge'
|
|
import dataProvider from '../dataProvider'
|
|
import en from './en.json'
|
|
import { i18nProvider } from './index'
|
|
|
|
// Only returns current selected locale if its translations are found in localStorage
|
|
const defaultLocale = function () {
|
|
const locale = localStorage.getItem('locale')
|
|
const current = JSON.parse(localStorage.getItem('translation'))
|
|
if (current && current.id === locale) {
|
|
// Asynchronously reload the translation from the server
|
|
retrieveTranslation(locale).then(() => {
|
|
i18nProvider.changeLocale(locale)
|
|
})
|
|
return locale
|
|
}
|
|
return 'en'
|
|
}
|
|
|
|
export function retrieveTranslation(locale) {
|
|
return dataProvider.getOne('translation', { id: locale }).then((res) => {
|
|
localStorage.setItem('translation', JSON.stringify(res.data))
|
|
return prepareLanguage(JSON.parse(res.data.data))
|
|
})
|
|
}
|
|
|
|
const removeEmpty = (obj) => {
|
|
for (let k in obj) {
|
|
if (
|
|
Object.prototype.hasOwnProperty.call(obj, k) &&
|
|
typeof obj[k] === 'object'
|
|
) {
|
|
removeEmpty(obj[k])
|
|
} else {
|
|
if (!obj[k]) {
|
|
delete obj[k]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const prepareLanguage = (lang) => {
|
|
removeEmpty(lang)
|
|
// Aliases below go on the merged copy: mutating `en` would corrupt the completion baseline
|
|
const merged = deepmerge(en, lang)
|
|
// Make "albumSong" and "playlistTrack" resource use the same translations as "song"
|
|
merged.resources.albumSong = merged.resources.song
|
|
merged.resources.playlistTrack = merged.resources.song
|
|
// ra.boolean.null should always be empty
|
|
merged.ra.boolean.null = ''
|
|
return merged
|
|
}
|
|
|
|
export default polyglotI18nProvider((locale) => {
|
|
// English is bundled
|
|
if (locale === 'en') {
|
|
return prepareLanguage(en)
|
|
}
|
|
// If the requested locale is in already loaded, return it
|
|
const current = JSON.parse(localStorage.getItem('translation'))
|
|
if (current && current.id === locale) {
|
|
return prepareLanguage(JSON.parse(current.data))
|
|
}
|
|
// If not, get it from the server, and store it in localStorage
|
|
return retrieveTranslation(locale)
|
|
}, defaultLocale())
|