mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-03-16 14:26:20 +00:00
More Translations
This commit is contained in:
@@ -7,6 +7,7 @@ import { ListItem } from "@/components/list/ListItem";
|
||||
import * as WebBrowser from "expo-web-browser";
|
||||
import Ionicons from "@expo/vector-icons/Ionicons";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export interface MenuLink {
|
||||
name: string;
|
||||
@@ -18,6 +19,7 @@ export default function menuLinks() {
|
||||
const [api] = useAtom(apiAtom);
|
||||
const insets = useSafeAreaInsets();
|
||||
const [menuLinks, setMenuLinks] = useState<MenuLink[]>([]);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const getMenuLinks = useCallback(async () => {
|
||||
try {
|
||||
@@ -67,7 +69,7 @@ export default function menuLinks() {
|
||||
)}
|
||||
ListEmptyComponent={
|
||||
<View className="flex flex-col items-center justify-center h-full">
|
||||
<Text className="font-bold text-xl text-neutral-500">No links</Text>
|
||||
<Text className="font-bold text-xl text-neutral-500">{t("custom_links.no_links")}</Text>
|
||||
</View>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -11,10 +11,13 @@ import { useAtom } from "jotai";
|
||||
import { useEffect, useState } from "react";
|
||||
import { ActivityIndicator, TouchableOpacity, View } from "react-native";
|
||||
import { toast } from "sonner-native";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export default function page() {
|
||||
const navigation = useNavigation();
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [api] = useAtom(apiAtom);
|
||||
const [settings, updateSettings] = useSettings();
|
||||
|
||||
@@ -24,7 +27,7 @@ export default function page() {
|
||||
const saveMutation = useMutation({
|
||||
mutationFn: async (newVal: string) => {
|
||||
if (newVal.length === 0 || !newVal.startsWith("http")) {
|
||||
toast.error("Invalid URL");
|
||||
toast.error(t("home.settings.toasts.invalid_url"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -42,13 +45,13 @@ export default function page() {
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
if (data) {
|
||||
toast.success("Connected");
|
||||
toast.success(t("home.settings.toasts.connected"));
|
||||
} else {
|
||||
toast.error("Could not connect");
|
||||
toast.error(t("home.settings.toasts.could_not_connect"));
|
||||
}
|
||||
},
|
||||
onError: () => {
|
||||
toast.error("Could not connect");
|
||||
toast.error(t("home.settings.toasts.could_not_connect"));
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -10,10 +10,13 @@ import { useAtom } from "jotai";
|
||||
import { useEffect, useState } from "react";
|
||||
import { ActivityIndicator, TouchableOpacity, View } from "react-native";
|
||||
import { toast } from "sonner-native";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export default function page() {
|
||||
const navigation = useNavigation();
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [api] = useAtom(apiAtom);
|
||||
const [settings, updateSettings] = useSettings();
|
||||
|
||||
@@ -23,7 +26,7 @@ export default function page() {
|
||||
const saveMutation = useMutation({
|
||||
mutationFn: async (newVal: string) => {
|
||||
if (newVal.length === 0 || !newVal.startsWith("http")) {
|
||||
toast.error("Invalid URL");
|
||||
toast.error(t("home.settings.toasts.invalid_url"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -41,13 +44,13 @@ export default function page() {
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
if (data) {
|
||||
toast.success("Connected");
|
||||
toast.success(t("home.settings.toasts.connected"));
|
||||
} else {
|
||||
toast.error("Could not connect");
|
||||
toast.error(t("home.settings.toasts.could_not_connect"));
|
||||
}
|
||||
},
|
||||
onError: () => {
|
||||
toast.error("Could not connect");
|
||||
toast.error(t("home.settings.toasts.could_not_connect"));
|
||||
},
|
||||
});
|
||||
|
||||
@@ -57,13 +60,13 @@ export default function page() {
|
||||
|
||||
useEffect(() => {
|
||||
navigation.setOptions({
|
||||
title: "Optimized Server",
|
||||
title: t("home.settings.downloads.optimized_server"),
|
||||
headerRight: () =>
|
||||
saveMutation.isPending ? (
|
||||
<ActivityIndicator size={"small"} color={"white"} />
|
||||
) : (
|
||||
<TouchableOpacity onPress={() => onSave(optimizedVersionsServerUrl)}>
|
||||
<Text className="text-blue-500">Save</Text>
|
||||
<Text className="text-blue-500">{t("home.settings.downloads.save_button")}</Text>
|
||||
</TouchableOpacity>
|
||||
),
|
||||
});
|
||||
|
||||
@@ -18,10 +18,12 @@ import { useLocalSearchParams } from "expo-router";
|
||||
import { useAtom } from "jotai";
|
||||
import { useCallback, useMemo } from "react";
|
||||
import { View } from "react-native";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const page: React.FC = () => {
|
||||
const local = useLocalSearchParams();
|
||||
const { actorId } = local as { actorId: string };
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [api] = useAtom(apiAtom);
|
||||
const [user] = useAtom(userAtom);
|
||||
@@ -110,7 +112,7 @@ const page: React.FC = () => {
|
||||
</View>
|
||||
|
||||
<Text className="px-4 text-2xl font-bold mb-2 text-neutral-100">
|
||||
Appeared In
|
||||
{t("item_card.appeared_in")}
|
||||
</Text>
|
||||
<InfiniteHorizontalScroll
|
||||
height={247}
|
||||
|
||||
@@ -10,6 +10,7 @@ import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
|
||||
import { getItemsApi } from "@jellyfin/sdk/lib/utils/api";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { router, useLocalSearchParams, useNavigation } from "expo-router";
|
||||
import { t } from "i18next";
|
||||
import { useAtom } from "jotai";
|
||||
import { useEffect, useState } from "react";
|
||||
import { ScrollView, TouchableOpacity, View } from "react-native";
|
||||
@@ -112,7 +113,7 @@ export default function page() {
|
||||
<View className="px-4 mb-8">
|
||||
<Text className="font-bold text-2xl mb-2">{album?.Name}</Text>
|
||||
<Text className="text-neutral-500">
|
||||
{songs?.TotalRecordCount} songs
|
||||
{t("item_card.x_songs", { count: songs?.TotalRecordCount })}
|
||||
</Text>
|
||||
</View>
|
||||
<View className="px-4">
|
||||
|
||||
@@ -5,6 +5,7 @@ import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
|
||||
import { getItemsApi } from "@jellyfin/sdk/lib/utils/api";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { router, useLocalSearchParams, useNavigation } from "expo-router";
|
||||
import { t } from "i18next";
|
||||
import { useAtom } from "jotai";
|
||||
import { useEffect, useState } from "react";
|
||||
import { FlatList, ScrollView, TouchableOpacity, View } from "react-native";
|
||||
@@ -107,7 +108,7 @@ export default function page() {
|
||||
<View className="px-4 mb-8">
|
||||
<Text className="font-bold text-2xl mb-2">{artist?.Name}</Text>
|
||||
<Text className="text-neutral-500">
|
||||
{albums.TotalRecordCount} albums
|
||||
{t("item_card.x_albums", { count: albums.TotalRecordCount })}
|
||||
</Text>
|
||||
</View>
|
||||
<View className="flex flex-row flex-wrap justify-between px-4">
|
||||
|
||||
@@ -7,6 +7,7 @@ import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
|
||||
import { getArtistsApi, getItemsApi } from "@jellyfin/sdk/lib/utils/api";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { t } from "i18next";
|
||||
import { useAtom } from "jotai";
|
||||
import { useMemo, useState } from "react";
|
||||
import { FlatList, TouchableOpacity, View } from "react-native";
|
||||
@@ -81,7 +82,7 @@ export default function page() {
|
||||
}}
|
||||
ListHeaderComponent={
|
||||
<View className="mb-4">
|
||||
<Text className="font-bold text-3xl mb-2">Artists</Text>
|
||||
<Text className="font-bold text-3xl mb-2">{t("item_card.artists")}</Text>
|
||||
</View>
|
||||
}
|
||||
nestedScrollEnabled
|
||||
|
||||
@@ -377,7 +377,7 @@ const page: React.FC = () => {
|
||||
<FlashList
|
||||
ListEmptyComponent={
|
||||
<View className="flex flex-col items-center justify-center h-full">
|
||||
<Text className="font-bold text-xl text-neutral-500">No results</Text>
|
||||
<Text className="font-bold text-xl text-neutral-500">{t("search.no_results")}</Text>
|
||||
</View>
|
||||
}
|
||||
extraData={[
|
||||
|
||||
@@ -13,11 +13,13 @@ import Animated, {
|
||||
useSharedValue,
|
||||
withTiming,
|
||||
} from "react-native-reanimated";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const Page: React.FC = () => {
|
||||
const [api] = useAtom(apiAtom);
|
||||
const [user] = useAtom(userAtom);
|
||||
const { id } = useLocalSearchParams() as { id: string };
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { data: item, isError } = useQuery({
|
||||
queryKey: ["item", id],
|
||||
@@ -74,7 +76,7 @@ const Page: React.FC = () => {
|
||||
if (isError)
|
||||
return (
|
||||
<View className="flex flex-col items-center justify-center h-screen w-screen">
|
||||
<Text>Could not load item</Text>
|
||||
<Text>{t("item_card.could_not_load_item")}</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
|
||||
@@ -27,10 +27,12 @@ import * as DropdownMenu from "zeego/dropdown-menu";
|
||||
import { TvDetails } from "@/utils/jellyseerr/server/models/Tv";
|
||||
import JellyseerrSeasons from "@/components/series/JellyseerrSeasons";
|
||||
import { JellyserrRatings } from "@/components/Ratings";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const Page: React.FC = () => {
|
||||
const insets = useSafeAreaInsets();
|
||||
const params = useLocalSearchParams();
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
mediaTitle,
|
||||
releaseYear,
|
||||
@@ -184,7 +186,7 @@ const Page: React.FC = () => {
|
||||
</View>
|
||||
{canRequest ? (
|
||||
<Button color="purple" onPress={request}>
|
||||
Request
|
||||
{t("jellyseerr.request_button")}
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
@@ -199,7 +201,7 @@ const Page: React.FC = () => {
|
||||
borderStyle: "solid",
|
||||
}}
|
||||
>
|
||||
Report issue
|
||||
{t("jellyseerr.report_issue_button")}
|
||||
</Button>
|
||||
)}
|
||||
<OverviewText text={result.overview} className="mt-4" />
|
||||
@@ -231,7 +233,7 @@ const Page: React.FC = () => {
|
||||
<View className="flex flex-col space-y-4 px-4 pb-8 pt-2">
|
||||
<View>
|
||||
<Text className="font-bold text-2xl text-neutral-100">
|
||||
Whats wrong?
|
||||
{t("jellyseerr.whats_wrong")}
|
||||
</Text>
|
||||
</View>
|
||||
<View className="flex flex-col space-y-2 items-start">
|
||||
@@ -240,13 +242,13 @@ const Page: React.FC = () => {
|
||||
<DropdownMenu.Trigger>
|
||||
<View className="flex flex-col">
|
||||
<Text className="opacity-50 mb-1 text-xs">
|
||||
Issue Type
|
||||
{t("jellyseerr.issue_type")}
|
||||
</Text>
|
||||
<TouchableOpacity className="bg-neutral-900 h-10 rounded-xl border-neutral-800 border px-3 py-2 flex flex-row items-center justify-between">
|
||||
<Text style={{}} className="" numberOfLines={1}>
|
||||
{issueType
|
||||
? IssueTypeName[issueType]
|
||||
: "Select an issue"}
|
||||
: t("jellyseerr.select_an_issue")}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
@@ -260,7 +262,7 @@ const Page: React.FC = () => {
|
||||
collisionPadding={0}
|
||||
sideOffset={0}
|
||||
>
|
||||
<DropdownMenu.Label>Types</DropdownMenu.Label>
|
||||
<DropdownMenu.Label>{t("jellyseerr.types")}</DropdownMenu.Label>
|
||||
{Object.entries(IssueTypeName)
|
||||
.reverse()
|
||||
.map(([key, value], idx) => (
|
||||
@@ -287,7 +289,7 @@ const Page: React.FC = () => {
|
||||
maxLength={254}
|
||||
style={{color: "white"}}
|
||||
clearButtonMode="always"
|
||||
placeholder="(optional) Describe the issue..."
|
||||
placeholder={t("jellyseerr.describe_the_issue")}
|
||||
placeholderTextColor="#9CA3AF"
|
||||
// Issue with multiline + Textinput inside a portal
|
||||
// https://github.com/callstack/react-native-paper/issues/1668
|
||||
@@ -297,7 +299,7 @@ const Page: React.FC = () => {
|
||||
</View>
|
||||
</View>
|
||||
<Button className="mt-auto" onPress={submitIssue} color="purple">
|
||||
Submit
|
||||
{t("jellyseerr.submit_button")}
|
||||
</Button>
|
||||
</View>
|
||||
</BottomSheetView>
|
||||
|
||||
@@ -320,7 +320,7 @@ export default function search() {
|
||||
<View className="flex flex-row flex-wrap space-x-2 px-4 mb-2">
|
||||
<TouchableOpacity onPress={() => setSearchType("Library")}>
|
||||
<Tag
|
||||
text="Library"
|
||||
text={t("search.library")}
|
||||
textClass="p-1"
|
||||
className={
|
||||
searchType === "Library" ? "bg-purple-600" : undefined
|
||||
@@ -329,7 +329,7 @@ export default function search() {
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity onPress={() => setSearchType("Discover")}>
|
||||
<Tag
|
||||
text="Discover"
|
||||
text={t("search.discover")}
|
||||
textClass="p-1"
|
||||
className={
|
||||
searchType === "Discover" ? "bg-purple-600" : undefined
|
||||
@@ -341,7 +341,7 @@ export default function search() {
|
||||
{!!q && (
|
||||
<View className="px-4 flex flex-col space-y-2">
|
||||
<Text className="text-neutral-500 ">
|
||||
Results for <Text className="text-purple-600">{q}</Text>
|
||||
{t("search.results_for_x")} <Text className="text-purple-600">{q}</Text>
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
@@ -423,7 +423,7 @@ export default function page() {
|
||||
if (isErrorItem || isErrorStreamUrl)
|
||||
return (
|
||||
<View className="w-screen h-screen flex flex-col items-center justify-center bg-black">
|
||||
<Text className="text-white">Error</Text>
|
||||
<Text className="text-white">{t("player.error")}</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import React, { useCallback, useMemo, useRef, useState } from "react";
|
||||
import { Pressable, useWindowDimensions, View } from "react-native";
|
||||
import { useSharedValue } from "react-native-reanimated";
|
||||
import Video, { OnProgressData, VideoRef } from "react-native-video";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export default function page() {
|
||||
const api = useAtomValue(apiAtom);
|
||||
@@ -32,6 +33,7 @@ export default function page() {
|
||||
const [settings] = useSettings();
|
||||
const videoRef = useRef<VideoRef | null>(null);
|
||||
const windowDimensions = useWindowDimensions();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const firstTime = useRef(true);
|
||||
|
||||
@@ -278,14 +280,14 @@ export default function page() {
|
||||
if (isErrorItem || isErrorStreamUrl)
|
||||
return (
|
||||
<View className="w-screen h-screen flex flex-col items-center justify-center bg-black">
|
||||
<Text className="text-white">Error</Text>
|
||||
<Text className="text-white">{t("player.error")}</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
if (!item || !stream)
|
||||
return (
|
||||
<View className="w-screen h-screen flex flex-col items-center justify-center bg-black">
|
||||
<Text className="text-white">Error</Text>
|
||||
<Text className="text-white">{t("player.error")}</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
|
||||
@@ -39,12 +39,14 @@ import Video, {
|
||||
VideoRef,
|
||||
} from "react-native-video";
|
||||
import { SubtitleHelper } from "@/utils/SubtitleHelper";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const Player = () => {
|
||||
const api = useAtomValue(apiAtom);
|
||||
const user = useAtomValue(userAtom);
|
||||
const [settings] = useSettings();
|
||||
const videoRef = useRef<VideoRef | null>(null);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const firstTime = useRef(true);
|
||||
const revalidateProgressCache = useInvalidatePlaybackProgressCache();
|
||||
@@ -373,7 +375,7 @@ const Player = () => {
|
||||
if (isErrorItem || isErrorStreamUrl)
|
||||
return (
|
||||
<View className="w-screen h-screen flex flex-col items-center justify-center bg-black">
|
||||
<Text className="text-white">Error</Text>
|
||||
<Text className="text-white">{t("player.error")}</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -440,7 +442,7 @@ const Player = () => {
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<Text>No video source...</Text>
|
||||
<Text>{t("player.no_video_source")}</Text>
|
||||
)}
|
||||
</View>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user