mirror of
https://github.com/streamyfin/streamyfin.git
synced 2025-08-20 18:37:18 +02:00
Add fr, search translation, fix login title
This commit is contained in:
@@ -56,7 +56,7 @@ type Section = ScrollingCollectionListSection | MediaListSection;
|
|||||||
export default function index() {
|
export default function index() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const { i18n, t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const api = useAtomValue(apiAtom);
|
const api = useAtomValue(apiAtom);
|
||||||
const user = useAtomValue(userAtom);
|
const user = useAtomValue(userAtom);
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import {commonScreenOptions, nestedTabPageScreenOptions} from "@/components/stacks/NestedTabPageStack";
|
import {commonScreenOptions, nestedTabPageScreenOptions} from "@/components/stacks/NestedTabPageStack";
|
||||||
import { Stack } from "expo-router";
|
import { Stack } from "expo-router";
|
||||||
import { Platform } from "react-native";
|
import { Platform } from "react-native";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
export default function SearchLayout() {
|
export default function SearchLayout() {
|
||||||
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<Stack>
|
<Stack>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
@@ -10,7 +12,7 @@ export default function SearchLayout() {
|
|||||||
options={{
|
options={{
|
||||||
headerShown: true,
|
headerShown: true,
|
||||||
headerLargeTitle: true,
|
headerLargeTitle: true,
|
||||||
headerTitle: "Search",
|
headerTitle: t("search.search_title"),
|
||||||
headerBlurEffect: "prominent",
|
headerBlurEffect: "prominent",
|
||||||
headerTransparent: Platform.OS === "ios" ? true : false,
|
headerTransparent: Platform.OS === "ios" ? true : false,
|
||||||
headerShadowVisible: false,
|
headerShadowVisible: false,
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import JellyseerrPoster from "@/components/posters/JellyseerrPoster";
|
|||||||
import {Tag} from "@/components/GenreTags";
|
import {Tag} from "@/components/GenreTags";
|
||||||
import DiscoverSlide from "@/components/jellyseerr/DiscoverSlide";
|
import DiscoverSlide from "@/components/jellyseerr/DiscoverSlide";
|
||||||
import {sortBy} from "lodash";
|
import {sortBy} from "lodash";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
type SearchType = 'Library' | 'Discover';
|
type SearchType = 'Library' | 'Discover';
|
||||||
|
|
||||||
@@ -120,6 +121,7 @@ export default function search() {
|
|||||||
},
|
},
|
||||||
[api, searchEngine, settings]
|
[api, searchEngine, settings]
|
||||||
);
|
);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const navigation = useNavigation();
|
const navigation = useNavigation();
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
@@ -283,7 +285,7 @@ export default function search() {
|
|||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
returnKeyType="done"
|
returnKeyType="done"
|
||||||
keyboardType="web-search"
|
keyboardType="web-search"
|
||||||
placeholder="Search here..."
|
placeholder={t("search.search_hint")}
|
||||||
value={search}
|
value={search}
|
||||||
onChangeText={(text) => setSearch(text)}
|
onChangeText={(text) => setSearch(text)}
|
||||||
/>
|
/>
|
||||||
@@ -462,7 +464,7 @@ export default function search() {
|
|||||||
) : noResults && debouncedSearch.length > 0 ? (
|
) : noResults && debouncedSearch.length > 0 ? (
|
||||||
<View>
|
<View>
|
||||||
<Text className="text-center text-lg font-bold mt-4">
|
<Text className="text-center text-lg font-bold mt-4">
|
||||||
No results found for
|
{t("search.no_results_found_for")}
|
||||||
</Text>
|
</Text>
|
||||||
<Text className="text-xs text-purple-600 text-center">
|
<Text className="text-xs text-purple-600 text-center">
|
||||||
"{debouncedSearch}"
|
"{debouncedSearch}"
|
||||||
|
|||||||
@@ -198,14 +198,13 @@ const CredentialsSchema = z.object({
|
|||||||
<View className="px-4 -mt-20 w-full">
|
<View className="px-4 -mt-20 w-full">
|
||||||
<View className="flex flex-col space-y-2">
|
<View className="flex flex-col space-y-2">
|
||||||
<Text className="text-2xl font-bold -mb-2">
|
<Text className="text-2xl font-bold -mb-2">
|
||||||
{t("login.login_title")}
|
|
||||||
<>
|
<>
|
||||||
{serverName ? (
|
{serverName ? (
|
||||||
<>
|
<>
|
||||||
{" to "}
|
{t("login.login_to_title") + " "}
|
||||||
<Text className="text-purple-600">{serverName}</Text>
|
<Text className="text-purple-600">{serverName}</Text>
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : t("login.login_title")}
|
||||||
</>
|
</>
|
||||||
</Text>
|
</Text>
|
||||||
<Text className="text-xs text-neutral-400">{serverURL}</Text>
|
<Text className="text-xs text-neutral-400">{serverURL}</Text>
|
||||||
@@ -251,7 +250,7 @@ const CredentialsSchema = z.object({
|
|||||||
onPress={handleQuickConnect}
|
onPress={handleQuickConnect}
|
||||||
className="w-full mb-2"
|
className="w-full mb-2"
|
||||||
>
|
>
|
||||||
Use Quick Connect
|
{t("login.use_quick_connect")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button onPress={handleLogin} loading={loading}>
|
<Button onPress={handleLogin} loading={loading}>
|
||||||
{t("login.login_button")}
|
{t("login.login_button")}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ interface Props extends ViewProps {}
|
|||||||
export const LanguageSwitcher: React.FC<Props> = ({ ...props }) => {
|
export const LanguageSwitcher: React.FC<Props> = ({ ...props }) => {
|
||||||
const { i18n } = useTranslation();
|
const { i18n } = useTranslation();
|
||||||
|
|
||||||
const lngs = ["en", "sv"];
|
const lngs = ["en", "fr", "sv"];
|
||||||
|
|
||||||
const [settings, updateSettings] = useSettings();
|
const [settings, updateSettings] = useSettings();
|
||||||
return (
|
return (
|
||||||
|
|||||||
2
i18n.ts
2
i18n.ts
@@ -2,6 +2,7 @@ import i18n from "i18next";
|
|||||||
import { initReactI18next } from "react-i18next";
|
import { initReactI18next } from "react-i18next";
|
||||||
|
|
||||||
import en from "./translations/en.json";
|
import en from "./translations/en.json";
|
||||||
|
import fr from "./translations/fr.json";
|
||||||
import sv from "./translations/sv.json";
|
import sv from "./translations/sv.json";
|
||||||
import { getLocales } from "expo-localization";
|
import { getLocales } from "expo-localization";
|
||||||
|
|
||||||
@@ -9,6 +10,7 @@ i18n.use(initReactI18next).init({
|
|||||||
compatibilityJSON: "v3",
|
compatibilityJSON: "v3",
|
||||||
resources: {
|
resources: {
|
||||||
en: { translation: en },
|
en: { translation: en },
|
||||||
|
fr: { translation: fr },
|
||||||
sv: { translation: sv },
|
sv: { translation: sv },
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,10 @@
|
|||||||
"username_required": "Username is required",
|
"username_required": "Username is required",
|
||||||
"error_title": "Error",
|
"error_title": "Error",
|
||||||
"login_title": "Log in",
|
"login_title": "Log in",
|
||||||
|
"login_to_title": "Log in to",
|
||||||
"username_placeholder": "Username",
|
"username_placeholder": "Username",
|
||||||
"password_placeholder": "Password",
|
"password_placeholder": "Password",
|
||||||
|
"use_quick_connect": "Use Quick Connect",
|
||||||
"login_button": "Log in"
|
"login_button": "Log in"
|
||||||
},
|
},
|
||||||
"server": {
|
"server": {
|
||||||
@@ -26,6 +28,11 @@
|
|||||||
"suggestedMovies": "Suggested Movies",
|
"suggestedMovies": "Suggested Movies",
|
||||||
"suggestedEpisodes": "Suggested Episodes"
|
"suggestedEpisodes": "Suggested Episodes"
|
||||||
},
|
},
|
||||||
|
"search": {
|
||||||
|
"search_title": "Search",
|
||||||
|
"search_hint": "Search here...",
|
||||||
|
"no_results_found_for": "No results found for"
|
||||||
|
},
|
||||||
"tabs": {
|
"tabs": {
|
||||||
"home": "Home",
|
"home": "Home",
|
||||||
"search": "Search",
|
"search": "Search",
|
||||||
|
|||||||
42
translations/fr.json
Normal file
42
translations/fr.json
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"login": {
|
||||||
|
"username_required": "Le nom d'utilisateur est requis",
|
||||||
|
"error_title": "Erreur",
|
||||||
|
"login_title": "Se connecter",
|
||||||
|
"login_to_title": "Se connecter à",
|
||||||
|
"username_placeholder": "Nom d'utilisateur",
|
||||||
|
"password_placeholder": "Mot de passe",
|
||||||
|
"use_quick_connect": "Utiliser Quick Connect",
|
||||||
|
"login_button": "Se connecter"
|
||||||
|
},
|
||||||
|
"server": {
|
||||||
|
"enter_url_to_jellyfin_server": "Entrez l'URL de votre serveur Jellyfin",
|
||||||
|
"server_url_placeholder": "URL du serveur",
|
||||||
|
"server_url_hint": "Assurez-vous d'inclure http ou https",
|
||||||
|
"connect_button": "Connexion"
|
||||||
|
},
|
||||||
|
"home": {
|
||||||
|
"home": "Accueil",
|
||||||
|
"noInternet": "Pas d'Internet",
|
||||||
|
"noInternetMessage": "Aucun problème, vous pouvez toujours regarder\nle contenu téléchargé.",
|
||||||
|
"goToDownloads": "Aller aux téléchargements",
|
||||||
|
"oops": "Oups!",
|
||||||
|
"errorMessage": "Quelque chose s'est mal passé.\nVeuillez vous reconnecter à nouveau.",
|
||||||
|
"continueWatching": "Continuer à regarder",
|
||||||
|
"nextUp": "À suivre",
|
||||||
|
"recentlyAddedIn": "Ajoutés récemment dans {{libraryName}}",
|
||||||
|
"suggestedMovies": "Films suggérés",
|
||||||
|
"suggestedEpisodes": "Épisodes suggérés"
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"search_title": "Recherche",
|
||||||
|
"search_hint": "Rechercher ici...",
|
||||||
|
"no_results_found_for": "Aucun résultat trouvé pour"
|
||||||
|
},
|
||||||
|
"tabs": {
|
||||||
|
"home": "Accueil",
|
||||||
|
"search": "Recherche",
|
||||||
|
"library": "Bibliothèque",
|
||||||
|
"customLinks": "Liens personalisés"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user