diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index e19f9db6fc..dc7d22fc57 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -504,6 +504,11 @@ jobs:
         with:
           channel: 'stable'
           flutter-version-file: ./mobile/pubspec.yaml
+
+      - name: Generate translation file
+        run: make translation
+        working-directory: ./mobile
+
       - name: Run tests
         working-directory: ./mobile
         run: flutter test -j 1
diff --git a/docs/src/pages/roadmap.tsx b/docs/src/pages/roadmap.tsx
index 50f7a47902..1258000052 100644
--- a/docs/src/pages/roadmap.tsx
+++ b/docs/src/pages/roadmap.tsx
@@ -218,7 +218,7 @@ const roadmap: Item[] = [
     iconColor: 'indianred',
     title: 'Stable release',
     description: 'Immich goes stable',
-    getDateLabel: () => 'Planned for early 2025',
+    getDateLabel: () => 'Planned for 2025',
   },
   {
     done: false,
diff --git a/mobile/lib/services/localization.service.dart b/mobile/lib/services/localization.service.dart
index c8ef662896..8bee710544 100644
--- a/mobile/lib/services/localization.service.dart
+++ b/mobile/lib/services/localization.service.dart
@@ -1,10 +1,10 @@
 // ignore_for_file: implementation_imports
 
-import 'package:flutter/foundation.dart';
-import 'package:easy_localization/src/asset_loader.dart';
 import 'package:easy_localization/src/easy_localization_controller.dart';
 import 'package:easy_localization/src/localization.dart';
+import 'package:flutter/foundation.dart';
 import 'package:immich_mobile/constants/locales.dart';
+import 'package:immich_mobile/generated/codegen_loader.g.dart';
 
 /// Workaround to manually load translations in another Isolate
 Future<bool> loadTranslations() async {
@@ -14,7 +14,7 @@ Future<bool> loadTranslations() async {
     supportedLocales: locales.values.toList(),
     useFallbackTranslations: true,
     saveLocale: true,
-    assetLoader: const RootBundleAssetLoader(),
+    assetLoader: const CodegenLoader(),
     path: translationsPath,
     useOnlyLangCode: false,
     onLoadError: (e) => debugPrint(e.toString()),
diff --git a/web/src/lib/components/assets/thumbnail/video-thumbnail.svelte b/web/src/lib/components/assets/thumbnail/video-thumbnail.svelte
index d59a03158a..2c03ca48f8 100644
--- a/web/src/lib/components/assets/thumbnail/video-thumbnail.svelte
+++ b/web/src/lib/components/assets/thumbnail/video-thumbnail.svelte
@@ -55,7 +55,7 @@
   };
 </script>
 
-<div class="absolute end-0 top-0 flex place-items-center gap-1 text-xs font-medium text-white">
+<div class="absolute end-0 top-0 z-1 flex place-items-center gap-1 text-xs font-medium text-white">
   {#if showTime}
     <span class="pt-2">
       {#if remainingSeconds < 60}
diff --git a/web/src/lib/components/photos-page/asset-grid.svelte b/web/src/lib/components/photos-page/asset-grid.svelte
index 7b45019ec3..2a2f5ceec4 100644
--- a/web/src/lib/components/photos-page/asset-grid.svelte
+++ b/web/src/lib/components/photos-page/asset-grid.svelte
@@ -564,12 +564,9 @@
         return;
       }
 
-      // Select/deselect assets in range (start,end]
+      // Select/deselect assets in range (start,end)
       let started = false;
       for (const bucket of assetStore.buckets) {
-        if (bucket === startBucket) {
-          started = true;
-        }
         if (bucket === endBucket) {
           break;
         }
@@ -583,27 +580,31 @@
             }
           }
         }
+        if (bucket === startBucket) {
+          started = true;
+        }
       }
 
-      // Update date group selection
+      // Update date group selection in range [start,end]
       started = false;
       for (const bucket of assetStore.buckets) {
         if (bucket === startBucket) {
           started = true;
         }
+        if (started) {
+          // Split bucket into date groups and check each group
+          for (const dateGroup of bucket.dateGroups) {
+            const dateGroupTitle = dateGroup.groupTitle;
+            if (dateGroup.getAssets().every((a) => assetInteraction.hasSelectedAsset(a.id))) {
+              assetInteraction.addGroupToMultiselectGroup(dateGroupTitle);
+            } else {
+              assetInteraction.removeGroupFromMultiselectGroup(dateGroupTitle);
+            }
+          }
+        }
         if (bucket === endBucket) {
           break;
         }
-
-        // Split bucket into date groups and check each group
-        for (const dateGroup of bucket.dateGroups) {
-          const dateGroupTitle = dateGroup.groupTitle;
-          if (dateGroup.getAssets().every((a) => assetInteraction.hasSelectedAsset(a.id))) {
-            assetInteraction.addGroupToMultiselectGroup(dateGroupTitle);
-          } else {
-            assetInteraction.removeGroupFromMultiselectGroup(dateGroupTitle);
-          }
-        }
       }
     }
 
diff --git a/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/+page.svelte
index 1e1dfc254d..8995483c84 100644
--- a/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/+page.svelte
+++ b/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/+page.svelte
@@ -452,7 +452,7 @@
             {/if}
           </section>
           {#if isEditingName}
-            <div class="absolute w-64 sm:w-96">
+            <div class="absolute w-64 sm:w-96 z-1">
               {#if isSearchingPeople}
                 <div
                   class="flex border h-14 rounded-b-lg border-gray-400 dark:border-immich-dark-gray place-items-center bg-gray-200 p-2 dark:bg-gray-700"