diff --git a/src/lib/libpthread.js b/src/lib/libpthread.js
index 6d979627e..97e3f8684 100644
--- a/src/lib/libpthread.js
+++ b/src/lib/libpthread.js
@@ -697,7 +697,7 @@ var LibraryPThread = {
     {
       transferredCanvasNames = UTF8ToString(transferredCanvasNames).trim();
     }
-    transferredCanvasNames = transferredCanvasNames ? transferredCanvasNames.split(',') : [];
+    transferredCanvasNames = transferredCanvasNames && !Module['disableOffscreenCanvases'] ? transferredCanvasNames.split(',') : [];
 #if GL_DEBUG
     dbg(`pthread_create: transferredCanvasNames="${transferredCanvasNames}"`);
 #endif
diff --git a/src/lib/libwasmfs_fetch.js b/src/lib/libwasmfs_fetch.js
index e8c9f7e21..caf1971d2 100644
--- a/src/lib/libwasmfs_fetch.js
+++ b/src/lib/libwasmfs_fetch.js
@@ -38,36 +38,7 @@ addToLibrary({
       var chunkSize = __wasmfs_fetch_get_chunk_size(file);
       offset ??= 0;
       len ??= chunkSize;
-      // In which chunk does the seeked range start?  E.g., 5-14 with chunksize 8 will start in chunk 0.
-      if (!(file in wasmFS$JSMemoryRanges)) {
-        var fileInfo = await fetch(url, {method:'HEAD', headers:{'Range': 'bytes=0-'}});
-        if (fileInfo.ok &&
-            fileInfo.headers.has('Content-Length') &&
-            fileInfo.headers.get('Accept-Ranges') == 'bytes' &&
-            (parseInt(fileInfo.headers.get('Content-Length'), 10) > chunkSize*2)) {
-          var size = parseInt(fileInfo.headers.get('Content-Length'), 10);
-          wasmFS$JSMemoryRanges[file] = {
-            size,
-            chunks: [],
-            chunkSize: chunkSize
-          };
-          len = Math.min(len, size-offset);
-        } else {
-          // may as well/forced to download the whole file
-          var wholeFileReq = await fetch(url);
-          if (!wholeFileReq.ok) {
-            throw wholeFileReq;
-          }
-          var wholeFileData = new Uint8Array(await wholeFileReq.arrayBuffer());
-          var text = new TextDecoder().decode(wholeFileData);
-          wasmFS$JSMemoryRanges[file] = {
-            size: wholeFileData.byteLength,
-            chunks: [wholeFileData],
-            chunkSize: wholeFileData.byteLength
-          };
-          return Promise.resolve();
-        }
-      }
+
       var firstChunk = (offset / chunkSize) | 0;
       // In which chunk does the seeked range end?  E.g., 5-14 with chunksize 8 will end in chunk 1, as will 5-16 (since byte 16 isn't requested).
       // This will always give us a chunk >= firstChunk since len > 0.
@@ -76,7 +47,7 @@ addToLibrary({
       var i;
       // Do we have all the chunks already?  If so, we don't need to do any fetches.
       for (i = firstChunk; i <= lastChunk; i++) {
-        if (!wasmFS$JSMemoryRanges[file].chunks[i]) {
+        if (!(file in wasmFS$JSMemoryRanges) || !wasmFS$JSMemoryRanges[file].chunks[i]) {
           allPresent = false;
           break;
         }
@@ -90,16 +61,37 @@ addToLibrary({
       // one request for all the chunks we need, rather than one
       // request per chunk.
       var start = firstChunk * chunkSize;
+
+      // Out of bounds. No request necessary.
+      if ((file in wasmFS$JSMemoryRanges) && start >= wasmFS$JSMemoryRanges[file].size) {
+        return Promise.resolve();
+      }
+
       // We must fetch *up to* the last byte of the last chunk.
       var end = (lastChunk+1) * chunkSize;
-      var response = await fetch(url, {headers:{'Range': `bytes=${start}-${end-1}`}});
+      var response = await fetch(url, {headers:{'Range': `bytes=${start}-${end-1}`, 'Accept-Language': wasmFS$language}});
       if (!response.ok) {
         throw response;
       }
-      var bytes = await response['bytes']();
+
+      const buffer = await response.arrayBuffer();
+      const bytes = new Uint8Array(buffer);
+      if (!(file in wasmFS$JSMemoryRanges)) {
+        var size = Math.max(
+          parseInt(response.headers.get('Content-Range').split('/')[1], 10),
+          bytes.length
+        );
+        wasmFS$JSMemoryRanges[file] = {
+          size,
+          chunks: [],
+          chunkSize: chunkSize
+        };
+      }
+
       for (i = firstChunk; i <= lastChunk; i++) {
         wasmFS$JSMemoryRanges[file].chunks[i] = bytes.slice(i*chunkSize-start,(i+1)*chunkSize-start);
       }
+
       return Promise.resolve();
     }
 
@@ -156,14 +148,31 @@ addToLibrary({
         return readLength;
       },
       getSize: async (file) => {
-        try {
-          await getFileRange(file, 0, 0);
-        } catch (failedResponse) {
-          return 0;
+        if (!(file in wasmFS$JSMemoryRanges)) {
+          try {
+            await getFileRange(file, undefined, undefined);
+          } catch (failedResponse) {
+            return 0;
+          }
         }
         return wasmFS$JSMemoryRanges[file].size;
       },
     };
+ 
+    wasmFS$language = await (async () => {
+      try {
+        const fileHandle = await (await navigator.storage.getDirectory()).getFileHandle('isle.ini');
+        const content = await (await fileHandle.getFile()).text();
+        const match = content.match(/^Language\s*=\s*(.*)/m);
+    
+        if (match && match[1]) {
+          return match[1].trim();
+        }
+      } catch (e) {
+        console.warn("Could not read 'isle.ini' or 'Language' key not found. Falling back to 'en'.", e);
+      }
+  
+      return 'en';
+    })();
   },
-
 });
diff --git a/src/preamble.js b/src/preamble.js
index 572694517..0d2f4421b 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -1062,3 +1062,13 @@ function getCompilerSetting(name) {
 // dynamic linker as symbols are loaded.
 var asyncifyStubs = {};
 #endif
+
+(async () => {
+  try {
+    await navigator.storage.getDirectory();
+    Module["disableOpfs"] = false;
+  } catch (e) {
+    Module["disableOpfs"] = true;
+  }
+})();
+
