Live video on the AT Protocol

it works on mobile (again) now

+40 -13
+3 -2
js/components/package.json
··· 43 43 "i18next-fluent": "^2.0.0", 44 44 "i18next-http-backend": "^3.0.2", 45 45 "i18next-resources-to-backend": "^1.2.1", 46 + "intl-pluralrules": "^2.0.1", 46 47 "lucide-react-native": "^0.514.0", 47 48 "react-i18next": "^15.7.3", 48 49 "react-native": "^0.79.0", ··· 58 59 "zustand": "^5.0.5" 59 60 }, 60 61 "peerDependencies": { 61 - "react": "*", 62 - "expo-localization": "*" 62 + "expo-localization": "*", 63 + "react": "*" 63 64 }, 64 65 "peerDependenciesMeta": { 65 66 "expo-localization": {
+26 -9
js/components/src/i18n/i18next-config.ts
··· 7 7 import "intl-pluralrules"; 8 8 import { initReactI18next } from "react-i18next"; 9 9 10 - // Import our manifest and loader 11 - import { manifest } from "./index"; 10 + // Import our manifest directly to avoid circular dependency 11 + import manifest from "../../locales/manifest.json"; 12 12 13 13 // Try to import expo-localization, but make it optional 14 14 let Localization: typeof import("expo-localization") | null = null; 15 15 try { 16 - Localization = require("expo-localization"); 16 + const localizationModule = require("expo-localization"); 17 + // Handle both default and named exports 18 + Localization = localizationModule.default 19 + ? localizationModule.default 20 + : localizationModule; 17 21 } catch { 18 22 // expo-localization not available, will use browser/fallback detection 19 23 } ··· 21 25 // Mock storage for now - replace with actual zustand storage 22 26 const storage = { 23 27 getItem: (key: string): string | null => { 24 - if (typeof window !== "undefined") { 25 - return localStorage.getItem(key); 28 + try { 29 + if (typeof window !== "undefined" && localStorage) { 30 + return localStorage.getItem(key); 31 + } 32 + } catch { 33 + // localStorage not available (e.g. in some test environments) 26 34 } 27 35 return null; 28 36 }, 29 37 setItem: (key: string, value: string): void => { 30 - if (typeof window !== "undefined") { 31 - localStorage.setItem(key, value); 38 + try { 39 + if (typeof window !== "undefined" && localStorage) { 40 + localStorage.setItem(key, value); 41 + } 42 + } catch { 43 + // localStorage not available (e.g. in some test environments) 32 44 } 33 45 }, 34 46 }; ··· 41 53 let systemLocale = "en"; 42 54 43 55 // Try to get locale from expo-localization if available 44 - if (Localization) { 45 - systemLocale = Localization.getLocales()[0]?.languageTag || "en"; 56 + if (Localization && typeof Localization.getLocales === "function") { 57 + try { 58 + const locales = Localization.getLocales(); 59 + systemLocale = locales?.[0]?.languageTag || "en"; 60 + } catch (error) { 61 + console.warn("Failed to get locales from expo-localization:", error); 62 + } 46 63 } else if (typeof navigator !== "undefined" && navigator.language) { 47 64 // Fallback to browser navigator.language 48 65 systemLocale = navigator.language;
+8 -2
js/components/tsconfig.json
··· 8 8 "noEmit": false, 9 9 "declaration": true, 10 10 "declarationMap": true, 11 - "sourceMap": true 11 + "sourceMap": true, 12 + "resolveJsonModule": true 12 13 }, 13 - "include": ["./src"] 14 + "include": ["./src"], 15 + "ts-node": { 16 + "compilerOptions": { 17 + "resolveJsonModule": true 18 + } 19 + } 14 20 }
+3
pnpm-lock.yaml
··· 488 488 i18next-resources-to-backend: 489 489 specifier: ^1.2.1 490 490 version: 1.2.1 491 + intl-pluralrules: 492 + specifier: ^2.0.1 493 + version: 2.0.1 491 494 lucide-react-native: 492 495 specifier: ^0.514.0 493 496 version: 0.514.0(react-native-svg@15.12.0(react-native@0.79.3(@babel/core@7.26.0)(bufferutil@4.0.8)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0))(react-native@0.79.3(@babel/core@7.26.0)(bufferutil@4.0.8)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0)