Implement locales in codebase
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
"clear-queue": "Clear Queue",
|
||||
"no-results": "No results...",
|
||||
"album": "Album",
|
||||
"albums": "Albums",
|
||||
"all-albums": "All Albums",
|
||||
"search": "Search",
|
||||
"music": "Music",
|
||||
|
||||
@@ -5,6 +5,7 @@ export type LocaleKeys = 'play-next'
|
||||
| 'clear-queue'
|
||||
| 'no-results'
|
||||
| 'album'
|
||||
| 'albums'
|
||||
| 'all-albums'
|
||||
| 'search'
|
||||
| 'music'
|
||||
|
||||
@@ -6,6 +6,7 @@ import Album from './stacks/Album';
|
||||
import RecentAlbums from './stacks/RecentAlbums';
|
||||
import Search from './stacks/Search';
|
||||
import { THEME_COLOR } from 'CONSTANTS';
|
||||
import { t } from '@localisation';
|
||||
|
||||
const Stack = createStackNavigator<StackParams>();
|
||||
|
||||
@@ -17,10 +18,10 @@ const navigationOptions = {
|
||||
function MusicStack() {
|
||||
return (
|
||||
<Stack.Navigator initialRouteName="RecentAlbums" screenOptions={navigationOptions}>
|
||||
<Stack.Screen name="RecentAlbums" component={RecentAlbums} options={{ headerTitle: 'Recent Albums' }} />
|
||||
<Stack.Screen name="Albums" component={Albums} />
|
||||
<Stack.Screen name="Album" component={Album} />
|
||||
<Stack.Screen name="Search" component={Search} />
|
||||
<Stack.Screen name="RecentAlbums" component={RecentAlbums} options={{ headerTitle: t('recent-albums') }} />
|
||||
<Stack.Screen name="Albums" component={Albums} options={{ headerTitle: t('albums') }} />
|
||||
<Stack.Screen name="Album" component={Album} options={{ headerTitle: t('album') }} />
|
||||
<Stack.Screen name="Search" component={Search} options={{ headerTitle: t('search') }} />
|
||||
</Stack.Navigator>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import TouchableHandler from 'components/TouchableHandler';
|
||||
import useCurrentTrack from 'utility/useCurrentTrack';
|
||||
import { colors } from 'components/Colors';
|
||||
import TrackPlayer from 'react-native-track-player';
|
||||
import { t } from '@localisation';
|
||||
|
||||
type Route = RouteProp<StackParams, 'Album'>;
|
||||
|
||||
@@ -114,7 +115,7 @@ const Album: React.FC = () => {
|
||||
<AlbumImage source={{ uri: getImage(album?.Id) }} style={colors.imageBackground} />
|
||||
<Text style={styles.name} >{album?.Name}</Text>
|
||||
<Text style={styles.artist}>{album?.AlbumArtist}</Text>
|
||||
<Button title="Play Album" onPress={selectAlbum} color={THEME_COLOR} />
|
||||
<Button title={t('play-album')} onPress={selectAlbum} color={THEME_COLOR} />
|
||||
{album?.Tracks?.length ? album.Tracks.map((trackId) =>
|
||||
<TouchableHandler
|
||||
key={trackId}
|
||||
|
||||
@@ -13,6 +13,7 @@ import { useRecentAlbums } from 'store/music/selectors';
|
||||
import { Header } from 'components/Typography';
|
||||
import ListButton from 'components/ListButton';
|
||||
import { colors } from 'components/Colors';
|
||||
import { t } from '@localisation';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
artist: {
|
||||
@@ -28,9 +29,9 @@ const NavigationHeader: React.FC = () => {
|
||||
|
||||
return (
|
||||
<ListContainer>
|
||||
<ListButton onPress={handleAllAlbumsClick}>All Albums</ListButton>
|
||||
<ListButton onPress={handleSearchClick}>Search</ListButton>
|
||||
<Header style={colors.text}>Recent Albums</Header>
|
||||
<ListButton onPress={handleAllAlbumsClick}>{t('all-albums')}</ListButton>
|
||||
<ListButton onPress={handleSearchClick}>{t('search')}</ListButton>
|
||||
<Header style={colors.text}>{t('recent-albums')}</Header>
|
||||
</ListContainer>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -12,6 +12,7 @@ import { useGetImage } from 'utility/JellyfinApi';
|
||||
import { NavigationProp } from '../types';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
import { colors } from 'components/Colors';
|
||||
import { t } from '@localisation';
|
||||
|
||||
const Container = styled.View`
|
||||
padding: 0 20px;
|
||||
@@ -88,8 +89,8 @@ export default function Search() {
|
||||
|
||||
const HeaderComponent = React.useMemo(() => (
|
||||
<Container>
|
||||
<Input value={searchTerm} onChangeText={setSearchTerm} style={colors.input} placeholder="Search..." />
|
||||
{(searchTerm.length && !results.length) ? <Text>No results...</Text> : null}
|
||||
<Input value={searchTerm} onChangeText={setSearchTerm} style={colors.input} placeholder={t('search') + '...'} />
|
||||
{(searchTerm.length && !results.length) ? <Text>{t('no-results')}</Text> : null}
|
||||
</Container>
|
||||
), [searchTerm, results, setSearchTerm]);
|
||||
|
||||
@@ -110,7 +111,7 @@ export default function Search() {
|
||||
<Text numberOfLines={1} ellipsizeMode="tail" style={colors.text}>
|
||||
{album.Name} - {album.AlbumArtist}
|
||||
</Text>
|
||||
<HalfOpacity style={colors.text}>Album</HalfOpacity>
|
||||
<HalfOpacity style={colors.text}>{t('album')}</HalfOpacity>
|
||||
</View>
|
||||
</SearchResult>
|
||||
</TouchableHandler>
|
||||
|
||||
@@ -7,6 +7,7 @@ import { NavigationProp } from 'screens';
|
||||
import { useTypedSelector } from 'store';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { setOnboardingStatus } from 'store/settings/actions';
|
||||
import { t } from '@localisation';
|
||||
|
||||
const Container = styled.SafeAreaView`
|
||||
background-color: ${THEME_COLOR};
|
||||
@@ -57,16 +58,16 @@ function Onboarding() {
|
||||
<TextContainer contentContainerStyle={{ flexGrow: 1, justifyContent: 'center' }}>
|
||||
<Logo source={require('../../assets/app-icon-white.png')} />
|
||||
<Text >
|
||||
Welcome!
|
||||
{t('onboarding-welcome')}
|
||||
</Text>
|
||||
<Text>
|
||||
Jellyfin Audio Player will allow you to stream your music library from anywhere, with full support for background audio and casting.
|
||||
{t('onboarding-intro')}
|
||||
</Text>
|
||||
<Text>
|
||||
In order to get started, you need a Jellyfin server. Click the button below to enter your Jellyfin server address and login to it.
|
||||
{t('onboarding-cta')}
|
||||
</Text>
|
||||
<ButtonContainer>
|
||||
<Button title="Set Jellyfin Server" color="#ffffff" onPress={handleClick} />
|
||||
<Button title={t('set-jellyfin-server')} color="#ffffff" onPress={handleClick} />
|
||||
</ButtonContainer>
|
||||
</TextContainer>
|
||||
</Container>
|
||||
|
||||
@@ -7,6 +7,7 @@ import TouchableHandler from 'components/TouchableHandler';
|
||||
import TrackPlayer from 'react-native-track-player';
|
||||
import { THEME_COLOR } from 'CONSTANTS';
|
||||
import { colors } from 'components/Colors';
|
||||
import { t } from '@localisation';
|
||||
|
||||
const QueueItem = styled.View<{ active?: boolean, alreadyPlayed?: boolean, isDark?: boolean }>`
|
||||
padding: 10px;
|
||||
@@ -52,7 +53,7 @@ export default function Queue() {
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Text style={{ marginTop: 20, marginBottom: 20 }}>Queue</Text>
|
||||
<Text style={{ marginTop: 20, marginBottom: 20 }}>{t('queue')}</Text>
|
||||
{queue.map((track, i) => (
|
||||
<TouchableHandler id={track.id} onPress={playTrack} key={i}>
|
||||
<QueueItem
|
||||
@@ -70,7 +71,7 @@ export default function Queue() {
|
||||
</TouchableHandler>
|
||||
))}
|
||||
<ClearQueue>
|
||||
<Button title="Clear Queue" color={THEME_COLOR} onPress={clearQueue} />
|
||||
<Button title={t('clear-queue')} color={THEME_COLOR} onPress={clearQueue} />
|
||||
</ClearQueue>
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Text, Button } from 'react-native';
|
||||
import { THEME_COLOR } from 'CONSTANTS';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import music from 'store/music';
|
||||
import { t } from '@localisation';
|
||||
|
||||
export default function CacheSettings() {
|
||||
const dispatch = useDispatch();
|
||||
@@ -18,9 +19,9 @@ export default function CacheSettings() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<SubHeader>Cache</SubHeader>
|
||||
<Text>If you have updated your Jellyfin library, but the app is holding on to cached assets, you can forcefully clear the cache using this button. This will force the app to fetch the library from scratch.</Text>
|
||||
<Button title="Reset Cache" onPress={handleClearCache} color={THEME_COLOR} />
|
||||
<SubHeader>{t('setting-cache')}</SubHeader>
|
||||
<Text>{t('setting-cache-description')}</Text>
|
||||
<Button title={t('reset-cache')} onPress={handleClearCache} color={THEME_COLOR} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import { SubHeader } from 'components/Typography';
|
||||
import { colors } from 'components/Colors';
|
||||
import { NavigationProp } from '../..';
|
||||
import { useTypedSelector } from 'store';
|
||||
import { t } from '@localisation';
|
||||
|
||||
const InputContainer = styled.View`
|
||||
margin: 10px 0;
|
||||
@@ -25,20 +26,20 @@ export default function LibrarySettings() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<SubHeader>Jellyfin Library</SubHeader>
|
||||
<SubHeader>{t('jellyfin-library')}</SubHeader>
|
||||
<InputContainer>
|
||||
<Text style={colors.text}>Jellyfin Server URL</Text>
|
||||
<Text style={colors.text}>{t('jellyfin-server-url')}</Text>
|
||||
<Input placeholder="https://jellyfin.yourserver.com/" value={jellyfin?.uri} editable={false} style={colors.input} />
|
||||
</InputContainer>
|
||||
<InputContainer>
|
||||
<Text style={colors.text}>Jellyfin Access Token</Text>
|
||||
<Text style={colors.text}>{t('jellyfin-access-token')}</Text>
|
||||
<Input placeholder="deadbeefdeadbeefdeadbeef" value={jellyfin?.access_token} editable={false} style={colors.input} />
|
||||
</InputContainer>
|
||||
<InputContainer>
|
||||
<Text style={colors.text}>Jellyfin User ID</Text>
|
||||
<Text style={colors.text}>{t('jellyfin-user-id')}</Text>
|
||||
<Input placeholder="deadbeefdeadbeefdeadbeef" value={jellyfin?.user_id} editable={false} style={colors.input} />
|
||||
</InputContainer>
|
||||
<Button title="Set Jellyfin server" onPress={handleSetLibrary} color={THEME_COLOR} />
|
||||
<Button title={t('set-jellyfin-server')} onPress={handleSetLibrary} color={THEME_COLOR} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -4,13 +4,14 @@ import { Header } from 'components/Typography';
|
||||
import { colors } from 'components/Colors';
|
||||
import Library from './components/Library';
|
||||
import Cache from './components/Cache';
|
||||
import { t } from '@localisation';
|
||||
|
||||
export default function Settings() {
|
||||
return (
|
||||
<ScrollView>
|
||||
<SafeAreaView>
|
||||
<View style={{ padding: 20 }}>
|
||||
<Header style={colors.text}>Settings</Header>
|
||||
<Header style={colors.text}>{t('settings')}</Header>
|
||||
<Library />
|
||||
<Cache />
|
||||
</View>
|
||||
|
||||
@@ -14,6 +14,7 @@ import { useTypedSelector } from 'store';
|
||||
import Onboarding from './Onboarding';
|
||||
import TrackPopupMenu from './modals/TrackPopupMenu';
|
||||
import { ModalStackParams } from './types';
|
||||
import { t } from '@localisation';
|
||||
|
||||
const Stack = createStackNavigator<ModalStackParams>();
|
||||
const Tab = createBottomTabNavigator();
|
||||
@@ -64,9 +65,9 @@ function Screens() {
|
||||
inactiveTintColor: 'gray',
|
||||
}}
|
||||
>
|
||||
<Tab.Screen name="NowPlaying" component={Player} options={{ tabBarLabel: 'Now Playing' }} />
|
||||
<Tab.Screen name="Music" component={Music} />
|
||||
<Tab.Screen name="Settings" component={Settings} />
|
||||
<Tab.Screen name="NowPlaying" component={Player} options={{ tabBarLabel: t('now-playing') }} />
|
||||
<Tab.Screen name="Music" component={Music} options={{ tabBarLabel: t('music') }} />
|
||||
<Tab.Screen name="Settings" component={Settings} options={{ tabBarLabel: t('settings') }} />
|
||||
</Tab.Navigator>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { useNavigation, StackActions } from '@react-navigation/native';
|
||||
import CredentialGenerator from './components/CredentialGenerator';
|
||||
import { THEME_COLOR } from 'CONSTANTS';
|
||||
import { colors } from 'components/Colors';
|
||||
import { t } from '@localisation';
|
||||
|
||||
export default function SetJellyfinServer() {
|
||||
// State for first screen
|
||||
@@ -34,7 +35,7 @@ export default function SetJellyfinServer() {
|
||||
) : (
|
||||
<View style={{ padding: 20, flex: 1, justifyContent: 'center', alignItems: 'center' }}>
|
||||
<Text style={colors.text}>
|
||||
Please enter your Jellyfin server URL. Make sure to include the protocol and port
|
||||
{t('set-jellyfin-server-instruction')}
|
||||
</Text>
|
||||
<Input
|
||||
placeholder="https://jellyfin.yourserver.io/"
|
||||
@@ -46,7 +47,7 @@ export default function SetJellyfinServer() {
|
||||
style={{ ...colors.input, width: '100%' }}
|
||||
/>
|
||||
<Button
|
||||
title="Set server"
|
||||
title={t('set-jellyfin-server')}
|
||||
onPress={() => setIsLogginIn(true)}
|
||||
disabled={!serverUrl?.length}
|
||||
color={THEME_COLOR}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { THEME_COLOR } from 'CONSTANTS';
|
||||
import { SubHeader } from 'components/Typography';
|
||||
import styled from 'styled-components/native';
|
||||
import usePlayTrack from 'utility/usePlayTrack';
|
||||
import { t } from '@localisation';
|
||||
|
||||
type Route = RouteProp<ModalStackParams, 'TrackPopupMenu'>;
|
||||
|
||||
@@ -48,8 +49,8 @@ function TrackPopupMenu() {
|
||||
<SubHeader>{track?.Name}</SubHeader>
|
||||
<Text>{track?.Album} - {track?.AlbumArtist}</Text>
|
||||
<Buttons>
|
||||
<Button title="Play Next" color={THEME_COLOR} onPress={handlePlayNext} />
|
||||
<Button title="Add to Queue" color={THEME_COLOR} onPress={handleAddToQueue} />
|
||||
<Button title={t('play-next')} color={THEME_COLOR} onPress={handlePlayNext} />
|
||||
<Button title={t('add-to-queue')} color={THEME_COLOR} onPress={handleAddToQueue} />
|
||||
</Buttons>
|
||||
</Container>
|
||||
</Modal>
|
||||
|
||||
Reference in New Issue
Block a user