@quran-lab/tajweedformer 2.0.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/dist/tajweedformer-opus.mjs +1 -1
- package/dist/tajweedformer-opus.wasm +0 -0
- package/docs/api.md +2 -2
- package/package.json +1 -1
- package/web/consent/copy.js +17 -9
- package/web/consent/decks.js +144 -56
- package/web/consent/element.js +21 -15
- package/web/consent/index.d.ts +76 -13
- package/web/consent/index.js +103 -18
- package/web/consent/state.js +91 -29
- package/web/consent/theme.js +31 -0
- package/web/consent/wording.js +126 -0
- package/web/index.d.ts +1 -1
- package/web/platform/client.js +484 -366
- package/web/platform/index.d.ts +39 -5
- package/web/platform/index.js +3 -2
- package/web/platform/telemetry.js +128 -13
- package/web/platform/update-notice.js +60 -0
- package/web/sharing/bitrate.js +69 -0
- package/web/sharing/encoder.js +26 -5
- package/web/sharing/index.d.ts +53 -6
- package/web/sharing/index.js +287 -257
- package/web/sharing/oggopus.js +325 -294
- package/web/sharing/outbox.js +670 -606
- package/web/sharing/uploader.js +10 -3
- package/web/tajweed/index.d.ts +2 -2
- package/web/tajweed/manifest.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.0.1
|
|
4
|
+
|
|
5
|
+
- Recitation sharing is offered where Quran Lab decides, per app, in the signed config; the `contributions`
|
|
6
|
+
option is ignored, and without a signed config nothing is offered. Nothing is recorded or sent before the
|
|
7
|
+
learner answers "Share".
|
|
8
|
+
- Fixed: web sessions were never uploaded in 2.0.0 (the consent controller passed the wrong device, token and
|
|
9
|
+
decode fields to the uploader).
|
|
10
|
+
- Asking: the sheet is shown at most three times per install, ever (the count carries over from 2.0.0);
|
|
11
|
+
"Not now" may lead to a later ask within those three, a yes ends asking forever, and so does turning
|
|
12
|
+
sharing off after a yes (the app's settings can still turn it on). A yes persists across copy decks, app
|
|
13
|
+
wording and the upgrade from 2.0.0 (no sheet, no pause), and each session carries the version the learner
|
|
14
|
+
agreed to. Stopping and deleting work whatever the learner agreed to.
|
|
15
|
+
- The consent sheet, default or yours: `theme` (or CSS custom properties) for the SDK's sheets; your own UI
|
|
16
|
+
with `ask: fn`, the SDK's localized strings and `sharing.answer(yes)`; your own wording with `setWording`,
|
|
17
|
+
recorded as consent version `custom-<24 hex>` with its SHA-256 sent with each session for Quran Lab to review.
|
|
18
|
+
- Copy deck 2026-11-09.1 (consent `share-2026-11-09`) in eight languages: no longer says the recited ayah is
|
|
19
|
+
sent (it is not), and deletion from Quran Lab's servers is immediate.
|
|
20
|
+
- Adaptive Opus bitrate on bad networks: 192, 96, 64 or 32 kbit/s, lowered when uploads fail or back up and
|
|
21
|
+
raised again when they succeed, changed between segments of the same Ogg stream; each segment's bitrate is
|
|
22
|
+
in the outbox items (`segmentBitrates`).
|
|
23
|
+
- Telemetry: deltas during the day (every 15 minutes while the page is visible and when it is hidden), each
|
|
24
|
+
with a random `report_id`; new aggregate counters (launches, ayahs, ayahs per surah, words, tajweed rule
|
|
25
|
+
checks and flags, sharing sheet outcomes). Register once per UTC day per install.
|
|
26
|
+
- Outside production (the new `debug` option, or `NODE_ENV` not `production`), one warning per load when
|
|
27
|
+
Quran Lab's signed config names a newer SDK: "Quran Lab SDK X is available (severity), you have Y: URL".
|
|
28
|
+
- `docs/platform-client.md`: what the SDK sends to Quran Lab, when, and what an app can change.
|
|
29
|
+
|
|
3
30
|
## 2.0.0 (first public release)
|
|
4
31
|
|
|
5
32
|
- TajweedFormer V4: `TajweedFormer.load` opens a signed `sdk/v4.0` folder (by URL, files or a
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
async function createTajweedFormerOpus(moduleArg={}){var Module=moduleArg;var ENVIRONMENT_IS_WEB=!!globalThis.window;var ENVIRONMENT_IS_WORKER=!!globalThis.WorkerGlobalScope;var ENVIRONMENT_IS_NODE=globalThis.process?.versions?.node&&globalThis.process?.type!="renderer";if(ENVIRONMENT_IS_NODE){const{createRequire}=await import("node:module");var require=createRequire(import.meta.url)}var programArgs=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var _scriptName=import.meta.url;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var readAsync,readBinary;if(ENVIRONMENT_IS_NODE){var fs=require("node:fs");if(_scriptName.startsWith("file:")){scriptDirectory=require("node:path").dirname(require("node:url").fileURLToPath(_scriptName))+"/"}readBinary=filename=>{filename=isFileURI(filename)?new URL(filename):filename;var ret=fs.readFileSync(filename);return ret};readAsync=async(filename,binary=true)=>{filename=isFileURI(filename)?new URL(filename):filename;var ret=fs.readFileSync(filename,binary?undefined:"utf8");return ret};if(process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}programArgs=process.argv.slice(2);quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){try{scriptDirectory=new URL(".",_scriptName).href}catch{}{if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=async url=>{var response=await fetch(url,{credentials:"same-origin"});if(response.ok){return response.arrayBuffer()}throw new Error(response.status+" : "+response.url)}}}else{}var out=console.log.bind(console);var err=console.error.bind(console);var wasmBinary;var ABORT=false;var isFileURI=filename=>filename.startsWith("file://");class EmscriptenEH{}class EmscriptenSjLj extends EmscriptenEH{}var runtimeInitialized=false;function getMemoryBuffer(){return wasmMemory.buffer}function updateMemoryViews(){if(HEAP8?.buffer?.resizable)return;var b=getMemoryBuffer();HEAP8=new Int8Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b)}function preRun(){var preRun=Module["preRun"];if(preRun){if(typeof preRun=="function")preRun=[preRun];onPreRuns.push(...preRun)}callRuntimeCallbacks(onPreRuns)}function initRuntime(){runtimeInitialized=true;wasmExports["c"]()}function postRun(){var postRun=Module["postRun"];if(postRun){if(typeof postRun=="function")postRun=[postRun];onPostRuns.push(...postRun)}callRuntimeCallbacks(onPostRuns)}function abort(what){Module["onAbort"]?.(what);what=`Aborted(${what})`;err(what);ABORT=true;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);throw e}var wasmBinaryFile;function findWasmBinary(){if(Module["locateFile"]){return locateFile("tajweedformer-opus.wasm")}return new URL("tajweedformer-opus.wasm",import.meta.url).href}function getBinarySync(file){if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}async function getWasmBinary(binaryFile){if(!wasmBinary){try{var response=await readAsync(binaryFile);return new Uint8Array(response)}catch{}}return getBinarySync(binaryFile)}async function instantiateArrayBuffer(binaryFile,imports){try{var binary=await getWasmBinary(binaryFile);var instance=await WebAssembly.instantiate(binary,imports);return instance}catch(reason){err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)}}async function instantiateAsync(binary,binaryFile,imports){if(!binary&&!ENVIRONMENT_IS_NODE){try{var response=fetch(binaryFile,{credentials:"same-origin"});var instantiationResult=await WebAssembly.instantiateStreaming(response,imports);return instantiationResult}catch(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation")}}return instantiateArrayBuffer(binaryFile,imports)}function getWasmImports(){var imports={a:wasmImports};return imports}async function createWasm(){function receiveInstance(instance){wasmExports=instance.exports;assignWasmExports(wasmExports);updateMemoryViews();return wasmExports}function receiveInstantiationResult(result){return receiveInstance(result["instance"])}var info=getWasmImports();var instantiateWasm=Module["instantiateWasm"];if(instantiateWasm){return new Promise(resolve=>{instantiateWasm(info,inst=>resolve(receiveInstance(inst)))})}wasmBinaryFile??=findWasmBinary();var result=await instantiateAsync(wasmBinary,wasmBinaryFile,info);var exports=receiveInstantiationResult(result);return exports}class ExitStatus{name="ExitStatus";constructor(status){this.message=`Program terminated with exit(${status})`;this.status=status}}var HEAP8;var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};var onPostRuns=[];var onPreRuns=[];var noExitRuntime=true;var getHeapMax=()=>2147483648;var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;var growMemory=size=>{var oldHeapSize=wasmMemory.buffer.byteLength;var pages=(size-oldHeapSize+65535)/65536|0;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var HEAPU8;var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignMemory(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};var HEAPF32;var HEAP32;var UTF8Decoder=globalThis.TextDecoder&&new TextDecoder;var findStringEnd=(heapOrArray,idx,maxBytesToRead,ignoreNul)=>{var maxIdx=idx+maxBytesToRead;if(ignoreNul)return maxIdx;while(heapOrArray[idx]&&!(idx>=maxIdx))++idx;return idx};var UTF8ArrayToString=(heapOrArray,idx=0,maxBytesToRead,ignoreNul)=>{var endPtr=findStringEnd(heapOrArray,idx,maxBytesToRead,ignoreNul);if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx<endPtr){var u0=heapOrArray[idx++];if(!(u0&128)){str+=String.fromCharCode(u0);continue}var u1=heapOrArray[idx++]&63;if((u0&224)==192){str+=String.fromCharCode((u0&31)<<6|u1);continue}var u2=heapOrArray[idx++]&63;if((u0&240)==224){u0=(u0&15)<<12|u1<<6|u2}else{u0=(u0&7)<<18|u1<<12|u2<<6|heapOrArray[idx++]&63}if(u0<65536){str+=String.fromCharCode(u0)}else{var ch=u0-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}}return str};var UTF8ToString=(ptr,maxBytesToRead,ignoreNul)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead,ignoreNul):"";{if(Module["noExitRuntime"])noExitRuntime=Module["noExitRuntime"];if(Module["print"])out=Module["print"];if(Module["printErr"])err=Module["printErr"];if(Module["arguments"])programArgs=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];var preInit=Module["preInit"];if(preInit){if(typeof preInit=="function")Module["preInit"]=preInit=[preInit];while(preInit.length>0){preInit.shift()()}}}Module["UTF8ToString"]=UTF8ToString;var _malloc,_free,_ow_enc_create,_ow_enc_get,_ow_enc_encode,_ow_enc_destroy,_ow_dec_create,_ow_dec_decode,_ow_dec_destroy,_ow_version,memory,__indirect_function_table,wasmMemory;function assignWasmExports(wasmExports){_malloc=Module["_malloc"]=wasmExports["d"];_free=Module["_free"]=wasmExports["e"];_ow_enc_create=Module["_ow_enc_create"]=wasmExports["f"];_ow_enc_get=Module["_ow_enc_get"]=wasmExports["g"];_ow_enc_encode=Module["_ow_enc_encode"]=wasmExports["
|
|
1
|
+
async function createTajweedFormerOpus(moduleArg={}){var Module=moduleArg;var ENVIRONMENT_IS_WEB=!!globalThis.window;var ENVIRONMENT_IS_WORKER=!!globalThis.WorkerGlobalScope;var ENVIRONMENT_IS_NODE=globalThis.process?.versions?.node&&globalThis.process?.type!="renderer";if(ENVIRONMENT_IS_NODE){const{createRequire}=await import("node:module");var require=createRequire(import.meta.url)}var programArgs=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var _scriptName=import.meta.url;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var readAsync,readBinary;if(ENVIRONMENT_IS_NODE){var fs=require("node:fs");if(_scriptName.startsWith("file:")){scriptDirectory=require("node:path").dirname(require("node:url").fileURLToPath(_scriptName))+"/"}readBinary=filename=>{filename=isFileURI(filename)?new URL(filename):filename;var ret=fs.readFileSync(filename);return ret};readAsync=async(filename,binary=true)=>{filename=isFileURI(filename)?new URL(filename):filename;var ret=fs.readFileSync(filename,binary?undefined:"utf8");return ret};if(process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}programArgs=process.argv.slice(2);quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){try{scriptDirectory=new URL(".",_scriptName).href}catch{}{if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=async url=>{var response=await fetch(url,{credentials:"same-origin"});if(response.ok){return response.arrayBuffer()}throw new Error(response.status+" : "+response.url)}}}else{}var out=console.log.bind(console);var err=console.error.bind(console);var wasmBinary;var ABORT=false;var isFileURI=filename=>filename.startsWith("file://");class EmscriptenEH{}class EmscriptenSjLj extends EmscriptenEH{}var runtimeInitialized=false;function getMemoryBuffer(){return wasmMemory.buffer}function updateMemoryViews(){if(HEAP8?.buffer?.resizable)return;var b=getMemoryBuffer();HEAP8=new Int8Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b)}function preRun(){var preRun=Module["preRun"];if(preRun){if(typeof preRun=="function")preRun=[preRun];onPreRuns.push(...preRun)}callRuntimeCallbacks(onPreRuns)}function initRuntime(){runtimeInitialized=true;wasmExports["c"]()}function postRun(){var postRun=Module["postRun"];if(postRun){if(typeof postRun=="function")postRun=[postRun];onPostRuns.push(...postRun)}callRuntimeCallbacks(onPostRuns)}function abort(what){Module["onAbort"]?.(what);what=`Aborted(${what})`;err(what);ABORT=true;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);throw e}var wasmBinaryFile;function findWasmBinary(){if(Module["locateFile"]){return locateFile("tajweedformer-opus.wasm")}return new URL("tajweedformer-opus.wasm",import.meta.url).href}function getBinarySync(file){if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}async function getWasmBinary(binaryFile){if(!wasmBinary){try{var response=await readAsync(binaryFile);return new Uint8Array(response)}catch{}}return getBinarySync(binaryFile)}async function instantiateArrayBuffer(binaryFile,imports){try{var binary=await getWasmBinary(binaryFile);var instance=await WebAssembly.instantiate(binary,imports);return instance}catch(reason){err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)}}async function instantiateAsync(binary,binaryFile,imports){if(!binary&&!ENVIRONMENT_IS_NODE){try{var response=fetch(binaryFile,{credentials:"same-origin"});var instantiationResult=await WebAssembly.instantiateStreaming(response,imports);return instantiationResult}catch(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation")}}return instantiateArrayBuffer(binaryFile,imports)}function getWasmImports(){var imports={a:wasmImports};return imports}async function createWasm(){function receiveInstance(instance){wasmExports=instance.exports;assignWasmExports(wasmExports);updateMemoryViews();return wasmExports}function receiveInstantiationResult(result){return receiveInstance(result["instance"])}var info=getWasmImports();var instantiateWasm=Module["instantiateWasm"];if(instantiateWasm){return new Promise(resolve=>{instantiateWasm(info,inst=>resolve(receiveInstance(inst)))})}wasmBinaryFile??=findWasmBinary();var result=await instantiateAsync(wasmBinary,wasmBinaryFile,info);var exports=receiveInstantiationResult(result);return exports}class ExitStatus{name="ExitStatus";constructor(status){this.message=`Program terminated with exit(${status})`;this.status=status}}var HEAP8;var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};var onPostRuns=[];var onPreRuns=[];var noExitRuntime=true;var getHeapMax=()=>2147483648;var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;var growMemory=size=>{var oldHeapSize=wasmMemory.buffer.byteLength;var pages=(size-oldHeapSize+65535)/65536|0;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var HEAPU8;var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignMemory(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};var HEAPF32;var HEAP32;var UTF8Decoder=globalThis.TextDecoder&&new TextDecoder;var findStringEnd=(heapOrArray,idx,maxBytesToRead,ignoreNul)=>{var maxIdx=idx+maxBytesToRead;if(ignoreNul)return maxIdx;while(heapOrArray[idx]&&!(idx>=maxIdx))++idx;return idx};var UTF8ArrayToString=(heapOrArray,idx=0,maxBytesToRead,ignoreNul)=>{var endPtr=findStringEnd(heapOrArray,idx,maxBytesToRead,ignoreNul);if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx<endPtr){var u0=heapOrArray[idx++];if(!(u0&128)){str+=String.fromCharCode(u0);continue}var u1=heapOrArray[idx++]&63;if((u0&224)==192){str+=String.fromCharCode((u0&31)<<6|u1);continue}var u2=heapOrArray[idx++]&63;if((u0&240)==224){u0=(u0&15)<<12|u1<<6|u2}else{u0=(u0&7)<<18|u1<<12|u2<<6|heapOrArray[idx++]&63}if(u0<65536){str+=String.fromCharCode(u0)}else{var ch=u0-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}}return str};var UTF8ToString=(ptr,maxBytesToRead,ignoreNul)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead,ignoreNul):"";{if(Module["noExitRuntime"])noExitRuntime=Module["noExitRuntime"];if(Module["print"])out=Module["print"];if(Module["printErr"])err=Module["printErr"];if(Module["arguments"])programArgs=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];var preInit=Module["preInit"];if(preInit){if(typeof preInit=="function")Module["preInit"]=preInit=[preInit];while(preInit.length>0){preInit.shift()()}}}Module["UTF8ToString"]=UTF8ToString;var _malloc,_free,_ow_enc_create,_ow_enc_get,_ow_enc_set,_ow_enc_encode,_ow_enc_destroy,_ow_dec_create,_ow_dec_decode,_ow_dec_destroy,_ow_version,memory,__indirect_function_table,wasmMemory;function assignWasmExports(wasmExports){_malloc=Module["_malloc"]=wasmExports["d"];_free=Module["_free"]=wasmExports["e"];_ow_enc_create=Module["_ow_enc_create"]=wasmExports["f"];_ow_enc_get=Module["_ow_enc_get"]=wasmExports["g"];_ow_enc_set=Module["_ow_enc_set"]=wasmExports["h"];_ow_enc_encode=Module["_ow_enc_encode"]=wasmExports["i"];_ow_enc_destroy=Module["_ow_enc_destroy"]=wasmExports["j"];_ow_dec_create=Module["_ow_dec_create"]=wasmExports["k"];_ow_dec_decode=Module["_ow_dec_decode"]=wasmExports["l"];_ow_dec_destroy=Module["_ow_dec_destroy"]=wasmExports["m"];_ow_version=Module["_ow_version"]=wasmExports["n"];memory=wasmMemory=wasmExports["b"];__indirect_function_table=wasmExports["__indirect_function_table"]}var wasmImports={a:_emscripten_resize_heap};async function run(){preRun();var setStatus=Module["setStatus"];if(setStatus){setStatus("Running...");await new Promise(resolve=>setTimeout(resolve,1));setTimeout(setStatus,1,"")}if(ABORT)return;initRuntime();Module["onRuntimeInitialized"]?.();postRun()}var wasmExports;wasmExports=await createWasm();await run();
|
|
2
2
|
;return Module}export default createTajweedFormerOpus;
|
|
Binary file
|
package/docs/api.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @quran-lab/tajweedformer 2.0.
|
|
1
|
+
# @quran-lab/tajweedformer 2.0.1: API
|
|
2
2
|
|
|
3
3
|
Every type is in [`web/tajweed/index.d.ts`](../web/tajweed/index.d.ts),
|
|
4
4
|
[`web/platform/index.d.ts`](../web/platform/index.d.ts) and
|
|
@@ -38,7 +38,7 @@ tf.free();
|
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
A folder is refused when its manifest is not format 2 with `engine_format` 2, when its
|
|
41
|
-
`min_sdk_version` is above 2.0.
|
|
41
|
+
`min_sdk_version` is above 2.0.1, when a signature does not verify (folders from the Quran Lab CDN must
|
|
42
42
|
be signed), or when a file it needs does not match its size and SHA-256. A file the manifest does not
|
|
43
43
|
list is never read.
|
|
44
44
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quran-lab/tajweedformer",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "TajweedFormer V4 for browsers and Node: the exact engine in WebAssembly (bit-identical to the native engine), cached and verified model delivery, every head of the network, the decoded layer (top-1 and runner-up, confidence, timings), per-site and per-word tajweed verdicts with calibrated settings, and the Quran Lab platform client (signed config, telemetry, opt-in recitation sharing).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "web/index.js",
|
package/web/consent/copy.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
// The sharing copy:
|
|
2
|
-
//
|
|
3
|
-
//
|
|
1
|
+
// The sharing copy: Quran Lab's copy decks (quranlab.sharing-copy/1), bundled in decks.js for en, ar, id, ur,
|
|
2
|
+
// tr, ms, fr, bn. Apps choose the language and the timing; an app that replaces strings with its own wording
|
|
3
|
+
// (wording.js) makes the learner agree to that wording instead. The hadith line is in every deck with its
|
|
4
|
+
// verified source.
|
|
4
5
|
|
|
5
6
|
import { DECKS } from './decks.js';
|
|
6
7
|
|
|
@@ -19,25 +20,32 @@ export const EN = DECKS.en;
|
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* The deck for a BCP 47 tag ("ar-EG" -> "ar"; English for a language not shipped), with helpers:
|
|
22
|
-
* t(key) a string (
|
|
23
|
+
* t(key) a string (the app's override, else the deck's, else English), minutes(n) the plural impact line.
|
|
24
|
+
* `overrides` is an app's validated wording ({key: text}, plural lines as `impact.minutes.<category>`).
|
|
25
|
+
* Decks up to 2026-11-07 had a `{days}` placeholder (filled from delete_days); later decks delete at once
|
|
26
|
+
* and have none.
|
|
23
27
|
*/
|
|
24
|
-
export function copyFor(lang = 'en') {
|
|
28
|
+
export function copyFor(lang = 'en', overrides = null) {
|
|
25
29
|
const tag = String(lang || 'en');
|
|
26
30
|
const base = tag.toLowerCase().split(/[-_]/)[0];
|
|
27
31
|
const d = extra.get(tag) || extra.get(base) || DECKS[base] || DECKS.en;
|
|
32
|
+
const own = overrides || {};
|
|
33
|
+
const fill = (v) => (typeof v === 'string' ? v.replace(/\{days\}/g, String(d.delete_days ?? 0)) : v);
|
|
28
34
|
const t = (k) => {
|
|
35
|
+
if (typeof own[k] === 'string') return own[k];
|
|
29
36
|
const v = d.strings[k] !== undefined ? d.strings[k] : DECKS.en.strings[k];
|
|
30
|
-
return
|
|
37
|
+
return fill(v);
|
|
31
38
|
};
|
|
32
39
|
const minutes = (n) => {
|
|
33
40
|
const forms = t('impact.minutes') || {};
|
|
34
41
|
let cat = 'other';
|
|
35
42
|
try { cat = new Intl.PluralRules(d.lang).select(n); } catch (_) { /* other */ }
|
|
36
|
-
const s = forms[cat]
|
|
43
|
+
const s = own[`impact.minutes.${cat}`] ?? forms[cat] ?? own['impact.minutes.other'] ?? forms.other ?? '';
|
|
37
44
|
let num = String(n);
|
|
38
45
|
try { num = new Intl.NumberFormat(d.lang).format(n); } catch (_) { /* plain */ }
|
|
39
46
|
return s.replace(/\{minutes\}/g, num);
|
|
40
47
|
};
|
|
41
|
-
return { lang: d.lang, dir: d.dir || 'ltr', version: d.version, consentVersion: d.consent_version, deleteDays: d.delete_days,
|
|
42
|
-
hadithSource: d.hadith_source || null,
|
|
48
|
+
return { lang: d.lang, dir: d.dir || 'ltr', version: d.version, consentVersion: d.consent_version, deleteDays: d.delete_days ?? 0,
|
|
49
|
+
deleteTiming: d.delete_timing || (d.delete_days ? 'delayed' : 'immediate'), hadithSource: d.hadith_source || null,
|
|
50
|
+
overridden: Object.keys(own), t, minutes };
|
|
43
51
|
}
|
package/web/consent/decks.js
CHANGED
|
@@ -2,18 +2,19 @@
|
|
|
2
2
|
export const DECKS = {
|
|
3
3
|
"ar": {
|
|
4
4
|
"format": "quranlab.sharing-copy/1",
|
|
5
|
-
"version": "2026-11-
|
|
5
|
+
"version": "2026-11-09.1",
|
|
6
6
|
"lang": "ar",
|
|
7
7
|
"dir": "rtl",
|
|
8
|
-
"consent_version": "share-2026-11-
|
|
9
|
-
"delete_days":
|
|
8
|
+
"consent_version": "share-2026-11-09",
|
|
9
|
+
"delete_days": 0,
|
|
10
|
+
"delete_timing": "immediate",
|
|
10
11
|
"strings": {
|
|
11
12
|
"sheet.title": "اجعل تلاوتك خيراً مستمراً",
|
|
12
13
|
"sheet.body": "عندما تشارك تلاواتك، فإنها تساعد في تدريب نموذج التجويد المجاني في هذا التطبيق على الاستماع بشكل أفضل. وكل متعلم يعينه بعدك هو عمل صالح قد يستمر طويلاً بعد فراغك من التلاوة إن شاء الله: صدقة جارية.",
|
|
13
14
|
"sheet.hadith": "قال النبي صلى الله عليه وسلم: «إِذَا مَاتَ الإِنْسَانُ انْقَطَعَ عَنْهُ عَمَلُهُ إِلاَّ مِنْ ثَلاَثَةٍ إِلاَّ مِنْ صَدَقَةٍ جَارِيَةٍ أَوْ عِلْمٍ يُنْتَفَعُ بِهِ أَوْ وَلَدٍ صَالِحٍ يَدْعُو لَهُ»",
|
|
14
15
|
"sheet.hadith_ref": "صحيح مسلم 1631",
|
|
15
16
|
"sheet.mistakes": "أخطاؤك هي الجزء الأثمن، فهي تُعلّم النموذج كيف يصوّب للمتعلم التالي برفق.",
|
|
16
|
-
"sheet.what": "التسجيل الصوتي لجلسات تلاوتك في هذا التطبيق أثناء استماعه،
|
|
17
|
+
"sheet.what": "التسجيل الصوتي لجلسات تلاوتك في هذا التطبيق أثناء استماعه، وتفاصيل تقنية أساسية مثل إصدار النموذج ونوع الجهاز. دون اسم، أو جهات اتصال، أو موقع جغرافي.",
|
|
17
18
|
"sheet.who": "Quran Lab، وهو وقف. النماذج التي يدرّبها مجانية للجميع دائماً، ولا تُباع أبداً.",
|
|
18
19
|
"sheet.control": "يمكنك التوقف في أي وقت وحذف ما شاركته من الإعدادات.",
|
|
19
20
|
"sheet.share": "مشاركة تلاواتي",
|
|
@@ -26,11 +27,21 @@ export const DECKS = {
|
|
|
26
27
|
"settings.toggle": "مشاركة تلاواتي",
|
|
27
28
|
"settings.what": "ما الذي تتم مشاركته",
|
|
28
29
|
"settings.delete": "حذف ما شاركته",
|
|
29
|
-
"what.detail": "عند تفعيل المشاركة، يُرسل التسجيل الصوتي لجلسات تلاوتك في هذا التطبيق إلى Quran Lab، مع
|
|
30
|
-
"delete.confirm": "ستُحذف تلاواتك
|
|
30
|
+
"what.detail": "عند تفعيل المشاركة، يُرسل التسجيل الصوتي لجلسات تلاوتك في هذا التطبيق إلى Quran Lab، مع تفاصيل تقنية عامة (إصدار النموذج، نوع الجهاز، إصدار النظام، واليوم)، ورمز عشوائي خاص بهذا التثبيت. ولا نجمع أبداً اسمك أو حسابك أو جهات اتصالك أو موقعك أو معرّفات جهازك. تُحفظ التسجيلات في الاتحاد الأوروبي وتُستخدم فقط لتحسين نماذج تلاوة القرآن الكريم المجانية. إيقاف المشاركة يوقف الإرسال فوراً، ويمكنك حذف كل ما شاركته من الإعدادات في أي وقت: حيث يُحذف من خوادم Quran Lab في الحال.",
|
|
31
|
+
"delete.confirm": "ستُحذف تلاواتك التي شاركتها من خوادم Quran Lab فوراً. لا يمكن التراجع عن هذا الإجراء.",
|
|
31
32
|
"delete.action": "حذف",
|
|
32
33
|
"delete.cancel": "إلغاء",
|
|
33
|
-
"delete.done": "
|
|
34
|
+
"delete.done": "تم. حُذف ما شاركته من خوادم Quran Lab. أما النسخ التي استُخدمت بالفعل في تدريب النموذج، فلن تُدرج في أي تدريب مستقبلي.",
|
|
35
|
+
"delete.failed.title": "تعذّر الحذف",
|
|
36
|
+
"delete.failed.network": "تعذّر الاتصال بـ Quran Lab، ولم يُحذف أي شيء. يُرجى التحقق من اتصالك بالإنترنت والمحاولة مجدداً.",
|
|
37
|
+
"delete.retry": "إعادة المحاولة",
|
|
38
|
+
"recovery.hint": "احتفظ بهذا الرمز، الذي يُستخدم لمرة واحدة، لحذف ما شاركته في حال فقدت هذا الجهاز: portal.quranlab.ai/delete",
|
|
39
|
+
"recovery.reveal": "إظهار رمز الاسترداد",
|
|
40
|
+
"recovery.copy": "نسخ",
|
|
41
|
+
"recovery.copied": "تم النسخ",
|
|
42
|
+
"recovery.keep": "احتفظ بهذا الرمز في مكان آمن. فهو وسيلتك الوحيدة لحذف ما شاركته من جهاز آخر، ويُستخدم لمرة واحدة فقط.",
|
|
43
|
+
"recovery.used": "تم استخدام رمز الاسترداد هذا من قبل.",
|
|
44
|
+
"recovery.invalid": "هذا الرمز غير صالح. يُرجى التحقق من صحة الكلمات والمحاولة مجدداً.",
|
|
34
45
|
"reask": "قد تساعد تلاوتك اليوم متعلماً آخر غداً. هل ترغب في مشاركتها؟",
|
|
35
46
|
"impact.minutes": {
|
|
36
47
|
"zero": "شاركت {minutes} دقيقة من التلاوة. جزاك الله خيراً.",
|
|
@@ -53,18 +64,19 @@ export const DECKS = {
|
|
|
53
64
|
},
|
|
54
65
|
"bn": {
|
|
55
66
|
"format": "quranlab.sharing-copy/1",
|
|
56
|
-
"version": "2026-11-
|
|
67
|
+
"version": "2026-11-09.1",
|
|
57
68
|
"lang": "bn",
|
|
58
69
|
"dir": "ltr",
|
|
59
|
-
"consent_version": "share-2026-11-
|
|
60
|
-
"delete_days":
|
|
70
|
+
"consent_version": "share-2026-11-09",
|
|
71
|
+
"delete_days": 0,
|
|
72
|
+
"delete_timing": "immediate",
|
|
61
73
|
"strings": {
|
|
62
74
|
"sheet.title": "আপনার তিলাওয়াতের কল্যাণ অব্যাহত থাকুক",
|
|
63
75
|
"sheet.body": "আপনি যখন আপনার তিলাওয়াত শেয়ার করেন, তা এই অ্যাপের ফ্রি তাজবিদ মডেলকে আরও ভালোভাবে শুনতে শেখায়। আপনার পরে এর মাধ্যমে উপকৃত হওয়া প্রতিটি শিক্ষার্থী আপনার জন্য এমন এক নেক আমল হতে পারে, যা তিলাওয়াত শেষ করার পরও অব্যাহত থাকতে পারে, ইনশাআল্লাহ: সাদাকায়ে জারিয়া।",
|
|
64
76
|
"sheet.hadith": "রাসূলুল্লাহ সাল্লাল্লাহু আলাইহি ওয়াসাল্লাম বলেছেন: “যখন মানুষ মৃত্যুবরণ করে তখন তার সমস্ত আমল বন্ধ হয়ে যায় তিন প্রকার আমল ছাড়া। সাদাকা জারিয়াহ্(চালু থাকে এমন) অথবা এমন ইলম যার দ্বারা উপকার হয় অথবা পুণ্যবান সন্তান যে তার জন্যে দু’আ করতে থাকে”",
|
|
65
77
|
"sheet.hadith_ref": "সহিহ মুসলিম 1631",
|
|
66
78
|
"sheet.mistakes": "আপনার ভুলগুলোই এখানে সবচেয়ে মূল্যবান অংশ। এগুলো পরবর্তী শিক্ষার্থীকে নম্রভাবে ভুল শুধরে দিতে মডেলটিকে শেখায়।",
|
|
67
|
-
"sheet.what": "অ্যাপটি শোনার সময় এতে আপনার তিলাওয়াতের
|
|
79
|
+
"sheet.what": "অ্যাপটি শোনার সময় এতে আপনার তিলাওয়াতের অডিও এবং মডেল ভার্সন ও ডিভাইসের ধরনের মতো সাধারণ কিছু কারিগরি তথ্য। কোনো নাম, যোগাযোগের তথ্য বা লোকেশন নয়।",
|
|
68
80
|
"sheet.who": "Quran Lab, একটি ওয়াকফ। এর তৈরি মডেলগুলো সবার জন্য চিরকাল সম্পূর্ণ বিনামূল্যে এবং এগুলো কখনোই বিক্রি করা হয় না।",
|
|
69
81
|
"sheet.control": "আপনি যেকোনো সময় এটি বন্ধ করতে পারেন এবং যা শেয়ার করেছেন তা সেটিংস থেকে মুছে ফেলতে পারেন।",
|
|
70
82
|
"sheet.share": "আমার তিলাওয়াত শেয়ার করুন",
|
|
@@ -77,11 +89,21 @@ export const DECKS = {
|
|
|
77
89
|
"settings.toggle": "আমার তিলাওয়াত শেয়ার করুন",
|
|
78
90
|
"settings.what": "যা শেয়ার করা হয়",
|
|
79
91
|
"settings.delete": "শেয়ার করা তিলাওয়াত মুছুন",
|
|
80
|
-
"what.detail": "
|
|
81
|
-
"delete.confirm": "আপনার শেয়ার করা
|
|
92
|
+
"what.detail": "শেয়ারিং চালু থাকলে, এই অ্যাপে আপনার তিলাওয়াত সেশনের অডিও Quran Lab-এ পাঠানো হয়। এর সাথে থাকে সাধারণ কিছু কারিগরি তথ্য (মডেল সংস্করণ, ডিভাইসের ধরন, সিস্টেম সংস্করণ, দিন) এবং এই ইনস্টলেশনের জন্য একটি র্যান্ডম কোড। আপনার নাম, অ্যাকাউন্ট, কনট্যাক্ট, লোকেশন বা ডিভাইস শনাক্তকারী তথ্য কখনোই নেওয়া হয় না। এটি ইইউ (EU)-তে সংরক্ষিত থাকে এবং কেবল বিনামূল্যে ব্যবহারযোগ্য কুরআন তিলাওয়াত মডেলগুলোর মানোন্নয়নে ব্যবহৃত হয়। শেয়ারিং বন্ধ করলে সাথে সাথেই আপলোড বন্ধ হয়ে যায়, আর সেটিংস থেকে যেকোনো সময় আপনি শেয়ার করা সবকিছু মুছে ফেলতে পারেন: Quran Lab-এর সার্ভার থেকে এটি সাথে সাথেই মুছে ফেলা হয়।",
|
|
93
|
+
"delete.confirm": "আপনার শেয়ার করা তিলাওয়াতগুলো সাথে সাথেই Quran Lab-এর সার্ভার থেকে মুছে ফেলা হবে। এটি আর ফিরিয়ে আনা সম্ভব নয়।",
|
|
82
94
|
"delete.action": "মুছে ফেলুন",
|
|
83
95
|
"delete.cancel": "বাতিল করুন",
|
|
84
|
-
"delete.done": "
|
|
96
|
+
"delete.done": "সম্পন্ন হয়েছে। আপনি যা শেয়ার করেছিলেন, তা Quran Lab-এর সার্ভার থেকে মুছে ফেলা হয়েছে। মডেল প্রশিক্ষণে ইতিমধ্যে ব্যবহৃত অনুলিপিগুলো ভবিষ্যতের প্রশিক্ষণ থেকে বাদ রাখা হবে।",
|
|
97
|
+
"delete.failed.title": "মুছে ফেলা যায়নি",
|
|
98
|
+
"delete.failed.network": "Quran Lab-এর সাথে সংযোগ করা যায়নি। কোনো কিছুই মুছে ফেলা হয়নি। আপনার ইন্টারনেট সংযোগ পরীক্ষা করে আবার চেষ্টা করুন।",
|
|
99
|
+
"delete.retry": "আবার চেষ্টা করুন",
|
|
100
|
+
"recovery.hint": "ডিভাইসটি হারিয়ে গেলে আপনার শেয়ার করা তথ্য মুছে ফেলার জন্য এই ওয়ান-টাইম কোডটি সংরক্ষণ করে রাখুন: portal.quranlab.ai/delete",
|
|
101
|
+
"recovery.reveal": "আমার রিকভারি কোড দেখুন",
|
|
102
|
+
"recovery.copy": "কপি করুন",
|
|
103
|
+
"recovery.copied": "কপি করা হয়েছে",
|
|
104
|
+
"recovery.keep": "এই কোডটি নিরাপদে সংরক্ষণ করুন। অন্য কোনো ডিভাইস থেকে আপনি যা শেয়ার করেছেন তা মুছে ফেলার এটিই একমাত্র উপায়, এবং এটি কেবল একবারই ব্যবহার করা যাবে।",
|
|
105
|
+
"recovery.used": "এই রিকভারি কোডটি ইতিমধ্যে ব্যবহার করা হয়েছে।",
|
|
106
|
+
"recovery.invalid": "এই কোডটি সঠিক নয়। শব্দগুলো মিলিয়ে দেখে আবার চেষ্টা করুন।",
|
|
85
107
|
"reask": "আজকের আপনার তিলাওয়াত হয়তো আগামী দিনে অন্য কোনো শিক্ষার্থীকে সাহায্য করতে পারে। আপনি কি এটি শেয়ার করতে চান?",
|
|
86
108
|
"impact.minutes": {
|
|
87
109
|
"one": "আপনি {minutes} মিনিট তিলাওয়াত শেয়ার করেছেন। আল্লাহ আপনাকে উত্তম প্রতিদান দিন।",
|
|
@@ -100,18 +122,19 @@ export const DECKS = {
|
|
|
100
122
|
},
|
|
101
123
|
"en": {
|
|
102
124
|
"format": "quranlab.sharing-copy/1",
|
|
103
|
-
"version": "2026-11-
|
|
125
|
+
"version": "2026-11-09.1",
|
|
104
126
|
"lang": "en",
|
|
105
127
|
"dir": "ltr",
|
|
106
|
-
"consent_version": "share-2026-11-
|
|
107
|
-
"delete_days":
|
|
128
|
+
"consent_version": "share-2026-11-09",
|
|
129
|
+
"delete_days": 0,
|
|
130
|
+
"delete_timing": "immediate",
|
|
108
131
|
"strings": {
|
|
109
132
|
"sheet.title": "Let your recitation keep doing good",
|
|
110
133
|
"sheet.body": "When you share your recitations, they help teach this app's free tajweed model to listen better. Every learner it helps after you is a good deed that may continue long after you finish reciting, in sha Allah: a sadaqah jariyah.",
|
|
111
134
|
"sheet.hadith": "The Prophet, peace be upon him, said: \"When a person dies, his deeds come to an end except for three things: ongoing charity, beneficial knowledge, or a pious child who supplicates for him.\"",
|
|
112
135
|
"sheet.hadith_ref": "Sahih Muslim 1631",
|
|
113
136
|
"sheet.mistakes": "Your mistakes are the most valuable part. They teach the model to correct the next learner gently.",
|
|
114
|
-
"sheet.what": "The audio of your recitation sessions in this app, while it listens,
|
|
137
|
+
"sheet.what": "The audio of your recitation sessions in this app, while it listens, and basic technical details such as the model version and device type. No name, no contacts, no location.",
|
|
115
138
|
"sheet.who": "Quran Lab, a waqf. The models it trains are free for everyone, forever, and are never sold.",
|
|
116
139
|
"sheet.control": "You can stop at any time and delete what you shared from the settings.",
|
|
117
140
|
"sheet.share": "Share my recitations",
|
|
@@ -124,11 +147,21 @@ export const DECKS = {
|
|
|
124
147
|
"settings.toggle": "Share my recitations",
|
|
125
148
|
"settings.what": "What is shared",
|
|
126
149
|
"settings.delete": "Delete what I shared",
|
|
127
|
-
"what.detail": "When sharing is on, the audio of your recitation sessions in this app is sent to Quran Lab, with
|
|
128
|
-
"delete.confirm": "Your shared recitations will be deleted from Quran Lab's servers
|
|
150
|
+
"what.detail": "When sharing is on, the audio of your recitation sessions in this app is sent to Quran Lab, with coarse technical details (model version, device type, system version, the day) and a random code for this install. Never your name, account, contacts, location or device identifiers. It is stored in the EU and used only to improve free Quran recitation models. Turning sharing off stops uploads at once, and you can delete everything you shared from the settings at any time: it is removed from Quran Lab's servers right away.",
|
|
151
|
+
"delete.confirm": "Your shared recitations will be deleted from Quran Lab's servers right away. This cannot be undone.",
|
|
129
152
|
"delete.action": "Delete",
|
|
130
153
|
"delete.cancel": "Cancel",
|
|
131
|
-
"delete.done": "
|
|
154
|
+
"delete.done": "Done. What you shared has been deleted from Quran Lab's servers. Copies already used to train a model are left out of future training.",
|
|
155
|
+
"delete.failed.title": "Could not delete",
|
|
156
|
+
"delete.failed.network": "We could not reach Quran Lab. Nothing was deleted. Check your connection and try again.",
|
|
157
|
+
"delete.retry": "Try again",
|
|
158
|
+
"recovery.hint": "Keep this one-time code to delete what you shared if you lose this device: portal.quranlab.ai/delete",
|
|
159
|
+
"recovery.reveal": "Show my recovery code",
|
|
160
|
+
"recovery.copy": "Copy",
|
|
161
|
+
"recovery.copied": "Copied",
|
|
162
|
+
"recovery.keep": "Keep this code safe. It is the only way to delete what you shared from another device, and it works once.",
|
|
163
|
+
"recovery.used": "This recovery code was already used.",
|
|
164
|
+
"recovery.invalid": "This code is not valid. Check the words and try again.",
|
|
132
165
|
"reask": "Your recitation today could help another learner tomorrow. Would you like to share it?",
|
|
133
166
|
"impact.minutes": {
|
|
134
167
|
"one": "You have shared {minutes} minute of recitation. May Allah reward you.",
|
|
@@ -147,18 +180,19 @@ export const DECKS = {
|
|
|
147
180
|
},
|
|
148
181
|
"fr": {
|
|
149
182
|
"format": "quranlab.sharing-copy/1",
|
|
150
|
-
"version": "2026-11-
|
|
183
|
+
"version": "2026-11-09.1",
|
|
151
184
|
"lang": "fr",
|
|
152
185
|
"dir": "ltr",
|
|
153
|
-
"consent_version": "share-2026-11-
|
|
154
|
-
"delete_days":
|
|
186
|
+
"consent_version": "share-2026-11-09",
|
|
187
|
+
"delete_days": 0,
|
|
188
|
+
"delete_timing": "immediate",
|
|
155
189
|
"strings": {
|
|
156
190
|
"sheet.title": "Que votre récitation continue de faire le bien",
|
|
157
191
|
"sheet.body": "Lorsque vous partagez vos récitations, elles permettent d'entraîner le modèle de tajwid gratuit de l'application à mieux écouter. Chaque apprenant qu'il aide après vous est une bonne action qui peut perdurer bien après votre récitation, inchâAllah : une sadaqa jâriya (aumône continue).",
|
|
158
192
|
"sheet.hadith": "Le Prophète, que la paix soit sur lui, a dit : « Quand une personne meurt, ses actions prennent fin sauf trois choses : une aumône continue (sadaqa jâriya), une science utile, ou un enfant pieux qui fait des invocations (du'â) pour elle. »",
|
|
159
193
|
"sheet.hadith_ref": "Sahih Muslim 1631",
|
|
160
194
|
"sheet.mistakes": "Vos erreurs sont ce qu'il y a de plus précieux. Elles apprennent au modèle à corriger le prochain apprenant avec douceur.",
|
|
161
|
-
"sheet.what": "L'enregistrement audio de vos séances de récitation dans cette application lorsqu'elle est à l'écoute,
|
|
195
|
+
"sheet.what": "L'enregistrement audio de vos séances de récitation dans cette application lorsqu'elle est à l'écoute, et des détails techniques simples comme la version du modèle et le type d'appareil. Aucun nom, aucun contact, aucune localisation.",
|
|
162
196
|
"sheet.who": "Quran Lab, un waqf. Les modèles entraînés sont gratuits pour tous, pour toujours, et ne sont jamais vendus.",
|
|
163
197
|
"sheet.control": "Vous pouvez arrêter à tout moment et supprimer ce que vous avez partagé depuis les paramètres.",
|
|
164
198
|
"sheet.share": "Partager mes récitations",
|
|
@@ -171,11 +205,21 @@ export const DECKS = {
|
|
|
171
205
|
"settings.toggle": "Partager mes récitations",
|
|
172
206
|
"settings.what": "Ce qui est partagé",
|
|
173
207
|
"settings.delete": "Supprimer mes partages",
|
|
174
|
-
"what.detail": "Lorsque le partage est activé, l'audio de vos séances de récitation dans cette application est envoyé à Quran Lab, avec
|
|
175
|
-
"delete.confirm": "Vos récitations partagées seront supprimées des serveurs de Quran Lab
|
|
208
|
+
"what.detail": "Lorsque le partage est activé, l'audio de vos séances de récitation dans cette application est envoyé à Quran Lab, avec quelques informations techniques générales (version du modèle, type d'appareil, version du système, date) et un code aléatoire propre à cette installation. Jamais votre nom, votre compte, vos contacts, votre localisation ou les identifiants de votre appareil. Ces données sont stockées dans l'Union européenne et servent uniquement à améliorer des modèles gratuits de récitation du Coran. Désactiver le partage interrompt immédiatement les envois, et vous pouvez supprimer tout ce que vous avez partagé à tout moment depuis les paramètres : vos données sont immédiatement effacées des serveurs de Quran Lab.",
|
|
209
|
+
"delete.confirm": "Vos récitations partagées seront immédiatement supprimées des serveurs de Quran Lab. Cette action est irréversible.",
|
|
176
210
|
"delete.action": "Supprimer",
|
|
177
211
|
"delete.cancel": "Annuler",
|
|
178
|
-
"delete.done": "
|
|
212
|
+
"delete.done": "C'est fait. Ce que vous avez partagé a été supprimé des serveurs de Quran Lab. Les copies déjà utilisées pour entraîner un modèle seront exclues des futurs entraînements.",
|
|
213
|
+
"delete.failed.title": "Impossible de supprimer",
|
|
214
|
+
"delete.failed.network": "Impossible de joindre Quran Lab. Rien n'a été supprimé. Vérifiez votre connexion et réessayez.",
|
|
215
|
+
"delete.retry": "Réessayer",
|
|
216
|
+
"recovery.hint": "Conservez ce code à usage unique pour supprimer vos partages si vous perdez cet appareil : portal.quranlab.ai/delete",
|
|
217
|
+
"recovery.reveal": "Afficher mon code de récupération",
|
|
218
|
+
"recovery.copy": "Copier",
|
|
219
|
+
"recovery.copied": "Copié",
|
|
220
|
+
"recovery.keep": "Conservez ce code en lieu sûr. C'est le seul moyen de supprimer ce que vous avez partagé depuis un autre appareil, et il ne fonctionne qu'une seule fois.",
|
|
221
|
+
"recovery.used": "Ce code de récupération a déjà été utilisé.",
|
|
222
|
+
"recovery.invalid": "Ce code n'est pas valide. Vérifiez les mots et réessayez.",
|
|
179
223
|
"reask": "Votre récitation d'aujourd'hui pourrait aider un autre apprenant demain. Souhaitez-vous la partager ?",
|
|
180
224
|
"impact.minutes": {
|
|
181
225
|
"one": "Vous avez partagé {minutes} minute de récitation. Qu'Allah vous récompense.",
|
|
@@ -195,18 +239,19 @@ export const DECKS = {
|
|
|
195
239
|
},
|
|
196
240
|
"id": {
|
|
197
241
|
"format": "quranlab.sharing-copy/1",
|
|
198
|
-
"version": "2026-11-
|
|
242
|
+
"version": "2026-11-09.1",
|
|
199
243
|
"lang": "id",
|
|
200
244
|
"dir": "ltr",
|
|
201
|
-
"consent_version": "share-2026-11-
|
|
202
|
-
"delete_days":
|
|
245
|
+
"consent_version": "share-2026-11-09",
|
|
246
|
+
"delete_days": 0,
|
|
247
|
+
"delete_timing": "immediate",
|
|
203
248
|
"strings": {
|
|
204
249
|
"sheet.title": "Biarkan bacaan Anda terus mengalirkan kebaikan",
|
|
205
250
|
"sheet.body": "Saat Anda membagikan bacaan Anda, rekaman tersebut membantu melatih model tajwid gratis di aplikasi ini agar dapat menyimak dengan lebih baik. Setiap pembelajar yang terbantu setelahnya bisa menjadi kebaikan yang terus mengalir walau Anda telah selesai membaca, insya Allah: sebuah sedekah jariyah.",
|
|
206
251
|
"sheet.hadith": "Rasulullah shallallahu 'alaihi wa sallam bersabda: \"Apabila manusia meninggal, maka terputuslah amalnya kecuali tiga perkara: sedekah yang mengalir, ilmu yang dimanfaatkan, dan anak saleh yang mendoakannya.\"",
|
|
207
252
|
"sheet.hadith_ref": "Shahih Muslim 1631",
|
|
208
253
|
"sheet.mistakes": "Kekeliruan bacaan Anda justru bagian yang paling berharga. Dari situ, model ini belajar cara mengoreksi pembelajar berikutnya dengan lembut.",
|
|
209
|
-
"sheet.what": "Audio dari sesi bacaan Anda di aplikasi ini saat aplikasi menyimak,
|
|
254
|
+
"sheet.what": "Audio dari sesi bacaan Anda di aplikasi ini saat aplikasi menyimak, serta informasi teknis dasar seperti versi model dan jenis perangkat. Tanpa nama, tanpa kontak, tanpa lokasi.",
|
|
210
255
|
"sheet.who": "Quran Lab, sebuah inisiatif wakaf. Model yang dilatih di sini gratis untuk siapa saja, selamanya, dan tidak pernah diperjualbelikan.",
|
|
211
256
|
"sheet.control": "Anda bisa berhenti kapan saja dan menghapus apa yang telah Anda bagikan melalui menu pengaturan.",
|
|
212
257
|
"sheet.share": "Bagikan bacaan saya",
|
|
@@ -219,11 +264,21 @@ export const DECKS = {
|
|
|
219
264
|
"settings.toggle": "Bagikan bacaan saya",
|
|
220
265
|
"settings.what": "Data yang dibagikan",
|
|
221
266
|
"settings.delete": "Hapus rekaman yang dibagikan",
|
|
222
|
-
"what.detail": "
|
|
223
|
-
"delete.confirm": "Rekaman
|
|
267
|
+
"what.detail": "Ketika fitur berbagi aktif, rekaman audio tilawah Anda di aplikasi ini akan dikirim ke Quran Lab, bersama rincian teknis umum (versi model, tipe perangkat, versi sistem, hari), dan kode acak untuk instalasi ini. Sama sekali tanpa nama, akun, kontak, lokasi, ataupun tanda pengenal perangkat Anda. Data disimpan di Uni Eropa dan hanya digunakan untuk menyempurnakan model tilawah Al-Qur'an gratis. Mematikan fitur berbagi akan langsung menghentikan pengiriman, dan Anda dapat menghapus semua yang telah dibagikan kapan saja melalui pengaturan: data akan langsung dihapus dari server Quran Lab saat itu juga.",
|
|
268
|
+
"delete.confirm": "Rekaman tilawah yang Anda bagikan akan langsung dihapus dari server Quran Lab saat itu juga. Tindakan ini tidak dapat dibatalkan.",
|
|
224
269
|
"delete.action": "Hapus rekaman",
|
|
225
270
|
"delete.cancel": "Batal hapus",
|
|
226
|
-
"delete.done": "
|
|
271
|
+
"delete.done": "Selesai. Apa yang Anda bagikan sudah dihapus dari server Quran Lab. Salinan yang sudah digunakan untuk melatih model tidak akan disertakan dalam pelatihan berikutnya.",
|
|
272
|
+
"delete.failed.title": "Tidak dapat menghapus",
|
|
273
|
+
"delete.failed.network": "Kami tidak dapat terhubung ke Quran Lab. Tidak ada yang dihapus. Periksa koneksi Anda dan coba lagi.",
|
|
274
|
+
"delete.retry": "Coba lagi",
|
|
275
|
+
"recovery.hint": "Simpan kode sekali pakai ini untuk menghapus data yang Anda bagikan jika perangkat ini hilang: portal.quranlab.ai/delete",
|
|
276
|
+
"recovery.reveal": "Tampilkan kode pemulihan",
|
|
277
|
+
"recovery.copy": "Salin",
|
|
278
|
+
"recovery.copied": "Tersalin",
|
|
279
|
+
"recovery.keep": "Simpan kode ini baik-baik. Ini satu-satunya cara untuk menghapus apa yang Anda bagikan dari perangkat lain, dan hanya bisa digunakan satu kali.",
|
|
280
|
+
"recovery.used": "Kode pemulihan ini sudah pernah digunakan.",
|
|
281
|
+
"recovery.invalid": "Kode ini tidak valid. Periksa kembali kata-katanya dan coba lagi.",
|
|
227
282
|
"reask": "Bacaan Anda hari ini bisa membantu pembelajar lain esok hari. Bersediakah Anda membagikannya?",
|
|
228
283
|
"impact.minutes": {
|
|
229
284
|
"other": "Anda telah membagikan {minutes} menit bacaan. Semoga Allah membalas kebaikan Anda."
|
|
@@ -241,18 +296,19 @@ export const DECKS = {
|
|
|
241
296
|
},
|
|
242
297
|
"ms": {
|
|
243
298
|
"format": "quranlab.sharing-copy/1",
|
|
244
|
-
"version": "2026-11-
|
|
299
|
+
"version": "2026-11-09.1",
|
|
245
300
|
"lang": "ms",
|
|
246
301
|
"dir": "ltr",
|
|
247
|
-
"consent_version": "share-2026-11-
|
|
248
|
-
"delete_days":
|
|
302
|
+
"consent_version": "share-2026-11-09",
|
|
303
|
+
"delete_days": 0,
|
|
304
|
+
"delete_timing": "immediate",
|
|
249
305
|
"strings": {
|
|
250
306
|
"sheet.title": "Biarlah bacaan anda terus mengalirkan kebaikan",
|
|
251
307
|
"sheet.body": "Apabila anda berkongsi bacaan, ia membantu melatih model tajwid percuma aplikasi ini agar dapat mendengar dengan lebih baik. Setiap pembelajar yang dibantunya selepas ini moga menjadi kebaikan yang terus mengalir buat anda walaupun selepas selesai membaca, insya-Allah: sebagai sedekah jariah.",
|
|
252
308
|
"sheet.hadith": "Rasulullah SAW bersabda: \"Apabila seseorang meninggal dunia, terputuslah amalannya melainkan tiga perkara: sedekah jariah, ilmu yang bermanfaat, atau anak soleh yang mendoakannya.\"",
|
|
253
309
|
"sheet.hadith_ref": "Sahih Muslim 1631",
|
|
254
310
|
"sheet.mistakes": "Kesilapan anda adalah bahagian yang paling bernilai. Ia mengajar model ini menegur pelajar seterusnya dengan lembut.",
|
|
255
|
-
"sheet.what": "Audio daripada sesi bacaan anda dalam aplikasi ini semasa ia mendengar,
|
|
311
|
+
"sheet.what": "Audio daripada sesi bacaan anda dalam aplikasi ini semasa ia mendengar, serta maklumat teknikal asas seperti versi model dan jenis peranti. Tiada nama, senarai kenalan mahupun lokasi.",
|
|
256
312
|
"sheet.who": "Quran Lab, sebuah inisiatif wakaf. Model yang dilatih adalah percuma untuk semua, selama-lamanya, dan tidak akan sesekali dijual.",
|
|
257
313
|
"sheet.control": "Anda boleh berhenti pada bila-bila masa dan memadam apa yang telah dikongsi melalui tetapan.",
|
|
258
314
|
"sheet.share": "Kongsi bacaan saya",
|
|
@@ -265,11 +321,21 @@ export const DECKS = {
|
|
|
265
321
|
"settings.toggle": "Kongsi bacaan saya",
|
|
266
322
|
"settings.what": "Maklumat yang dikongsi",
|
|
267
323
|
"settings.delete": "Padam apa yang dikongsi",
|
|
268
|
-
"what.detail": "Apabila perkongsian diaktifkan, audio sesi bacaan anda dalam aplikasi ini akan dihantar kepada Quran Lab bersama
|
|
269
|
-
"delete.confirm": "
|
|
324
|
+
"what.detail": "Apabila perkongsian diaktifkan, audio sesi bacaan anda dalam aplikasi ini akan dihantar kepada Quran Lab bersama butiran teknikal umum (versi model, jenis peranti, versi sistem, hari) dan kod rawak bagi pemasangan ini. Nama, akaun, kenalan, lokasi atau pengecam peranti anda tidak akan diambil sama sekali. Data ini disimpan di EU dan hanya digunakan untuk menambah baik model bacaan al-Quran percuma. Mematikan perkongsian akan menghentikan muat naik serta-merta, dan anda boleh memadamkan semua yang telah dikongsi melalui tetapan pada bila-bila masa: ia akan dipadamkan daripada pelayan Quran Lab serta-merta.",
|
|
325
|
+
"delete.confirm": "Rakaman bacaan yang anda kongsi akan dipadamkan daripada pelayan Quran Lab serta-merta. Tindakan ini tidak boleh dibatalkan.",
|
|
270
326
|
"delete.action": "Padam",
|
|
271
327
|
"delete.cancel": "Batal",
|
|
272
|
-
"delete.done": "
|
|
328
|
+
"delete.done": "Selesai. Apa yang anda kongsikan telah dipadamkan daripada pelayan Quran Lab. Salinan yang sudah digunakan untuk melatih model tidak akan disertakan dalam latihan akan datang.",
|
|
329
|
+
"delete.failed.title": "Tidak dapat memadam",
|
|
330
|
+
"delete.failed.network": "Kami tidak dapat menghubungi Quran Lab. Tiada apa-apa yang dipadamkan. Semak sambungan internet anda dan cuba lagi.",
|
|
331
|
+
"delete.retry": "Cuba lagi",
|
|
332
|
+
"recovery.hint": "Simpan kod sekali guna ini untuk memadamkan apa yang telah anda kongsi sekiranya anda kehilangan peranti ini: portal.quranlab.ai/delete",
|
|
333
|
+
"recovery.reveal": "Tunjukkan kod pemulihan saya",
|
|
334
|
+
"recovery.copy": "Salin",
|
|
335
|
+
"recovery.copied": "Disalin",
|
|
336
|
+
"recovery.keep": "Simpan kod ini dengan selamat. Ini satu-satunya cara untuk memadam apa yang anda kongsikan daripada peranti lain, dan ia hanya boleh digunakan sekali.",
|
|
337
|
+
"recovery.used": "Kod pemulihan ini sudah digunakan.",
|
|
338
|
+
"recovery.invalid": "Kod ini tidak sah. Semak perkataan dan cuba lagi.",
|
|
273
339
|
"reask": "Bacaan anda hari ini mungkin dapat membantu pembelajar lain esok. Sudikah anda berkongsinya?",
|
|
274
340
|
"impact.minutes": {
|
|
275
341
|
"other": "Anda telah berkongsi {minutes} minit bacaan. Semoga Allah membalas kebaikan anda."
|
|
@@ -287,18 +353,19 @@ export const DECKS = {
|
|
|
287
353
|
},
|
|
288
354
|
"tr": {
|
|
289
355
|
"format": "quranlab.sharing-copy/1",
|
|
290
|
-
"version": "2026-11-
|
|
356
|
+
"version": "2026-11-09.1",
|
|
291
357
|
"lang": "tr",
|
|
292
358
|
"dir": "ltr",
|
|
293
|
-
"consent_version": "share-2026-11-
|
|
294
|
-
"delete_days":
|
|
359
|
+
"consent_version": "share-2026-11-09",
|
|
360
|
+
"delete_days": 0,
|
|
361
|
+
"delete_timing": "immediate",
|
|
295
362
|
"strings": {
|
|
296
363
|
"sheet.title": "Tilavetiniz hayra vesile olmaya devam etsin",
|
|
297
364
|
"sheet.body": "Okumalarınızı paylaştığınızda, bu uygulamanın ücretsiz tecvid modelinin daha iyi dinlemeyi öğrenmesine yardımcı olursunuz. Sizden sonra istifade eden her bir öğrenci, okumanız bittikten çok sonra da devam edebilecek bir hayır olabilir, inşallah: bir sadaka-i câriye.",
|
|
298
365
|
"sheet.hadith": "Peygamberimiz (aleyhisselam) şöyle buyurmuştur: «Bir insan öldüğü zaman, üç ameli dışında bütün amellerinin sevabı kesilir: Sadaka-i câriye, kendisinden faydalanılan ilim ve kendisine dua eden salih evlat.»",
|
|
299
366
|
"sheet.hadith_ref": "Sahih Müslim 1631",
|
|
300
367
|
"sheet.mistakes": "Hatalarınız işin en kıymetli kısmıdır. Modele, bir sonraki talebeyi incitmeden, nazikçe düzeltmeyi öğretirler.",
|
|
301
|
-
"sheet.what": "Uygulama dinlerken yapılan tilavet kayıtlarınız
|
|
368
|
+
"sheet.what": "Uygulama dinlerken yapılan tilavet kayıtlarınız ile model sürümü ve cihaz türü gibi temel teknik detaylar. İsim, rehber veya konum asla paylaşılmaz.",
|
|
302
369
|
"sheet.who": "Quran Lab bir vakıftır. Geliştirdiği modeller herkes için daima ücretsizdir ve asla satılmaz.",
|
|
303
370
|
"sheet.control": "Dilediğiniz an paylaşımı durdurabilir ve paylaştıklarınızı ayarlar bölümünden silebilirsiniz.",
|
|
304
371
|
"sheet.share": "Tilavetlerimi paylaş",
|
|
@@ -311,11 +378,21 @@ export const DECKS = {
|
|
|
311
378
|
"settings.toggle": "Tilavetlerimi paylaş",
|
|
312
379
|
"settings.what": "Neler paylaşılır",
|
|
313
380
|
"settings.delete": "Paylaştıklarımı sil",
|
|
314
|
-
"what.detail": "Paylaşım
|
|
315
|
-
"delete.confirm": "Paylaştığınız
|
|
381
|
+
"what.detail": "Paylaşım açık olduğunda, bu uygulamadaki kıraat çalışmalarınızın ses kayıtları; temel teknik ayrıntılar (model sürümü, cihaz türü, sistem sürümü, gün) ve bu kuruluma özel rastgele bir kodla birlikte Quran Lab'e gönderilir. İsminiz, hesabınız, kişileriniz, konumunuz veya cihaz tanıtıcılarınız asla alınmaz. Veriler AB içinde saklanır ve sadece ücretsiz Kur'an kıraat modellerini geliştirmek için kullanılır. Paylaşımı kapattığınız anda yüklemeler durur ve paylaştığınız her şeyi ayarlardan dilediğiniz zaman silebilirsiniz: veriler Quran Lab sunucularından anında kaldırılır.",
|
|
382
|
+
"delete.confirm": "Paylaştığınız kıraat kayıtları Quran Lab sunucularından anında silinecektir. Bu işlem geri alınamaz.",
|
|
316
383
|
"delete.action": "Paylaşılanları sil",
|
|
317
384
|
"delete.cancel": "İptal et",
|
|
318
|
-
"delete.done": "
|
|
385
|
+
"delete.done": "Tamamlandı. Paylaştıklarınız Quran Lab sunucularından silindi. Bir modeli eğitmek için önceden kullanılmış kopyalar ise sonraki eğitimlere dahil edilmeyecektir.",
|
|
386
|
+
"delete.failed.title": "Silinemedi",
|
|
387
|
+
"delete.failed.network": "Quran Lab'e ulaşılamadı. Hiçbir şey silinmedi. Bağlantınızı kontrol edip tekrar deneyin.",
|
|
388
|
+
"delete.retry": "Tekrar deneyin",
|
|
389
|
+
"recovery.hint": "Cihazınızı kaybetmeniz durumunda paylaştıklarınızı silebilmek için bu tek kullanımlık kodu saklayın: portal.quranlab.ai/delete",
|
|
390
|
+
"recovery.reveal": "Kurtarma kodumu göster",
|
|
391
|
+
"recovery.copy": "Kopyala",
|
|
392
|
+
"recovery.copied": "Kopyalandı",
|
|
393
|
+
"recovery.keep": "Bu kodu güvenli bir yerde saklayın. Paylaştıklarınızı başka bir cihazdan silmenin tek yolu budur ve yalnızca bir kez kullanılabilir.",
|
|
394
|
+
"recovery.used": "Bu kurtarma kodu daha önce kullanıldı.",
|
|
395
|
+
"recovery.invalid": "Bu kod geçerli değil. Kelimeleri kontrol edip tekrar deneyin.",
|
|
319
396
|
"reask": "Bugünkü tilavetiniz yarın bir başka öğrenciye yardımcı olabilir. Paylaşmak ister misiniz?",
|
|
320
397
|
"impact.minutes": {
|
|
321
398
|
"one": "{minutes} dakika tilavet paylaştınız. Allah razı olsun.",
|
|
@@ -334,18 +411,19 @@ export const DECKS = {
|
|
|
334
411
|
},
|
|
335
412
|
"ur": {
|
|
336
413
|
"format": "quranlab.sharing-copy/1",
|
|
337
|
-
"version": "2026-11-
|
|
414
|
+
"version": "2026-11-09.1",
|
|
338
415
|
"lang": "ur",
|
|
339
416
|
"dir": "rtl",
|
|
340
|
-
"consent_version": "share-2026-11-
|
|
341
|
-
"delete_days":
|
|
417
|
+
"consent_version": "share-2026-11-09",
|
|
418
|
+
"delete_days": 0,
|
|
419
|
+
"delete_timing": "immediate",
|
|
342
420
|
"strings": {
|
|
343
421
|
"sheet.title": "اپنی تلاوت سے خیر کا سلسلہ جاری رکھیے",
|
|
344
422
|
"sheet.body": "جب آپ اپنی تلاوت شیئر کرتے ہیں تو اس سے اس ایپ کے مفت تجوید ماڈل کو بہتر طور پر سننے میں مدد ملتی ہے۔ آپ کے بعد جس بھی سیکھنے والے کی اس سے مدد ہوگی، وہ ان شاء اللہ آپ کی تلاوت مکمل ہو جانے کے بعد بھی ایک مسلسل نیکی بن سکتی ہے: صدقہ جاریہ۔",
|
|
345
423
|
"sheet.hadith": "نبی کریم صلی اللہ علیہ وسلم نے فرمایا: «جب انسان مر جاتا ہے تو اس کا عمل بھی منقطع ہو جاتا ہے، مگر تین قسم کے عمل (کا ثواب) جاری رہتا ہے۔ صدقۂ جاریہ، یا ایسا علم جس سے اس کے بعد بھی فائدہ اٹھایا جائے، یا نیک اولاد جو اس کے لیے دعا کرے۔»",
|
|
346
424
|
"sheet.hadith_ref": "صحیح مسلم 1631",
|
|
347
425
|
"sheet.mistakes": "آپ کی غلطیاں سب سے زیادہ قیمتی ہیں۔ ان سے ماڈل سیکھتا ہے کہ اگلے سیکھنے والے کی نرمی سے کیسے اصلاح کی جائے۔",
|
|
348
|
-
"sheet.what": "اس ایپ میں آپ کی تلاوت کی آڈیو جب ایپ سن رہی ہو،
|
|
426
|
+
"sheet.what": "اس ایپ میں آپ کی تلاوت کی آڈیو جب ایپ سن رہی ہو، اور بنیادی تکنیکی تفصیلات جیسے ماڈل کا ورژن اور ڈیوائس کی قسم۔ کوئی نام، رابطے یا لوکیشن شامل نہیں۔",
|
|
349
427
|
"sheet.who": "Quran Lab، جو کہ ایک وقف ہے۔ اس کے تیار کردہ ماڈلز ہمیشہ سب کے لیے مفت رہیں گے اور کبھی بیچے نہیں جائیں گے۔",
|
|
350
428
|
"sheet.control": "آپ کسی بھی وقت اسے روک سکتے ہیں اور سیٹنگز سے اپنا شیئر کردہ ڈیٹا ڈیلیٹ کر سکتے ہیں۔",
|
|
351
429
|
"sheet.share": "میری تلاوتیں شیئر کریں",
|
|
@@ -358,11 +436,21 @@ export const DECKS = {
|
|
|
358
436
|
"settings.toggle": "میری تلاوتیں شیئر کریں",
|
|
359
437
|
"settings.what": "کیا شیئر کیا جاتا ہے",
|
|
360
438
|
"settings.delete": "شیئر کردہ مواد مٹائیں",
|
|
361
|
-
"what.detail": "جب شیئرنگ آن
|
|
362
|
-
"delete.confirm": "آپ کی شیئر کردہ تلاوتیں
|
|
439
|
+
"what.detail": "جب شیئرنگ آن ہو، تو اس ایپ میں آپ کی تلاوت کی آڈیو Quran Lab کو بھیجی جاتی ہے، جس کے ساتھ کچھ بنیادی تکنیکی تفصیلات (ماڈل ورژن، ڈیوائس کی قسم، سسٹم ورژن اور دن) اور اس انسٹالیشن کا ایک بے ترتیب کوڈ شامل ہوتا ہے۔ آپ کا نام، اکاؤنٹ، رابطے، لوکیشن یا ڈیوائس کی ذاتی شناخت کبھی بھی شامل نہیں کی جاتی۔ یہ ڈیٹا EU میں محفوظ کیا جاتا ہے اور اسے صرف تلاوتِ قرآن کے مفت ماڈلز کو بہتر بنانے کے لیے استعمال کیا جاتا ہے۔ شیئرنگ بند کرنے سے اپ لوڈز فوراً رک جاتے ہیں، اور آپ سیٹنگز میں جا کر کسی بھی وقت اپنا شیئر کردہ تمام مواد ڈیلیٹ کر سکتے ہیں: اسے اسی وقت Quran Lab کے سرورز سے مٹا دیا جاتا ہے۔",
|
|
440
|
+
"delete.confirm": "آپ کی شیئر کردہ تلاوتیں فوراً Quran Lab کے سرورز سے ڈیلیٹ کر دی جائیں گی۔ اس عمل کو واپس نہیں لایا جا سکتا۔",
|
|
363
441
|
"delete.action": "ڈیلیٹ کریں",
|
|
364
442
|
"delete.cancel": "منسوخ کریں",
|
|
365
|
-
"delete.done": "
|
|
443
|
+
"delete.done": "مکمل ہو گیا۔ آپ کا شیئر کردہ مواد Quran Lab کے سرورز سے حذف کر دیا گیا ہے۔ جو کاپیاں ماڈل کی ٹریننگ کے لیے پہلے استعمال ہو چکی ہیں، انہیں آئندہ کی ٹریننگ میں شامل نہیں کیا جائے گا۔",
|
|
444
|
+
"delete.failed.title": "حذف نہیں ہو سکا",
|
|
445
|
+
"delete.failed.network": "Quran Lab سے رابطہ نہیں ہو سکا۔ کچھ بھی حذف نہیں ہوا۔ اپنا انٹرنیٹ کنکشن چیک کریں اور دوبارہ کوشش کریں۔",
|
|
446
|
+
"delete.retry": "دوبارہ کوشش کریں",
|
|
447
|
+
"recovery.hint": "اگر آپ کی یہ ڈیوائس گم ہو جائے، تو اپنا شیئر کردہ مواد ڈیلیٹ کرنے کے لیے یہ یک وقتی کوڈ اپنے پاس محفوظ رکھیں: portal.quranlab.ai/delete",
|
|
448
|
+
"recovery.reveal": "ریکوری کوڈ دکھائیں",
|
|
449
|
+
"recovery.copy": "کاپی کریں",
|
|
450
|
+
"recovery.copied": "کاپی ہو گیا",
|
|
451
|
+
"recovery.keep": "اس کوڈ کو محفوظ رکھیں۔ کسی اور ڈیوائس سے اپنا شیئر کردہ مواد حذف کرنے کا یہ واحد طریقہ ہے، اور یہ صرف ایک بار استعمال ہو سکتا ہے۔",
|
|
452
|
+
"recovery.used": "یہ ریکوری کوڈ پہلے ہی استعمال ہو چکا ہے۔",
|
|
453
|
+
"recovery.invalid": "یہ کوڈ درست نہیں ہے۔ الفاظ چیک کر کے دوبارہ کوشش کریں۔",
|
|
366
454
|
"reask": "آج آپ کی تلاوت سے کل کسی اور سیکھنے والے کی مدد ہو سکتی ہے۔ کیا آپ اسے شیئر کرنا چاہیں گے؟",
|
|
367
455
|
"impact.minutes": {
|
|
368
456
|
"one": "آپ نے تلاوت کا {minutes} منٹ شیئر کیا ہے۔ اللہ تعالیٰ آپ کو جزائے خیر عطا فرمائے۔",
|