remove direct references to plural translation keys

This commit is contained in:
jeffvli
2026-01-29 19:52:42 -08:00
parent c1f48b21a4
commit 74b0e38f7e
10 changed files with 50 additions and 28 deletions
@@ -35,8 +35,8 @@ export const AlbumListHeaderFilters = ({ toggleGenreTarget }: { toggleGenreTarge
const choice = useMemo(() => { const choice = useMemo(() => {
return target === GenreTarget.ALBUM return target === GenreTarget.ALBUM
? t('entity.album_other', { postProcess: 'titleCase' }) ? t('entity.album', { count: 2, postProcess: 'titleCase' })
: t('entity.track_other', { postProcess: 'titleCase' }); : t('entity.track', { count: 2, postProcess: 'titleCase' });
}, [target, t]); }, [target, t]);
const handleToggleGenreTarget = useCallback(() => { const handleToggleGenreTarget = useCallback(() => {
@@ -19,7 +19,7 @@ interface ArtistListHeaderProps {
export const ArtistListHeader = ({ title }: ArtistListHeaderProps) => { export const ArtistListHeader = ({ title }: ArtistListHeaderProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
const pageTitle = title || t('entity.artist_other', { postProcess: 'titleCase' }); const pageTitle = title || t('entity.artist', { count: 2, postProcess: 'titleCase' });
return ( return (
<Stack gap={0}> <Stack gap={0}>
@@ -87,15 +87,18 @@ export const FavoritesHeader = ({ itemType }: FavoritesHeaderProps) => {
</Group> </Group>
<Text isMuted size="sm"> <Text isMuted size="sm">
{itemType === LibraryItem.ALBUM && {itemType === LibraryItem.ALBUM &&
t('entity.album_other', { t('entity.album', {
count: 2,
postProcess: 'sentenceCase', postProcess: 'sentenceCase',
})} })}
{itemType === LibraryItem.ALBUM_ARTIST && {itemType === LibraryItem.ALBUM_ARTIST &&
t('entity.artist_other', { t('entity.artist', {
count: 2,
postProcess: 'sentenceCase', postProcess: 'sentenceCase',
})} })}
{itemType === LibraryItem.SONG && {itemType === LibraryItem.SONG &&
t('entity.track_other', { t('entity.track', {
count: 2,
postProcess: 'sentenceCase', postProcess: 'sentenceCase',
})} })}
</Text> </Text>
@@ -107,14 +110,20 @@ export const FavoritesHeader = ({ itemType }: FavoritesHeaderProps) => {
leftSection={<Icon icon="track" size="xl" />} leftSection={<Icon icon="track" size="xl" />}
onClick={() => handleItemTypeChange(LibraryItem.SONG)} onClick={() => handleItemTypeChange(LibraryItem.SONG)}
> >
{t('entity.track_other', { postProcess: 'sentenceCase' })} {t('entity.track', {
count: 2,
postProcess: 'sentenceCase',
})}
</DropdownMenu.Item> </DropdownMenu.Item>
<DropdownMenu.Item <DropdownMenu.Item
isSelected={itemType === LibraryItem.ALBUM} isSelected={itemType === LibraryItem.ALBUM}
leftSection={<Icon icon="album" size="xl" />} leftSection={<Icon icon="album" size="xl" />}
onClick={() => handleItemTypeChange(LibraryItem.ALBUM)} onClick={() => handleItemTypeChange(LibraryItem.ALBUM)}
> >
{t('entity.album_other', { postProcess: 'sentenceCase' })} {t('entity.album', {
count: 2,
postProcess: 'sentenceCase',
})}
</DropdownMenu.Item> </DropdownMenu.Item>
<DropdownMenu.Item <DropdownMenu.Item
isSelected={itemType === LibraryItem.ALBUM_ARTIST} isSelected={itemType === LibraryItem.ALBUM_ARTIST}
@@ -123,7 +132,10 @@ export const FavoritesHeader = ({ itemType }: FavoritesHeaderProps) => {
handleItemTypeChange(LibraryItem.ALBUM_ARTIST) handleItemTypeChange(LibraryItem.ALBUM_ARTIST)
} }
> >
{t('entity.artist_other', { postProcess: 'sentenceCase' })} {t('entity.artist', {
count: 2,
postProcess: 'sentenceCase',
})}
</DropdownMenu.Item> </DropdownMenu.Item>
</DropdownMenu.Dropdown> </DropdownMenu.Dropdown>
</DropdownMenu> </DropdownMenu>
@@ -120,7 +120,7 @@ export const FeaturedGenres = () => {
<> <>
<Group align="flex-end" justify="space-between"> <Group align="flex-end" justify="space-between">
<TextTitle fw={700} isNoSelect order={3}> <TextTitle fw={700} isNoSelect order={3}>
{t('entity.genre_other', { postProcess: 'titleCase' })} {t('entity.genre', { count: 2, postProcess: 'titleCase' })}
</TextTitle> </TextTitle>
<Button <Button
component={Link} component={Link}
@@ -36,6 +36,7 @@ export type ItemDetailsModalProps = {
}; };
type ItemDetailRow<T> = { type ItemDetailRow<T> = {
count?: number;
key?: keyof T; key?: keyof T;
label: string; label: string;
postprocess?: string[]; postprocess?: string[];
@@ -61,7 +62,10 @@ const handleRow = <T extends AnyLibraryItem>(
return ( return (
<Table.Tr key={rule.label}> <Table.Tr key={rule.label}>
<Table.Th> <Table.Th>
{t(rule.label, { postProcess: rule.postprocess || 'sentenceCase' })} {t(rule.label, {
...(rule.count !== undefined && { count: rule.count }),
postProcess: rule.postprocess || 'sentenceCase',
})}
</Table.Th> </Table.Th>
<Table.Td>{value}</Table.Td> <Table.Td>{value}</Table.Td>
</Table.Tr> </Table.Tr>
@@ -135,12 +139,12 @@ const BoolField = (key: boolean) =>
const AlbumPropertyMapping: ItemDetailRow<Album>[] = [ const AlbumPropertyMapping: ItemDetailRow<Album>[] = [
{ key: 'name', label: 'common.title' }, { key: 'name', label: 'common.title' },
{ label: 'entity.albumArtist_one', render: (item) => formatArtists(item.albumArtists) }, { count: 1, label: 'entity.albumArtist', render: (item) => formatArtists(item.albumArtists) },
{ {
label: 'common.releaseType', label: 'common.releaseType',
render: (item, t) => normalizeReleaseTypes(item.releaseTypes, t).join(SEPARATOR_STRING), render: (item, t) => normalizeReleaseTypes(item.releaseTypes, t).join(SEPARATOR_STRING),
}, },
{ label: 'entity.genre_other', render: FormatGenre }, { count: 2, label: 'entity.genre', render: FormatGenre },
{ {
label: 'common.duration', label: 'common.duration',
render: (album) => album.duration && formatDurationString(album.duration), render: (album) => album.duration && formatDurationString(album.duration),
@@ -198,7 +202,7 @@ const AlbumPropertyMapping: ItemDetailRow<Album>[] = [
const AlbumArtistPropertyMapping: ItemDetailRow<AlbumArtist>[] = [ const AlbumArtistPropertyMapping: ItemDetailRow<AlbumArtist>[] = [
{ key: 'name', label: 'common.name' }, { key: 'name', label: 'common.name' },
{ label: 'entity.genre_other', render: FormatGenre }, { count: 2, label: 'entity.genre', render: FormatGenre },
{ {
label: 'common.duration', label: 'common.duration',
render: (artist) => artist.duration && formatDurationString(artist.duration), render: (artist) => artist.duration && formatDurationString(artist.duration),
@@ -243,7 +247,7 @@ const AlbumArtistPropertyMapping: ItemDetailRow<AlbumArtist>[] = [
const PlaylistPropertyMapping: ItemDetailRow<Playlist>[] = [ const PlaylistPropertyMapping: ItemDetailRow<Playlist>[] = [
{ key: 'name', label: 'common.title' }, { key: 'name', label: 'common.title' },
{ key: 'description', label: 'common.description' }, { key: 'description', label: 'common.description' },
{ label: 'entity.genre_other', render: FormatGenre }, { count: 2, label: 'entity.genre', render: FormatGenre },
{ {
label: 'common.duration', label: 'common.duration',
render: (playlist) => playlist.duration && formatDurationString(playlist.duration), render: (playlist) => playlist.duration && formatDurationString(playlist.duration),
@@ -266,11 +270,17 @@ const PlaylistPropertyMapping: ItemDetailRow<Playlist>[] = [
const SongPropertyMapping: ItemDetailRow<Song>[] = [ const SongPropertyMapping: ItemDetailRow<Song>[] = [
{ key: 'name', label: 'common.title' }, { key: 'name', label: 'common.title' },
{ key: 'path', label: 'common.path', render: SongPath }, { key: 'path', label: 'common.path', render: SongPath },
{ label: 'entity.albumArtist_one', render: (item) => formatArtists(item.albumArtists) }, { count: 1, label: 'entity.albumArtist', render: (item) => formatArtists(item.albumArtists) },
{ key: 'artists', label: 'entity.artist_other', render: (item) => formatArtists(item.artists) },
{ {
count: 2,
key: 'artists',
label: 'entity.artist',
render: (item) => formatArtists(item.artists),
},
{
count: 1,
key: 'album', key: 'album',
label: 'entity.album_one', label: 'entity.album',
render: (song) => render: (song) =>
song.albumId && song.albumId &&
song.album && ( song.album && (
@@ -304,7 +314,7 @@ const SongPropertyMapping: ItemDetailRow<Song>[] = [
? t('common.clean', { postProcess: 'sentenceCase' }) ? t('common.clean', { postProcess: 'sentenceCase' })
: null, : null,
}, },
{ label: 'entity.genre_other', render: FormatGenre }, { count: 2, label: 'entity.genre', render: FormatGenre },
{ {
label: 'common.duration', label: 'common.duration',
render: (song) => formatDurationString(song.duration), render: (song) => formatDurationString(song.duration),
@@ -314,7 +324,7 @@ const SongPropertyMapping: ItemDetailRow<Song>[] = [
{ key: 'bitRate', label: 'common.bitrate', render: (song) => `${song.bitRate} kbps` }, { key: 'bitRate', label: 'common.bitrate', render: (song) => `${song.bitRate} kbps` },
{ key: 'sampleRate', label: 'common.sampleRate' }, { key: 'sampleRate', label: 'common.sampleRate' },
{ key: 'bitDepth', label: 'common.bitDepth' }, { key: 'bitDepth', label: 'common.bitDepth' },
{ key: 'channels', label: 'common.channel_other' }, { count: 2, key: 'channels', label: 'common.channel' },
{ key: 'size', label: 'common.size', render: (song) => formatSizeString(song.size) }, { key: 'size', label: 'common.size', render: (song) => formatSizeString(song.size) },
{ {
label: 'common.favorite', label: 'common.favorite',
@@ -19,7 +19,7 @@ export const openLyricsSettingsModal = (settingsKey: string = 'default') => {
width: '100%', width: '100%',
}, },
}, },
title: i18n.t('common.setting_other', { postProcess: 'titleCase' }), title: i18n.t('common.setting', { count: 2, postProcess: 'titleCase' }),
transitionProps: { transitionProps: {
transition: 'pop', transition: 'pop',
}, },
@@ -186,7 +186,7 @@ export const PlayerConfig = () => {
size="sm" size="sm"
stopsPropagation stopsPropagation
tooltip={{ tooltip={{
label: t('common.setting_other', { postProcess: 'titleCase' }), label: t('common.setting', { count: 2, postProcess: 'titleCase' }),
openDelay: 0, openDelay: 0,
}} }}
variant="subtle" variant="subtle"
@@ -19,7 +19,7 @@ export const openVisualizerSettingsModal = () => {
width: '100%', width: '100%',
}, },
}, },
title: i18n.t('common.setting_other', { postProcess: 'titleCase' }), title: i18n.t('common.setting', { count: 2, postProcess: 'titleCase' }),
transitionProps: { transitionProps: {
transition: 'pop', transition: 'pop',
}, },
@@ -81,7 +81,7 @@ export const SearchHeader = ({ navigationId }: SearchHeaderProps) => {
}} }}
variant={itemType === LibraryItem.SONG ? 'filled' : 'default'} variant={itemType === LibraryItem.SONG ? 'filled' : 'default'}
> >
{t('entity.track_other', { postProcess: 'sentenceCase' })} {t('entity.track', { count: 2, postProcess: 'sentenceCase' })}
</Button> </Button>
<Button <Button
component={Link} component={Link}
@@ -97,7 +97,7 @@ export const SearchHeader = ({ navigationId }: SearchHeaderProps) => {
}} }}
variant={itemType === LibraryItem.ALBUM ? 'filled' : 'default'} variant={itemType === LibraryItem.ALBUM ? 'filled' : 'default'}
> >
{t('entity.album_other', { postProcess: 'sentenceCase' })} {t('entity.album', { count: 2, postProcess: 'sentenceCase' })}
</Button> </Button>
<Button <Button
component={Link} component={Link}
@@ -113,7 +113,7 @@ export const SearchHeader = ({ navigationId }: SearchHeaderProps) => {
}} }}
variant={itemType === LibraryItem.ALBUM_ARTIST ? 'filled' : 'default'} variant={itemType === LibraryItem.ALBUM_ARTIST ? 'filled' : 'default'}
> >
{t('entity.artist_other', { postProcess: 'sentenceCase' })} {t('entity.artist', { count: 2, postProcess: 'sentenceCase' })}
</Button> </Button>
</ButtonGroup> </ButtonGroup>
<ListConfigMenu {...listConfigMenuProps[itemType]} /> <ListConfigMenu {...listConfigMenuProps[itemType]} />
@@ -44,8 +44,8 @@ export const SongListHeaderFilters = ({ toggleGenreTarget }: { toggleGenreTarget
const choice = useMemo(() => { const choice = useMemo(() => {
return target === GenreTarget.ALBUM return target === GenreTarget.ALBUM
? t('entity.album_other', { postProcess: 'titleCase' }) ? t('entity.album', { count: 2, postProcess: 'titleCase' })
: t('entity.track_other', { postProcess: 'titleCase' }); : t('entity.track', { count: 2, postProcess: 'titleCase' });
}, [target, t]); }, [target, t]);
const hasActiveFilters = useMemo(() => { const hasActiveFilters = useMemo(() => {