chore: prepare local web and Android release 3.3.1-local.2

This commit is contained in:
Codex
2026-10-12 21:01:23 +03:00
parent 60327b2665
commit 4fdcfb7ed9
9 changed files with 51 additions and 6 deletions
+3 -1
View File
@@ -1,7 +1,9 @@
import 'dart:ui'; import 'dart:ui';
const defaultAppLocale = Locale('ru');
const Map<String, Locale> locales = { const Map<String, Locale> locales = {
// Default locale // Fallback locale for missing translations
'English (en)': Locale('en'), 'English (en)': Locale('en'),
// Additional locales // Additional locales
'Arabic (ar)': Locale('ar'), 'Arabic (ar)': Locale('ar'),
+1
View File
@@ -309,6 +309,7 @@ class MainWidget extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return EasyLocalization( return EasyLocalization(
supportedLocales: locales.values.toList(), supportedLocales: locales.values.toList(),
startLocale: defaultAppLocale,
path: translationsPath, path: translationsPath,
useFallbackTranslations: true, useFallbackTranslations: true,
fallbackLocale: locales.values.first, fallbackLocale: locales.values.first,
@@ -41,6 +41,7 @@ class BootstrapErrorWidget extends StatelessWidget {
return EasyLocalization( return EasyLocalization(
supportedLocales: locales.values.toList(), supportedLocales: locales.values.toList(),
startLocale: defaultAppLocale,
path: translationsPath, path: translationsPath,
useFallbackTranslations: true, useFallbackTranslations: true,
fallbackLocale: locales.values.first, fallbackLocale: locales.values.first,
@@ -12,6 +12,7 @@ Future<bool> loadTranslations() async {
final controller = EasyLocalizationController( final controller = EasyLocalizationController(
supportedLocales: locales.values.toList(), supportedLocales: locales.values.toList(),
startLocale: defaultAppLocale,
useFallbackTranslations: true, useFallbackTranslations: true,
saveLocale: true, saveLocale: true,
assetLoader: const CodegenLoader(), assetLoader: const CodegenLoader(),
+2
View File
@@ -2,6 +2,8 @@ import 'package:immich_mobile/domain/models/store.model.dart';
import 'package:immich_mobile/entities/store.entity.dart'; import 'package:immich_mobile/entities/store.entity.dart';
import 'package:punycode/punycode.dart'; import 'package:punycode/punycode.dart';
const defaultServerUrl = 'https://immich.kusoft.xyz';
/// Normalizes a server URL, guaranteeing that it has a schema and no trailing slashes /// Normalizes a server URL, guaranteeing that it has a schema and no trailing slashes
String normalizeServerUrl(String url) { String normalizeServerUrl(String url) {
final trimmedUrl = url.trim(); final trimmedUrl = url.trim();
@@ -164,9 +164,7 @@ class LoginForm extends HookConsumerWidget {
useEffect(() { useEffect(() {
final serverUrl = getServerUrl(); final serverUrl = getServerUrl();
if (serverUrl != null) { serverEndpointController.text = serverUrl ?? defaultServerUrl;
serverEndpointController.text = serverUrl;
}
return null; return null;
}, []); }, []);
+1 -1
View File
@@ -2,7 +2,7 @@ name: immich_mobile
description: Immich - selfhosted backup media file on mobile phone description: Immich - selfhosted backup media file on mobile phone
publish_to: 'none' publish_to: 'none'
version: 3.3.1+3030199 version: 3.3.1-local.2+3030200
environment: environment:
sdk: '>=3.12.0 <4.0.0' sdk: '>=3.12.0 <4.0.0'
+13
View File
@@ -1,6 +1,19 @@
<!doctype html> <!doctype html>
<html class="dark"> <html class="dark">
<head> <head>
<script id="immich-ru-default">
try {
if (!localStorage.getItem('lang')) {
localStorage.setItem('lang', 'ru');
}
if (!localStorage.getItem('locale')) {
localStorage.setItem('locale', 'ru-RU');
}
document.documentElement.lang = localStorage.getItem('lang') || 'ru';
} catch {
// noop
}
</script>
<!-- (used for SSR) --> <!-- (used for SSR) -->
<!-- metadata:tags --> <!-- metadata:tags -->
+28 -1
View File
@@ -1,4 +1,4 @@
import { render, screen } from '@testing-library/svelte'; import { fireEvent, render, screen } from '@testing-library/svelte';
import { vi } from 'vitest'; import { vi } from 'vitest';
import SideBarSection from '$lib/components/sidebar/Sidebar.svelte'; import SideBarSection from '$lib/components/sidebar/Sidebar.svelte';
import { sidebarStore } from '$lib/stores/sidebar.svelte'; import { sidebarStore } from '$lib/stores/sidebar.svelte';
@@ -77,4 +77,31 @@ describe('Sidebar component', () => {
// then // then
expect(sidebarStore.reset).toHaveBeenCalled(); expect(sidebarStore.reset).toHaveBeenCalled();
}); });
it.each`
isFullSidebar | isSidebarOpen | shouldBubble
${false} | ${false} | ${true}
${false} | ${true} | ${false}
${true} | ${false} | ${true}
${true} | ${true} | ${true}
`(
'Escape bubbles=$shouldBubble when isFullSidebar=$isFullSidebar and isSidebarOpen=$isSidebarOpen',
async ({ isFullSidebar, isSidebarOpen, shouldBubble }) => {
mocks.mediaQueryManager.isFullSidebar = isFullSidebar;
sidebarStore.isOpen = isSidebarOpen;
render(SideBarSection);
vi.mocked(sidebarStore.reset).mockClear();
const onDocumentKeydown = vi.fn();
document.addEventListener('keydown', onDocumentKeydown);
try {
await fireEvent.keyDown(screen.getByTestId('sidebar-parent'), { key: 'Escape', code: 'Escape' });
expect(onDocumentKeydown).toHaveBeenCalledTimes(shouldBubble ? 1 : 0);
expect(sidebarStore.reset).toHaveBeenCalledTimes(shouldBubble ? 0 : 1);
} finally {
document.removeEventListener('keydown', onDocumentKeydown);
}
},
);
}); });