From c388cf7a9630d426d6ee9914cdb522096cfbc36e Mon Sep 17 00:00:00 2001 From: Luis Guzman Date: Fri, 28 Aug 2026 09:14:55 -0600 Subject: [PATCH 1/5] ADFA-4898 (follow-up): confirmed cancel + movement-based stall hint for a running module install MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The remaining in-flight controls of ADFA-4898 (which shipped failure surfacing + retry). P5 — confirmed cancel + immediate retry: cancel a running module from its live card. A strong confirmation, then a clean kill of the runrole (proot --kill-on-exit takes its container children), local_vars rolled back to install/enabled: False so a half-installed module is never offered as installed, and the module marked failed so the existing per-module Retry appears at once. Ordering mirrors finishModuleQueue (InstallGuard cleared before postDone) so the pdsm-stopped server restarts; the base system is untouched. Cancel reuses the host detail bar's secondary slot (Back stays primary). revertModuleInLocalVars now writes explicit False (was delete-only), covering the graceful-failure path too. P4 — movement-based stall hint (surface only): a running module with no runrole output and no write-directory growth for a generous window (120s, above Freshness.STALE_MS) shows a "seems stalled" hint on the live card, next to the Cancel/Retry escape. It never auto-kills: the foreground service keeps running and the hint clears when movement resumes or on a terminal. Heartbeat stamped on each log line + a bounded, file-capped write-dir growth backstop for quiet network phases (calibre-web's git clone); published via a separate stalled LiveData kept out of the immutable ModuleQueueState. --- .../install/presentation/InstallService.java | 126 +++++++++++++++++- .../presentation/ModuleQueueRepository.java | 17 ++- .../redesign/ModuleInstallFragment.java | 10 ++ .../redesign/SetupProgressActivity.java | 33 ++++- .../app/src/main/res/values/strings.xml | 7 + 5 files changed, 181 insertions(+), 12 deletions(-) diff --git a/controller/app/src/main/java/org/iiab/controller/install/presentation/InstallService.java b/controller/app/src/main/java/org/iiab/controller/install/presentation/InstallService.java index 378053121..7363b2b03 100644 --- a/controller/app/src/main/java/org/iiab/controller/install/presentation/InstallService.java +++ b/controller/app/src/main/java/org/iiab/controller/install/presentation/InstallService.java @@ -135,6 +135,15 @@ public final class InstallService extends Service { private volatile boolean finished = false; private volatile boolean started = false; + // ADFA-4898 P4: movement-based stall detection for the running module (surface only, never kills). + /** Generous, minute-scale: well above a quiet git-clone/apt phase, so a slow-but-alive install is + * never flagged. Above Freshness.STALE_MS (30s), which is tuned for ~1s-cadence REST polls. */ + private static final long MODULE_STALL_MS = 120_000L; + private static final long MODULE_STALL_POLL_MS = 15_000L; + private volatile long lastModuleMovementMs = 0L; // stamped on a runrole output line OR write-dir growth + private volatile long lastModuleDirSize = -1L; + private Runnable moduleStallCheck; // main-thread poller; null when not watching + /** * ADFA-5119: which kind of work is running, for the one question Cancel has to answer — does * abandoning it leave the device with no system (see {@code AbandonedInstall}). @@ -955,9 +964,11 @@ private void installNextModule() { // ADFA-4435: Ansible can print its failure to stdout yet still exit 0, so the verdict // considers the output as well as the exit code (pure, unit-tested domain object). final AnsibleRunOutcome outcome = new AnsibleRunOutcome(); + startModuleStallWatch(nextModule); // ADFA-4898 P4: watch this runrole for a stall (surface only) prootEngine.executeInContainer(this, debianRootfs.getAbsolutePath(), installCmd, new PRootEngine.OutputListener() { @Override public void onOutputLine(String line) { + lastModuleMovementMs = android.os.SystemClock.elapsedRealtime(); // ADFA-4898 P4: heartbeat outcome.observe(line); log("[Ansible] " + line); // ADFA-5228: advance the determinate bar as known tasks are reached. Post only on a @@ -1043,12 +1054,20 @@ private static long estimateEtaSeconds(org.iiab.controller.install.domain.Runrol } /** - * ADFA-4435: roll back the speculative local_vars edit made before runrole, so a failed - * install is not left looking installed/enabled. Always runs {@code then} afterwards. + * ADFA-4435: roll back the speculative local_vars edit made before runrole, so a failed or + * cancelled install is not left looking installed/enabled. Always runs {@code then} afterwards. + * + *

ADFA-4898 P5: write {@code _install: False} / {@code _enabled: False} explicitly + * rather than only deleting the speculative lines. Both read as "not installed" (the reader keys on + * the flag being true), but an explicit False also tells a later ansible run the module is off, so a + * partially-installed module is never offered as installed. The leading sed-delete keeps it + * idempotent, and the write-before-runrole path deletes these lines before echoing True on a retry. */ private void revertModuleInLocalVars(String module, Runnable then) { if (prootEngine == null) prootEngine = new PRootEngine(); - String revertCmd = "sed -i -E '/^[[:space:]]*" + module + "_(install|enabled)[[:space:]]*:/d' /etc/iiab/local_vars.yml"; + String revertCmd = "sed -i -E '/^[[:space:]]*" + module + "_(install|enabled)[[:space:]]*:/d' /etc/iiab/local_vars.yml && " + + "echo '" + module + "_install: False' >> /etc/iiab/local_vars.yml && " + + "echo '" + module + "_enabled: False' >> /etc/iiab/local_vars.yml"; prootEngine.executeInContainer(this, debianRootfs.getAbsolutePath(), revertCmd, new PRootEngine.OutputListener() { @Override public void onOutputLine(String line) { } @Override public void onProcessExit(int exitCode) { then.run(); } @@ -1056,6 +1075,81 @@ private void revertModuleInLocalVars(String module, Runnable then) { }); } + // ---- ADFA-4898 P4: movement-based stall watch (surface only, never kills) ------------------- + + /** + * Watch the running module for movement — a runrole output line (stamped in onOutputLine) OR growth + * of its on-disk write directory. When neither moves for {@link #MODULE_STALL_MS}, publish a + * "stalled" hint the live card shows; the install is never touched. Re-armed per module; the + * dir-growth backstop covers quiet network phases (e.g. calibre-web's git clone) that emit no log. + */ + private void startModuleStallWatch(final String moduleKey) { + stopModuleStallWatch(); + lastModuleMovementMs = android.os.SystemClock.elapsedRealtime(); + lastModuleDirSize = -1L; + ModuleQueueRepository.get().postStalled(false); + moduleStallCheck = new Runnable() { + @Override public void run() { + if (finished || cancelled) return; + org.iiab.controller.util.AppExecutors.get().io().execute(() -> { + long size = moduleWriteDirSize(moduleKey); + if (size >= 0 && size != lastModuleDirSize) { + lastModuleDirSize = size; + lastModuleMovementMs = android.os.SystemClock.elapsedRealtime(); + } + boolean fresh = org.iiab.controller.env.Freshness.fresh( + lastModuleMovementMs, android.os.SystemClock.elapsedRealtime(), MODULE_STALL_MS); + ModuleQueueRepository.get().postStalled(!fresh); + }); + heldHandler.postDelayed(this, MODULE_STALL_POLL_MS); + } + }; + heldHandler.postDelayed(moduleStallCheck, MODULE_STALL_POLL_MS); + } + + private void stopModuleStallWatch() { + if (moduleStallCheck != null) { heldHandler.removeCallbacks(moduleStallCheck); moduleStallCheck = null; } + ModuleQueueRepository.get().postStalled(false); + } + + /** Total bytes under the module's write directory on the host rootfs, or -1 if unknown/absent. */ + private long moduleWriteDirSize(String key) { + String rel = moduleWriteDirRel(key); + if (rel == null || debianRootfs == null) return -1L; + File d = new File(debianRootfs, rel); + if (!d.isDirectory()) return -1L; + return boundedDirSize(d, 20000); + } + + /** Where each module does its heavy on-disk writes (relative to the rootfs), for the growth backstop. */ + private static String moduleWriteDirRel(String key) { + if (key == null) return null; + switch (key) { + case "calibreweb": return "usr/local/calibre-web-py3"; // git clone + venv + case "maps": return "library/downloads/maps"; + case "matomo": return "library/www/matomo"; + case "kolibri": return "var/cache/apt/archives"; // chatty on stdout too; disk is the fallback + default: return null; + } + } + + /** Iterative, file-capped directory size so a large tree can't make the poll expensive. */ + private static long boundedDirSize(File root, int fileCap) { + long total = 0L; int count = 0; + java.util.ArrayDeque stack = new java.util.ArrayDeque<>(); + stack.push(root); + while (!stack.isEmpty() && count < fileCap) { + File[] kids = stack.pop().listFiles(); + if (kids == null) continue; + for (File k : kids) { + if (count >= fileCap) break; + if (k.isDirectory()) stack.push(k); + else { total += k.length(); count++; } + } + } + return total; + } + /** * ADFA-4900: build the maps runrole command from the wizard's per-layer selection. Translates * the selection into the maps role's local_vars (roles/maps/tasks/install_frontend.yml): @@ -1096,6 +1190,7 @@ public static void retryModules(Context ctx, java.util.List modules) { private void finishModuleQueue() { if (finished) return; finished = true; + stopModuleStallWatch(); // ADFA-4898 P4 persistClearQueue(); // ADFA-4842: clear the durable install guard BEFORE publishing DONE so the LibraryActivity // observer that restarts the server (canStartServer() requires !InstallGuard.inProgress) is not @@ -1485,10 +1580,27 @@ private void doCancel() { } catch (Exception ignored) { } if (moduleMode) { - persistClearQueue(); - ModuleQueueRepository.get().postDone( - failedModules != null ? new java.util.ArrayList<>(failedModules) : new java.util.ArrayList<>()); - teardown(); + // ADFA-4898 P5: user-confirmed cancel of a running module install. Kill the in-flight runrole + // (proot runs with --kill-on-exit, so its container children go with it), roll back that + // module's speculative _install so a cancel is not left looking installed, and surface it + // as failed so the existing per-module Retry is offered immediately. Ordering mirrors + // finishModuleQueue: clear InstallGuard BEFORE postDone so the server-restart observer (the + // server was pdsm-stopped for the runroles) is not raced by teardown's later clear. + final String cur = ModuleQueueRepository.get().current().currentModule; + stopModuleStallWatch(); // ADFA-4898 P4 + if (prootEngine != null) prootEngine.killProcess(); + if (failedModules == null) failedModules = new java.util.ArrayList<>(); + if (cur != null && !failedModules.contains(cur)) failedModules.add(cur); + final java.util.List failedSnapshot = new java.util.ArrayList<>(failedModules); + final Runnable finishCancel = () -> { + persistClearQueue(); + org.iiab.controller.InstallGuard.end(this); + ModuleQueueRepository.get().postDone(failedSnapshot); + if (!failedSnapshot.isEmpty()) postModuleFailureNotification(failedSnapshot); + teardown(); + }; + if (cur != null) revertModuleInLocalVars(cur, finishCancel); // best-effort rollback, then finish + else finishCancel.run(); return; } if (!org.iiab.controller.install.domain.AbandonedInstall.leavesNoSystem(work)) { diff --git a/controller/app/src/main/java/org/iiab/controller/install/presentation/ModuleQueueRepository.java b/controller/app/src/main/java/org/iiab/controller/install/presentation/ModuleQueueRepository.java index f5d431568..ab9830971 100644 --- a/controller/app/src/main/java/org/iiab/controller/install/presentation/ModuleQueueRepository.java +++ b/controller/app/src/main/java/org/iiab/controller/install/presentation/ModuleQueueRepository.java @@ -29,6 +29,9 @@ public static ModuleQueueRepository get() { } private final MutableLiveData state = new MutableLiveData<>(ModuleQueueState.idle()); + /** ADFA-4898 P4: movement-based stall hint for the current module (surface only, never auto-kill). + * Kept separate from the immutable ModuleQueueState so a transient hint never rewrites the queue. */ + private final MutableLiveData stalled = new MutableLiveData<>(false); private long seq = 0L; private ModuleQueueRepository() { @@ -38,6 +41,16 @@ public LiveData state() { return state; } + /** ADFA-4898 P4: true while the current module's runrole has shown no movement (log line or write-dir + * growth) for the stall window. A surface-only hint — the install keeps running. */ + public LiveData stalled() { + return stalled; + } + + public void postStalled(boolean isStalled) { + stalled.postValue(isStalled); + } + public ModuleQueueState current() { ModuleQueueState s = state.getValue(); return s != null ? s : ModuleQueueState.idle(); @@ -64,8 +77,8 @@ public boolean isInstalling(String moduleKey) { public void postRunning(String currentModule, int remaining, int percent) { post(ModuleQueueState.running(currentModule, remaining, percent)); } /** ADFA-5228: running with a determinate percent and an estimated seconds-remaining. */ public void postRunning(String currentModule, int remaining, int percent, long etaSeconds) { post(ModuleQueueState.running(currentModule, remaining, percent, etaSeconds)); } - public void postDone(List failedModules) { post(ModuleQueueState.done(failedModules)); } - public void postIdle() { post(ModuleQueueState.idle()); } + public void postDone(List failedModules) { stalled.postValue(false); post(ModuleQueueState.done(failedModules)); } + public void postIdle() { stalled.postValue(false); post(ModuleQueueState.idle()); } private synchronized void post(ModuleQueueState s) { state.postValue(s.withSeq(++seq)); diff --git a/controller/app/src/main/java/org/iiab/controller/redesign/ModuleInstallFragment.java b/controller/app/src/main/java/org/iiab/controller/redesign/ModuleInstallFragment.java index 8a5514f9d..77943a1ad 100644 --- a/controller/app/src/main/java/org/iiab/controller/redesign/ModuleInstallFragment.java +++ b/controller/app/src/main/java/org/iiab/controller/redesign/ModuleInstallFragment.java @@ -84,6 +84,16 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c updateStatus(); ModuleQueueRepository.get().state().observe(getViewLifecycleOwner(), st -> updateStatus()); + // ADFA-4898 P4: surface a "seems stalled" hint over the frozen status line while this module is + // the one running and no movement (log line / write-dir growth) has arrived for the stall window. + // Surface only — the install keeps going; a new log line or updateStatus restores the live line. + ModuleQueueRepository.get().stalled().observe(getViewLifecycleOwner(), s -> { + if (Boolean.TRUE.equals(s) && installing() && !terminalDone) { + status.setText(getString(R.string.k2go_mod_phase_stalled)); + } else { + updateStatus(); + } + }); logListener = new LogRepository.Listener() { @Override public void onAppend(String line) { diff --git a/controller/app/src/main/java/org/iiab/controller/redesign/SetupProgressActivity.java b/controller/app/src/main/java/org/iiab/controller/redesign/SetupProgressActivity.java index ca64c5873..9276968b1 100644 --- a/controller/app/src/main/java/org/iiab/controller/redesign/SetupProgressActivity.java +++ b/controller/app/src/main/java/org/iiab/controller/redesign/SetupProgressActivity.java @@ -1321,15 +1321,26 @@ private boolean isLiveDetail(String key) { */ private void configureDetailBar() { if (!showingDetail || detailKey == null || detailBackBtn == null) return; - boolean moduleFailed = detailKey.startsWith("mod:") - && ModuleQueueRepository.get().current().didFail(detailKey.substring(4)); + final boolean isModule = detailKey.startsWith("mod:"); + final String moduleKey = isModule ? detailKey.substring(4) : null; + ModuleQueueState mq = ModuleQueueRepository.get().current(); + boolean moduleFailed = isModule && mq.didFail(moduleKey); + boolean moduleRunning = isModule && mq.isInstalling(moduleKey); if (moduleFailed) { - final String moduleKey = detailKey.substring(4); detailBackBtn.setText(R.string.k2go_home_retry); detailBackBtn.setOnClickListener(v -> ModuleRetry.fire(v, moduleKey)); detailRunBgBtn.setText(R.string.k2go_setup_back); detailRunBgBtn.setOnClickListener(v -> backToIndex()); detailRunBgBtn.setVisibility(View.VISIBLE); + } else if (moduleRunning) { + // ADFA-4898 P5: while this module's runrole runs, offer a confirmed Cancel in the same + // secondary slot (Back stays primary). Cancel kills the runrole and surfaces the module as + // failed, so the Retry above appears on the next tick — the "immediate retry" of the ticket. + detailBackBtn.setText(R.string.k2go_setup_back); + detailBackBtn.setOnClickListener(v -> backToIndex()); + detailRunBgBtn.setText(R.string.k2go_setup_cancel); + detailRunBgBtn.setOnClickListener(v -> confirmCancelModule()); + detailRunBgBtn.setVisibility(View.VISIBLE); } else { detailBackBtn.setText(R.string.k2go_setup_back); detailBackBtn.setOnClickListener(v -> backToIndex()); @@ -1339,6 +1350,22 @@ private void configureDetailBar() { } } + /** + * ADFA-4898 P5: strong confirmation before cancelling a running module install, then send + * ACTION_CANCEL. The service kills the runrole (proot --kill-on-exit), rolls back the speculative + * flag and marks the module failed; the base system is untouched and the server restarts. + */ + private void confirmCancelModule() { + new com.google.android.material.dialog.MaterialAlertDialogBuilder(this) + .setTitle(R.string.k2go_mod_cancel_title) + .setMessage(R.string.k2go_mod_cancel_body) + .setNegativeButton(R.string.k2go_mod_cancel_dismiss, null) + .setPositiveButton(R.string.k2go_mod_cancel_confirm, (d, w) -> + startService(new Intent(this, org.iiab.controller.install.presentation.InstallService.class) + .setAction(org.iiab.controller.install.presentation.InstallService.ACTION_CANCEL))) + .show(); + } + private void backToIndex() { showingDetail = false; detailKey = null; diff --git a/controller/app/src/main/res/values/strings.xml b/controller/app/src/main/res/values/strings.xml index f3e25ccd7..700c56fcc 100644 --- a/controller/app/src/main/res/values/strings.xml +++ b/controller/app/src/main/res/values/strings.xml @@ -734,6 +734,13 @@ Installing… Installed Couldn\'t install + + Still working — this is taking longer than usual. You can keep waiting, or cancel and retry. + + Stop installing? + What\'s been done so far is rolled back and the module won\'t be installed. You can start it again afterward. + Stop install + Keep installing This can take a while. Thanks for your patience. Installing a module changes the system and can take a while. You can safely leave the screen because the installation will continue in the background. From 7ff8bb2d0596247850f4f8c08e3d3101717095f4 Mon Sep 17 00:00:00 2001 From: Luis Guzman Date: Fri, 28 Aug 2026 09:35:31 -0600 Subject: [PATCH 2/5] ADFA-4898 (follow-up): fix compile errors in the cancel/stall change - ModuleInstallFragment: rename the stalled-observer lambda param, which shadowed the onCreateView Bundle parameter `s`. - SetupProgressActivity: qualify Intent as android.content.Intent in confirmCancelModule (the class was not imported). --- .../org/iiab/controller/redesign/ModuleInstallFragment.java | 4 ++-- .../org/iiab/controller/redesign/SetupProgressActivity.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/controller/app/src/main/java/org/iiab/controller/redesign/ModuleInstallFragment.java b/controller/app/src/main/java/org/iiab/controller/redesign/ModuleInstallFragment.java index 77943a1ad..5918e8895 100644 --- a/controller/app/src/main/java/org/iiab/controller/redesign/ModuleInstallFragment.java +++ b/controller/app/src/main/java/org/iiab/controller/redesign/ModuleInstallFragment.java @@ -87,8 +87,8 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c // ADFA-4898 P4: surface a "seems stalled" hint over the frozen status line while this module is // the one running and no movement (log line / write-dir growth) has arrived for the stall window. // Surface only — the install keeps going; a new log line or updateStatus restores the live line. - ModuleQueueRepository.get().stalled().observe(getViewLifecycleOwner(), s -> { - if (Boolean.TRUE.equals(s) && installing() && !terminalDone) { + ModuleQueueRepository.get().stalled().observe(getViewLifecycleOwner(), isStalled -> { + if (Boolean.TRUE.equals(isStalled) && installing() && !terminalDone) { status.setText(getString(R.string.k2go_mod_phase_stalled)); } else { updateStatus(); diff --git a/controller/app/src/main/java/org/iiab/controller/redesign/SetupProgressActivity.java b/controller/app/src/main/java/org/iiab/controller/redesign/SetupProgressActivity.java index 9276968b1..42b5a0c00 100644 --- a/controller/app/src/main/java/org/iiab/controller/redesign/SetupProgressActivity.java +++ b/controller/app/src/main/java/org/iiab/controller/redesign/SetupProgressActivity.java @@ -1361,7 +1361,7 @@ private void confirmCancelModule() { .setMessage(R.string.k2go_mod_cancel_body) .setNegativeButton(R.string.k2go_mod_cancel_dismiss, null) .setPositiveButton(R.string.k2go_mod_cancel_confirm, (d, w) -> - startService(new Intent(this, org.iiab.controller.install.presentation.InstallService.class) + startService(new android.content.Intent(this, org.iiab.controller.install.presentation.InstallService.class) .setAction(org.iiab.controller.install.presentation.InstallService.ACTION_CANCEL))) .show(); } From ca203e1bd4f9495d3d949eccc1d99a779d789a06 Mon Sep 17 00:00:00 2001 From: Luis Guzman Date: Fri, 28 Aug 2026 09:41:05 -0600 Subject: [PATCH 3/5] ADFA-4898 (follow-up): park the new P4/P5 strings in strings_beta_notranslate_yet.xml The 5 new strings (P4 stall hint + P5 cancel-confirm dialog) move out of strings.xml into a translatable="false" beta file, so the build stays clean (no MissingTranslation) until the 33 locales are translated. Move each back into strings.xml (dropping translatable="false") when its translations land. --- controller/app/src/main/res/values/strings.xml | 7 ------- .../res/values/strings_beta_notranslate_yet.xml | 13 +++++++++++++ 2 files changed, 13 insertions(+), 7 deletions(-) create mode 100644 controller/app/src/main/res/values/strings_beta_notranslate_yet.xml diff --git a/controller/app/src/main/res/values/strings.xml b/controller/app/src/main/res/values/strings.xml index 700c56fcc..f3e25ccd7 100644 --- a/controller/app/src/main/res/values/strings.xml +++ b/controller/app/src/main/res/values/strings.xml @@ -734,13 +734,6 @@ Installing… Installed Couldn\'t install - - Still working — this is taking longer than usual. You can keep waiting, or cancel and retry. - - Stop installing? - What\'s been done so far is rolled back and the module won\'t be installed. You can start it again afterward. - Stop install - Keep installing This can take a while. Thanks for your patience. Installing a module changes the system and can take a while. You can safely leave the screen because the installation will continue in the background. diff --git a/controller/app/src/main/res/values/strings_beta_notranslate_yet.xml b/controller/app/src/main/res/values/strings_beta_notranslate_yet.xml new file mode 100644 index 000000000..fa294d073 --- /dev/null +++ b/controller/app/src/main/res/values/strings_beta_notranslate_yet.xml @@ -0,0 +1,13 @@ + + + + + Still working — this is taking longer than usual. You can keep waiting, or cancel and retry. + + Stop installing? + What\'s been done so far is rolled back and the module won\'t be installed. You can start it again afterward. + Stop install + Keep installing + From 895a71b3075319867e8c0487065f2519b6739172 Mon Sep 17 00:00:00 2001 From: Luis Guzman Date: Fri, 28 Aug 2026 10:02:53 -0600 Subject: [PATCH 4/5] ADFA-4898 (follow-up): make stall write-dir drift visible (code-review fondo) The per-module write-dir map is a best-effort backstop and a silent drift point. Keep it fail-safe (a wrong/missing path just falls back to the log heartbeat, never a false verdict) but log the unmapped case at watch start, so a module added without a mapped dir is noticed in logcat instead of silently losing its growth backstop. Comment updated (keep-in-sync + fail-safe). --- .../install/presentation/InstallService.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/controller/app/src/main/java/org/iiab/controller/install/presentation/InstallService.java b/controller/app/src/main/java/org/iiab/controller/install/presentation/InstallService.java index 7363b2b03..06c7be3d7 100644 --- a/controller/app/src/main/java/org/iiab/controller/install/presentation/InstallService.java +++ b/controller/app/src/main/java/org/iiab/controller/install/presentation/InstallService.java @@ -1088,6 +1088,13 @@ private void startModuleStallWatch(final String moduleKey) { lastModuleMovementMs = android.os.SystemClock.elapsedRealtime(); lastModuleDirSize = -1L; ModuleQueueRepository.get().postStalled(false); + // ADFA-4898 P4: make write-dir drift visible instead of silent. If a module has no mapped dir + // (a new module added without updating moduleWriteDirRel), the watch still works off the log + // heartbeat — but this line says so in the log, so the missing backstop is noticed, not hidden. + if (moduleWriteDirRel(moduleKey) == null) { + log("[Stall] no write-dir backstop mapped for '" + moduleKey + + "'; stall watch relies on the log heartbeat only"); + } moduleStallCheck = new Runnable() { @Override public void run() { if (finished || cancelled) return; @@ -1121,7 +1128,12 @@ private long moduleWriteDirSize(String key) { return boundedDirSize(d, 20000); } - /** Where each module does its heavy on-disk writes (relative to the rootfs), for the growth backstop. */ + /** + * Where each module does its heavy on-disk writes (relative to the rootfs), for the stall watch's + * growth backstop. Heuristic and best-effort — keep it in sync with the ansible roles. If a key is + * unmapped or the path drifts, the watch silently falls back to the log heartbeat (never a false + * verdict); {@link #startModuleStallWatch} logs the unmapped case so that drift is visible, not silent. + */ private static String moduleWriteDirRel(String key) { if (key == null) return null; switch (key) { From c5eae99c1c51024609e90b97e53894efba42f0b8 Mon Sep 17 00:00:00 2001 From: Luis Guzman Date: Fri, 28 Aug 2026 12:13:33 -0600 Subject: [PATCH 5/5] ADFA-4898 (follow-up): localize the P4/P5 strings across all locales Move the 5 new strings (P4 stall hint + P5 cancel-confirm dialog) out of the temporary strings_beta_notranslate_yet.xml holding file into strings.xml (default English) and add translations to every values-*/strings.xml, so the build is clean (no MissingTranslation) with the strings fully localized. The non-English translations are best-effort and should get a native-speaker / translation-service review pass before release; the wording is easy to refine per locale since each lives in its own values-*/strings.xml. --- controller/app/src/main/res/values-ar/strings.xml | 5 +++++ controller/app/src/main/res/values-az/strings.xml | 5 +++++ controller/app/src/main/res/values-bg/strings.xml | 5 +++++ controller/app/src/main/res/values-bn/strings.xml | 5 +++++ controller/app/src/main/res/values-cs/strings.xml | 5 +++++ controller/app/src/main/res/values-de/strings.xml | 5 +++++ controller/app/src/main/res/values-el/strings.xml | 5 +++++ controller/app/src/main/res/values-es/strings.xml | 5 +++++ controller/app/src/main/res/values-fa/strings.xml | 5 +++++ controller/app/src/main/res/values-fr/strings.xml | 5 +++++ controller/app/src/main/res/values-gu/strings.xml | 5 +++++ controller/app/src/main/res/values-hi/strings.xml | 5 +++++ controller/app/src/main/res/values-hu/strings.xml | 5 +++++ controller/app/src/main/res/values-in/strings.xml | 5 +++++ controller/app/src/main/res/values-it/strings.xml | 5 +++++ controller/app/src/main/res/values-ja/strings.xml | 5 +++++ controller/app/src/main/res/values-ko/strings.xml | 5 +++++ controller/app/src/main/res/values-lt/strings.xml | 5 +++++ controller/app/src/main/res/values-nl/strings.xml | 5 +++++ controller/app/src/main/res/values-no/strings.xml | 5 +++++ controller/app/src/main/res/values-pl/strings.xml | 5 +++++ controller/app/src/main/res/values-pt/strings.xml | 5 +++++ controller/app/src/main/res/values-ro/strings.xml | 5 +++++ .../app/src/main/res/values-ru-rRU/strings.xml | 5 +++++ controller/app/src/main/res/values-sk/strings.xml | 5 +++++ controller/app/src/main/res/values-sr/strings.xml | 5 +++++ controller/app/src/main/res/values-sw/strings.xml | 5 +++++ controller/app/src/main/res/values-ta/strings.xml | 5 +++++ controller/app/src/main/res/values-tr/strings.xml | 5 +++++ controller/app/src/main/res/values-uk/strings.xml | 5 +++++ controller/app/src/main/res/values-vi/strings.xml | 5 +++++ controller/app/src/main/res/values-yo/strings.xml | 5 +++++ .../app/src/main/res/values-zh-rCN/strings.xml | 5 +++++ controller/app/src/main/res/values/strings.xml | 5 +++++ .../res/values/strings_beta_notranslate_yet.xml | 13 ------------- 35 files changed, 170 insertions(+), 13 deletions(-) delete mode 100644 controller/app/src/main/res/values/strings_beta_notranslate_yet.xml diff --git a/controller/app/src/main/res/values-ar/strings.xml b/controller/app/src/main/res/values-ar/strings.xml index f8067e845..ca2fdb56b 100644 --- a/controller/app/src/main/res/values-ar/strings.xml +++ b/controller/app/src/main/res/values-ar/strings.xml @@ -1286,4 +1286,9 @@ %1$d دورة لم تكتمل. أعد محاولة ما فشل قبل المغادرة — المغادرة تمسح هذه القائمة. تم تحديث الكتالوج في %1$s + لا يزال يعمل — يستغرق وقتًا أطول من المعتاد. يمكنك الانتظار أو الإلغاء وإعادة المحاولة. + إيقاف التثبيت؟ + يُتراجع عمّا تم حتى الآن ولن يُثبَّت المكوّن. يمكنك بدؤه من جديد لاحقًا. + إيقاف التثبيت + متابعة التثبيت diff --git a/controller/app/src/main/res/values-az/strings.xml b/controller/app/src/main/res/values-az/strings.xml index 8280a692e..c82105c9e 100644 --- a/controller/app/src/main/res/values-az/strings.xml +++ b/controller/app/src/main/res/values-az/strings.xml @@ -1306,4 +1306,9 @@ %1$d kurs tamamlanmadı. Getməzdən əvvəl uğursuzları yenidən yoxlayın — çıxış bu siyahını silir. Kataloq %1$s tarixində yeniləndi + Hələ də işləyir — bu, adətən olduğundan daha uzun çəkir. Gözləyə, yaxud ləğv edib yenidən cəhd edə bilərsiniz. + Quraşdırma dayandırılsın? + İndiyədək edilənlər geri qaytarılır və modul quraşdırılmayacaq. Onu sonra yenidən başlada bilərsiniz. + Quraşdırmanı dayandır + Quraşdırmaya davam et diff --git a/controller/app/src/main/res/values-bg/strings.xml b/controller/app/src/main/res/values-bg/strings.xml index aef55b869..5bd3a6747 100644 --- a/controller/app/src/main/res/values-bg/strings.xml +++ b/controller/app/src/main/res/values-bg/strings.xml @@ -1293,4 +1293,9 @@ %1$d курса не завършиха. Опитайте отново неуспешните, преди да излезете — излизането изчиства този списък. Каталогът е обновен на %1$s + Все още работи — отнема повече време от обичайното. Можете да изчакате или да откажете и опитате отново. + Спиране на инсталацията? + Направеното дотук се връща назад и модулът няма да бъде инсталиран. Можете да го стартирате отново по-късно. + Спри + Продължи инсталацията diff --git a/controller/app/src/main/res/values-bn/strings.xml b/controller/app/src/main/res/values-bn/strings.xml index 3c5b35069..9ebc2b612 100644 --- a/controller/app/src/main/res/values-bn/strings.xml +++ b/controller/app/src/main/res/values-bn/strings.xml @@ -1299,4 +1299,9 @@ %1$dটি কোর্স শেষ হয়নি। চলে যাওয়ার আগে ব্যর্থগুলো আবার চেষ্টা করুন — চলে গেলে এই তালিকা মুছে যাবে। ক্যাটালগ %1$s তারিখে আপডেট হয়েছে + এখনও চলছে — এটি স্বাভাবিকের চেয়ে বেশি সময় নিচ্ছে। আপনি অপেক্ষা করতে পারেন, অথবা বাতিল করে আবার চেষ্টা করতে পারেন। + ইনস্টল করা বন্ধ করবেন? + এ পর্যন্ত যা হয়েছে তা পূর্বাবস্থায় ফিরিয়ে আনা হয় এবং মডিউলটি ইনস্টল হবে না। আপনি পরে আবার এটি শুরু করতে পারেন। + ইনস্টল বন্ধ করুন + ইনস্টল চালিয়ে যান diff --git a/controller/app/src/main/res/values-cs/strings.xml b/controller/app/src/main/res/values-cs/strings.xml index 2adb84883..9b36932ee 100644 --- a/controller/app/src/main/res/values-cs/strings.xml +++ b/controller/app/src/main/res/values-cs/strings.xml @@ -1293,4 +1293,9 @@ %1$d kurzů se nedokončilo. Než odejdete, zkuste neúspěšné znovu — odchodem se tento seznam smaže. Katalog aktualizován %1$s + Stále probíhá — trvá to déle než obvykle. Můžete počkat, nebo zrušit a zkusit to znovu. + Zastavit instalaci? + Dosud provedené se vrátí zpět a modul se nenainstaluje. Můžete jej spustit znovu později. + Zastavit + Pokračovat v instalaci diff --git a/controller/app/src/main/res/values-de/strings.xml b/controller/app/src/main/res/values-de/strings.xml index 2510e2136..3f6fea616 100644 --- a/controller/app/src/main/res/values-de/strings.xml +++ b/controller/app/src/main/res/values-de/strings.xml @@ -1286,4 +1286,9 @@ %1$d Kurse wurden nicht fertig. Wiederholen Sie die fehlgeschlagenen, bevor Sie gehen — beim Verlassen wird diese Liste gelöscht. Katalog aktualisiert am %1$s + Läuft noch — das dauert länger als üblich. Du kannst warten oder abbrechen und erneut versuchen. + Installation abbrechen? + Das bisher Erledigte wird zurückgesetzt und das Modul wird nicht installiert. Du kannst es später erneut starten. + Abbrechen + Weiter installieren diff --git a/controller/app/src/main/res/values-el/strings.xml b/controller/app/src/main/res/values-el/strings.xml index 2a61b1199..236d0aed1 100644 --- a/controller/app/src/main/res/values-el/strings.xml +++ b/controller/app/src/main/res/values-el/strings.xml @@ -1293,4 +1293,9 @@ %1$d μαθήματα δεν ολοκληρώθηκαν. Δοκιμάστε ξανά όσα απέτυχαν πριν φύγετε — η έξοδος διαγράφει αυτή τη λίστα. Ο κατάλογος ενημερώθηκε στις %1$s + Ακόμη σε εξέλιξη — καθυστερεί περισσότερο από το συνηθισμένο. Μπορείτε να περιμένετε ή να ακυρώσετε και να δοκιμάσετε ξανά. + Διακοπή εγκατάστασης; + Ό,τι έγινε μέχρι τώρα αναιρείται και η μονάδα δεν θα εγκατασταθεί. Μπορείτε να την ξεκινήσετε ξανά αργότερα. + Διακοπή + Συνέχιση εγκατάστασης diff --git a/controller/app/src/main/res/values-es/strings.xml b/controller/app/src/main/res/values-es/strings.xml index e66d5e9fa..d870ca286 100644 --- a/controller/app/src/main/res/values-es/strings.xml +++ b/controller/app/src/main/res/values-es/strings.xml @@ -1362,4 +1362,9 @@ %1$d curso(s) no terminaron. Reintenta los que fallaron antes de salir: al salir se borra esta lista. Catálogo actualizado el %1$s + Sigue trabajando — está tardando más de lo normal. Puedes seguir esperando, o cancelar y reintentar. + ¿Detener la instalación? + Lo hecho hasta ahora se revierte y el módulo no se instalará. Puedes iniciarlo de nuevo después. + Detener instalación + Seguir instalando diff --git a/controller/app/src/main/res/values-fa/strings.xml b/controller/app/src/main/res/values-fa/strings.xml index bf29379e0..1316a1b5e 100644 --- a/controller/app/src/main/res/values-fa/strings.xml +++ b/controller/app/src/main/res/values-fa/strings.xml @@ -1286,4 +1286,9 @@ %1$d دوره کامل نشد. پیش از خروج، موارد ناموفق را دوباره تلاش کنید — خروج این فهرست را پاک می‌کند. کاتالوگ در %1$s به‌روزرسانی شد + هنوز در حال کار است — بیش از حد معمول طول می‌کشد. می‌توانید صبر کنید یا لغو کرده و دوباره تلاش کنید. + نصب متوقف شود؟ + کارهای انجام‌شده تا کنون بازگردانده می‌شود و ماژول نصب نخواهد شد. می‌توانید بعداً دوباره آن را شروع کنید. + توقف نصب + ادامه نصب diff --git a/controller/app/src/main/res/values-fr/strings.xml b/controller/app/src/main/res/values-fr/strings.xml index ec7b5e489..87f187b77 100644 --- a/controller/app/src/main/res/values-fr/strings.xml +++ b/controller/app/src/main/res/values-fr/strings.xml @@ -1373,4 +1373,9 @@ %1$d cours ne se sont pas terminés. Réessayez ceux qui ont échoué avant de partir : quitter efface cette liste. Catalogue mis à jour le %1$s + Toujours en cours — cela prend plus de temps que d\'habitude. Vous pouvez patienter, ou annuler et réessayer. + Arrêter l\'installation ? + Ce qui a été fait jusqu\'ici est annulé et le module ne sera pas installé. Vous pourrez le relancer plus tard. + Arrêter + Continuer diff --git a/controller/app/src/main/res/values-gu/strings.xml b/controller/app/src/main/res/values-gu/strings.xml index 8d594244b..738dba5cf 100644 --- a/controller/app/src/main/res/values-gu/strings.xml +++ b/controller/app/src/main/res/values-gu/strings.xml @@ -1299,4 +1299,9 @@ %1$d કોર્સ પૂરા થયા નથી. જતાં પહેલાં નિષ્ફળ થયેલા ફરી પ્રયાસ કરો — જવાથી આ યાદી ભૂંસાઈ જશે. કૅટલૉગ %1$s ના રોજ અપડેટ થયું + હજી ચાલી રહ્યું છે — સામાન્ય કરતાં વધુ સમય લાગી રહ્યો છે. તમે રાહ જોઈ શકો છો, અથવા રદ કરીને ફરી પ્રયાસ કરી શકો છો. + ઇન્સ્ટોલ કરવાનું બંધ કરવું છે? + અત્યાર સુધી થયેલું પાછું વળે છે અને મોડ્યુલ ઇન્સ્ટોલ થશે નહીં. તમે તેને પછીથી ફરી શરૂ કરી શકો છો. + ઇન્સ્ટોલ બંધ કરો + ઇન્સ્ટોલ ચાલુ રાખો diff --git a/controller/app/src/main/res/values-hi/strings.xml b/controller/app/src/main/res/values-hi/strings.xml index 5a086a900..d48b3002a 100644 --- a/controller/app/src/main/res/values-hi/strings.xml +++ b/controller/app/src/main/res/values-hi/strings.xml @@ -1363,4 +1363,9 @@ %1$d कोर्स पूरे नहीं हुए। जाने से पहले विफल हुए फिर से आज़माएँ — जाने पर यह सूची मिट जाएगी। कैटलॉग %1$s को अपडेट हुआ + अभी भी चल रहा है — इसमें सामान्य से ज़्यादा समय लग रहा है. आप प्रतीक्षा कर सकते हैं, या रद्द करके फिर से कोशिश कर सकते हैं. + इंस्टॉल करना रोकें? + अब तक जो हुआ है वह पूर्ववत हो जाता है और मॉड्यूल इंस्टॉल नहीं होगा. आप इसे बाद में फिर से शुरू कर सकते हैं. + इंस्टॉल रोकें + इंस्टॉल जारी रखें diff --git a/controller/app/src/main/res/values-hu/strings.xml b/controller/app/src/main/res/values-hu/strings.xml index 16f779336..3b16d018e 100644 --- a/controller/app/src/main/res/values-hu/strings.xml +++ b/controller/app/src/main/res/values-hu/strings.xml @@ -1286,4 +1286,9 @@ %1$d tanfolyam nem fejeződött be. Távozás előtt próbálja újra a sikerteleneket — a kilépés törli ezt a listát. Katalógus frissítve: %1$s + Még dolgozik — a szokásosnál tovább tart. Várhatsz, vagy megszakíthatod és újrapróbálhatod. + Leállítod a telepítést? + Az eddigiek visszavonásra kerülnek, és a modul nem lesz telepítve. Később újraindíthatod. + Leállítás + Telepítés folytatása diff --git a/controller/app/src/main/res/values-in/strings.xml b/controller/app/src/main/res/values-in/strings.xml index 26111e8a5..b6ccf861f 100644 --- a/controller/app/src/main/res/values-in/strings.xml +++ b/controller/app/src/main/res/values-in/strings.xml @@ -1293,4 +1293,9 @@ %1$d kursus tidak selesai. Coba lagi yang gagal sebelum keluar — keluar akan menghapus daftar ini. Katalog diperbarui pada %1$s + Masih berjalan — ini memakan waktu lebih lama dari biasanya. Anda dapat menunggu, atau membatalkan dan mencoba lagi. + Hentikan pemasangan? + Yang sudah dilakukan sejauh ini dibatalkan dan modul tidak akan dipasang. Anda dapat memulainya lagi nanti. + Hentikan pemasangan + Lanjutkan pemasangan diff --git a/controller/app/src/main/res/values-it/strings.xml b/controller/app/src/main/res/values-it/strings.xml index aa9f4a619..d2d27ba81 100644 --- a/controller/app/src/main/res/values-it/strings.xml +++ b/controller/app/src/main/res/values-it/strings.xml @@ -1286,4 +1286,9 @@ %1$d corsi non sono stati completati. Riprova quelli falliti prima di uscire: uscendo questa lista viene cancellata. Catalogo aggiornato il %1$s + Ancora in corso — sta impiegando più del solito. Puoi aspettare, oppure annullare e riprovare. + Interrompere l\'installazione? + Quanto fatto finora viene annullato e il modulo non verrà installato. Puoi riavviarlo in seguito. + Interrompi + Continua a installare diff --git a/controller/app/src/main/res/values-ja/strings.xml b/controller/app/src/main/res/values-ja/strings.xml index a0ac87d4a..71bbd007e 100644 --- a/controller/app/src/main/res/values-ja/strings.xml +++ b/controller/app/src/main/res/values-ja/strings.xml @@ -1287,4 +1287,9 @@ %1$d 件のコースが完了しませんでした。 退出する前に失敗したものを再試行してください。退出するとこの一覧は消えます。 カタログの更新日: %1$s + まだ実行中です — 通常より時間がかかっています。このまま待つか、キャンセルして再試行できます。 + インストールを停止しますか? + これまでの作業は元に戻され、モジュールはインストールされません。後でもう一度開始できます。 + インストールを停止 + インストールを続行 diff --git a/controller/app/src/main/res/values-ko/strings.xml b/controller/app/src/main/res/values-ko/strings.xml index 1fa8cebdb..29719cbf9 100644 --- a/controller/app/src/main/res/values-ko/strings.xml +++ b/controller/app/src/main/res/values-ko/strings.xml @@ -1287,4 +1287,9 @@ %1$d개 강의가 완료되지 않았습니다. 나가기 전에 실패한 항목을 다시 시도하세요. 나가면 이 목록이 지워집니다. 카탈로그 업데이트: %1$s + 아직 진행 중입니다 — 평소보다 오래 걸리고 있습니다. 기다리거나, 취소하고 다시 시도할 수 있습니다. + 설치를 중지할까요? + 지금까지 진행된 내용은 되돌려지고 모듈이 설치되지 않습니다. 나중에 다시 시작할 수 있습니다. + 설치 중지 + 설치 계속 diff --git a/controller/app/src/main/res/values-lt/strings.xml b/controller/app/src/main/res/values-lt/strings.xml index 64e3767f7..9c436baec 100644 --- a/controller/app/src/main/res/values-lt/strings.xml +++ b/controller/app/src/main/res/values-lt/strings.xml @@ -1303,4 +1303,9 @@ %1$d kursų nebaigta. Prieš išeidami pakartokite nepavykusius — išėjus šis sąrašas išvalomas. Katalogas atnaujintas %1$s + Vis dar vyksta — tai užtrunka ilgiau nei įprastai. Galite palaukti arba atšaukti ir bandyti dar kartą. + Stabdyti diegimą? + Iki šiol atlikti veiksmai atšaukiami ir modulis nebus įdiegtas. Vėliau galėsite pradėti iš naujo. + Stabdyti diegimą + Tęsti diegimą diff --git a/controller/app/src/main/res/values-nl/strings.xml b/controller/app/src/main/res/values-nl/strings.xml index ebb16c263..0df7f56fa 100644 --- a/controller/app/src/main/res/values-nl/strings.xml +++ b/controller/app/src/main/res/values-nl/strings.xml @@ -1286,4 +1286,9 @@ %1$d cursussen zijn niet afgerond. Probeer de mislukte opnieuw voordat u weggaat — weggaan wist deze lijst. Catalogus bijgewerkt op %1$s + Nog bezig — dit duurt langer dan normaal. Je kunt wachten, of annuleren en opnieuw proberen. + Installatie stoppen? + Wat tot nu toe is gedaan wordt teruggedraaid en de module wordt niet geïnstalleerd. Je kunt het later opnieuw starten. + Stoppen + Doorgaan met installeren diff --git a/controller/app/src/main/res/values-no/strings.xml b/controller/app/src/main/res/values-no/strings.xml index 480ee893b..8ed937b15 100644 --- a/controller/app/src/main/res/values-no/strings.xml +++ b/controller/app/src/main/res/values-no/strings.xml @@ -1296,4 +1296,9 @@ %1$d kurs ble ikke ferdige. Prøv de mislykkede på nytt før du går — å gå tømmer denne listen. Katalog oppdatert %1$s + Fortsatt i gang — dette tar lengre tid enn vanlig. Du kan vente, eller avbryte og prøve igjen. + Stoppe installasjonen? + Det som er gjort så langt tilbakestilles, og modulen blir ikke installert. Du kan starte den på nytt senere. + Stopp installasjon + Fortsett installasjonen diff --git a/controller/app/src/main/res/values-pl/strings.xml b/controller/app/src/main/res/values-pl/strings.xml index 7b8750ed6..95fb33468 100644 --- a/controller/app/src/main/res/values-pl/strings.xml +++ b/controller/app/src/main/res/values-pl/strings.xml @@ -1296,4 +1296,9 @@ %1$d kursów nie ukończono. Ponów nieudane przed wyjściem — wyjście czyści tę listę. Katalog zaktualizowano %1$s + Wciąż trwa — trwa to dłużej niż zwykle. Możesz poczekać albo anulować i spróbować ponownie. + Zatrzymać instalację? + Dotychczasowe działania zostaną cofnięte, a moduł nie zostanie zainstalowany. Możesz uruchomić go ponownie później. + Zatrzymaj + Kontynuuj instalację diff --git a/controller/app/src/main/res/values-pt/strings.xml b/controller/app/src/main/res/values-pt/strings.xml index a9c776a40..6371e4ba8 100644 --- a/controller/app/src/main/res/values-pt/strings.xml +++ b/controller/app/src/main/res/values-pt/strings.xml @@ -1365,4 +1365,9 @@ %1$d curso(s) não terminaram. Tente de novo os que falharam antes de sair: sair apaga esta lista. Catálogo atualizado em %1$s + Ainda trabalhando — está demorando mais que o normal. Você pode aguardar, ou cancelar e tentar de novo. + Parar a instalação? + O que foi feito até agora é revertido e o módulo não será instalado. Você pode iniciá-lo novamente depois. + Parar instalação + Continuar instalando diff --git a/controller/app/src/main/res/values-ro/strings.xml b/controller/app/src/main/res/values-ro/strings.xml index 3b72ed08f..3c6fa3a91 100644 --- a/controller/app/src/main/res/values-ro/strings.xml +++ b/controller/app/src/main/res/values-ro/strings.xml @@ -1286,4 +1286,9 @@ %1$d cursuri nu s-au terminat. Reîncearcă-le pe cele eșuate înainte să pleci — plecarea șterge lista. Catalog actualizat pe %1$s + Încă lucrează — durează mai mult decât de obicei. Poți aștepta sau anula și reîncerca. + Oprești instalarea? + Ce s-a făcut până acum se anulează și modulul nu va fi instalat. Îl poți porni din nou mai târziu. + Oprește + Continuă instalarea diff --git a/controller/app/src/main/res/values-ru-rRU/strings.xml b/controller/app/src/main/res/values-ru-rRU/strings.xml index b60eda272..2f174681c 100644 --- a/controller/app/src/main/res/values-ru-rRU/strings.xml +++ b/controller/app/src/main/res/values-ru-rRU/strings.xml @@ -1362,4 +1362,9 @@ %1$d курс(ов) не завершились. Повторите неудавшиеся перед выходом — выход очищает этот список. Каталог обновлён %1$s + Ещё выполняется — это занимает больше времени, чем обычно. Можно подождать или отменить и повторить. + Остановить установку? + Сделанное до сих пор отменяется, и модуль не будет установлен. Вы сможете запустить его снова позже. + Остановить + Продолжить установку diff --git a/controller/app/src/main/res/values-sk/strings.xml b/controller/app/src/main/res/values-sk/strings.xml index 966d9aa35..02ce0be10 100644 --- a/controller/app/src/main/res/values-sk/strings.xml +++ b/controller/app/src/main/res/values-sk/strings.xml @@ -1293,4 +1293,9 @@ %1$d kurzov sa nedokončilo. Pred odchodom skúste neúspešné znova — odchodom sa tento zoznam vymaže. Katalóg aktualizovaný %1$s + Stále prebieha — trvá to dlhšie než zvyčajne. Môžete počkať, alebo zrušiť a skúsiť znova. + Zastaviť inštaláciu? + Doteraz vykonané sa vráti späť a modul sa nenainštaluje. Môžete ho spustiť znova neskôr. + Zastaviť + Pokračovať v inštalácii diff --git a/controller/app/src/main/res/values-sr/strings.xml b/controller/app/src/main/res/values-sr/strings.xml index bead64b73..afdc8fdea 100644 --- a/controller/app/src/main/res/values-sr/strings.xml +++ b/controller/app/src/main/res/values-sr/strings.xml @@ -1299,4 +1299,9 @@ %1$d курсева није завршено. Покушајте поново неуспеле пре него што одете — одлазак брише овај списак. Каталог ажуриран %1$s + Још увек ради — траје дуже него обично. Можете сачекати или отказати и покушати поново. + Зауставити инсталацију? + Оно што је до сада урађено се поништава и модул неће бити инсталиран. Можете га поново покренути касније. + Заустави + Настави инсталацију diff --git a/controller/app/src/main/res/values-sw/strings.xml b/controller/app/src/main/res/values-sw/strings.xml index c1cd56741..30d4a3af3 100644 --- a/controller/app/src/main/res/values-sw/strings.xml +++ b/controller/app/src/main/res/values-sw/strings.xml @@ -1306,4 +1306,9 @@ Kozi %1$d hazikukamilika. Jaribu tena zilizoshindwa kabla ya kuondoka — kuondoka kunafuta orodha hii. Katalogi ilisasishwa tarehe %1$s + Bado inaendelea — inachukua muda mrefu kuliko kawaida. Unaweza kusubiri, au kughairi na kujaribu tena. + Kusimamisha usakinishaji? + Yaliyofanyika hadi sasa yanabatilishwa na moduli haitasakinishwa. Unaweza kuanza tena baadaye. + Simamisha usakinishaji + Endelea kusakinisha diff --git a/controller/app/src/main/res/values-ta/strings.xml b/controller/app/src/main/res/values-ta/strings.xml index 23bf36d5c..670bf0903 100644 --- a/controller/app/src/main/res/values-ta/strings.xml +++ b/controller/app/src/main/res/values-ta/strings.xml @@ -1306,4 +1306,9 @@ %1$d பாடநெறிகள் முடியவில்லை. வெளியேறும் முன் தோல்வியடைந்தவற்றை மீண்டும் முயற்சிக்கவும் — வெளியேறினால் இந்தப் பட்டியல் அழிக்கப்படும். பட்டியல் %1$s அன்று புதுப்பிக்கப்பட்டது + இன்னும் இயங்குகிறது — வழக்கத்தை விட அதிக நேரம் எடுக்கிறது. நீங்கள் காத்திருக்கலாம் அல்லது ரத்து செய்து மீண்டும் முயற்சிக்கலாம். + நிறுவலை நிறுத்தவா? + இதுவரை செய்தது மீட்டமைக்கப்படும், தொகுதி நிறுவப்படாது. பிறகு மீண்டும் தொடங்கலாம். + நிறுவலை நிறுத்து + நிறுவலைத் தொடர் diff --git a/controller/app/src/main/res/values-tr/strings.xml b/controller/app/src/main/res/values-tr/strings.xml index 81fc06abb..5b5f179c7 100644 --- a/controller/app/src/main/res/values-tr/strings.xml +++ b/controller/app/src/main/res/values-tr/strings.xml @@ -1286,4 +1286,9 @@ %1$d kurs tamamlanmadı. Ayrılmadan önce başarısız olanları yeniden deneyin — ayrılmak bu listeyi siler. Katalog %1$s tarihinde güncellendi + Hâlâ çalışıyor — bu her zamankinden uzun sürüyor. Bekleyebilir ya da iptal edip yeniden deneyebilirsiniz. + Kurulum durdurulsun mu? + Şimdiye kadar yapılanlar geri alınır ve modül kurulmaz. Daha sonra yeniden başlatabilirsiniz. + Kurulumu durdur + Kuruluma devam et diff --git a/controller/app/src/main/res/values-uk/strings.xml b/controller/app/src/main/res/values-uk/strings.xml index c050cc630..e1735c8e7 100644 --- a/controller/app/src/main/res/values-uk/strings.xml +++ b/controller/app/src/main/res/values-uk/strings.xml @@ -1286,4 +1286,9 @@ %1$d курс(ів) не завершено. Повторіть невдалі перед виходом — вихід очищає цей список. Каталог оновлено %1$s + Ще триває — це займає більше часу, ніж зазвичай. Можна зачекати або скасувати та повторити. + Зупинити встановлення? + Зроблене досі скасовується, і модуль не буде встановлено. Ви зможете запустити його знову пізніше. + Зупинити + Продовжити встановлення diff --git a/controller/app/src/main/res/values-vi/strings.xml b/controller/app/src/main/res/values-vi/strings.xml index 873a5c6d7..f2d9dc379 100644 --- a/controller/app/src/main/res/values-vi/strings.xml +++ b/controller/app/src/main/res/values-vi/strings.xml @@ -1286,4 +1286,9 @@ %1$d khóa học chưa hoàn tất. Hãy thử lại những mục lỗi trước khi rời đi — rời đi sẽ xóa danh sách này. Danh mục cập nhật ngày %1$s + Vẫn đang chạy — việc này lâu hơn bình thường. Bạn có thể chờ, hoặc hủy và thử lại. + Dừng cài đặt? + Những gì đã làm đến giờ sẽ được hoàn tác và mô-đun sẽ không được cài đặt. Bạn có thể bắt đầu lại sau. + Dừng cài đặt + Tiếp tục cài đặt diff --git a/controller/app/src/main/res/values-yo/strings.xml b/controller/app/src/main/res/values-yo/strings.xml index 3ef256eda..a981b9538 100644 --- a/controller/app/src/main/res/values-yo/strings.xml +++ b/controller/app/src/main/res/values-yo/strings.xml @@ -1306,4 +1306,9 @@ %1$d ìdánilẹ́kọ̀ọ́ kò parí. Tún gbìyànjú àwọn tí ó kùnà kí o tó lọ — lílọ máa pa àtòjọ yìí rẹ́. A ṣe àfikún àtòjọ ní %1$s + Ó ṣì ń ṣiṣẹ́ — ó ń gba àkókò ju bí ó ṣe máa ń rí lọ. O lè dúró, tàbí fagilé kí o sì gbìyànjú lẹ́ẹ̀kansí. + Ṣé kí a dá fífi sórí ẹ̀rọ dúró? + Ohun tí a ti ṣe títí di báyìí ni a ó yí padà, a kì yóò sì fi módùlù náà sórí ẹ̀rọ. O lè bẹ̀rẹ̀ rẹ̀ lẹ́ẹ̀kansí lẹ́yìn náà. + Dá dúró + Máa bá a lọ diff --git a/controller/app/src/main/res/values-zh-rCN/strings.xml b/controller/app/src/main/res/values-zh-rCN/strings.xml index 0f924e3da..2fcd0163e 100644 --- a/controller/app/src/main/res/values-zh-rCN/strings.xml +++ b/controller/app/src/main/res/values-zh-rCN/strings.xml @@ -1287,4 +1287,9 @@ %1$d 门课程未完成。 离开前请重试失败的项目——离开会清空此列表。 目录更新于 %1$s + 仍在进行 — 用时比平常长。您可以继续等待,或取消并重试。 + 停止安装? + 目前所做的更改将被撤销,模块不会被安装。您稍后可以重新开始。 + 停止安装 + 继续安装 diff --git a/controller/app/src/main/res/values/strings.xml b/controller/app/src/main/res/values/strings.xml index f3e25ccd7..09aa42ea1 100644 --- a/controller/app/src/main/res/values/strings.xml +++ b/controller/app/src/main/res/values/strings.xml @@ -1462,4 +1462,9 @@ Done — go to my library %1$d course(s) didn\'t finish. Retry the ones that failed before you leave — leaving clears this list. + Still working — this is taking longer than usual. You can keep waiting, or cancel and retry. + Stop installing? + What\'s been done so far is rolled back and the module won\'t be installed. You can start it again afterward. + Stop install + Keep installing diff --git a/controller/app/src/main/res/values/strings_beta_notranslate_yet.xml b/controller/app/src/main/res/values/strings_beta_notranslate_yet.xml deleted file mode 100644 index fa294d073..000000000 --- a/controller/app/src/main/res/values/strings_beta_notranslate_yet.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - Still working — this is taking longer than usual. You can keep waiting, or cancel and retry. - - Stop installing? - What\'s been done so far is rolled back and the module won\'t be installed. You can start it again afterward. - Stop install - Keep installing -