mirror of
https://github.com/austinried/subtracks.git
synced 2026-02-11 23:32:42 +01:00
Localization support (#99)
* basic i18n poc * translate home, filters, tabs support dot notation in backend for namespaces * i18n context menu, artist filters, list controls also nothings here fix backend not caching fallback * i18n queue, artist view, search/results * i18n settings and server view * Added translation using Weblate (Norwegian Bokmål) * Translated using Weblate (Norwegian Bokmål) Currently translated at 100.0% (6 of 6 strings) Translation: Subtracks/subtracks Translate-URL: https://hosted.weblate.org/projects/subtracks/subtracks/nb_NO/ * Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: Subtracks/subtracks Translate-URL: https://hosted.weblate.org/projects/subtracks/subtracks/ * Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: Subtracks/subtracks Translate-URL: https://hosted.weblate.org/projects/subtracks/subtracks/ * Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: Subtracks/subtracks Translate-URL: https://hosted.weblate.org/projects/subtracks/subtracks/ * fix url escaping * added some mostly naive text overflow fixes rewrote filter context menu as a slide in because the old one apparently can't handle dynamic width * Added translation using Weblate (French) * Translated using Weblate (French) Currently translated at 17.4% (11 of 63 strings) Translation: Subtracks/subtracks Translate-URL: https://hosted.weblate.org/projects/subtracks/subtracks/fr/ * Translated using Weblate (French) Currently translated at 19.0% (12 of 63 strings) Translation: Subtracks/subtracks Translate-URL: https://hosted.weblate.org/projects/subtracks/subtracks/fr/ * Translated using Weblate (French) Currently translated at 40.0% (26 of 65 strings) Translation: Subtracks/subtracks Translate-URL: https://hosted.weblate.org/projects/subtracks/subtracks/fr/ * add weblate and some pretty badges to readme * fix link * Translated using Weblate (French) Currently translated at 50.7% (33 of 65 strings) Translation: Subtracks/subtracks Translate-URL: https://hosted.weblate.org/projects/subtracks/subtracks/fr/ * Translated using Weblate (English) Currently translated at 100.0% (65 of 65 strings) Translation: Subtracks/subtracks Translate-URL: https://hosted.weblate.org/projects/subtracks/subtracks/en/ * Translated using Weblate (French) Currently translated at 90.7% (59 of 65 strings) Translation: Subtracks/subtracks Translate-URL: https://hosted.weblate.org/projects/subtracks/subtracks/fr/ * i18n now playing context type fix overscroll on new filter menu fix getting default namespace from the i18n backend * Translated using Weblate (French) Currently translated at 96.9% (63 of 65 strings) Translation: Subtracks/subtracks Translate-URL: https://hosted.weblate.org/projects/subtracks/subtracks/fr/ * Translated using Weblate (French) Currently translated at 100.0% (66 of 66 strings) Translation: Subtracks/subtracks Translate-URL: https://hosted.weblate.org/projects/subtracks/subtracks/fr/ * Translated using Weblate (Japanese) (#98) Currently translated at 7.5% (5 of 66 strings) Translation: Subtracks/subtracks Translate-URL: https://hosted.weblate.org/projects/subtracks/subtracks/ja/ Co-authored-by: Austin Riedhammer <austinried@functionkey.xyz> * little note to remind me why that's there * update licenses Co-authored-by: Allan Nordhøy <epost@anotheragency.no> Co-authored-by: Hosted Weblate <hosted@weblate.org> Co-authored-by: Clyhtsuriva <aimeric@adjutor.xyz>
This commit is contained in:
@@ -47,7 +47,9 @@ const BottomTabButton = React.memo<{
|
||||
return (
|
||||
<PressableOpacity onPress={onPress} style={styles.button} disabled={disabled}>
|
||||
<Image source={imgSource} style={imgStyle} fadeDuration={0} />
|
||||
<Text style={textStyle}>{label}</Text>
|
||||
<Text style={textStyle} numberOfLines={1} ellipsizeMode="clip">
|
||||
{label}
|
||||
</Text>
|
||||
</PressableOpacity>
|
||||
)
|
||||
})
|
||||
@@ -92,6 +94,7 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
button: {
|
||||
alignItems: 'center',
|
||||
flexGrow: 1,
|
||||
flex: 1,
|
||||
height: '100%',
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { withSuspense } from '@app/components/withSuspense'
|
||||
import { useFirstRun } from '@app/hooks/settings'
|
||||
import { Album, Playlist } from '@app/models/library'
|
||||
import BottomTabBar from '@app/navigation/BottomTabBar'
|
||||
@@ -16,6 +17,7 @@ import font from '@app/styles/font'
|
||||
import { BottomTabNavigationProp, createBottomTabNavigator } from '@react-navigation/bottom-tabs'
|
||||
import { RouteProp, StackActions } from '@react-navigation/native'
|
||||
import React, { useEffect } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { StyleSheet } from 'react-native'
|
||||
import { createNativeStackNavigator, NativeStackNavigationProp } from 'react-native-screens/native-stack'
|
||||
|
||||
@@ -116,7 +118,7 @@ const SearchTab = createTabStackNavigator(Search)
|
||||
type SettingsStackParamList = {
|
||||
main: undefined
|
||||
server?: { id?: string }
|
||||
web: { uri: string }
|
||||
web: { uri: string; title?: string }
|
||||
}
|
||||
|
||||
type ServerScreenNavigationProp = NativeStackNavigationProp<SettingsStackParamList, 'server'>
|
||||
@@ -133,7 +135,9 @@ type WebScreenProps = {
|
||||
route: WebScreenRouteProp
|
||||
navigation: WebScreenNavigationProp
|
||||
}
|
||||
const WebScreen: React.FC<WebScreenProps> = ({ route }) => <WebViewScreen uri={route.params.uri} />
|
||||
const WebScreen: React.FC<WebScreenProps> = ({ route }) => (
|
||||
<WebViewScreen uri={route.params.uri} title={route.params.title} />
|
||||
)
|
||||
|
||||
const SettingsStack = createNativeStackNavigator()
|
||||
|
||||
@@ -156,7 +160,6 @@ const SettingsTab = () => {
|
||||
name="web"
|
||||
component={WebScreen}
|
||||
options={{
|
||||
title: 'Web View',
|
||||
headerStyle: styles.stackheaderStyle,
|
||||
headerHideShadow: true,
|
||||
headerTintColor: 'white',
|
||||
@@ -169,7 +172,8 @@ const SettingsTab = () => {
|
||||
|
||||
const Tab = createBottomTabNavigator()
|
||||
|
||||
const BottomTabNavigator = () => {
|
||||
const BottomTabNavigator = withSuspense(() => {
|
||||
const { t } = useTranslation('navigation.tabs')
|
||||
const firstRun = useFirstRun()
|
||||
const resetServer = useStore(store => store.resetServer)
|
||||
|
||||
@@ -179,14 +183,14 @@ const BottomTabNavigator = () => {
|
||||
<></>
|
||||
) : (
|
||||
<>
|
||||
<Tab.Screen name="home" component={HomeTab} options={{ tabBarLabel: 'Home' }} />
|
||||
<Tab.Screen name="library" component={LibraryTab} options={{ tabBarLabel: 'Library' }} />
|
||||
<Tab.Screen name="search" component={SearchTab} options={{ tabBarLabel: 'Search' }} />
|
||||
<Tab.Screen name="home" component={HomeTab} options={{ tabBarLabel: t('home') }} />
|
||||
<Tab.Screen name="library" component={LibraryTab} options={{ tabBarLabel: t('library') }} />
|
||||
<Tab.Screen name="search" component={SearchTab} options={{ tabBarLabel: t('search') }} />
|
||||
</>
|
||||
)}
|
||||
<Tab.Screen name="settings" component={SettingsTab} options={{ tabBarLabel: 'Settings' }} />
|
||||
<Tab.Screen name="settings" component={SettingsTab} options={{ tabBarLabel: t('settings') }} />
|
||||
</Tab.Navigator>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
export default BottomTabNavigator
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { withSuspense } from '@app/components/withSuspense'
|
||||
import AlbumsTab from '@app/screens/LibraryAlbums'
|
||||
import ArtistsTab from '@app/screens/LibraryArtists'
|
||||
import PlaylistsTab from '@app/screens/LibraryPlaylists'
|
||||
@@ -6,12 +7,14 @@ import dimensions from '@app/styles/dimensions'
|
||||
import font from '@app/styles/font'
|
||||
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { StyleSheet } from 'react-native'
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
||||
|
||||
const Tab = createMaterialTopTabNavigator()
|
||||
|
||||
const LibraryTopTabNavigator = () => {
|
||||
const LibraryTopTabNavigator = withSuspense(() => {
|
||||
const { t } = useTranslation('resources')
|
||||
const marginTop = useSafeAreaInsets().top
|
||||
|
||||
return (
|
||||
@@ -22,12 +25,16 @@ const LibraryTopTabNavigator = () => {
|
||||
indicatorStyle: styles.tabindicatorStyle,
|
||||
}}
|
||||
initialRouteName="albums">
|
||||
<Tab.Screen name="albums" component={AlbumsTab} options={{ tabBarLabel: 'Albums' }} />
|
||||
<Tab.Screen name="artists" component={ArtistsTab} options={{ tabBarLabel: 'Artists' }} />
|
||||
<Tab.Screen name="playlists" component={PlaylistsTab} options={{ tabBarLabel: 'Playlists' }} />
|
||||
<Tab.Screen name="albums" component={AlbumsTab} options={{ tabBarLabel: t('album.name', { count: 2 }) }} />
|
||||
<Tab.Screen name="artists" component={ArtistsTab} options={{ tabBarLabel: t('artist.name', { count: 2 }) }} />
|
||||
<Tab.Screen
|
||||
name="playlists"
|
||||
component={PlaylistsTab}
|
||||
options={{ tabBarLabel: t('playlist.name', { count: 2 }) }}
|
||||
/>
|
||||
</Tab.Navigator>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
tabBar: {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { withSuspense } from '@app/components/withSuspense'
|
||||
import BottomTabNavigator from '@app/navigation/BottomTabNavigator'
|
||||
import NowPlayingQueue from '@app/screens/NowPlayingQueue'
|
||||
import NowPlayingView from '@app/screens/NowPlayingView'
|
||||
@@ -5,32 +6,37 @@ import colors from '@app/styles/colors'
|
||||
import font from '@app/styles/font'
|
||||
import { DarkTheme, NavigationContainer } from '@react-navigation/native'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
|
||||
|
||||
const NowPlayingStack = createNativeStackNavigator()
|
||||
|
||||
const NowPlayingNavigator = () => (
|
||||
<NowPlayingStack.Navigator>
|
||||
<NowPlayingStack.Screen name="main" component={NowPlayingView} options={{ headerShown: false }} />
|
||||
<NowPlayingStack.Screen
|
||||
name="queue"
|
||||
component={NowPlayingQueue}
|
||||
options={{
|
||||
title: 'Queue',
|
||||
headerStyle: {
|
||||
backgroundColor: colors.gradient.high,
|
||||
},
|
||||
headerTitleStyle: {
|
||||
fontSize: 18,
|
||||
fontFamily: font.semiBold,
|
||||
color: colors.text.primary,
|
||||
},
|
||||
headerHideShadow: true,
|
||||
headerTintColor: 'white',
|
||||
}}
|
||||
/>
|
||||
</NowPlayingStack.Navigator>
|
||||
)
|
||||
const NowPlayingNavigator = withSuspense(() => {
|
||||
const { t } = useTranslation('resources.queue')
|
||||
|
||||
return (
|
||||
<NowPlayingStack.Navigator>
|
||||
<NowPlayingStack.Screen name="main" component={NowPlayingView} options={{ headerShown: false }} />
|
||||
<NowPlayingStack.Screen
|
||||
name="queue"
|
||||
component={NowPlayingQueue}
|
||||
options={{
|
||||
title: t('name'),
|
||||
headerStyle: {
|
||||
backgroundColor: colors.gradient.high,
|
||||
},
|
||||
headerTitleStyle: {
|
||||
fontSize: 18,
|
||||
fontFamily: font.semiBold,
|
||||
color: colors.text.primary,
|
||||
},
|
||||
headerHideShadow: true,
|
||||
headerTintColor: 'white',
|
||||
}}
|
||||
/>
|
||||
</NowPlayingStack.Navigator>
|
||||
)
|
||||
})
|
||||
|
||||
const RootStack = createNativeStackNavigator()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user