diff --git a/resources/i18n/pt-br.json b/resources/i18n/pt-br.json
index 238919259..1a0c1ab8a 100644
--- a/resources/i18n/pt-br.json
+++ b/resources/i18n/pt-br.json
@@ -660,6 +660,11 @@
"options": {
"theme": "Tema",
"language": "Língua",
+ "dateFormat": "Formato de data",
+ "dateFormats": {
+ "language": "Igual à língua",
+ "browser": "Igual ao navegador"
+ },
"defaultView": "Tela inicial",
"desktop_notifications": "Notificações",
"lastfmScrobbling": "Enviar scrobbles para Last.fm",
diff --git a/ui/src/album/AlbumInfo.jsx b/ui/src/album/AlbumInfo.jsx
index 075841e43..1de904031 100644
--- a/ui/src/album/AlbumInfo.jsx
+++ b/ui/src/album/AlbumInfo.jsx
@@ -8,7 +8,6 @@ import {
ArrayField,
BooleanField,
ChipField,
- DateField,
FunctionField,
SingleFieldList,
TextField,
@@ -17,6 +16,7 @@ import {
} from 'react-admin'
import { makeStyles } from '@material-ui/core/styles'
import {
+ DateField,
ArtistLinkField,
MultiLineTextField,
ParticipantsInfo,
diff --git a/ui/src/album/AlbumTableView.jsx b/ui/src/album/AlbumTableView.jsx
index 051d5988e..46a86c6bc 100644
--- a/ui/src/album/AlbumTableView.jsx
+++ b/ui/src/album/AlbumTableView.jsx
@@ -3,7 +3,6 @@ import {
Datagrid,
DatagridBody,
DatagridRow,
- DateField,
NumberField,
TextField,
FunctionField,
@@ -13,6 +12,7 @@ import FavoriteBorderIcon from '@material-ui/icons/FavoriteBorder'
import { makeStyles } from '@material-ui/core/styles'
import { useDrag } from 'react-dnd'
import {
+ DateField,
ArtistLinkField,
ArtworkAvatar,
DurationField,
diff --git a/ui/src/common/DateField.jsx b/ui/src/common/DateField.jsx
index dac9cff08..8aab34ae1 100644
--- a/ui/src/common/DateField.jsx
+++ b/ui/src/common/DateField.jsx
@@ -1,12 +1,12 @@
import React from 'react'
import { isDateSet } from '../utils/validations'
-import { DateField as RADateField } from 'react-admin'
+import { DateField as RADateField, useRecordContext } from 'react-admin'
import { useDateLocale } from '../i18n/useDateLocale'
export const DateField = (props) => {
- const { record, source } = props
+ const record = useRecordContext(props)
const locale = useDateLocale()
- const value = record?.[source]
+ const value = record?.[props.source]
if (!isDateSet(value)) return null
return
}
diff --git a/ui/src/common/DateField.test.jsx b/ui/src/common/DateField.test.jsx
index 47d56756b..7494b7887 100644
--- a/ui/src/common/DateField.test.jsx
+++ b/ui/src/common/DateField.test.jsx
@@ -1,6 +1,7 @@
import React from 'react'
import { render, screen } from '@testing-library/react'
import { describe, it, expect, beforeEach, vi } from 'vitest'
+import { RecordContextProvider } from 'react-admin'
import { DateField } from './DateField'
vi.mock('react-admin', async (importOriginal) => ({
@@ -29,4 +30,13 @@ describe('', () => {
)
expect(container).toBeEmptyDOMElement()
})
+
+ it('reads the record from the record context', () => {
+ render(
+
+
+ ,
+ )
+ expect(screen.getByText('17.9.2026')).toBeInTheDocument()
+ })
})
diff --git a/ui/src/common/SongInfo.jsx b/ui/src/common/SongInfo.jsx
index 1b1a014f1..b9f7bea8c 100644
--- a/ui/src/common/SongInfo.jsx
+++ b/ui/src/common/SongInfo.jsx
@@ -6,7 +6,6 @@ import TableContainer from '@material-ui/core/TableContainer'
import TableRow from '@material-ui/core/TableRow'
import {
BooleanField,
- DateField,
TextField,
NumberField,
FunctionField,
@@ -15,6 +14,7 @@ import {
} from 'react-admin'
import { humanize, underscore } from 'inflection'
import {
+ DateField,
ArtistLinkField,
BitrateField,
ParticipantsInfo,
diff --git a/ui/src/i18n/en.json b/ui/src/i18n/en.json
index f694ea75f..8f086f516 100644
--- a/ui/src/i18n/en.json
+++ b/ui/src/i18n/en.json
@@ -677,6 +677,11 @@
"options": {
"theme": "Theme",
"language": "Language",
+ "dateFormat": "Date Format",
+ "dateFormats": {
+ "language": "Match language",
+ "browser": "Match browser"
+ },
"defaultView": "Default View",
"desktop_notifications": "Desktop Notifications",
"lastfmNotConfigured": "Last.fm API-Key is not configured",
diff --git a/ui/src/i18n/useDateLocale.js b/ui/src/i18n/useDateLocale.js
index c9298a473..f02402f29 100644
--- a/ui/src/i18n/useDateLocale.js
+++ b/ui/src/i18n/useDateLocale.js
@@ -1,5 +1,8 @@
import { useLocale } from 'react-admin'
+export const getStoredDateFormat = () =>
+ localStorage.getItem('dateFormat') || 'language'
+
// Our language codes are mostly region-less ("en"), and Intl reads a bare "en"
// as en-US. Borrow the region from the browser when it speaks the same language.
const resolveDateLocale = (locale, browserLocales = []) => {
@@ -10,5 +13,10 @@ const resolveDateLocale = (locale, browserLocales = []) => {
)
}
-export const useDateLocale = () =>
- resolveDateLocale(useLocale(), navigator.languages)
+// With the "browser" date format, return undefined so Intl uses the browser's
+// own locale, regardless of the selected language.
+export const useDateLocale = () => {
+ const locale = useLocale()
+ if (getStoredDateFormat() === 'browser') return undefined
+ return resolveDateLocale(locale, navigator.languages)
+}
diff --git a/ui/src/i18n/useDateLocale.test.js b/ui/src/i18n/useDateLocale.test.js
index c0ea5ab40..16707a084 100644
--- a/ui/src/i18n/useDateLocale.test.js
+++ b/ui/src/i18n/useDateLocale.test.js
@@ -9,6 +9,7 @@ vi.mock('react-admin', () => ({
describe('useDateLocale', () => {
beforeEach(() => {
vi.clearAllMocks()
+ localStorage.removeItem('dateFormat')
})
const renderWith = async (locale, browserLocales) => {
@@ -42,4 +43,10 @@ describe('useDateLocale', () => {
const result = await renderWith(undefined, ['en-GB'])
expect(result.current).toBeUndefined()
})
+
+ it('returns undefined to use the browser locale when set to browser', async () => {
+ localStorage.setItem('dateFormat', 'browser')
+ const result = await renderWith('en', ['fr-FR'])
+ expect(result.current).toBeUndefined()
+ })
})
diff --git a/ui/src/missing/MissingFilesList.jsx b/ui/src/missing/MissingFilesList.jsx
index a09f552d9..64ab0487d 100644
--- a/ui/src/missing/MissingFilesList.jsx
+++ b/ui/src/missing/MissingFilesList.jsx
@@ -1,4 +1,5 @@
import {
+ DateField,
List,
Pagination,
SizeField,
@@ -7,7 +8,6 @@ import {
} from '../common/index'
import {
Datagrid,
- DateField,
TextField,
downloadCSV,
Filter,
diff --git a/ui/src/personal/Personal.jsx b/ui/src/personal/Personal.jsx
index 84f9b63e6..75c4dd45a 100644
--- a/ui/src/personal/Personal.jsx
+++ b/ui/src/personal/Personal.jsx
@@ -2,6 +2,7 @@ import { SimpleForm, Title, useTranslate } from 'react-admin'
import { Card } from '@material-ui/core'
import { makeStyles } from '@material-ui/core/styles'
import { SelectLanguage } from './SelectLanguage'
+import { SelectDateFormat } from './SelectDateFormat'
import { SelectTheme } from './SelectTheme'
import { SelectDefaultView } from './SelectDefaultView'
import { NotificationsToggle } from './NotificationsToggle'
@@ -24,6 +25,7 @@ const Personal = () => {
+
{config.enableReplayGain && }
diff --git a/ui/src/personal/SelectDateFormat.jsx b/ui/src/personal/SelectDateFormat.jsx
new file mode 100644
index 000000000..fdc9583d2
--- /dev/null
+++ b/ui/src/personal/SelectDateFormat.jsx
@@ -0,0 +1,22 @@
+import { SelectInput, useTranslate } from 'react-admin'
+import { getStoredDateFormat } from '../i18n/useDateLocale'
+
+export const SelectDateFormat = (props) => {
+ const translate = useTranslate()
+
+ return (
+ {
+ localStorage.setItem('dateFormat', event.target.value)
+ }}
+ />
+ )
+}
diff --git a/ui/src/playlist/PlaylistList.jsx b/ui/src/playlist/PlaylistList.jsx
index e1695e980..be77672a9 100644
--- a/ui/src/playlist/PlaylistList.jsx
+++ b/ui/src/playlist/PlaylistList.jsx
@@ -1,7 +1,6 @@
import React, { useMemo } from 'react'
import {
Datagrid,
- DateField,
EditButton,
Filter,
NullableBooleanInput,
@@ -20,6 +19,7 @@ import Switch from '@material-ui/core/Switch'
import { makeStyles } from '@material-ui/core/styles'
import { useMediaQuery } from '@material-ui/core'
import {
+ DateField,
ArtworkAvatar,
DurationField,
List,
diff --git a/ui/src/radio/RadioList.jsx b/ui/src/radio/RadioList.jsx
index 0cfb2cd68..46e59ffcc 100644
--- a/ui/src/radio/RadioList.jsx
+++ b/ui/src/radio/RadioList.jsx
@@ -3,7 +3,6 @@ import React, { cloneElement } from 'react'
import {
CreateButton,
Datagrid,
- DateField,
EditButton,
Filter,
sanitizeListRestProps,
@@ -15,6 +14,7 @@ import {
useTranslate,
} from 'react-admin'
import {
+ DateField,
List,
defaultRowsPerPageOptions,
getStoredPerPage,