mirror of
https://github.com/jakejarvis/sofa.git
synced 2026-10-15 23:55:43 -04:00
feat(native): follow the system language instead of an in-app picker
Declare the app's 12 languages to iOS and Android via expo-localization, resolve the language from the device's preferred languages at start-up and on Android runtime changes, and make Settings > Language open the system settings page. Drops the MMKV-stored locale. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
20 files changed
+218
-137
No files matched your search
@@ -145,7 +145,25 @@
|
|||||||
"microphonePermission": false
|
"microphonePermission": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
[
|
||||||
"expo-localization",
|
"expo-localization",
|
||||||
|
{
|
||||||
|
"supportedLocales": [
|
||||||
|
"en",
|
||||||
|
"fr",
|
||||||
|
"de",
|
||||||
|
"es",
|
||||||
|
"it",
|
||||||
|
"pt",
|
||||||
|
"nl",
|
||||||
|
"ar",
|
||||||
|
"he",
|
||||||
|
"zh",
|
||||||
|
"ja",
|
||||||
|
"ko"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"expo-widgets",
|
"expo-widgets",
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import {
|
|||||||
IconWorld,
|
IconWorld,
|
||||||
} from "@tabler/icons-react-native";
|
} from "@tabler/icons-react-native";
|
||||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||||
import { reloadAppAsync } from "expo";
|
|
||||||
import * as Application from "expo-application";
|
import * as Application from "expo-application";
|
||||||
import * as ImagePicker from "expo-image-picker";
|
import * as ImagePicker from "expo-image-picker";
|
||||||
import { useRouter } from "expo-router";
|
import { useRouter } from "expo-router";
|
||||||
@@ -32,6 +31,7 @@ import { useCallback, useState } from "react";
|
|||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
Linking,
|
Linking,
|
||||||
|
Platform,
|
||||||
Pressable,
|
Pressable,
|
||||||
RefreshControl,
|
RefreshControl,
|
||||||
ScrollView,
|
ScrollView,
|
||||||
@@ -47,11 +47,9 @@ import { SettingsSection } from "@/components/settings/settings-section";
|
|||||||
import { TmdbLogo } from "@/components/tmdb-logo";
|
import { TmdbLogo } from "@/components/tmdb-logo";
|
||||||
import { Image } from "@/components/ui/image";
|
import { Image } from "@/components/ui/image";
|
||||||
import { ScaledIcon } from "@/components/ui/scaled-icon";
|
import { ScaledIcon } from "@/components/ui/scaled-icon";
|
||||||
import { SelectModal } from "@/components/ui/select-modal";
|
|
||||||
import { Spinner } from "@/components/ui/spinner";
|
import { Spinner } from "@/components/ui/spinner";
|
||||||
import { Switch } from "@/components/ui/switch";
|
import { Switch } from "@/components/ui/switch";
|
||||||
import { Text } from "@/components/ui/text";
|
import { Text } from "@/components/ui/text";
|
||||||
import { setPersistedLocale } from "@/lib/i18n";
|
|
||||||
import { orpc } from "@/lib/orpc";
|
import { orpc } from "@/lib/orpc";
|
||||||
import { isAnalyticsEnabled, setAnalyticsEnabled } from "@/lib/posthog";
|
import { isAnalyticsEnabled, setAnalyticsEnabled } from "@/lib/posthog";
|
||||||
import { queryClient } from "@/lib/query-client";
|
import { queryClient } from "@/lib/query-client";
|
||||||
@@ -59,7 +57,6 @@ import { isCrashReportingEnabled, setCrashReportingEnabled } from "@/lib/sentry"
|
|||||||
import { authClient, getServerUrl } from "@/lib/server";
|
import { authClient, getServerUrl } from "@/lib/server";
|
||||||
import { markSessionEnding } from "@/lib/session-end";
|
import { markSessionEnding } from "@/lib/session-end";
|
||||||
import { toast } from "@/lib/toast";
|
import { toast } from "@/lib/toast";
|
||||||
import { activateLocale, isLocaleRTL, type SupportedLocale } from "@sofa/i18n";
|
|
||||||
import { LOCALE_INFO } from "@sofa/i18n/locales";
|
import { LOCALE_INFO } from "@sofa/i18n/locales";
|
||||||
|
|
||||||
const settingsContentContainerStyle = {
|
const settingsContentContainerStyle = {
|
||||||
@@ -77,6 +74,14 @@ const removePhotoIcon = Icon.select({
|
|||||||
android: import("@expo/material-symbols/delete.xml"),
|
android: import("@expo/material-symbols/delete.xml"),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Per-app language is in system settings: iOS 13+ (Settings → Sofa → Language) and Android 13+
|
||||||
|
// (App info → Language). Older Android only has the device language.
|
||||||
|
const canOpenLanguageSettings =
|
||||||
|
process.env.EXPO_OS === "ios" ||
|
||||||
|
(process.env.EXPO_OS === "android" &&
|
||||||
|
typeof Platform.Version === "number" &&
|
||||||
|
Platform.Version >= 33);
|
||||||
|
|
||||||
export default function SettingsScreen() {
|
export default function SettingsScreen() {
|
||||||
const { t, i18n } = useLingui();
|
const { t, i18n } = useLingui();
|
||||||
const { push } = useRouter();
|
const { push } = useRouter();
|
||||||
@@ -93,7 +98,6 @@ export default function SettingsScreen() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const [languageModalOpen, setLanguageModalOpen] = useState(false);
|
|
||||||
const languageLabel = LOCALE_INFO.find((o) => o.code === i18n.locale)?.nativeName ?? i18n.locale;
|
const languageLabel = LOCALE_INFO.find((o) => o.code === i18n.locale)?.nativeName ?? i18n.locale;
|
||||||
const [analyticsEnabled, setAnalyticsToggle] = useState(isAnalyticsEnabled);
|
const [analyticsEnabled, setAnalyticsToggle] = useState(isAnalyticsEnabled);
|
||||||
const [crashReportingEnabled, setCrashReportingToggle] = useState(isCrashReportingEnabled);
|
const [crashReportingEnabled, setCrashReportingToggle] = useState(isCrashReportingEnabled);
|
||||||
@@ -428,7 +432,7 @@ export default function SettingsScreen() {
|
|||||||
label={t`Language`}
|
label={t`Language`}
|
||||||
value={languageLabel}
|
value={languageLabel}
|
||||||
icon={IconLanguage}
|
icon={IconLanguage}
|
||||||
onPress={() => setLanguageModalOpen(true)}
|
onPress={canOpenLanguageSettings ? () => void Linking.openSettings() : undefined}
|
||||||
/>
|
/>
|
||||||
<SettingsRow
|
<SettingsRow
|
||||||
label={t`Anonymous usage reporting`}
|
label={t`Anonymous usage reporting`}
|
||||||
@@ -568,36 +572,6 @@ export default function SettingsScreen() {
|
|||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
|
|
||||||
{/* Language Modal */}
|
|
||||||
<SelectModal
|
|
||||||
open={languageModalOpen}
|
|
||||||
onOpenChange={setLanguageModalOpen}
|
|
||||||
label={t`Language`}
|
|
||||||
icon={IconLanguage}
|
|
||||||
selection={i18n.locale}
|
|
||||||
options={LOCALE_INFO.map((info) => ({
|
|
||||||
value: info.code,
|
|
||||||
label: info.nativeName,
|
|
||||||
}))}
|
|
||||||
onSelect={(locale) => {
|
|
||||||
setLanguageModalOpen(false);
|
|
||||||
const previousLocale = i18n.locale;
|
|
||||||
activateLocale(locale as SupportedLocale).then(
|
|
||||||
() => {
|
|
||||||
setPersistedLocale(locale as SupportedLocale);
|
|
||||||
if (isLocaleRTL(locale) !== isLocaleRTL(previousLocale)) {
|
|
||||||
Alert.alert(
|
|
||||||
t`Restart Required`,
|
|
||||||
t`Sofa needs to restart to apply the new layout direction.`,
|
|
||||||
[{ text: t`Restart`, onPress: () => reloadAppAsync() }],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {},
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Version */}
|
{/* Version */}
|
||||||
<Animated.View entering={FadeInDown.duration(300).delay(400)} className="mt-6 items-center">
|
<Animated.View entering={FadeInDown.duration(300).delay(400)} className="mt-6 items-center">
|
||||||
<Text className="text-muted-foreground text-xs">
|
<Text className="text-muted-foreground text-xs">
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import { Uniwind, useResolveClassNames } from "uniwind";
|
|||||||
|
|
||||||
import { OfflineBanner } from "@/components/ui/offline-banner";
|
import { OfflineBanner } from "@/components/ui/offline-banner";
|
||||||
import { ServerUnreachableBanner } from "@/components/ui/server-unreachable-banner";
|
import { ServerUnreachableBanner } from "@/components/ui/server-unreachable-banner";
|
||||||
|
import { useFollowDeviceLocale } from "@/hooks/use-follow-device-locale";
|
||||||
import { useServerConnection } from "@/hooks/use-server-connection";
|
import { useServerConnection } from "@/hooks/use-server-connection";
|
||||||
import { useWidgetRefresh } from "@/hooks/use-widget-refresh";
|
import { useWidgetRefresh } from "@/hooks/use-widget-refresh";
|
||||||
import { initLocale } from "@/lib/i18n";
|
import { initLocale } from "@/lib/i18n";
|
||||||
@@ -68,6 +69,8 @@ function AppContent() {
|
|||||||
localeReady.then(() => setLocaleReady(true)).catch(() => setLocaleReady(true));
|
localeReady.then(() => setLocaleReady(true)).catch(() => setLocaleReady(true));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useFollowDeviceLocale();
|
||||||
|
|
||||||
// --- Analytics init (sync PostHog opt-in/out from stored preference) ---
|
// --- Analytics init (sync PostHog opt-in/out from stored preference) ---
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
initAnalytics();
|
initAnalytics();
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { useLocales } from "expo-localization";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
|
import { applyLocale } from "@/lib/i18n";
|
||||||
|
import { resolveLocale } from "@/lib/resolve-locale";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keep the app language in step with the OS setting. Android delivers per-app and system language
|
||||||
|
* changes without restarting the activity; iOS relaunches the app instead, so there this only
|
||||||
|
* confirms the language chosen at start-up.
|
||||||
|
*/
|
||||||
|
export function useFollowDeviceLocale(): void {
|
||||||
|
const deviceLocales = useLocales();
|
||||||
|
const locale = resolveLocale(deviceLocales.map((l) => l.languageTag));
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
applyLocale(locale).catch(() => {});
|
||||||
|
}, [locale]);
|
||||||
|
}
|
||||||
+21
-28
@@ -2,46 +2,39 @@ import { reloadAppAsync } from "expo";
|
|||||||
import * as Localization from "expo-localization";
|
import * as Localization from "expo-localization";
|
||||||
import { I18nManager } from "react-native";
|
import { I18nManager } from "react-native";
|
||||||
|
|
||||||
import { activateLocale, isLocaleRTL, SUPPORTED_LOCALES, type SupportedLocale } from "@sofa/i18n";
|
import { activateLocale, isLocaleRTL, type SupportedLocale } from "@sofa/i18n";
|
||||||
|
|
||||||
import { globalStorage } from "./mmkv";
|
import { globalStorage } from "./mmkv";
|
||||||
|
import { resolveLocale } from "./resolve-locale";
|
||||||
|
|
||||||
const LOCALE_STORAGE_KEY = "sofa:locale";
|
// Written by app versions that had an in-app language picker. The OS language setting is now the
|
||||||
|
// only source of truth; the key is deleted on launch.
|
||||||
|
const LEGACY_LOCALE_STORAGE_KEY = "sofa:locale";
|
||||||
|
|
||||||
export function getPersistedLocale(): SupportedLocale {
|
let appliedLocale: SupportedLocale | null = null;
|
||||||
const stored = globalStorage.getString(LOCALE_STORAGE_KEY);
|
|
||||||
if (stored && SUPPORTED_LOCALES.includes(stored as SupportedLocale)) {
|
export function getDeviceLocale(): SupportedLocale {
|
||||||
return stored as SupportedLocale;
|
return resolveLocale(Localization.getLocales().map((l) => l.languageTag));
|
||||||
}
|
|
||||||
const deviceLocales = Localization.getLocales();
|
|
||||||
for (const loc of deviceLocales) {
|
|
||||||
const lang = loc.languageCode;
|
|
||||||
if (lang && SUPPORTED_LOCALES.includes(lang as SupportedLocale)) {
|
|
||||||
return lang as SupportedLocale;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "en";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setPersistedLocale(locale: SupportedLocale): void {
|
/**
|
||||||
globalStorage.set(LOCALE_STORAGE_KEY, locale);
|
* Activate `locale`'s catalog. When its layout direction differs from the running one, store the
|
||||||
|
* new direction and reload: React Native only reads it at start-up. The flag is persisted
|
||||||
|
* natively, so this also clears a direction forced by the old in-app picker.
|
||||||
|
*/
|
||||||
|
export function applyLocale(locale: SupportedLocale): Promise<void> {
|
||||||
|
if (locale === appliedLocale) return Promise.resolve();
|
||||||
|
appliedLocale = locale;
|
||||||
const rtl = isLocaleRTL(locale);
|
const rtl = isLocaleRTL(locale);
|
||||||
I18nManager.allowRTL(rtl);
|
I18nManager.allowRTL(rtl);
|
||||||
I18nManager.forceRTL(rtl);
|
I18nManager.forceRTL(rtl);
|
||||||
}
|
|
||||||
|
|
||||||
export function initLocale(): Promise<void> {
|
|
||||||
const locale = getPersistedLocale();
|
|
||||||
const rtl = isLocaleRTL(locale);
|
|
||||||
I18nManager.allowRTL(rtl);
|
|
||||||
I18nManager.forceRTL(rtl);
|
|
||||||
// forceRTL only takes effect on the next launch — if the current layout
|
|
||||||
// doesn't match (e.g. fresh install on an RTL device), reload immediately.
|
|
||||||
if (I18nManager.isRTL !== rtl) {
|
if (I18nManager.isRTL !== rtl) {
|
||||||
reloadAppAsync();
|
reloadAppAsync();
|
||||||
}
|
}
|
||||||
if (locale !== "en") {
|
|
||||||
return activateLocale(locale);
|
return activateLocale(locale);
|
||||||
}
|
}
|
||||||
return Promise.resolve();
|
|
||||||
|
export function initLocale(): Promise<void> {
|
||||||
|
globalStorage.remove(LEGACY_LOCALE_STORAGE_KEY);
|
||||||
|
return applyLocale(getDeviceLocale());
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import { readFileSync } from "node:fs";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
|
||||||
|
import { describe, expect, test } from "vitest";
|
||||||
|
|
||||||
|
import { resolveLocale } from "@/lib/resolve-locale";
|
||||||
|
import { SUPPORTED_LOCALES } from "@sofa/i18n/locales";
|
||||||
|
|
||||||
|
describe("resolveLocale", () => {
|
||||||
|
test("matches a supported language with a region", () => {
|
||||||
|
expect(resolveLocale(["de-DE"])).toBe("de");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("skips an unsupported first language", () => {
|
||||||
|
expect(resolveLocale(["fa-IR", "fr-FR"])).toBe("fr");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("maps the legacy Android Hebrew code", () => {
|
||||||
|
expect(resolveLocale(["iw-IL"])).toBe("he");
|
||||||
|
expect(resolveLocale(["he-IL"])).toBe("he");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("matches on the primary subtag regardless of script, region or case", () => {
|
||||||
|
expect(resolveLocale(["zh-Hant-TW"])).toBe("zh");
|
||||||
|
expect(resolveLocale(["pt-BR"])).toBe("pt");
|
||||||
|
expect(resolveLocale(["EN_us"])).toBe("en");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("falls back to English", () => {
|
||||||
|
expect(resolveLocale([null, "ko-KR"])).toBe("ko");
|
||||||
|
expect(resolveLocale(["fa-IR"])).toBe("en");
|
||||||
|
expect(resolveLocale([])).toBe("en");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("app.json", () => {
|
||||||
|
test("app.json declares every supported locale to the OS (add new locales to the expo-localization plugin)", () => {
|
||||||
|
const appJson = JSON.parse(
|
||||||
|
readFileSync(fileURLToPath(new URL("../../app.json", import.meta.url)), "utf8"),
|
||||||
|
) as { expo: { plugins: unknown[] } };
|
||||||
|
const entry = appJson.expo.plugins.find(
|
||||||
|
(plugin): plugin is [string, { supportedLocales: string[] }] =>
|
||||||
|
Array.isArray(plugin) && plugin[0] === "expo-localization",
|
||||||
|
);
|
||||||
|
expect(entry).toBeDefined();
|
||||||
|
expect([...(entry?.[1].supportedLocales ?? [])].sort()).toEqual([...SUPPORTED_LOCALES].sort());
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { SUPPORTED_LOCALES, type SupportedLocale } from "@sofa/i18n/locales";
|
||||||
|
|
||||||
|
const SUBTAG_SEPARATOR = /[-_]/;
|
||||||
|
|
||||||
|
// Android's java.util.Locale can still report Hebrew as the legacy "iw".
|
||||||
|
const LEGACY_LANGUAGE_CODES: Record<string, string> = { iw: "he" };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The first of the user's preferred languages (BCP-47 tags, in preference order) that Sofa has a
|
||||||
|
* catalog for, else English. Matches on the primary language subtag: "pt-BR" → "pt",
|
||||||
|
* "zh-Hant-TW" → "zh".
|
||||||
|
*/
|
||||||
|
export function resolveLocale(
|
||||||
|
languageTags: readonly (string | null | undefined)[],
|
||||||
|
): SupportedLocale {
|
||||||
|
for (const tag of languageTags) {
|
||||||
|
if (!tag) continue;
|
||||||
|
const primary = (tag.split(SUBTAG_SEPARATOR)[0] ?? "").toLowerCase();
|
||||||
|
const code = LEGACY_LANGUAGE_CODES[primary] ?? primary;
|
||||||
|
if ((SUPPORTED_LOCALES as readonly string[]).includes(code)) {
|
||||||
|
return code as SupportedLocale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "en";
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@ Sofa supports multiple languages for the web and mobile apps. The current suppor
|
|||||||
- Portuguese
|
- Portuguese
|
||||||
- Spanish
|
- Spanish
|
||||||
|
|
||||||
You can switch languages in **Settings > Language** on web or the mobile app. Sofa detects your browser or device language on first launch and defaults to it if supported. This setting is **not** saved to the server — it is only persisted to the current browser or device.
|
On the web, switch languages in **Settings > Language**. Sofa detects your browser language on first visit, and the choice is saved in that browser only. The mobile app follows your device's language. To use a different language for Sofa only, change it in your phone's settings (iOS: **Settings > Apps > Sofa > Language**; Android 13+: **App info > Language**). Language preferences are never saved to the server.
|
||||||
|
|
||||||
## How translations work
|
## How translations work
|
||||||
|
|
||||||
@@ -70,6 +70,7 @@ The script only translates strings with empty `msgstr` — existing translations
|
|||||||
2. Run `bun run i18n:extract` — this creates a new `.po` file for the locale
|
2. Run `bun run i18n:extract` — this creates a new `.po` file for the locale
|
||||||
3. Translate the strings (via Crowdin, manually, or with `bun packages/i18n/scripts/claude.ts <locale>`)
|
3. Translate the strings (via Crowdin, manually, or with `bun packages/i18n/scripts/claude.ts <locale>`)
|
||||||
4. Add the locale to the `LOCALE_INFO` array in [`packages/i18n/src/locales.ts`](https://github.com/jakejarvis/sofa/blob/main/packages/i18n/src/locales.ts) with its native name
|
4. Add the locale to the `LOCALE_INFO` array in [`packages/i18n/src/locales.ts`](https://github.com/jakejarvis/sofa/blob/main/packages/i18n/src/locales.ts) with its native name
|
||||||
|
5. Add the locale to `supportedLocales` in the `expo-localization` plugin in [`apps/native/app.json`](https://github.com/jakejarvis/sofa/blob/main/apps/native/app.json) so iOS and Android offer it (a native test fails until you do)
|
||||||
|
|
||||||
## Translation guidelines
|
## Translation guidelines
|
||||||
|
|
||||||
|
|||||||
@@ -2711,12 +2711,12 @@ msgid "Requires Emby Server 4.7.9+ and an active Emby Premiere license."
|
|||||||
msgstr "يتطلب Emby Server 4.7.9+ وترخيصاً نشطاً لـ Emby Premiere."
|
msgstr "يتطلب Emby Server 4.7.9+ وترخيصاً نشطاً لـ Emby Premiere."
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Restart"
|
#~ msgid "Restart"
|
||||||
msgstr "إعادة التشغيل"
|
#~ msgstr "إعادة التشغيل"
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Restart Required"
|
#~ msgid "Restart Required"
|
||||||
msgstr "إعادة التشغيل مطلوبة"
|
#~ msgstr "إعادة التشغيل مطلوبة"
|
||||||
|
|
||||||
#: apps/web/src/components/settings/backup-restore-section.tsx
|
#: apps/web/src/components/settings/backup-restore-section.tsx
|
||||||
msgid "Restore"
|
msgid "Restore"
|
||||||
@@ -3042,8 +3042,8 @@ msgid "Skipped"
|
|||||||
msgstr "تم التخطي"
|
msgstr "تم التخطي"
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Sofa needs to restart to apply the new layout direction."
|
#~ msgid "Sofa needs to restart to apply the new layout direction."
|
||||||
msgstr "يحتاج Sofa إلى إعادة التشغيل لتطبيق اتجاه التخطيط الجديد."
|
#~ msgstr "يحتاج Sofa إلى إعادة التشغيل لتطبيق اتجاه التخطيط الجديد."
|
||||||
|
|
||||||
#: apps/web/src/routes/setup.tsx
|
#: apps/web/src/routes/setup.tsx
|
||||||
msgid "Sofa uses <0>The Movie Database{linkIcon}</0> for movie & TV metadata, posters, and streaming availability. You'll need a free API key to get started."
|
msgid "Sofa uses <0>The Movie Database{linkIcon}</0> for movie & TV metadata, posters, and streaming availability. You'll need a free API key to get started."
|
||||||
|
|||||||
@@ -2711,12 +2711,12 @@ msgid "Requires Emby Server 4.7.9+ and an active Emby Premiere license."
|
|||||||
msgstr "Erfordert Emby Server 4.7.9+ und eine aktive Emby Premiere-Lizenz."
|
msgstr "Erfordert Emby Server 4.7.9+ und eine aktive Emby Premiere-Lizenz."
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Restart"
|
#~ msgid "Restart"
|
||||||
msgstr "Neu starten"
|
#~ msgstr "Neu starten"
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Restart Required"
|
#~ msgid "Restart Required"
|
||||||
msgstr "Neustart erforderlich"
|
#~ msgstr "Neustart erforderlich"
|
||||||
|
|
||||||
#: apps/web/src/components/settings/backup-restore-section.tsx
|
#: apps/web/src/components/settings/backup-restore-section.tsx
|
||||||
msgid "Restore"
|
msgid "Restore"
|
||||||
@@ -3042,8 +3042,8 @@ msgid "Skipped"
|
|||||||
msgstr "Übersprungen"
|
msgstr "Übersprungen"
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Sofa needs to restart to apply the new layout direction."
|
#~ msgid "Sofa needs to restart to apply the new layout direction."
|
||||||
msgstr "Sofa muss neu gestartet werden, um die neue Layoutrichtung anzuwenden."
|
#~ msgstr "Sofa muss neu gestartet werden, um die neue Layoutrichtung anzuwenden."
|
||||||
|
|
||||||
#: apps/web/src/routes/setup.tsx
|
#: apps/web/src/routes/setup.tsx
|
||||||
msgid "Sofa uses <0>The Movie Database{linkIcon}</0> for movie & TV metadata, posters, and streaming availability. You'll need a free API key to get started."
|
msgid "Sofa uses <0>The Movie Database{linkIcon}</0> for movie & TV metadata, posters, and streaming availability. You'll need a free API key to get started."
|
||||||
|
|||||||
@@ -2711,12 +2711,12 @@ msgid "Requires Emby Server 4.7.9+ and an active Emby Premiere license."
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Restart"
|
#~ msgid "Restart"
|
||||||
msgstr "Restart"
|
#~ msgstr "Restart"
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Restart Required"
|
#~ msgid "Restart Required"
|
||||||
msgstr "Restart Required"
|
#~ msgstr "Restart Required"
|
||||||
|
|
||||||
#: apps/web/src/components/settings/backup-restore-section.tsx
|
#: apps/web/src/components/settings/backup-restore-section.tsx
|
||||||
msgid "Restore"
|
msgid "Restore"
|
||||||
@@ -3042,8 +3042,8 @@ msgid "Skipped"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Sofa needs to restart to apply the new layout direction."
|
#~ msgid "Sofa needs to restart to apply the new layout direction."
|
||||||
msgstr "Sofa needs to restart to apply the new layout direction."
|
#~ msgstr "Sofa needs to restart to apply the new layout direction."
|
||||||
|
|
||||||
#: apps/web/src/routes/setup.tsx
|
#: apps/web/src/routes/setup.tsx
|
||||||
msgid "Sofa uses <0>The Movie Database{linkIcon}</0> for movie & TV metadata, posters, and streaming availability. You'll need a free API key to get started."
|
msgid "Sofa uses <0>The Movie Database{linkIcon}</0> for movie & TV metadata, posters, and streaming availability. You'll need a free API key to get started."
|
||||||
|
|||||||
@@ -2711,12 +2711,12 @@ msgid "Requires Emby Server 4.7.9+ and an active Emby Premiere license."
|
|||||||
msgstr "Requiere Emby Server 4.7.9+ y una licencia activa de Emby Premiere."
|
msgstr "Requiere Emby Server 4.7.9+ y una licencia activa de Emby Premiere."
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Restart"
|
#~ msgid "Restart"
|
||||||
msgstr "Reiniciar"
|
#~ msgstr "Reiniciar"
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Restart Required"
|
#~ msgid "Restart Required"
|
||||||
msgstr "Reinicio requerido"
|
#~ msgstr "Reinicio requerido"
|
||||||
|
|
||||||
#: apps/web/src/components/settings/backup-restore-section.tsx
|
#: apps/web/src/components/settings/backup-restore-section.tsx
|
||||||
msgid "Restore"
|
msgid "Restore"
|
||||||
@@ -3042,8 +3042,8 @@ msgid "Skipped"
|
|||||||
msgstr "Omitido"
|
msgstr "Omitido"
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Sofa needs to restart to apply the new layout direction."
|
#~ msgid "Sofa needs to restart to apply the new layout direction."
|
||||||
msgstr "Sofa necesita reiniciarse para aplicar la nueva dirección del diseño."
|
#~ msgstr "Sofa necesita reiniciarse para aplicar la nueva dirección del diseño."
|
||||||
|
|
||||||
#: apps/web/src/routes/setup.tsx
|
#: apps/web/src/routes/setup.tsx
|
||||||
msgid "Sofa uses <0>The Movie Database{linkIcon}</0> for movie & TV metadata, posters, and streaming availability. You'll need a free API key to get started."
|
msgid "Sofa uses <0>The Movie Database{linkIcon}</0> for movie & TV metadata, posters, and streaming availability. You'll need a free API key to get started."
|
||||||
|
|||||||
@@ -2711,12 +2711,12 @@ msgid "Requires Emby Server 4.7.9+ and an active Emby Premiere license."
|
|||||||
msgstr "Nécessite Emby Server 4.7.9+ et une licence Emby Premiere active."
|
msgstr "Nécessite Emby Server 4.7.9+ et une licence Emby Premiere active."
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Restart"
|
#~ msgid "Restart"
|
||||||
msgstr "Redémarrer"
|
#~ msgstr "Redémarrer"
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Restart Required"
|
#~ msgid "Restart Required"
|
||||||
msgstr "Redémarrage requis"
|
#~ msgstr "Redémarrage requis"
|
||||||
|
|
||||||
#: apps/web/src/components/settings/backup-restore-section.tsx
|
#: apps/web/src/components/settings/backup-restore-section.tsx
|
||||||
msgid "Restore"
|
msgid "Restore"
|
||||||
@@ -3042,8 +3042,8 @@ msgid "Skipped"
|
|||||||
msgstr "Ignoré"
|
msgstr "Ignoré"
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Sofa needs to restart to apply the new layout direction."
|
#~ msgid "Sofa needs to restart to apply the new layout direction."
|
||||||
msgstr "Sofa doit redémarrer pour appliquer la nouvelle direction de mise en page."
|
#~ msgstr "Sofa doit redémarrer pour appliquer la nouvelle direction de mise en page."
|
||||||
|
|
||||||
#: apps/web/src/routes/setup.tsx
|
#: apps/web/src/routes/setup.tsx
|
||||||
msgid "Sofa uses <0>The Movie Database{linkIcon}</0> for movie & TV metadata, posters, and streaming availability. You'll need a free API key to get started."
|
msgid "Sofa uses <0>The Movie Database{linkIcon}</0> for movie & TV metadata, posters, and streaming availability. You'll need a free API key to get started."
|
||||||
|
|||||||
@@ -2711,12 +2711,12 @@ msgid "Requires Emby Server 4.7.9+ and an active Emby Premiere license."
|
|||||||
msgstr "דורש Emby Server 4.7.9+ ורישיון Emby Premiere פעיל."
|
msgstr "דורש Emby Server 4.7.9+ ורישיון Emby Premiere פעיל."
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Restart"
|
#~ msgid "Restart"
|
||||||
msgstr "הפעל מחדש"
|
#~ msgstr "הפעל מחדש"
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Restart Required"
|
#~ msgid "Restart Required"
|
||||||
msgstr "נדרשת הפעלה מחדש"
|
#~ msgstr "נדרשת הפעלה מחדש"
|
||||||
|
|
||||||
#: apps/web/src/components/settings/backup-restore-section.tsx
|
#: apps/web/src/components/settings/backup-restore-section.tsx
|
||||||
msgid "Restore"
|
msgid "Restore"
|
||||||
@@ -3042,8 +3042,8 @@ msgid "Skipped"
|
|||||||
msgstr "דולג"
|
msgstr "דולג"
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Sofa needs to restart to apply the new layout direction."
|
#~ msgid "Sofa needs to restart to apply the new layout direction."
|
||||||
msgstr "יש להפעיל מחדש את Sofa כדי להחיל את כיוון הפריסה החדש."
|
#~ msgstr "יש להפעיל מחדש את Sofa כדי להחיל את כיוון הפריסה החדש."
|
||||||
|
|
||||||
#: apps/web/src/routes/setup.tsx
|
#: apps/web/src/routes/setup.tsx
|
||||||
msgid "Sofa uses <0>The Movie Database{linkIcon}</0> for movie & TV metadata, posters, and streaming availability. You'll need a free API key to get started."
|
msgid "Sofa uses <0>The Movie Database{linkIcon}</0> for movie & TV metadata, posters, and streaming availability. You'll need a free API key to get started."
|
||||||
|
|||||||
@@ -2711,12 +2711,12 @@ msgid "Requires Emby Server 4.7.9+ and an active Emby Premiere license."
|
|||||||
msgstr "Richiede Emby Server 4.7.9+ e una licenza Emby Premiere attiva."
|
msgstr "Richiede Emby Server 4.7.9+ e una licenza Emby Premiere attiva."
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Restart"
|
#~ msgid "Restart"
|
||||||
msgstr "Riavvia"
|
#~ msgstr "Riavvia"
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Restart Required"
|
#~ msgid "Restart Required"
|
||||||
msgstr "Riavvio necessario"
|
#~ msgstr "Riavvio necessario"
|
||||||
|
|
||||||
#: apps/web/src/components/settings/backup-restore-section.tsx
|
#: apps/web/src/components/settings/backup-restore-section.tsx
|
||||||
msgid "Restore"
|
msgid "Restore"
|
||||||
@@ -3042,8 +3042,8 @@ msgid "Skipped"
|
|||||||
msgstr "Ignorati"
|
msgstr "Ignorati"
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Sofa needs to restart to apply the new layout direction."
|
#~ msgid "Sofa needs to restart to apply the new layout direction."
|
||||||
msgstr "Sofa deve essere riavviato per applicare la nuova direzione del layout."
|
#~ msgstr "Sofa deve essere riavviato per applicare la nuova direzione del layout."
|
||||||
|
|
||||||
#: apps/web/src/routes/setup.tsx
|
#: apps/web/src/routes/setup.tsx
|
||||||
msgid "Sofa uses <0>The Movie Database{linkIcon}</0> for movie & TV metadata, posters, and streaming availability. You'll need a free API key to get started."
|
msgid "Sofa uses <0>The Movie Database{linkIcon}</0> for movie & TV metadata, posters, and streaming availability. You'll need a free API key to get started."
|
||||||
|
|||||||
@@ -2711,12 +2711,12 @@ msgid "Requires Emby Server 4.7.9+ and an active Emby Premiere license."
|
|||||||
msgstr "Emby Server 4.7.9+と有効なEmby Premiereライセンスが必要です。"
|
msgstr "Emby Server 4.7.9+と有効なEmby Premiereライセンスが必要です。"
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Restart"
|
#~ msgid "Restart"
|
||||||
msgstr "再起動"
|
#~ msgstr "再起動"
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Restart Required"
|
#~ msgid "Restart Required"
|
||||||
msgstr "再起動が必要です"
|
#~ msgstr "再起動が必要です"
|
||||||
|
|
||||||
#: apps/web/src/components/settings/backup-restore-section.tsx
|
#: apps/web/src/components/settings/backup-restore-section.tsx
|
||||||
msgid "Restore"
|
msgid "Restore"
|
||||||
@@ -3042,8 +3042,8 @@ msgid "Skipped"
|
|||||||
msgstr "スキップ済み"
|
msgstr "スキップ済み"
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Sofa needs to restart to apply the new layout direction."
|
#~ msgid "Sofa needs to restart to apply the new layout direction."
|
||||||
msgstr "Sofaは新しいレイアウト方向を適用するために再起動が必要です。"
|
#~ msgstr "Sofaは新しいレイアウト方向を適用するために再起動が必要です。"
|
||||||
|
|
||||||
#: apps/web/src/routes/setup.tsx
|
#: apps/web/src/routes/setup.tsx
|
||||||
msgid "Sofa uses <0>The Movie Database{linkIcon}</0> for movie & TV metadata, posters, and streaming availability. You'll need a free API key to get started."
|
msgid "Sofa uses <0>The Movie Database{linkIcon}</0> for movie & TV metadata, posters, and streaming availability. You'll need a free API key to get started."
|
||||||
|
|||||||
@@ -2711,12 +2711,12 @@ msgid "Requires Emby Server 4.7.9+ and an active Emby Premiere license."
|
|||||||
msgstr "Emby Server 4.7.9+ 및 활성 Emby Premiere 라이선스가 필요합니다."
|
msgstr "Emby Server 4.7.9+ 및 활성 Emby Premiere 라이선스가 필요합니다."
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Restart"
|
#~ msgid "Restart"
|
||||||
msgstr "재시작"
|
#~ msgstr "재시작"
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Restart Required"
|
#~ msgid "Restart Required"
|
||||||
msgstr "재시작 필요"
|
#~ msgstr "재시작 필요"
|
||||||
|
|
||||||
#: apps/web/src/components/settings/backup-restore-section.tsx
|
#: apps/web/src/components/settings/backup-restore-section.tsx
|
||||||
msgid "Restore"
|
msgid "Restore"
|
||||||
@@ -3042,8 +3042,8 @@ msgid "Skipped"
|
|||||||
msgstr "건너뜀"
|
msgstr "건너뜀"
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Sofa needs to restart to apply the new layout direction."
|
#~ msgid "Sofa needs to restart to apply the new layout direction."
|
||||||
msgstr "Sofa를 재시작해야 새 레이아웃 방향이 적용됩니다."
|
#~ msgstr "Sofa를 재시작해야 새 레이아웃 방향이 적용됩니다."
|
||||||
|
|
||||||
#: apps/web/src/routes/setup.tsx
|
#: apps/web/src/routes/setup.tsx
|
||||||
msgid "Sofa uses <0>The Movie Database{linkIcon}</0> for movie & TV metadata, posters, and streaming availability. You'll need a free API key to get started."
|
msgid "Sofa uses <0>The Movie Database{linkIcon}</0> for movie & TV metadata, posters, and streaming availability. You'll need a free API key to get started."
|
||||||
|
|||||||
@@ -2711,12 +2711,12 @@ msgid "Requires Emby Server 4.7.9+ and an active Emby Premiere license."
|
|||||||
msgstr "Vereist Emby Server 4.7.9+ en een actieve Emby Premiere-licentie."
|
msgstr "Vereist Emby Server 4.7.9+ en een actieve Emby Premiere-licentie."
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Restart"
|
#~ msgid "Restart"
|
||||||
msgstr "Herstarten"
|
#~ msgstr "Herstarten"
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Restart Required"
|
#~ msgid "Restart Required"
|
||||||
msgstr "Herstart vereist"
|
#~ msgstr "Herstart vereist"
|
||||||
|
|
||||||
#: apps/web/src/components/settings/backup-restore-section.tsx
|
#: apps/web/src/components/settings/backup-restore-section.tsx
|
||||||
msgid "Restore"
|
msgid "Restore"
|
||||||
@@ -3042,8 +3042,8 @@ msgid "Skipped"
|
|||||||
msgstr "Overgeslagen"
|
msgstr "Overgeslagen"
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Sofa needs to restart to apply the new layout direction."
|
#~ msgid "Sofa needs to restart to apply the new layout direction."
|
||||||
msgstr "Sofa moet herstarten om de nieuwe lay-outrichting toe te passen."
|
#~ msgstr "Sofa moet herstarten om de nieuwe lay-outrichting toe te passen."
|
||||||
|
|
||||||
#: apps/web/src/routes/setup.tsx
|
#: apps/web/src/routes/setup.tsx
|
||||||
msgid "Sofa uses <0>The Movie Database{linkIcon}</0> for movie & TV metadata, posters, and streaming availability. You'll need a free API key to get started."
|
msgid "Sofa uses <0>The Movie Database{linkIcon}</0> for movie & TV metadata, posters, and streaming availability. You'll need a free API key to get started."
|
||||||
|
|||||||
@@ -2711,12 +2711,12 @@ msgid "Requires Emby Server 4.7.9+ and an active Emby Premiere license."
|
|||||||
msgstr "Requer Emby Server 4.7.9+ e uma licença ativa do Emby Premiere."
|
msgstr "Requer Emby Server 4.7.9+ e uma licença ativa do Emby Premiere."
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Restart"
|
#~ msgid "Restart"
|
||||||
msgstr "Reiniciar"
|
#~ msgstr "Reiniciar"
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Restart Required"
|
#~ msgid "Restart Required"
|
||||||
msgstr "Reinício Necessário"
|
#~ msgstr "Reinício Necessário"
|
||||||
|
|
||||||
#: apps/web/src/components/settings/backup-restore-section.tsx
|
#: apps/web/src/components/settings/backup-restore-section.tsx
|
||||||
msgid "Restore"
|
msgid "Restore"
|
||||||
@@ -3042,8 +3042,8 @@ msgid "Skipped"
|
|||||||
msgstr "Ignorado"
|
msgstr "Ignorado"
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Sofa needs to restart to apply the new layout direction."
|
#~ msgid "Sofa needs to restart to apply the new layout direction."
|
||||||
msgstr "O Sofa precisa de reiniciar para aplicar a nova direção do layout."
|
#~ msgstr "O Sofa precisa de reiniciar para aplicar a nova direção do layout."
|
||||||
|
|
||||||
#: apps/web/src/routes/setup.tsx
|
#: apps/web/src/routes/setup.tsx
|
||||||
msgid "Sofa uses <0>The Movie Database{linkIcon}</0> for movie & TV metadata, posters, and streaming availability. You'll need a free API key to get started."
|
msgid "Sofa uses <0>The Movie Database{linkIcon}</0> for movie & TV metadata, posters, and streaming availability. You'll need a free API key to get started."
|
||||||
|
|||||||
@@ -2711,12 +2711,12 @@ msgid "Requires Emby Server 4.7.9+ and an active Emby Premiere license."
|
|||||||
msgstr "需要 Emby Server 4.7.9+ 以及有效的 Emby Premiere 授权。"
|
msgstr "需要 Emby Server 4.7.9+ 以及有效的 Emby Premiere 授权。"
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Restart"
|
#~ msgid "Restart"
|
||||||
msgstr "重启"
|
#~ msgstr "重启"
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Restart Required"
|
#~ msgid "Restart Required"
|
||||||
msgstr "需要重启"
|
#~ msgstr "需要重启"
|
||||||
|
|
||||||
#: apps/web/src/components/settings/backup-restore-section.tsx
|
#: apps/web/src/components/settings/backup-restore-section.tsx
|
||||||
msgid "Restore"
|
msgid "Restore"
|
||||||
@@ -3042,8 +3042,8 @@ msgid "Skipped"
|
|||||||
msgstr "已跳过"
|
msgstr "已跳过"
|
||||||
|
|
||||||
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
#: apps/native/src/app/(tabs)/(settings)/index.tsx
|
||||||
msgid "Sofa needs to restart to apply the new layout direction."
|
#~ msgid "Sofa needs to restart to apply the new layout direction."
|
||||||
msgstr "Sofa 需要重启以应用新的布局方向。"
|
#~ msgstr "Sofa 需要重启以应用新的布局方向。"
|
||||||
|
|
||||||
#: apps/web/src/routes/setup.tsx
|
#: apps/web/src/routes/setup.tsx
|
||||||
msgid "Sofa uses <0>The Movie Database{linkIcon}</0> for movie & TV metadata, posters, and streaming availability. You'll need a free API key to get started."
|
msgid "Sofa uses <0>The Movie Database{linkIcon}</0> for movie & TV metadata, posters, and streaming availability. You'll need a free API key to get started."
|
||||||
|
|||||||
Reference in new issue
Block a user