}
*/
function confirm(titleText, message, isHTML, options = {}) {
@@ -59,7 +59,8 @@ function confirm(titleText, message, isHTML, options = {}) {
onclick: cancel,
});
const confirmDiv = tag("div", {
- className: "prompt confirm",
+ className: `prompt confirm${options.aboveOverlay ? " above-overlay" : ""}`,
+ dir: options.direction,
children: [
titleSpan,
messageSpan,
diff --git a/src/dialogs/loader.js b/src/dialogs/loader.js
index e7a34cea40..dfb98946fe 100644
--- a/src/dialogs/loader.js
+++ b/src/dialogs/loader.js
@@ -6,14 +6,15 @@ import restoreTheme from "lib/restoreTheme";
let loaderIsImmortal = false;
let onCancelCallback = null;
+let cancelButtonTimeout = null;
let $currentDialog = null;
let $currentMask = null;
const titleLoaderId = "__title-loader";
/**
* @typedef {object} LoaderOptions
- * @property {number} timeout Timeout in milliseconds after which the loader will be shown
- * @property {function():void} oncancel Callback function to be called when the loader is shown
+ * @property {number} timeout Delay before the cancel button is shown, in milliseconds
+ * @property {function():void} oncancel Callback invoked only when the user cancels
*/
/**
@@ -64,19 +65,21 @@ function create(titleText, message = "", options = {}) {
);
- const { timeout, oncancel } = options;
- if (typeof oncancel === "function") {
- onCancelCallback = oncancel;
- }
+ clearTimeout(cancelButtonTimeout);
+ cancelButtonTimeout = null;
+ onCancelCallback =
+ typeof options.oncancel === "function" ? options.oncancel : null;
- if (typeof timeout === "number") {
- setTimeout(() => {
+ if (typeof options.timeout === "number") {
+ cancelButtonTimeout = setTimeout(() => {
+ cancelButtonTimeout = null;
+ if (!$dialog.isConnected) return;
$dialog.append(
-
+
,
);
- }, timeout);
+ }, options.timeout);
}
if (!$oldLoader) {
@@ -98,6 +101,13 @@ function create(titleText, message = "", options = {}) {
};
}
+function cancel() {
+ const callback = onCancelCallback;
+ onCancelCallback = null;
+ destroy();
+ callback?.();
+}
+
function createTitleLoader() {
const $titleLoader = tag.get(`#${titleLoaderId}`) || (
@@ -116,6 +126,9 @@ function createTitleLoader() {
function destroy() {
const loaderDiv = tag.get("#__loader");
const mask = tag.get("#__loader-mask");
+ clearTimeout(cancelButtonTimeout);
+ cancelButtonTimeout = null;
+ onCancelCallback = null;
restoreTheme();
if (!loaderDiv && !mask) {
@@ -128,7 +141,6 @@ function destroy() {
actionStack.unfreeze();
if (loaderDiv?.isConnected) loaderDiv.remove();
if (mask?.isConnected) mask.remove();
- onCancelCallback?.();
}, 300);
}
diff --git a/src/dialogs/style.scss b/src/dialogs/style.scss
index 91fe9ab802..0380b5c0d5 100644
--- a/src/dialogs/style.scss
+++ b/src/dialogs/style.scss
@@ -49,6 +49,14 @@
z-index: 113;
}
+ &.above-overlay {
+ z-index: 1001;
+
+ & + .mask {
+ z-index: 1000;
+ }
+ }
+
&.multi {
textarea:not(:first-of-type) {
margin-top: 20px;
diff --git a/src/fileSystem/sftp.js b/src/fileSystem/sftp.js
index 41bff24af7..803be8af45 100644
--- a/src/fileSystem/sftp.js
+++ b/src/fileSystem/sftp.js
@@ -407,6 +407,23 @@ class SftpClient {
}
}
+ /**
+ * Tests a profile once without the normal remote-filesystem retry policy.
+ * @param {string} requestID Native request ID used for cancellation
+ */
+ testConnection(requestID) {
+ return new Promise((resolve, reject) => {
+ sftp.testProfile(this.#profileID, requestID, 10000, resolve, reject);
+ });
+ }
+
+ /** Cancel an in-flight profile test. */
+ cancelConnection(requestID) {
+ return new Promise((resolve) => {
+ sftp.cancelConnection(requestID, resolve, resolve);
+ });
+ }
+
async #connectWithRetry() {
const attempts = settings.value.retryRemoteFsAfterFail
? this.#MAX_TRY + 1
diff --git a/src/handlers/intent.js b/src/handlers/intent.js
index fc5f5b9cb1..78c0009ab6 100644
--- a/src/handlers/intent.js
+++ b/src/handlers/intent.js
@@ -17,11 +17,14 @@ const pendingIntents = [];
* @param {Intent} intent
*/
export default async function HandleIntent(intent = {}) {
- const type = intent.action.split(".").slice(-1)[0];
+ const type = intent.action?.split(".").slice(-1)[0];
if (["SEND", "VIEW", "EDIT"].includes(type)) {
/**@type {string} */
- const url = intent.fileUri || intent.data;
+ const url =
+ intent.fileUri ||
+ intent.data ||
+ intent.extras?.["android.intent.extra.STREAM"];
if (!url) return;
if (url.startsWith("acode://")) {
@@ -72,19 +75,19 @@ export default async function HandleIntent(intent = {}) {
return;
}
+ const options = {
+ mode: "single",
+ render: true,
+ persistInSession: false,
+ };
+
if (sessionStorage.getItem("isfilesRestored") === "true") {
- await openFile(url, {
- mode: "single",
- render: true,
- });
+ await openFile(url, options);
} else {
// Store the intent for later processing when files are restored
pendingIntents.push({
url,
- options: {
- mode: "single",
- render: true,
- },
+ options,
});
}
}
diff --git a/src/lang/ar-ye.json b/src/lang/ar-ye.json
index e96e78e135..f593714cca 100644
--- a/src/lang/ar-ye.json
+++ b/src/lang/ar-ye.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "هل تريد مشاهدة إعلان بمكافأة لتطبيق أيقونة التطبيق هذه؟",
"rewarded ad unavailable": "الإعلانات بمكافأة غير متاحة الآن. يُرجى المحاولة مرة أخرى.",
"rewarded ad failed": "تعذر إكمال الإعلان. يُرجى المحاولة مرة أخرى.",
- "rewarded ad incomplete": "شاهد الإعلان حتى النهاية للحصول على المكافأة."
+ "rewarded ad incomplete": "شاهد الإعلان حتى النهاية للحصول على المكافأة.",
+ "plugin-review:dialog-label": "تقييمات الإضافة",
+ "plugin-review:account-check-failed": "تعذّر التحقق من حسابك. حاول مرة أخرى.",
+ "plugin-review:sign-in": "سجّل الدخول لكتابة تقييم",
+ "plugin-review:edit": "عدّل تقييمك",
+ "plugin-review:add": "أضف تقييمًا...",
+ "plugin-review:placeholder": "شارك تجربتك...",
+ "plugin-review:input-label": "تقييم الإضافة",
+ "plugin-review:vote-group-label": "التصويت",
+ "plugin-review:thumbs-up": "أعجبني",
+ "plugin-review:thumbs-down": "لم يعجبني",
+ "plugin-review:delete": "حذف التقييم",
+ "plugin-review:load-failed": "تعذّر تحميل التقييمات.",
+ "plugin-review:retry": "إعادة المحاولة",
+ "plugin-review:empty-title": "لا توجد تقييمات بعد",
+ "plugin-review:empty-description": "كن أول من يشارك تجربته.",
+ "plugin-review:yours": "تقييمك",
+ "plugin-review:community": "تقييمات المجتمع",
+ "plugin-review:no-other-reviews": "لا توجد تقييمات أخرى بعد.",
+ "plugin-review:login-incomplete": "لم يكتمل تسجيل الدخول.",
+ "plugin-review:sign-in-failed": "تعذّر تسجيل الدخول.",
+ "plugin-review:session-expired-review": "انتهت جلستك. سجّل الدخول مجددًا لكتابة تقييم.",
+ "plugin-review:save-failed": "تعذّر حفظ التقييم.",
+ "plugin-review:delete-confirmation": "هل تريد حذف تقييمك؟ لا يمكن التراجع عن هذا الإجراء.",
+ "plugin-review:session-expired-continue": "انتهت جلستك. سجّل الدخول مجددًا للمتابعة.",
+ "plugin-review:delete-failed": "تعذّر حذف التقييم.",
+ "plugin-review:you": "أنت",
+ "plugin-review:edit-action": "تعديل التقييم",
+ "plugin-review:recommended": "أوصى بهذه الإضافة",
+ "plugin-review:error-max-length": "يجب ألا يتجاوز التقييم {max} حرفًا.",
+ "plugin-review:error-downvote-comment": "أخبر المطوّر بما يمكن تحسينه.",
+ "plugin-review:error-empty": "أضف تعليقًا أو اختر «أعجبني».",
+ "plugin-review:unrated": "غير مقيّم"
}
diff --git a/src/lang/be-by.json b/src/lang/be-by.json
index 6cddef6f07..14562075a7 100644
--- a/src/lang/be-by.json
+++ b/src/lang/be-by.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "Паглядзець рэкламу з узнагародай, каб ужыць гэты значок праграмы?",
"rewarded ad unavailable": "Рэклама з узнагародай зараз недаступная. Паспрабуйце яшчэ раз.",
"rewarded ad failed": "Не ўдалося завяршыць прагляд рэкламы. Паспрабуйце яшчэ раз.",
- "rewarded ad incomplete": "Даглядзіце рэкламу да канца, каб атрымаць узнагароду."
+ "rewarded ad incomplete": "Даглядзіце рэкламу да канца, каб атрымаць узнагароду.",
+ "plugin-review:dialog-label": "Водгукі пра плагін",
+ "plugin-review:account-check-failed": "Не ўдалося праверыць ваш уліковы запіс. Паспрабуйце яшчэ раз.",
+ "plugin-review:sign-in": "Увайсці, каб пакінуць водгук",
+ "plugin-review:edit": "Рэдагаваць свой водгук",
+ "plugin-review:add": "Дадаць водгук…",
+ "plugin-review:placeholder": "Падзяліцеся сваім досведам…",
+ "plugin-review:input-label": "Водгук пра плагін",
+ "plugin-review:vote-group-label": "Ацэнка",
+ "plugin-review:thumbs-up": "Падабаецца",
+ "plugin-review:thumbs-down": "Не падабаецца",
+ "plugin-review:delete": "Выдаліць водгук",
+ "plugin-review:load-failed": "Не ўдалося загрузіць водгукі.",
+ "plugin-review:retry": "Паспрабаваць яшчэ раз",
+ "plugin-review:empty-title": "Водгукаў пакуль няма",
+ "plugin-review:empty-description": "Падзяліцеся сваім досведам першымі.",
+ "plugin-review:yours": "Ваш водгук",
+ "plugin-review:community": "Водгукі супольнасці",
+ "plugin-review:no-other-reviews": "Іншых водгукаў пакуль няма.",
+ "plugin-review:login-incomplete": "Уваход не быў завершаны.",
+ "plugin-review:sign-in-failed": "Не ўдалося ўвайсці.",
+ "plugin-review:session-expired-review": "Сеанс скончыўся. Увайдзіце зноў, каб пакінуць водгук.",
+ "plugin-review:save-failed": "Не ўдалося захаваць водгук.",
+ "plugin-review:delete-confirmation": "Выдаліць ваш водгук? Гэта дзеянне нельга скасаваць.",
+ "plugin-review:session-expired-continue": "Сеанс скончыўся. Увайдзіце зноў, каб працягнуць.",
+ "plugin-review:delete-failed": "Не ўдалося выдаліць водгук.",
+ "plugin-review:you": "Вы",
+ "plugin-review:edit-action": "Рэдагаваць водгук",
+ "plugin-review:recommended": "Рэкамендуе гэты плагін",
+ "plugin-review:error-max-length": "Водгук павінен змяшчаць не больш за {max} сімвалаў.",
+ "plugin-review:error-downvote-comment": "Раскажыце распрацоўшчыку, што можна палепшыць.",
+ "plugin-review:error-empty": "Дадайце каментарый або выберыце «Падабаецца».",
+ "plugin-review:unrated": "Без ацэнкі"
}
diff --git a/src/lang/bn-bd.json b/src/lang/bn-bd.json
index 166738aff1..75cc364b1f 100644
--- a/src/lang/bn-bd.json
+++ b/src/lang/bn-bd.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "এই অ্যাপ আইকনটি প্রয়োগ করতে একটি পুরস্কারযুক্ত বিজ্ঞাপন দেখবেন?",
"rewarded ad unavailable": "পুরস্কারযুক্ত বিজ্ঞাপন এখন উপলভ্য নেই। অনুগ্রহ করে আবার চেষ্টা করুন।",
"rewarded ad failed": "বিজ্ঞাপনটি সম্পূর্ণ করা যায়নি। অনুগ্রহ করে আবার চেষ্টা করুন।",
- "rewarded ad incomplete": "পুরস্কার পেতে বিজ্ঞাপনটি সম্পূর্ণ দেখুন।"
+ "rewarded ad incomplete": "পুরস্কার পেতে বিজ্ঞাপনটি সম্পূর্ণ দেখুন।",
+ "plugin-review:dialog-label": "প্লাগইন পর্যালোচনা",
+ "plugin-review:account-check-failed": "আপনার অ্যাকাউন্ট যাচাই করা যায়নি। আবার চেষ্টা করুন।",
+ "plugin-review:sign-in": "পর্যালোচনা দিতে সাইন ইন করুন",
+ "plugin-review:edit": "আপনার পর্যালোচনা সম্পাদনা করুন",
+ "plugin-review:add": "পর্যালোচনা যোগ করুন...",
+ "plugin-review:placeholder": "আপনার অভিজ্ঞতা শেয়ার করুন...",
+ "plugin-review:input-label": "প্লাগইন পর্যালোচনা",
+ "plugin-review:vote-group-label": "ভোট",
+ "plugin-review:thumbs-up": "পছন্দ",
+ "plugin-review:thumbs-down": "অপছন্দ",
+ "plugin-review:delete": "পর্যালোচনা মুছুন",
+ "plugin-review:load-failed": "পর্যালোচনাগুলো লোড করা যায়নি।",
+ "plugin-review:retry": "আবার চেষ্টা করুন",
+ "plugin-review:empty-title": "এখনও কোনো পর্যালোচনা নেই",
+ "plugin-review:empty-description": "সবার আগে আপনার অভিজ্ঞতা শেয়ার করুন।",
+ "plugin-review:yours": "আপনার পর্যালোচনা",
+ "plugin-review:community": "কমিউনিটির পর্যালোচনা",
+ "plugin-review:no-other-reviews": "এখনও অন্য কোনো পর্যালোচনা নেই।",
+ "plugin-review:login-incomplete": "সাইন ইন সম্পন্ন হয়নি।",
+ "plugin-review:sign-in-failed": "সাইন ইন করা যায়নি।",
+ "plugin-review:session-expired-review": "আপনার সেশনের মেয়াদ শেষ। পর্যালোচনা দিতে আবার সাইন ইন করুন।",
+ "plugin-review:save-failed": "পর্যালোচনা সংরক্ষণ করা যায়নি।",
+ "plugin-review:delete-confirmation": "আপনার পর্যালোচনা মুছবেন? এটি আর ফিরিয়ে আনা যাবে না।",
+ "plugin-review:session-expired-continue": "আপনার সেশনের মেয়াদ শেষ। চালিয়ে যেতে আবার সাইন ইন করুন।",
+ "plugin-review:delete-failed": "পর্যালোচনা মোছা যায়নি।",
+ "plugin-review:you": "আপনি",
+ "plugin-review:edit-action": "পর্যালোচনা সম্পাদনা করুন",
+ "plugin-review:recommended": "এই প্লাগইনটি সুপারিশ করেছেন",
+ "plugin-review:error-max-length": "পর্যালোচনা {max} অক্ষর বা তার কম হতে হবে।",
+ "plugin-review:error-downvote-comment": "কী উন্নত করা যায় তা ডেভেলপারকে জানান।",
+ "plugin-review:error-empty": "একটি মন্তব্য যোগ করুন বা পছন্দ নির্বাচন করুন।",
+ "plugin-review:unrated": "এখনও মূল্যায়ন নেই"
}
diff --git a/src/lang/cs-cz.json b/src/lang/cs-cz.json
index 69a1605a87..38b332d152 100644
--- a/src/lang/cs-cz.json
+++ b/src/lang/cs-cz.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "Chcete zhlédnout reklamu s odměnou a použít tuto ikonu aplikace?",
"rewarded ad unavailable": "Reklamy s odměnou nejsou nyní dostupné. Zkuste to znovu.",
"rewarded ad failed": "Reklamu se nepodařilo dokončit. Zkuste to znovu.",
- "rewarded ad incomplete": "Pro získání odměny zhlédněte reklamu až do konce."
+ "rewarded ad incomplete": "Pro získání odměny zhlédněte reklamu až do konce.",
+ "plugin-review:dialog-label": "Recenze pluginu",
+ "plugin-review:account-check-failed": "Váš účet se nepodařilo ověřit. Zkuste to znovu.",
+ "plugin-review:sign-in": "Přihlásit se a napsat recenzi",
+ "plugin-review:edit": "Upravit vaši recenzi",
+ "plugin-review:add": "Přidat recenzi…",
+ "plugin-review:placeholder": "Podělte se o své zkušenosti…",
+ "plugin-review:input-label": "Recenze pluginu",
+ "plugin-review:vote-group-label": "Hlas",
+ "plugin-review:thumbs-up": "Líbí se mi",
+ "plugin-review:thumbs-down": "Nelíbí se mi",
+ "plugin-review:delete": "Smazat recenzi",
+ "plugin-review:load-failed": "Recenze se nepodařilo načíst.",
+ "plugin-review:retry": "Zkusit znovu",
+ "plugin-review:empty-title": "Zatím žádné recenze",
+ "plugin-review:empty-description": "Podělte se o zkušenost jako první.",
+ "plugin-review:yours": "Vaše recenze",
+ "plugin-review:community": "Recenze komunity",
+ "plugin-review:no-other-reviews": "Zatím žádné další recenze.",
+ "plugin-review:login-incomplete": "Přihlášení nebylo dokončeno.",
+ "plugin-review:sign-in-failed": "Přihlášení se nezdařilo.",
+ "plugin-review:session-expired-review": "Vaše relace vypršela. Chcete-li napsat recenzi, přihlaste se znovu.",
+ "plugin-review:save-failed": "Recenzi se nepodařilo uložit.",
+ "plugin-review:delete-confirmation": "Smazat vaši recenzi? Tuto akci nelze vrátit zpět.",
+ "plugin-review:session-expired-continue": "Vaše relace vypršela. Chcete-li pokračovat, přihlaste se znovu.",
+ "plugin-review:delete-failed": "Recenzi se nepodařilo smazat.",
+ "plugin-review:you": "Vy",
+ "plugin-review:edit-action": "Upravit recenzi",
+ "plugin-review:recommended": "Doporučuje tento plugin",
+ "plugin-review:error-max-length": "Recenze může mít nejvýše {max} znaků.",
+ "plugin-review:error-downvote-comment": "Sdělte vývojáři, co by se dalo zlepšit.",
+ "plugin-review:error-empty": "Přidejte komentář nebo zvolte Líbí se mi.",
+ "plugin-review:unrated": "Nehodnoceno"
}
diff --git a/src/lang/de-de.json b/src/lang/de-de.json
index 1efd40fe58..a3c9447c7f 100644
--- a/src/lang/de-de.json
+++ b/src/lang/de-de.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "Eine belohnte Anzeige ansehen, um dieses App-Symbol anzuwenden?",
"rewarded ad unavailable": "Belohnte Anzeigen sind derzeit nicht verfügbar. Bitte versuche es erneut.",
"rewarded ad failed": "Die Anzeige konnte nicht abgeschlossen werden. Bitte versuche es erneut.",
- "rewarded ad incomplete": "Sieh dir die Anzeige bis zum Ende an, um die Belohnung zu erhalten."
+ "rewarded ad incomplete": "Sieh dir die Anzeige bis zum Ende an, um die Belohnung zu erhalten.",
+ "plugin-review:dialog-label": "Plugin-Bewertungen",
+ "plugin-review:account-check-failed": "Dein Konto konnte nicht überprüft werden. Versuche es erneut.",
+ "plugin-review:sign-in": "Zum Bewerten anmelden",
+ "plugin-review:edit": "Deine Bewertung bearbeiten",
+ "plugin-review:add": "Bewertung hinzufügen…",
+ "plugin-review:placeholder": "Teile deine Erfahrung…",
+ "plugin-review:input-label": "Plugin-Bewertung",
+ "plugin-review:vote-group-label": "Stimme",
+ "plugin-review:thumbs-up": "Gefällt mir",
+ "plugin-review:thumbs-down": "Gefällt mir nicht",
+ "plugin-review:delete": "Bewertung löschen",
+ "plugin-review:load-failed": "Bewertungen konnten nicht geladen werden.",
+ "plugin-review:retry": "Erneut versuchen",
+ "plugin-review:empty-title": "Noch keine Bewertungen",
+ "plugin-review:empty-description": "Teile als Erste oder Erster deine Erfahrung.",
+ "plugin-review:yours": "Deine Bewertung",
+ "plugin-review:community": "Bewertungen der Community",
+ "plugin-review:no-other-reviews": "Noch keine weiteren Bewertungen.",
+ "plugin-review:login-incomplete": "Die Anmeldung wurde nicht abgeschlossen.",
+ "plugin-review:sign-in-failed": "Anmeldung nicht möglich.",
+ "plugin-review:session-expired-review": "Deine Sitzung ist abgelaufen. Melde dich erneut an, um eine Bewertung abzugeben.",
+ "plugin-review:save-failed": "Bewertung konnte nicht gespeichert werden.",
+ "plugin-review:delete-confirmation": "Deine Bewertung löschen? Dies kann nicht rückgängig gemacht werden.",
+ "plugin-review:session-expired-continue": "Deine Sitzung ist abgelaufen. Melde dich erneut an, um fortzufahren.",
+ "plugin-review:delete-failed": "Bewertung konnte nicht gelöscht werden.",
+ "plugin-review:you": "Du",
+ "plugin-review:edit-action": "Bewertung bearbeiten",
+ "plugin-review:recommended": "Empfiehlt dieses Plugin",
+ "plugin-review:error-max-length": "Die Bewertung darf höchstens {max} Zeichen lang sein.",
+ "plugin-review:error-downvote-comment": "Sage dem Entwickler, was verbessert werden könnte.",
+ "plugin-review:error-empty": "Füge einen Kommentar hinzu oder wähle „Gefällt mir“.",
+ "plugin-review:unrated": "Nicht bewertet"
}
diff --git a/src/lang/en-us.json b/src/lang/en-us.json
index 53063bc74c..2f7a159f7e 100644
--- a/src/lang/en-us.json
+++ b/src/lang/en-us.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "Watch one rewarded ad to apply this app icon?",
"rewarded ad unavailable": "Rewarded ads are unavailable right now. Please try again.",
"rewarded ad failed": "The ad could not be completed. Please try again.",
- "rewarded ad incomplete": "Finish watching the ad to earn the reward."
+ "rewarded ad incomplete": "Finish watching the ad to earn the reward.",
+ "plugin-review:dialog-label": "Plugin reviews",
+ "plugin-review:account-check-failed": "Unable to check your account. Try again.",
+ "plugin-review:sign-in": "Sign in to review",
+ "plugin-review:edit": "Edit your review",
+ "plugin-review:add": "Add a review...",
+ "plugin-review:placeholder": "Share your experience...",
+ "plugin-review:input-label": "Plugin review",
+ "plugin-review:vote-group-label": "Vote",
+ "plugin-review:thumbs-up": "Thumbs up",
+ "plugin-review:thumbs-down": "Thumbs down",
+ "plugin-review:delete": "Delete review",
+ "plugin-review:load-failed": "Unable to load reviews.",
+ "plugin-review:retry": "Retry",
+ "plugin-review:empty-title": "No reviews yet",
+ "plugin-review:empty-description": "Be the first to share your experience.",
+ "plugin-review:yours": "Your review",
+ "plugin-review:community": "Community reviews",
+ "plugin-review:no-other-reviews": "No other reviews yet.",
+ "plugin-review:login-incomplete": "Login was not completed.",
+ "plugin-review:sign-in-failed": "Unable to sign in.",
+ "plugin-review:session-expired-review": "Your session expired. Sign in again to review.",
+ "plugin-review:save-failed": "Unable to save review.",
+ "plugin-review:delete-confirmation": "Delete your review? This cannot be undone.",
+ "plugin-review:session-expired-continue": "Your session expired. Sign in again to continue.",
+ "plugin-review:delete-failed": "Unable to delete review.",
+ "plugin-review:you": "You",
+ "plugin-review:edit-action": "Edit review",
+ "plugin-review:recommended": "Recommended this plugin",
+ "plugin-review:error-max-length": "Review must be {max} characters or less.",
+ "plugin-review:error-downvote-comment": "Tell the developer what could be improved.",
+ "plugin-review:error-empty": "Add a comment or choose thumbs up.",
+ "plugin-review:unrated": "Unrated"
}
diff --git a/src/lang/es-sv.json b/src/lang/es-sv.json
index 2147ba35fe..276965e483 100644
--- a/src/lang/es-sv.json
+++ b/src/lang/es-sv.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "¿Ver un anuncio con recompensa para aplicar este icono de la aplicación?",
"rewarded ad unavailable": "Los anuncios con recompensa no están disponibles en este momento. Inténtalo de nuevo.",
"rewarded ad failed": "No se pudo completar el anuncio. Inténtalo de nuevo.",
- "rewarded ad incomplete": "Termina de ver el anuncio para obtener la recompensa."
+ "rewarded ad incomplete": "Termina de ver el anuncio para obtener la recompensa.",
+ "plugin-review:dialog-label": "Reseñas del complemento",
+ "plugin-review:account-check-failed": "No se pudo verificar tu cuenta. Inténtalo de nuevo.",
+ "plugin-review:sign-in": "Inicia sesión para opinar",
+ "plugin-review:edit": "Editar tu reseña",
+ "plugin-review:add": "Agregar una reseña...",
+ "plugin-review:placeholder": "Comparte tu experiencia...",
+ "plugin-review:input-label": "Reseña del complemento",
+ "plugin-review:vote-group-label": "Voto",
+ "plugin-review:thumbs-up": "Me gusta",
+ "plugin-review:thumbs-down": "No me gusta",
+ "plugin-review:delete": "Eliminar reseña",
+ "plugin-review:load-failed": "No se pudieron cargar las reseñas.",
+ "plugin-review:retry": "Reintentar",
+ "plugin-review:empty-title": "Aún no hay reseñas",
+ "plugin-review:empty-description": "Sé la primera persona en compartir tu experiencia.",
+ "plugin-review:yours": "Tu reseña",
+ "plugin-review:community": "Reseñas de la comunidad",
+ "plugin-review:no-other-reviews": "Aún no hay otras reseñas.",
+ "plugin-review:login-incomplete": "No se completó el inicio de sesión.",
+ "plugin-review:sign-in-failed": "No se pudo iniciar sesión.",
+ "plugin-review:session-expired-review": "Tu sesión venció. Inicia sesión de nuevo para opinar.",
+ "plugin-review:save-failed": "No se pudo guardar la reseña.",
+ "plugin-review:delete-confirmation": "¿Eliminar tu reseña? Esta acción no se puede deshacer.",
+ "plugin-review:session-expired-continue": "Tu sesión venció. Inicia sesión de nuevo para continuar.",
+ "plugin-review:delete-failed": "No se pudo eliminar la reseña.",
+ "plugin-review:you": "Tú",
+ "plugin-review:edit-action": "Editar reseña",
+ "plugin-review:recommended": "Recomendó este complemento",
+ "plugin-review:error-max-length": "La reseña debe tener {max} caracteres o menos.",
+ "plugin-review:error-downvote-comment": "Dile al desarrollador qué podría mejorar.",
+ "plugin-review:error-empty": "Agrega un comentario o elige Me gusta.",
+ "plugin-review:unrated": "Sin calificar"
}
diff --git a/src/lang/fr-fr.json b/src/lang/fr-fr.json
index ac2403ef35..5cf8f8b56f 100644
--- a/src/lang/fr-fr.json
+++ b/src/lang/fr-fr.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "Regarder une publicité récompensée pour appliquer cette icône d’application ?",
"rewarded ad unavailable": "Les publicités récompensées sont indisponibles pour le moment. Réessayez.",
"rewarded ad failed": "La publicité n’a pas pu être terminée. Réessayez.",
- "rewarded ad incomplete": "Regardez la publicité jusqu’à la fin pour obtenir la récompense."
+ "rewarded ad incomplete": "Regardez la publicité jusqu’à la fin pour obtenir la récompense.",
+ "plugin-review:dialog-label": "Avis sur l’extension",
+ "plugin-review:account-check-failed": "Impossible de vérifier votre compte. Réessayez.",
+ "plugin-review:sign-in": "Se connecter pour donner un avis",
+ "plugin-review:edit": "Modifier votre avis",
+ "plugin-review:add": "Ajouter un avis…",
+ "plugin-review:placeholder": "Partagez votre expérience…",
+ "plugin-review:input-label": "Avis sur l’extension",
+ "plugin-review:vote-group-label": "Vote",
+ "plugin-review:thumbs-up": "J’aime",
+ "plugin-review:thumbs-down": "Je n’aime pas",
+ "plugin-review:delete": "Supprimer l’avis",
+ "plugin-review:load-failed": "Impossible de charger les avis.",
+ "plugin-review:retry": "Réessayer",
+ "plugin-review:empty-title": "Aucun avis pour le moment",
+ "plugin-review:empty-description": "Soyez la première personne à partager votre expérience.",
+ "plugin-review:yours": "Votre avis",
+ "plugin-review:community": "Avis de la communauté",
+ "plugin-review:no-other-reviews": "Aucun autre avis pour le moment.",
+ "plugin-review:login-incomplete": "La connexion n’a pas abouti.",
+ "plugin-review:sign-in-failed": "Impossible de se connecter.",
+ "plugin-review:session-expired-review": "Votre session a expiré. Reconnectez-vous pour donner un avis.",
+ "plugin-review:save-failed": "Impossible d’enregistrer l’avis.",
+ "plugin-review:delete-confirmation": "Supprimer votre avis ? Cette action est irréversible.",
+ "plugin-review:session-expired-continue": "Votre session a expiré. Reconnectez-vous pour continuer.",
+ "plugin-review:delete-failed": "Impossible de supprimer l’avis.",
+ "plugin-review:you": "Vous",
+ "plugin-review:edit-action": "Modifier l’avis",
+ "plugin-review:recommended": "Recommande cette extension",
+ "plugin-review:error-max-length": "L’avis doit contenir au maximum {max} caractères.",
+ "plugin-review:error-downvote-comment": "Indiquez au développeur ce qui pourrait être amélioré.",
+ "plugin-review:error-empty": "Ajoutez un commentaire ou choisissez J’aime.",
+ "plugin-review:unrated": "Non évalué"
}
diff --git a/src/lang/he-il.json b/src/lang/he-il.json
index 56b2071a6e..4c306eb535 100644
--- a/src/lang/he-il.json
+++ b/src/lang/he-il.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "לצפות בפרסומת מתגמלת כדי להחיל את סמל האפליקציה הזה?",
"rewarded ad unavailable": "פרסומות מתגמלות אינן זמינות כרגע. יש לנסות שוב.",
"rewarded ad failed": "לא ניתן היה להשלים את הפרסומת. יש לנסות שוב.",
- "rewarded ad incomplete": "יש לצפות בפרסומת עד הסוף כדי לקבל את התגמול."
+ "rewarded ad incomplete": "יש לצפות בפרסומת עד הסוף כדי לקבל את התגמול.",
+ "plugin-review:dialog-label": "ביקורות על התוסף",
+ "plugin-review:account-check-failed": "לא ניתן לבדוק את החשבון שלך. נסה שוב.",
+ "plugin-review:sign-in": "יש להתחבר כדי לכתוב ביקורת",
+ "plugin-review:edit": "עריכת הביקורת שלך",
+ "plugin-review:add": "הוספת ביקורת...",
+ "plugin-review:placeholder": "שתף את החוויה שלך...",
+ "plugin-review:input-label": "ביקורת על התוסף",
+ "plugin-review:vote-group-label": "הצבעה",
+ "plugin-review:thumbs-up": "אהבתי",
+ "plugin-review:thumbs-down": "לא אהבתי",
+ "plugin-review:delete": "מחיקת ביקורת",
+ "plugin-review:load-failed": "לא ניתן לטעון את הביקורות.",
+ "plugin-review:retry": "נסה שוב",
+ "plugin-review:empty-title": "אין עדיין ביקורות",
+ "plugin-review:empty-description": "היה הראשון לשתף את החוויה שלך.",
+ "plugin-review:yours": "הביקורת שלך",
+ "plugin-review:community": "ביקורות הקהילה",
+ "plugin-review:no-other-reviews": "אין עדיין ביקורות נוספות.",
+ "plugin-review:login-incomplete": "ההתחברות לא הושלמה.",
+ "plugin-review:sign-in-failed": "לא ניתן להתחבר.",
+ "plugin-review:session-expired-review": "פג תוקף ההפעלה שלך. התחבר שוב כדי לכתוב ביקורת.",
+ "plugin-review:save-failed": "לא ניתן לשמור את הביקורת.",
+ "plugin-review:delete-confirmation": "למחוק את הביקורת שלך? לא ניתן לבטל פעולה זו.",
+ "plugin-review:session-expired-continue": "פג תוקף ההפעלה שלך. התחבר שוב כדי להמשיך.",
+ "plugin-review:delete-failed": "לא ניתן למחוק את הביקורת.",
+ "plugin-review:you": "אתה",
+ "plugin-review:edit-action": "עריכת ביקורת",
+ "plugin-review:recommended": "המליץ על התוסף הזה",
+ "plugin-review:error-max-length": "הביקורת צריכה להכיל עד {max} תווים.",
+ "plugin-review:error-downvote-comment": "ספר למפתח מה אפשר לשפר.",
+ "plugin-review:error-empty": "הוסף תגובה או בחר באהבתי.",
+ "plugin-review:unrated": "ללא דירוג"
}
diff --git a/src/lang/hi-in.json b/src/lang/hi-in.json
index a26d5eaae9..97857b6bc6 100644
--- a/src/lang/hi-in.json
+++ b/src/lang/hi-in.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "क्या इस ऐप आइकन को लागू करने के लिए इनाम वाला एक विज्ञापन देखना चाहते हैं?",
"rewarded ad unavailable": "इनाम वाले विज्ञापन अभी उपलब्ध नहीं हैं। कृपया फिर से कोशिश करें।",
"rewarded ad failed": "विज्ञापन पूरा नहीं हो सका। कृपया फिर से कोशिश करें।",
- "rewarded ad incomplete": "इनाम पाने के लिए विज्ञापन पूरा देखें।"
+ "rewarded ad incomplete": "इनाम पाने के लिए विज्ञापन पूरा देखें।",
+ "plugin-review:dialog-label": "प्लगइन समीक्षाएँ",
+ "plugin-review:account-check-failed": "आपके खाते की जाँच नहीं हो सकी। फिर से कोशिश करें।",
+ "plugin-review:sign-in": "समीक्षा देने के लिए साइन इन करें",
+ "plugin-review:edit": "अपनी समीक्षा संपादित करें",
+ "plugin-review:add": "समीक्षा जोड़ें...",
+ "plugin-review:placeholder": "अपना अनुभव साझा करें...",
+ "plugin-review:input-label": "प्लगइन समीक्षा",
+ "plugin-review:vote-group-label": "वोट",
+ "plugin-review:thumbs-up": "पसंद",
+ "plugin-review:thumbs-down": "नापसंद",
+ "plugin-review:delete": "समीक्षा हटाएँ",
+ "plugin-review:load-failed": "समीक्षाएँ लोड नहीं हो सकीं।",
+ "plugin-review:retry": "फिर से कोशिश करें",
+ "plugin-review:empty-title": "अभी कोई समीक्षा नहीं है",
+ "plugin-review:empty-description": "अपना अनुभव साझा करने वाले पहले व्यक्ति बनें।",
+ "plugin-review:yours": "आपकी समीक्षा",
+ "plugin-review:community": "समुदाय की समीक्षाएँ",
+ "plugin-review:no-other-reviews": "अभी कोई अन्य समीक्षा नहीं है।",
+ "plugin-review:login-incomplete": "साइन इन पूरा नहीं हुआ।",
+ "plugin-review:sign-in-failed": "साइन इन नहीं हो सका।",
+ "plugin-review:session-expired-review": "आपका सत्र समाप्त हो गया। समीक्षा देने के लिए फिर से साइन इन करें।",
+ "plugin-review:save-failed": "समीक्षा सहेजी नहीं जा सकी।",
+ "plugin-review:delete-confirmation": "अपनी समीक्षा हटाएँ? इसे वापस नहीं किया जा सकता।",
+ "plugin-review:session-expired-continue": "आपका सत्र समाप्त हो गया। जारी रखने के लिए फिर से साइन इन करें।",
+ "plugin-review:delete-failed": "समीक्षा हटाई नहीं जा सकी।",
+ "plugin-review:you": "आप",
+ "plugin-review:edit-action": "समीक्षा संपादित करें",
+ "plugin-review:recommended": "इस प्लगइन की सिफ़ारिश की",
+ "plugin-review:error-max-length": "समीक्षा {max} वर्णों या उससे कम की होनी चाहिए।",
+ "plugin-review:error-downvote-comment": "डेवलपर को बताएँ कि क्या बेहतर किया जा सकता है।",
+ "plugin-review:error-empty": "टिप्पणी जोड़ें या पसंद चुनें।",
+ "plugin-review:unrated": "अभी रेटिंग नहीं"
}
diff --git a/src/lang/hu-hu.json b/src/lang/hu-hu.json
index 086b82bb69..5616f4f889 100644
--- a/src/lang/hu-hu.json
+++ b/src/lang/hu-hu.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "Megnézel egy jutalmazott hirdetést az alkalmazásikon beállításához?",
"rewarded ad unavailable": "A jutalmazott hirdetések jelenleg nem érhetők el. Próbáld újra.",
"rewarded ad failed": "A hirdetést nem sikerült befejezni. Próbáld újra.",
- "rewarded ad incomplete": "Nézd végig a hirdetést a jutalom megszerzéséhez."
+ "rewarded ad incomplete": "Nézd végig a hirdetést a jutalom megszerzéséhez.",
+ "plugin-review:dialog-label": "Bővítményértékelések",
+ "plugin-review:account-check-failed": "Nem sikerült ellenőrizni a fiókját. Próbálja újra.",
+ "plugin-review:sign-in": "Megjegyzés írásához be kell jelentkezni",
+ "plugin-review:edit": "Megjegyzés szerkesztése",
+ "plugin-review:add": "Megjegyzés hozzáadása…",
+ "plugin-review:placeholder": "Ossza meg a tapasztalatait…",
+ "plugin-review:input-label": "Megjegyzés hozzáadása",
+ "plugin-review:vote-group-label": "Szavazás",
+ "plugin-review:thumbs-up": "Tetszik",
+ "plugin-review:thumbs-down": "Nem tetszik",
+ "plugin-review:delete": "Megjegyzés törlése",
+ "plugin-review:load-failed": "Nem sikerült betölteni a megjegyzéseket.",
+ "plugin-review:retry": "Újrapróbálkozás",
+ "plugin-review:empty-title": "Még nincsenek megjegyzések",
+ "plugin-review:empty-description": "Ossza meg elsőként a tapasztalatait.",
+ "plugin-review:yours": "Saját megjegyzés",
+ "plugin-review:community": "Közösségi megjegyzések",
+ "plugin-review:no-other-reviews": "Még nincsenek további megjegyzések.",
+ "plugin-review:login-incomplete": "A bejelentkezési folyamat még nem fejeződött be.",
+ "plugin-review:sign-in-failed": "Nem sikerült bejelentkezni.",
+ "plugin-review:session-expired-review": "A munkamenet lejárt. Jelentkezzen be újra a megjegyzés írásához.",
+ "plugin-review:save-failed": "Nem sikerült menteni a megjegyzést.",
+ "plugin-review:delete-confirmation": "Biztosan törli a megjegyzést? Ez a művelet nem vonható vissza.",
+ "plugin-review:session-expired-continue": "A munkamenet lejárt. A folytatáshoz jelentkezzen be újra.",
+ "plugin-review:delete-failed": "Nem sikerült törölni a megjegyzést.",
+ "plugin-review:you": "Ön",
+ "plugin-review:edit-action": "Megjegyzés szerkesztése",
+ "plugin-review:recommended": "Bővítmény ajánlása",
+ "plugin-review:error-max-length": "A megjegyzés szövege legfeljebb {max} karakter lehet.",
+ "plugin-review:error-downvote-comment": "Írja meg a fejlesztőknek, hogy min lehetne javítani.",
+ "plugin-review:error-empty": "Adjon hozzá megjegyzést vagy válassza a „Tetszik” lehetőséget.",
+ "plugin-review:unrated": "Még nem értékelte senki"
}
diff --git a/src/lang/id-id.json b/src/lang/id-id.json
index dd62d02bb0..9b38fe0ef1 100644
--- a/src/lang/id-id.json
+++ b/src/lang/id-id.json
@@ -8,18 +8,18 @@
"autosave": "Simpan Otomatis",
"cancel": "Batal",
"change language": "Ubah Bahasa",
- "choose color": "Pilih warna",
+ "choose color": "Pilih Warna",
"clear": "Kosongkan",
- "close app": "Tutup aplikasi?",
- "commit message": "Pesan komit",
+ "close app": "Tutup Aplikasi?",
+ "commit message": "Pesan Komit",
"console": "Konsol",
"conflict error": "Terjadi konflik! Harap tunggu sebelum melakukan komit lain.",
"copy": "Salin",
- "create folder error": "Maaf, tidak dapat membuat folder baru",
+ "create folder error": "Maaf, tidak dapat membuat folder baru.",
"cut": "Potong",
"delete": "Hapus",
- "dependencies": "Ketergantungan",
- "delay": "Waktu dalam milidetik",
+ "dependencies": "Dependensi",
+ "delay": "Waktu dalam Milidetik",
"editor settings": "Pengaturan Editor",
"editor theme": "Tema Editor",
"enter file name": "Masukkan nama berkas",
@@ -34,13 +34,13 @@
"file deleted": "Berkas dihapus",
"file is not supported": "Berkas tidak didukung",
"file not supported": "Jenis berkas ini tidak didukung.",
- "file too large": "Berkas terlalu besar untuk ditangani. Ukuran maksimal berkas yang diizinkan adalah {size}",
+ "file too large": "Berkas terlalu besar untuk ditangani. Ukuran maksimal berkas yang diizinkan adalah {size}.",
"file renamed": "Berkas berganti nama",
"file saved": "Berkas disimpan",
"folder added": "Folder ditambahkan",
"folder already added": "Folder sudah ditambahkan",
"font size": "Ukuran Font",
- "goto": "Pergi ke baris",
+ "goto": "Pergi ke Baris",
"icons definition": "Definisi ikon",
"info": "Info",
"invalid value": "Nilai tidak valid",
@@ -48,23 +48,23 @@
"linting": "Cek kesalahan sintaks",
"logout": "Keluar",
"loading": "Memuat",
- "my profile": "Profil saya",
+ "my profile": "Profil Saya",
"new file": "Berkas baru",
"new folder": "Folder baru",
"no": "Tidak",
- "no editor message": "Buka atau buat berkas dan folder baru dari menu",
+ "no editor message": "Buka atau buat berkas dan folder baru dari menu.",
"not set": "Tidak diatur",
"unsaved files close app": "Ada berkas yang belum disimpan. Tutup Aplikasi?",
"notice": "Pemberitahuan",
"open file": "Buka berkas",
"open files and folders": "Buka berkas dan folder",
"open folder": "Buka folder",
- "open recent": "Buka baru-baru ini",
+ "open recent": "Buka Yang Baru-Baru Ini",
"ok": "OK",
"overwrite": "Timpa",
"paste": "Tempel",
"preview mode": "Mode Pratinjau",
- "read only file": "Tidak dapat menyimpan berkas hanya baca. Silakan coba simpan sebagai",
+ "read only file": "Tidak dapat menyimpan berkas hanya-baca. Silakan coba simpan sebagai.",
"reload": "Muat Ulang",
"rename": "Ubah Nama",
"replace": "Ganti",
@@ -73,7 +73,7 @@
"save": "Simpan",
"saving": "Menyimpan",
"save as": "Simpan sebagai",
- "save file to run": "Silakan simpan berkas ini untuk berjalan di peramban",
+ "save file to run": "Silakan simpan berkas ini agar dapat berjalan di peramban.",
"search": "Cari",
"see logs and errors": "Lihat log dan kesalahan",
"select folder": "Pilih folder",
@@ -160,7 +160,7 @@
"dark": "Gelap",
"file browser": "Penjelajah Berkas",
"operation not permitted": "Operasi tidak diizinkan",
- "no such file or directory": "Tidak ada berkas atau direktori seperti itu",
+ "no such file or directory": "Tidak ada berkas atau direktori seperti itu.",
"input/output error": "Kesalahan masukan/keluaran",
"permission denied": "Izin ditolak",
"bad address": "Alamat tidak valid",
@@ -177,7 +177,7 @@
"too many users": "Terlalu banyak pengguna",
"connection timed out": "Waktu koneksi habis",
"connection refused": "Koneksi ditolak",
- "owner died": "Proses induk terhenti",
+ "owner died": "Proses induk berhenti.",
"an error occurred": "Terjadi kesalahan",
"add ftp": "Tambahkan FTP",
"add sftp": "Tambahkan SFTP",
@@ -191,7 +191,7 @@
"deleted file": "Berkas yang dihapus",
"line height": "Tinggi baris",
"preview info": "Jika Anda ingin menjalankan berkas aktif, ketuk dan tahan ikon Putar.",
- "manage all files": "Izinkan Acode Editor untuk mengelola semua berkas dalam pengaturan untuk mengedit berkas di perangkat Anda dengan mudah.",
+ "manage all files": "Izinkan Acode Editor untuk mengelola semua berkas di pengaturan agar dapat mengedit berkas di perangkat Anda dengan mudah.",
"close file": "Tutup berkas",
"reset connections": "Atur ulang koneksi",
"check file changes": "Periksa perubahan berkas",
@@ -252,25 +252,25 @@
"select key file": "Pilih berkas kunci",
"passphrase": "Frasa sandi",
"connecting...": "Menghubungkan...",
- "type filename": "Jenis nama berkas",
+ "type filename": "Ketik nama berkas",
"unable to load files": "Tidak dapat memuat berkas",
"preview port": "Port pratinjau",
"find file": "Temukan berkas",
"system": "Sistem",
"please select a formatter": "Mohon pilih pemformat",
"case sensitive": "Sensitif huruf besar",
- "regular expression": "Ekspresi Regular",
+ "regular expression": "Ekspresi Reguler",
"whole word": "Seluruh kata",
"edit with": "Edit dengan",
"open with": "Buka dengan",
"no app found to handle this file": "Tidak ditemukan aplikasi untuk menangani berkas ini",
- "restore default settings": "Kembalikan pengaturan default",
+ "restore default settings": "Kembalikan Pengaturan Bawaan",
"server port": "Port server",
"preview settings": "Pengaturan pratinjau",
- "preview settings note": "Jika port pratinjau dan port server berbeda, aplikasi tidak akan memulai server dan sebaliknya akan membuka https://: di peramban atau peramban-dalam-aplikasi. Ini berguna ketika Anda menjalankan server di tempat lain.",
+ "preview settings note": "Jika port pratinjau dan port server berbeda, aplikasi tidak akan memulai server dan sebaliknya akan membuka https://: di peramban atau peramban-dalam-aplikasi. Ini berguna ketika Anda menjalankan server di tempat lain.",
"backup/restore note": "Ini hanya akan membuat cadangan pengaturan Anda, tema khusus, plugin yang dipasang, dan pemetaan tombol. Ini tidak akan membuat cadangan FTP/SFTP atau status aplikasi Anda.",
"host": "Host",
- "retry ftp/sftp when fail": "Ulangi FTP/SFTP ketika gagal",
+ "retry ftp/sftp when fail": "Ulangi FTP/SFTP saat gagal",
"more": "Lebih banyak",
"thank you :)": "Terima kasih :)",
"purchase pending": "Pembelian Tertunda",
@@ -292,42 +292,42 @@
"quicktools trigger mode": "Mode Pemicu Alat Cepat",
"print margin": "Cetak margin",
"touch move threshold": "Ambang pergerakan sentuh",
- "info-retryremotefsafterfail": "Ulangi koneksi FTP/SFTP ketika gagal.",
- "info-fullscreen": "Sembunyikan Bilah Judul di Layar Beranda.",
- "info-checkfiles": "Periksa perubahan berkas ketika aplikasi di latar belakang.",
- "info-console": "Pilih konsol JavaScript. Legacy adalah konsol default, Eruda adalah konsol pihak ketiga.",
- "info-keyboardmode": "Mode keyboard untuk input teks, tidak ada saran akan menyembunyikan saran dan koreksi otomatis. Jika tidak ada saran tidak berfungsi, cobalah untuk mengubah nilai ke tanpa saran yang agresif.",
- "info-rememberfiles": "Ingat berkas yang dibuka ketika aplikasi ditutup.",
- "info-rememberfolders": "Ingat folder yang dibuka ketika aplikasi ditutup.",
+ "info-retryremotefsafterfail": "Ulangi koneksi FTP/SFTP saat gagal.",
+ "info-fullscreen": "Sembunyikan bilah judul di layar beranda.",
+ "info-checkfiles": "Periksa perubahan berkas saat aplikasi berjalan di latar belakang.",
+ "info-console": "Pilih konsol JavaScript. Legacy adalah konsol bawaan, Eruda adalah konsol pihak ketiga.",
+ "info-keyboardmode": "Mode papan ketik untuk input teks. Pilihan tanpa saran akan menyembunyikan saran dan koreksi otomatis. Jika tidak ada saran tidak berfungsi, coba ubah nilainya ke tanpa saran yang agresif.",
+ "info-rememberfiles": "Ingat berkas yang dibuka saat aplikasi ditutup.",
+ "info-rememberfolders": "Ingat folder yang dibuka saat aplikasi ditutup.",
"info-floatingbutton": "Tampilkan atau sembunyikan tombol apung Alat Cepat.",
- "info-openfilelistpos": "Di mana untuk menampilkan daftar berkas aktif.",
+ "info-openfilelistpos": "Lokasi untuk menampilkan daftar berkas aktif.",
"info-touchmovethreshold": "Jika sensitivitas sentuhan perangkat Anda terlalu tinggi, Anda dapat meningkatkan nilai ini untuk mencegah gerakan sentuh yang tidak disengaja.",
- "info-scroll-settings": "Pengaturan ini berisi pengaturan gulir termasuk bungkus teks.",
+ "info-scroll-settings": "Pengaturan ini mencakup pengaturan gulir termasuk bungkus teks.",
"info-animation": "Jika aplikasi terasa lag, nonaktifkan animasi.",
- "info-quicktoolstriggermode": "Jika tombol dalam alat cepat tidak berfungsi, cobalah untuk mengubah nilai ini.",
+ "info-quicktoolstriggermode": "Jika tombol dalam alat cepat tidak berfungsi, coba ubah nilai ini.",
"info-checkForAppUpdates": "Periksa pembaruan aplikasi secara otomatis.",
"info-quickTools": "Tampilkan atau sembunyikan alat cepat.",
- "info-showHiddenFiles": "Tampilkan berkas dan folder tersembunyi. (Berawal dengan .)",
- "info-listFiles": "Otomatis daftarkan semua berkas saat folder dibuka",
+ "info-showHiddenFiles": "Tampilkan berkas dan folder tersembunyi. (Diawali dengan .)",
+ "info-listFiles": "Secara otomatis daftarkan semua berkas saat folder dibuka.",
"info-all_file_access": "Aktifkan akses ke /sdcard dan /storage di terminal.",
"info-fontSize": "Ukuran font yang digunakan untuk menampilkan teks.",
"info-fontFamily": "Jenis font yang digunakan untuk menampilkan teks.",
"info-theme": "Tema warna terminal.",
"info-cursorStyle": "Gaya kursor saat terminal sedang aktif.",
"info-cursorInactiveStyle": "Gaya kursor saat terminal tidak terfokus.",
- "info-fontWeight": "Ketebalan font yang digunakan untuk menampilkan teks tidak tebal.",
+ "info-fontWeight": "Ketebalan font yang digunakan untuk menampilkan teks biasa.",
"info-cursorBlink": "Apakah kursor berkedip.",
- "info-scrollback": "Jumlah scrollback di terminal. Scrollback adalah jumlah baris yang dipertahankan ketika baris digulirkan melampaui tampilan awal.",
- "info-tabStopWidth": "Ukuran tab berhenti di terminal.",
+ "info-scrollback": "Jumlah gulir balik di terminal. Gulir balik adalah jumlah baris yang dipertahankan saat baris digulirkan melampaui tampilan awal.",
+ "info-tabStopWidth": "Ukuran hentian tab di terminal.",
"info-letterSpacing": "Jarak antar karakter dalam piksel penuh.",
"info-imageSupport": "Apakah gambar didukung di terminal.",
"info-fontLigatures": "Apakah ligatur font diaktifkan di terminal.",
- "info-confirmTabClose": "Mintalah konfirmasi sebelum menutup tab terminal.",
+ "info-confirmTabClose": "Minta konfirmasi sebelum menutup tab terminal.",
"info-backup": "Membuat cadangan instalasi terminal.",
"info-restore": "Memulihkan cadangan instalasi terminal.",
"info-uninstall": "Menghapus instalasi terminal.",
"owned": "Dimiliki",
- "api_error": "API server turun, silakan coba setelah beberapa waktu.",
+ "api_error": "Server API sedang down, silakan coba beberapa saat lagi.",
"installed": "Terpasang",
"all": "Semua",
"medium": "Sedang",
@@ -345,10 +345,10 @@
"bottom": "Bawah",
"save all": "Simpan semua",
"close all": "Tutup semua",
- "unsaved files warning": "Beberapa berkas tidak disimpan. Klik 'Oke' pilih apa yang harus dilakukan atau tekan 'Batal' untuk kembali.",
- "save all warning": "Apakah Anda yakin ingin menyimpan semua berkas dan tutup? Tindakan ini tidak dapat dibalik.",
+ "unsaved files warning": "Beberapa berkas belum disimpan. Klik 'Oke' untuk memilih tindakan atau tekan 'Batal' untuk kembali.",
+ "save all warning": "Apakah Anda yakin ingin menyimpan semua berkas dan menutupnya? Tindakan ini tidak dapat diurungkan.",
"save all changes warning": "Apakah Anda yakin ingin menyimpan semua berkas?",
- "close all warning": "Apakah Anda yakin ingin menutup semua berkas? Anda akan kehilangan perubahan yang belum disimpan dan tindakan ini tidak dapat dibalik.",
+ "close all warning": "Apakah Anda yakin ingin menutup semua berkas? Anda akan kehilangan perubahan yang belum disimpan dan tindakan ini tidak dapat diurungkan.",
"refresh": "Segarkan",
"shortcut buttons": "Tombol pintasan",
"no result": "Tidak ada hasil",
@@ -387,17 +387,17 @@
"quicktools:search-settings": "Pengaturan Pencarian",
"quicktools:search-replace": "Mengganti",
"quicktools:search-replace-all": "Ganti Semua",
- "info-quicktoolssettings": "Kustomisasi tombol pintas dan tombol keyboard dalam wadah alat cepat di bawah editor untuk meningkatkan pengalaman pengkodean Anda.",
- "info-excludefolders": "Gunakan pola **/node_modules/** untuk mengabaikan semua berkas dari folder node_modules. Ini akan mengecualikan berkas dari terdaftar dan juga akan mencegah mereka dimasukkan dalam pencarian berkas.",
- "missed files": "Memindai {count} berkas setelah pencarian dimulai dan tidak akan dimasukkan dalam pencarian.",
+ "info-quicktoolssettings": "Sesuaikan tombol pintasan dan tombol papan ketik dalam wadah alat cepat di bawah editor untuk meningkatkan pengalaman pengkodean Anda.",
+ "info-excludefolders": "Gunakan pola **/node_modules/** untuk mengabaikan semua berkas dari folder node_modules. Ini akan mengecualikan berkas dari daftar dan juga mencegahnya diikutsertakan dalam pencarian berkas.",
+ "missed files": "Memindai {count} berkas setelah pencarian dimulai dan tidak akan dimasukkan dalam hasil pencarian.",
"remove": "Hapus",
"quicktools:command-palette": "Palet perintah",
"default file encoding": "Enkoding berkas default",
- "remove entry": "Apakah Anda yakin ingin menghapus '{name}' dari jalur yang disimpan? Harap dicatat bahwa menghapusnya tidak akan menghapus jalur itu sendiri.",
- "delete entry": "Konfirmasikan penghapusan: '{name}'. Tindakan ini tidak dapat diurungkan. Melanjutkan?",
- "change encoding": "Buka kembali '{file}' dengan enkoding '{encoding}'? Tindakan ini akan mengakibatkan hilangnya perubahan yang belum disimpan yang dilakukan pada berkas. Apakah Anda ingin melanjutkan pembukaan kembali?",
- "reopen file": "Apakah Anda yakin ingin membuka kembali '{file}'? Setiap perubahan yang belum disimpan akan hilang.",
- "plugin min version": "{name} hanya tersedia dalam Acode - {v-code} dan di atas. Klik di sini untuk memperbarui.",
+ "remove entry": "Apakah Anda yakin ingin menghapus '{name}' dari jalur yang disimpan? Perlu diketahui bahwa menghapusnya tidak akan menghapus jalur itu sendiri.",
+ "delete entry": "Konfirmasi penghapusan: '{name}'. Tindakan ini tidak dapat diurungkan. Lanjutkan?",
+ "change encoding": "Buka kembali '{file}' dengan enkoding '{encoding}'? Tindakan ini akan mengakibatkan hilangnya perubahan yang belum disimpan pada berkas ini. Apakah Anda ingin melanjutkan?",
+ "reopen file": "Apakah Anda yakin ingin membuka kembali '{file}'? Semua perubahan yang belum disimpan akan hilang.",
+ "plugin min version": "{name} hanya tersedia di Acode - {v-code} ke atas. Klik di sini untuk memperbarui.",
"color preview": "Pratinjau warna",
"confirm": "Konfirmasi",
"problems": "Masalah",
@@ -407,16 +407,16 @@
"most_downloaded": "Paling Banyak Diunduh",
"newly_added": "Baru Ditambahkan",
"top_rated": "Peringkat Teratas",
- "rename not supported": "Mengganti nama pada direktori Termux tidak didukung",
+ "rename not supported": "Mengganti nama pada direktori Termux tidak didukung.",
"compress": "Kompres",
"copy uri": "Salin Uri",
"delete entries": "Apakah Anda yakin ingin menghapus {count} item?",
- "deleting items": "menghapus {count} item...",
+ "deleting items": "Menghapus {count} item...",
"import project zip": "Impor Proyek (zip)",
"changelog": "Catatan Perubahan",
"notifications": "Notifikasi",
"no_unread_notifications": "Tidak ada pemberitahuan yang belum dibaca",
- "should_use_current_file_for_preview": "Harus menggunakan berkas saat ini untuk pratinjau alih-alih default (index.html)",
+ "should_use_current_file_for_preview": "Gunakan berkas saat ini untuk pratinjau, alih-alih default (index.html).",
"fade fold widgets": "Widget Lipat Pudar",
"quicktools:home-key": "Kunci Home",
"quicktools:end-key": "Kunci End",
@@ -513,7 +513,7 @@
"add to home screen": "Tambah ke layar beranda",
"pin shortcuts not supported": "Pintasan layar beranda tidak didukung di perangkat ini.",
"save file before home shortcut": "Simpan berkas sebelum menambahkannya ke layar beranda.",
- "terminal_required_message_for_lsp": "Terminal tidak terpasang. Mohon pasang Terminal terlebih dahulu untuk menggunakan server LSP.",
+ "terminal_required_message_for_lsp": "Terminal belum terpasang. Mohon pasang Terminal terlebih dahulu untuk menggunakan server LSP.",
"shift click selection": "Pemilihan Shift + tekan/klik",
"earn ad-free time": "Ambil waktu bebas iklan",
"indent guides": "Panduan indentasi",
@@ -534,7 +534,7 @@
"lsp-empty": "Kosong",
"lsp-enabled": "Diaktifkan",
"lsp-error-add-server-failed": "Gagal menambahkan server",
- "lsp-error-args-must-be-array": "Argumen harus berupa sebuah senarai JSON",
+ "lsp-error-args-must-be-array": "Argumen harus berupa senarai JSON.",
"lsp-error-binary-command-required": "Perintah biner diperlukan",
"lsp-error-language-id-required": "Setidaknya satu ID bahasa diperlukan",
"lsp-error-package-required": "Setidaknya satu paket diperlukan",
@@ -552,14 +552,14 @@
"lsp-feature-signature": "Bantuan parameter fungsi",
"lsp-feature-signature-info": "Tampilkan petunjuk parameter fungsi saat mengetik.",
"lsp-feature-state-toast": "{feature} {state}",
- "lsp-initialization-options": "Opsi inisiasi",
- "lsp-initialization-options-json": "Opsi inisiasi (JSON)",
- "lsp-initialization-options-updated": "Opsi inisiasi diperbarui",
- "lsp-install-command": "Perintah pasang",
- "lsp-install-command-unavailable": "Perintah pasang tidak tersedia",
+ "lsp-initialization-options": "Opsi Inisialisasi",
+ "lsp-initialization-options-json": "Opsi Inisialisasi (JSON)",
+ "lsp-initialization-options-updated": "Opsi inisialisasi diperbarui.",
+ "lsp-install-command": "Perintah Pasang",
+ "lsp-install-command-unavailable": "Perintah pasang tidak tersedia.",
"lsp-install-info-check-failed": "Acode tidak dapat memverifikasi status pemasangan.",
- "lsp-install-info-missing": "Server bahasa tidak terpasang di dalam lingkungan terminal.",
- "lsp-install-info-ready": "Server bahasa terpasang dan siap.",
+ "lsp-install-info-missing": "Server bahasa belum terpasang di dalam lingkungan terminal.",
+ "lsp-install-info-ready": "Server bahasa terpasang dan siap digunakan.",
"lsp-install-info-unknown": "Status pemasangan tidak dapat diperiksa secara otomatis.",
"lsp-install-info-version-available": "Versi {version} tersedia.",
"lsp-install-notification": "{server} belum terpasang. Ketuk untuk memasang.",
@@ -570,8 +570,8 @@
"lsp-install-method-pip": "Paket pip",
"lsp-install-method-shell": "Shell kustom",
"lsp-install-method-title": "Metode pasang",
- "lsp-install-repair": "Pasang / perbaiki",
- "lsp-installation-status": "Status pemasangan",
+ "lsp-install-repair": "Pasang / Perbaiki",
+ "lsp-installation-status": "Status Pemasangan",
"lsp-installed": "Terpasang",
"lsp-invalid-timeout": "Nilai timeout tidak valid",
"lsp-language-ids": "ID bahasa (dipisah koma)",
@@ -582,10 +582,10 @@
"lsp-server-id": "ID server",
"lsp-server-label": "Label server",
"lsp-server-not-found": "Server tidak ditemukan",
- "lsp-server-uninstalled": "Server dicopot pemasangannya",
- "lsp-startup-timeout": "Batas waktu mulai",
- "lsp-startup-timeout-ms": "Batas waktu mulai (milidetik)",
- "lsp-startup-timeout-set": "Batas waktu mulai diatur ke {timeout} ms",
+ "lsp-server-uninstalled": "Server dicopot pemasangannya.",
+ "lsp-startup-timeout": "Batas Waktu Mulai",
+ "lsp-startup-timeout-ms": "Batas Waktu Mulai (Milidetik)",
+ "lsp-startup-timeout-set": "Batas waktu mulai diatur ke {timeout} ms.",
"lsp-state-disabled": "dinonaktifkan",
"lsp-state-enabled": "diaktifkan",
"lsp-status": "Status",
@@ -596,14 +596,14 @@
"lsp-status-not-installed": "Tidak terpasang",
"lsp-status-unknown": "Tidak diketahui",
"lsp-timeout-ms": "{timeout} ms",
- "lsp-uninstall-command-unavailable": "Perintah copot pemasangan tidak tersedia",
+ "lsp-uninstall-command-unavailable": "Perintah copot pemasangan tidak tersedia.",
"lsp-uninstall-notification": "Ketuk untuk menghapus {server}.",
- "lsp-uninstall-server": "Copot pemasangan server",
+ "lsp-uninstall-server": "Copot Pemasangan Server",
"lsp-update-command-optional": "Perintah perbarui (opsional)",
"lsp-update-command-unavailable": "Perintah perbarui tidak tersedia",
- "lsp-update-server": "Perbarui server",
+ "lsp-update-server": "Perbarui Server",
"lsp-version-line": "Versi: {version}",
- "lsp-view-initialization-options": "Lihat opsi inisiasi",
+ "lsp-view-initialization-options": "Lihat Opsi Inisialisasi",
"settings-category-about-acode": "Tentang Acode",
"settings-category-discover-apps": "Temukan lebih banyak aplikasi",
"settings-category-advanced": "Lanjutan",
@@ -632,63 +632,63 @@
"settings-category-support-acode": "Dukung Acode",
"settings-category-text-layout": "Teks & tampilan",
"settings-info-app-animation": "Kendalikan animasi transisi di seluruh aplikasi.",
- "settings-info-app-check-files": "Segarkan ulang editor ketika berkas berubah di luar Acode.",
+ "settings-info-app-check-files": "Segarkan editor saat berkas berubah di luar Acode.",
"settings-info-app-clean-install-state": "Hapus status instalasi yang tersimpan yang digunakan oleh alur orientasi dan pengaturan.",
"settings-info-app-confirm-on-exit": "Tanyakan sebelum menutup aplikasi.",
- "settings-info-app-console": "Pilih mana integrasi konsol debug yang Acode gunakan.",
+ "settings-info-app-console": "Pilih integrasi konsol debug yang digunakan Acode.",
"settings-info-app-default-file-encoding": "Enkoding bawaan ketika membuka atau membuat berkas.",
"settings-info-app-exclude-folders": "Lewati folder dan pola ketika mencari atau memindai.",
"settings-info-app-floating-button": "Tampilkan tombol aksi cepat yang melayang.",
- "settings-info-app-font-manager": "Pasang, kelola, atau menghapus font aplikasi.",
- "settings-info-app-fullscreen": "Sembunyikan bar status sistem ketika menggunakan Acode.",
+ "settings-info-app-font-manager": "Pasang, kelola, atau hapus font aplikasi.",
+ "settings-info-app-fullscreen": "Sembunyikan bilah status sistem saat menggunakan Acode.",
"settings-info-app-keybindings": "Edit berkas pemetaan tombol atau atur ulang pintasan.",
- "settings-info-app-keyboard-mode": "Pilih bagaimana papan ketik perangkat lunak berperilaku ketika mengedit.",
+ "settings-info-app-keyboard-mode": "Pilih perilaku papan ketik perangkat lunak saat mengedit.",
"settings-info-app-language": "Pilih bahasa aplikasi dan label yang diterjemahkan.",
- "settings-info-app-open-file-list-position": "Pilih dimana daftar berkas aktif muncul.",
- "settings-info-app-quick-tools-settings": "Urutkan ulang dan kustomisaikan pintasan alat cepat.",
- "settings-info-app-quick-tools-trigger-mode": "Pilih bagaimana alat cepat terbuka saat ditekan atau disentuh.",
- "settings-info-app-remember-files": "Buka ulang berkas yang dibuka terakhir kali.",
- "settings-info-app-remember-folders": "Buka ulang folder dari sesi sebelumnya.",
- "settings-info-app-retry-remote-fs": "Ulangi lagi operasi berkas jarak jauh setelah transfer gagal.",
+ "settings-info-app-open-file-list-position": "Pilih di mana daftar berkas aktif muncul.",
+ "settings-info-app-quick-tools-settings": "Urutkan ulang dan sesuaikan pintasan alat cepat.",
+ "settings-info-app-quick-tools-trigger-mode": "Pilih cara alat cepat terbuka saat ditekan atau disentuh.",
+ "settings-info-app-remember-files": "Buka kembali berkas yang terakhir dibuka.",
+ "settings-info-app-remember-folders": "Buka kembali folder dari sesi sebelumnya.",
+ "settings-info-app-retry-remote-fs": "Ulangi operasi berkas jarak jauh setelah transfer gagal.",
"settings-info-app-side-buttons": "Tampilkan tombol aksi ekstra di samping editor.",
"settings-info-app-sponsor-sidebar": "Tampilkan entri sponsor di bar samping.",
- "settings-info-app-touch-move-threshold": "Pergerakan minimum sebelum penyeretan sentuh terdeteksi.",
- "settings-info-app-vibrate-on-tap": "Aktifkan umpan balik getar untuk tekan dan kendali.",
+ "settings-info-app-touch-move-threshold": "Pergerakan minimum sebelum gestur seret sentuh terdeteksi.",
+ "settings-info-app-vibrate-on-tap": "Aktifkan umpan balik getar untuk ketukan dan kontrol.",
"settings-info-editor-autosave": "Simpan perubahan secara otomatis setelah jeda.",
- "settings-info-editor-color-preview": "Pratinjau nilai warna langsung di dalam editor.",
- "settings-info-editor-fade-fold-widgets": "Redupkan penanda lipatan hingga dibutuhkan.",
+ "settings-info-editor-color-preview": "Pratinjau nilai warna secara langsung di dalam editor.",
+ "settings-info-editor-fade-fold-widgets": "Redupkan penanda lipatan hingga diperlukan.",
"settings-info-editor-font-family": "Pilih tipe font yang digunakan di dalam editor.",
"settings-info-editor-font-size": "Atur ukuran teks di editor.",
- "settings-info-editor-format-on-save": "Jalankan pemformat ketika sebuah berkas tersimpan.",
- "settings-info-editor-hard-wrap": "Masukkan pemotong baris asli daripada hanya membungkusnya secara visual.",
- "settings-info-editor-indent-guides": "Tampilkan baris panduan indentasi.",
- "settings-info-editor-line-height": "Atur jarak vertikal diantara baris.",
+ "settings-info-editor-format-on-save": "Jalankan pemformat saat berkas disimpan.",
+ "settings-info-editor-hard-wrap": "Sisipkan pemotong baris asli daripada hanya membungkusnya secara visual.",
+ "settings-info-editor-indent-guides": "Tampilkan garis panduan indentasi.",
+ "settings-info-editor-line-height": "Atur jarak vertikal antarbaris.",
"settings-info-editor-line-numbers": "Tampilkan nomor baris di dalam gutter.",
"settings-info-editor-lint-gutter": "Tampilkan alat diagnostik dan penanda lint di gutter.",
"settings-info-editor-live-autocomplete": "Tampilkan saran ketika Anda mengetik.",
- "settings-info-editor-rainbow-brackets": "Warna menyamakan kurung dari kedalaman bersarang.",
+ "settings-info-editor-rainbow-brackets": "Warnai tanda kurung berdasarkan kedalaman bersarang.",
"settings-info-editor-relative-line-numbers": "Tampilkan jarak dari baris saat ini.",
- "settings-info-editor-rtl-text": "Ganti perilaku kanan-ke-kiri setiap baris.",
- "settings-info-editor-scroll-settings": "Atur ukuran bar gulir, kecepatan, dan perilaku gestur.",
- "settings-info-editor-shift-click-selection": "Perluas pemilihan dengan Shift + tekan atau klik.",
- "settings-info-editor-show-spaces": "Tampilkan penanda spasi dan jeda baris yang terlihat.",
- "settings-info-editor-soft-tab": "Masukkan spasi daripada karakter tab.",
- "settings-info-editor-tab-size": "Atur seberapa banyak spasi setiap langkah tab digunakan.",
+ "settings-info-editor-rtl-text": "Ganti perilaku kanan-ke-kiri per baris.",
+ "settings-info-editor-scroll-settings": "Atur ukuran bilah gulir, kecepatan, dan perilaku gestur.",
+ "settings-info-editor-shift-click-selection": "Perluas pemilihan dengan Shift + ketuk atau klik.",
+ "settings-info-editor-show-spaces": "Tampilkan penanda spasi dan pemotong baris yang terlihat.",
+ "settings-info-editor-soft-tab": "Sisipkan spasi sebagai pengganti karakter tab.",
+ "settings-info-editor-tab-size": "Atur jumlah spasi yang digunakan setiap langkah tab.",
"settings-info-editor-teardrop-size": "Atur ukuran penangan kursor untuk pengeditan sentuh.",
"settings-info-editor-text-wrap": "Bungkus baris panjang di dalam editor.",
- "settings-info-lsp-add-custom-server": "Daftarkan server bahasa kustom dengan perintah pasang, perbarui, dan luncur.",
- "settings-info-lsp-edit-init-options": "Edit opsi inisiasi sebagai JSON.",
+ "settings-info-lsp-add-custom-server": "Daftarkan server bahasa kustom dengan perintah pasang, perbarui, dan luncurkan.",
+ "settings-info-lsp-edit-init-options": "Edit opsi inisialisasi sebagai JSON.",
"settings-info-lsp-install-server": "Pasang atau perbaiki server bahasa ini.",
"settings-info-lsp-server-enabled": "Aktifkan atau nonaktifkan server bahasa ini.",
- "settings-info-lsp-startup-timeout": "Atur seberapa lama Acode menunggu untuk server memulai.",
+ "settings-info-lsp-startup-timeout": "Atur durasi tunggu Acode untuk server mulai.",
"settings-info-lsp-uninstall-server": "Hapus paket terpasang atau biner dari server ini.",
- "settings-info-lsp-update-server": "Perbarui server bahasa ini jika alur pembaruan tersedia.",
- "settings-info-lsp-view-init-options": "Lihat opsi inisiasi efektif sebagai JSON.",
+ "settings-info-lsp-update-server": "Perbarui server bahasa ini jika jalur pembaruan tersedia.",
+ "settings-info-lsp-view-init-options": "Lihat opsi inisialisasi efektif sebagai JSON.",
"settings-info-main-ad-rewards": "Tonton iklan untuk membuka akses bebas iklan sementara.",
"settings-info-main-app-settings": "Bahasa, perilaku aplikasi, dan alat akses cepat.",
- "settings-info-main-backup-restore": "Ekspor pengaturan ke pencadangan atau atur ulang mereka nanti.",
- "settings-info-main-changelog": "Lihat perbaruan saat ini dan catatan rilis.",
- "settings-info-main-edit-settings": "Edit berkas mentah settings.json secara langsung.",
+ "settings-info-main-backup-restore": "Ekspor pengaturan ke cadangan atau pulihkan nanti.",
+ "settings-info-main-changelog": "Lihat pembaruan saat ini dan catatan rilis.",
+ "settings-info-main-edit-settings": "Edit berkas settings.json secara langsung.",
"settings-info-main-editor-settings": "Font, tab, saran, dan tampilan editor.",
"settings-info-main-formatter": "Pilih pemformat untuk setiap bahasa yang didukung.",
"settings-info-main-lsp-settings": "Konfigurasi server bahasa dan kecerdasan editor.",
@@ -697,25 +697,25 @@
"settings-info-main-rateapp": "Nilai Acode di Google Play.",
"settings-info-main-remove-ads": "Buka akses permanen bebas iklan.",
"settings-info-main-reset": "Atur ulang Acode ke konfigurasi bawaannya.",
- "settings-info-main-sponsors": "Mendukung pengembangan Acode yang berkelanjutan.",
+ "settings-info-main-sponsors": "Dukung pengembangan Acode secara berkelanjutan.",
"settings-info-main-terminal-settings": "Tema Terminal, font, kursor, dan perilaku sesi.",
"settings-info-main-theme": "Tema aplikasi, kontras, dan warna kustom.",
"settings-info-preview-disable-cache": "Selalu muat ulang konten di dalam peramban-dalam-aplikasi.",
"settings-info-preview-host": "Nama host yang digunakan ketika membuka URL pratinjau.",
- "settings-info-preview-mode": "Pilih dimana pratinjau dibuka ketika Anda meluncurkannya.",
+ "settings-info-preview-mode": "Pilih di mana pratinjau dibuka saat Anda meluncurkannya.",
"settings-info-preview-preview-port": "Port yang digunakan oleh server pratinjau langsung.",
"settings-info-preview-server-port": "Port yang digunakan oleh server internal aplikasi.",
"settings-info-preview-show-console-toggler": "Tampilkan tombol konsol di dalam pratinjau.",
"settings-info-preview-use-current-file": "Utamakan berkas saat ini ketika memulai pratinjau.",
- "settings-info-terminal-convert-eol": "Konversikan akhiran baris saat menempelkan atau menampilkan output terminal.",
+ "settings-info-terminal-convert-eol": "Konversikan akhir baris saat menempel atau menampilkan keluaran terminal.",
"settings-note-formatter-settings": "Tetapkan pemformat untuk setiap bahasa. Pasang plugin pemformat untuk membuka lebih banyak opsi.",
- "settings-note-lsp-settings": "Server bahasa menambahkan penyelesaian otomatis, diagnostik, detail melayang, dan sebagainya. Mereka bekerja lebih baik dengan folder yang bisa diakses langsung oleh terminal bawaan Acode, seperti folder terminal/publik. Lokasi SAF, eksternal, dan jarak jauh dilewati secara default karena mereka mungkin menggunakan jalur yang di-cache atau virtual; aktifkan opsi kompatibilitas hanya jika Anda ingin mencobanya.",
+ "settings-note-lsp-settings": "Server bahasa menambahkan penyelesaian otomatis, diagnostik, informasi saat kursor diarahkan, dan sebagainya. Server bekerja lebih baik dengan folder yang dapat diakses langsung oleh terminal bawaan Acode, seperti folder terminal/publik. Lokasi SAF, eksternal, dan jarak jauh dilewati secara bawaan karena mungkin menggunakan jalur yang di-cache atau virtual; aktifkan opsi kompatibilitas hanya jika Anda ingin mencobanya.",
"search result label singular": "hasil",
"search result label plural": "hasil",
"pin tab": "Sematkan tab",
"unpin tab": "Lepas sematan tab",
"pinned tab": "Tab yang tersematkan",
- "unpin tab before closing": "Lepas sematan tab sebelum ditutup.",
+ "unpin tab before closing": "Lepas sematan tab sebelum menutupnya.",
"app font": "Font Aplikasi",
"app icon": "App icon",
"app icon changed": "App icon changed",
@@ -724,52 +724,52 @@
"lsp-transport-method-stdio": "STDIO (luncurkan perintah biner)",
"lsp-transport-method-websocket": "WebSocket (hubungkan ke sebuah URL ws/wss)",
"lsp-websocket-url": "URL WebSocket",
- "lsp-websocket-server-managed-externally": "Server ini dikelola secara eksternal lewat WebSocket.",
- "lsp-error-websocket-url-invalid": "URL WebSocket harus berawalan ws:// atau wss://",
- "lsp-error-websocket-url-required": "URL WebSocket diperlukan",
+ "lsp-websocket-server-managed-externally": "Server ini dikelola secara eksternal melalui WebSocket.",
+ "lsp-error-websocket-url-invalid": "URL WebSocket harus diawali dengan ws:// atau wss://.",
+ "lsp-error-websocket-url-required": "URL WebSocket diperlukan.",
"lsp-remove-custom-server": "Hapus server kustom",
"lsp-remove-custom-server-confirm": "Hapus server bahasa kustom {server}?",
"lsp-custom-server-removed": "Server kustom dihapus",
"settings-info-lsp-remove-custom-server": "Hapus server bahasa kustom ini dari Acode.",
- "unsaved selected tabs warning": "Beberapa tab terpilih tidak disimpan. Pilih apa yang harus dilakukan.",
+ "unsaved selected tabs warning": "Beberapa tab yang dipilih belum disimpan. Pilih tindakan yang akan dilakukan.",
"save selected tabs": "Simpan tab terpilih",
"close selected tabs": "Tutup tab terpilih",
- "save selected tabs warning": "Apakah Anda yakin ingin menyimpan dan menutup tab terpilih?",
- "close selected tabs warning": "Apakah Anda yakin ingin menutup tab terpilih? Anda akan kehilangan perubahan yang belum disimpan dan aksi ini tidak dapat dibatalkan.",
+ "save selected tabs warning": "Apakah Anda yakin ingin menyimpan dan menutup tab yang dipilih?",
+ "close selected tabs warning": "Apakah Anda yakin ingin menutup tab yang dipilih? Anda akan kehilangan perubahan yang belum disimpan dan tindakan ini tidak dapat diurungkan.",
"close tabs to right": "Tutup Kanan",
"close tabs to left": "Tutup Kiri",
"close other tabs": "Tutup Lainnya",
"auto close tags": "Penutup tag otomatis",
- "settings-info-editor-auto-close-tags": "Menyisipkan tag penutup di berkas HTML, XML, Vue, Angular, dan templat PHP secara otomatis.",
+ "settings-info-editor-auto-close-tags": "Sisipkan tag penutup secara otomatis di berkas HTML, XML, Vue, Angular, dan templat PHP.",
"ui zoom": "Pembesaran UI",
"settings-info-app-ui-zoom": "Skalakan teks di seluruh antarmuka Acode.",
"show share button": "Tampilkan tombol bagikan",
"settings-info-editor-show-share-button": "Tampilkan tombol bagikan di menu pemilihan.",
"plugin-not-supported": "Plugin tidak didukung",
"plugin-not-supported-info": "Plugin dibuat untuk versi lama dari Acode.",
- "login-to-view": "Mohon login untuk melihat ini...",
+ "login-to-view": "Mohon masuk untuk melihat ini...",
"iap-plugin-purchase-warning": "Plugin yang dibeli tidak disinkronkan ke akun Acode Anda. Gunakan akun Google yang sama di Play Store untuk memulihkan pembelian Anda.",
"iap-pro-purchase-warning": "Pembelian ini tidak akan disinkronkan ke akun Acode Anda. Gunakan akun Google yang sama di Play Store untuk memulihkan pembelian Anda.",
"confirm-login": "Anda belum masuk ke Acode, masuk sekarang?",
"local word completion": "Penyelesaian kata lokal",
"language package completion": "Penyelesaian paket bahasa",
"settings-info-editor-local-word-completion": "Sarankan kata dari berkas saat ini.",
- "settings-info-editor-language-completion": "Sarankan kata kunci, snippet, dan penyelesaian lainnya dari paket bahasa CodeMirror.",
+ "settings-info-editor-language-completion": "Sarankan kata kunci, cuplikan, dan penyelesaian lainnya dari paket bahasa CodeMirror.",
"terminal:failsafe": "Mode FailSafe",
- "terminal:failsafe-info": "Mulai terminal dengan shell sistem",
+ "terminal:failsafe-info": "Mulai terminal dengan shell sistem.",
"auto rename tags": "Ubah nama tag otomatis",
- "settings-info-editor-auto-rename-tags": "Ubah nama tag pembuka atau penutup yang sama ketika mengedit tag yang mirip HTML.",
+ "settings-info-editor-auto-rename-tags": "Ubah nama tag pembuka atau penutup yang berpasangan saat mengedit tag mirip HTML.",
"copying items": "Menyalin {count} item...",
- "cannot paste folder into itself": "Tidak bisa menempelkan folder ke dalam dirinya sendiri",
+ "cannot paste folder into itself": "Tidak dapat menempelkan folder ke dalam dirinya sendiri.",
"folder already exists": "Folder sudah ada",
"file already exists force named": "'{name}' sudah ada. Timpa?",
"lsp-allow-non-terminal-workspace": "Jalankan LSP di folder eksternal",
- "settings-info-lsp-allow-non-terminal-workspace": "Izinkan server bahasa untuk lokasi SAF, eksternal, dan jarak jauh. LSP berjalan di terminal bawaan Acode, yang tidak dapat mengakses lokasi tersebut, jadi fitur-fitur mungkin tidak dapat bekerja dengan benar. Karena itu akan terhubung ke jalur virtual atau lokasi cache.",
+ "settings-info-lsp-allow-non-terminal-workspace": "Izinkan server bahasa untuk lokasi SAF, eksternal, dan jarak jauh. LSP berjalan di terminal bawaan Acode yang tidak dapat mengakses lokasi tersebut, sehingga beberapa fitur mungkin tidak dapat bekerja dengan benar karena akan terhubung ke jalur virtual atau lokasi cache.",
"don't ask again": "Jangan tanyakan lagi",
"scrollbar height": "Tinggi bilah gulir",
"full": "Penuh",
"scroll past end": "Gulir melewati akhir",
- "settings-info-scroll-past-end": "Menambahkan spasi kosong ekstra di bawah editor, memungkinkan Anda untuk gulir baris terakhir ke atas.",
+ "settings-info-scroll-past-end": "Menambahkan ruang kosong tambahan di bawah editor, sehingga Anda dapat menggulirkan baris terakhir ke atas.",
"compact": "Ringkas",
"off": "Mati",
"quick tools height": "Tinggi alat cepat",
@@ -778,9 +778,9 @@
"recommend extensions": "Rekomendasikan ekstensi",
"settings-info-editor-recommend-extensions": "Sarankan plugin saat file dibuka sebagai teks biasa karena mode bahasa tidak tersedia.",
"extension recommendation title": "Ekstensi yang tersedia untuk {extension}",
- "extension recommendation message": "Tidak ada mode sintaksis yang diinstal untuk {extension}. Cari plugin untuk \"{keyword}\".",
+ "extension recommendation message": "Tidak ada mode sintaksis yang terpasang untuk {extension}. Cari plugin untuk \"{keyword}\".",
"extension request title": "Ekstensi tidak ditemukan untuk {extension}",
- "extension request message": "Minta plugin agar Acode dapat menyoroti jenis file ini.",
+ "extension request message": "Minta plugin agar Acode dapat menyoroti jenis berkas ini.",
"search plugins": "Cari plugin",
"request plugin": "Minta plugin",
"terminal:block": "Blok",
@@ -836,11 +836,43 @@
"info-terminal-show-scrollbar": "Tampilkan bilah gulir xterm di samping terminal.",
"terminal:show scrollbar": "Tampilkan Bilah Gulir",
"apply exclusions when copying": "Terapkan pengecualian saat menyalin",
- "settings-info-app-use-file-operation-exclusions": "Lewati file dan folder yang cocok dengan pola pengecualian selama operasi salin dan tempel.",
+ "settings-info-app-use-file-operation-exclusions": "Lewati berkas dan folder yang cocok dengan pola pengecualian selama operasi salin dan tempel.",
"horizontal scroll margin": "Margin gulir horizontal",
- "settings-info-horizontal-scroll-margin": "Menambahkan ruang kosong setelah baris terpanjang saat pembungkusan kata (word wrap) nonaktif. Masukkan nilai piksel utuh non-negatif apa pun.",
+ "settings-info-horizontal-scroll-margin": "Menambahkan ruang kosong setelah baris terpanjang saat pembungkus kata (word wrap) dinonaktifkan. Masukkan nilai piksel bilangan bulat non-negatif.",
"confirm app icon reward": "Tonton satu iklan berhadiah untuk menerapkan ikon aplikasi ini?",
"rewarded ad unavailable": "Iklan berhadiah saat ini tidak tersedia. Silakan coba lagi.",
"rewarded ad failed": "Iklan tidak dapat diselesaikan. Silakan coba lagi.",
- "rewarded ad incomplete": "Tonton iklan hingga selesai untuk mendapatkan hadiah."
+ "rewarded ad incomplete": "Tonton iklan hingga selesai untuk mendapatkan hadiah.",
+ "plugin-review:dialog-label": "Ulasan plugin",
+ "plugin-review:account-check-failed": "Akun Anda tidak dapat diperiksa. Coba lagi.",
+ "plugin-review:sign-in": "Masuk untuk memberi ulasan",
+ "plugin-review:edit": "Edit ulasan Anda",
+ "plugin-review:add": "Tambahkan ulasan...",
+ "plugin-review:placeholder": "Bagikan pengalaman Anda...",
+ "plugin-review:input-label": "Ulasan plugin",
+ "plugin-review:vote-group-label": "Suara",
+ "plugin-review:thumbs-up": "Suka",
+ "plugin-review:thumbs-down": "Tidak suka",
+ "plugin-review:delete": "Hapus ulasan",
+ "plugin-review:load-failed": "Ulasan tidak dapat dimuat.",
+ "plugin-review:retry": "Coba lagi",
+ "plugin-review:empty-title": "Belum ada ulasan",
+ "plugin-review:empty-description": "Jadilah yang pertama membagikan pengalaman Anda.",
+ "plugin-review:yours": "Ulasan Anda",
+ "plugin-review:community": "Ulasan komunitas",
+ "plugin-review:no-other-reviews": "Belum ada ulasan lain.",
+ "plugin-review:login-incomplete": "Proses masuk tidak selesai.",
+ "plugin-review:sign-in-failed": "Tidak dapat masuk.",
+ "plugin-review:session-expired-review": "Sesi Anda telah berakhir. Masuk lagi untuk memberi ulasan.",
+ "plugin-review:save-failed": "Ulasan tidak dapat disimpan.",
+ "plugin-review:delete-confirmation": "Hapus ulasan Anda? Tindakan ini tidak dapat dibatalkan.",
+ "plugin-review:session-expired-continue": "Sesi Anda telah berakhir. Masuk lagi untuk melanjutkan.",
+ "plugin-review:delete-failed": "Ulasan tidak dapat dihapus.",
+ "plugin-review:you": "Anda",
+ "plugin-review:edit-action": "Edit ulasan",
+ "plugin-review:recommended": "Merekomendasikan plugin ini",
+ "plugin-review:error-max-length": "Ulasan harus terdiri dari {max} karakter atau kurang.",
+ "plugin-review:error-downvote-comment": "Beri tahu developer apa yang dapat ditingkatkan.",
+ "plugin-review:error-empty": "Tambahkan komentar atau pilih Suka.",
+ "plugin-review:unrated": "Belum dinilai"
}
diff --git a/src/lang/index.d.ts b/src/lang/index.d.ts
index 84a5387d7c..b8291061ed 100644
--- a/src/lang/index.d.ts
+++ b/src/lang/index.d.ts
@@ -846,6 +846,38 @@ declare type LangStrings = {
"rewarded ad unavailable": string;
"rewarded ad failed": string;
"rewarded ad incomplete": string;
+ "plugin-review:dialog-label": string;
+ "plugin-review:account-check-failed": string;
+ "plugin-review:sign-in": string;
+ "plugin-review:edit": string;
+ "plugin-review:add": string;
+ "plugin-review:placeholder": string;
+ "plugin-review:input-label": string;
+ "plugin-review:vote-group-label": string;
+ "plugin-review:thumbs-up": string;
+ "plugin-review:thumbs-down": string;
+ "plugin-review:delete": string;
+ "plugin-review:load-failed": string;
+ "plugin-review:retry": string;
+ "plugin-review:empty-title": string;
+ "plugin-review:empty-description": string;
+ "plugin-review:yours": string;
+ "plugin-review:community": string;
+ "plugin-review:no-other-reviews": string;
+ "plugin-review:login-incomplete": string;
+ "plugin-review:sign-in-failed": string;
+ "plugin-review:session-expired-review": string;
+ "plugin-review:save-failed": string;
+ "plugin-review:delete-confirmation": string;
+ "plugin-review:session-expired-continue": string;
+ "plugin-review:delete-failed": string;
+ "plugin-review:you": string;
+ "plugin-review:edit-action": string;
+ "plugin-review:recommended": string;
+ "plugin-review:error-max-length": string;
+ "plugin-review:error-downvote-comment": string;
+ "plugin-review:error-empty": string;
+ "plugin-review:unrated": string;
};
declare var strings: LangStrings;
diff --git a/src/lang/ir-fa.json b/src/lang/ir-fa.json
index c1ef78a612..8d7957a6f7 100644
--- a/src/lang/ir-fa.json
+++ b/src/lang/ir-fa.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "برای اعمال این نماد برنامه، یک تبلیغ پاداشدار تماشا میکنید؟",
"rewarded ad unavailable": "تبلیغات پاداشدار در حال حاضر در دسترس نیستند. لطفاً دوباره تلاش کنید.",
"rewarded ad failed": "تبلیغ کامل نشد. لطفاً دوباره تلاش کنید.",
- "rewarded ad incomplete": "برای دریافت پاداش، تبلیغ را تا پایان تماشا کنید."
+ "rewarded ad incomplete": "برای دریافت پاداش، تبلیغ را تا پایان تماشا کنید.",
+ "plugin-review:dialog-label": "نظرهای افزونه",
+ "plugin-review:account-check-failed": "امکان بررسی حساب شما نبود. دوباره تلاش کنید.",
+ "plugin-review:sign-in": "برای ثبت نظر وارد شوید",
+ "plugin-review:edit": "نظر خود را ویرایش کنید",
+ "plugin-review:add": "افزودن نظر...",
+ "plugin-review:placeholder": "تجربهٔ خود را به اشتراک بگذارید...",
+ "plugin-review:input-label": "نظر افزونه",
+ "plugin-review:vote-group-label": "رأی",
+ "plugin-review:thumbs-up": "پسندیدم",
+ "plugin-review:thumbs-down": "نپسندیدم",
+ "plugin-review:delete": "حذف نظر",
+ "plugin-review:load-failed": "بارگیری نظرها ممکن نبود.",
+ "plugin-review:retry": "تلاش دوباره",
+ "plugin-review:empty-title": "هنوز نظری ثبت نشده است",
+ "plugin-review:empty-description": "نخستین نفری باشید که تجربهٔ خود را به اشتراک میگذارد.",
+ "plugin-review:yours": "نظر شما",
+ "plugin-review:community": "نظرهای کاربران",
+ "plugin-review:no-other-reviews": "هنوز نظر دیگری ثبت نشده است.",
+ "plugin-review:login-incomplete": "ورود کامل نشد.",
+ "plugin-review:sign-in-failed": "ورود ممکن نبود.",
+ "plugin-review:session-expired-review": "نشست شما منقضی شده است. برای ثبت نظر دوباره وارد شوید.",
+ "plugin-review:save-failed": "ذخیرهٔ نظر ممکن نبود.",
+ "plugin-review:delete-confirmation": "نظر شما حذف شود؟ این کار قابل بازگشت نیست.",
+ "plugin-review:session-expired-continue": "نشست شما منقضی شده است. برای ادامه دوباره وارد شوید.",
+ "plugin-review:delete-failed": "حذف نظر ممکن نبود.",
+ "plugin-review:you": "شما",
+ "plugin-review:edit-action": "ویرایش نظر",
+ "plugin-review:recommended": "این افزونه را پیشنهاد کرده است",
+ "plugin-review:error-max-length": "نظر باید حداکثر {max} نویسه باشد.",
+ "plugin-review:error-downvote-comment": "به توسعهدهنده بگویید چه چیزی میتواند بهتر شود.",
+ "plugin-review:error-empty": "یک دیدگاه بنویسید یا «پسندیدم» را انتخاب کنید.",
+ "plugin-review:unrated": "بدون امتیاز"
}
diff --git a/src/lang/it-it.json b/src/lang/it-it.json
index 775c346e91..9d09694c3c 100644
--- a/src/lang/it-it.json
+++ b/src/lang/it-it.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "Guardare un annuncio con ricompensa per applicare questa icona dell’app?",
"rewarded ad unavailable": "Gli annunci con ricompensa non sono disponibili al momento. Riprova.",
"rewarded ad failed": "Non è stato possibile completare l’annuncio. Riprova.",
- "rewarded ad incomplete": "Guarda l’annuncio fino alla fine per ottenere la ricompensa."
+ "rewarded ad incomplete": "Guarda l’annuncio fino alla fine per ottenere la ricompensa.",
+ "plugin-review:dialog-label": "Recensioni del plugin",
+ "plugin-review:account-check-failed": "Impossibile verificare il tuo account. Riprova.",
+ "plugin-review:sign-in": "Accedi per lasciare una recensione",
+ "plugin-review:edit": "Modifica la tua recensione",
+ "plugin-review:add": "Aggiungi una recensione…",
+ "plugin-review:placeholder": "Condividi la tua esperienza…",
+ "plugin-review:input-label": "Recensione del plugin",
+ "plugin-review:vote-group-label": "Voto",
+ "plugin-review:thumbs-up": "Mi piace",
+ "plugin-review:thumbs-down": "Non mi piace",
+ "plugin-review:delete": "Elimina recensione",
+ "plugin-review:load-failed": "Impossibile caricare le recensioni.",
+ "plugin-review:retry": "Riprova",
+ "plugin-review:empty-title": "Ancora nessuna recensione",
+ "plugin-review:empty-description": "Condividi per primo la tua esperienza.",
+ "plugin-review:yours": "La tua recensione",
+ "plugin-review:community": "Recensioni della community",
+ "plugin-review:no-other-reviews": "Ancora nessun'altra recensione.",
+ "plugin-review:login-incomplete": "Accesso non completato.",
+ "plugin-review:sign-in-failed": "Impossibile accedere.",
+ "plugin-review:session-expired-review": "La sessione è scaduta. Accedi di nuovo per lasciare una recensione.",
+ "plugin-review:save-failed": "Impossibile salvare la recensione.",
+ "plugin-review:delete-confirmation": "Eliminare la tua recensione? Questa azione non può essere annullata.",
+ "plugin-review:session-expired-continue": "La sessione è scaduta. Accedi di nuovo per continuare.",
+ "plugin-review:delete-failed": "Impossibile eliminare la recensione.",
+ "plugin-review:you": "Tu",
+ "plugin-review:edit-action": "Modifica recensione",
+ "plugin-review:recommended": "Consiglia questo plugin",
+ "plugin-review:error-max-length": "La recensione deve contenere al massimo {max} caratteri.",
+ "plugin-review:error-downvote-comment": "Spiega allo sviluppatore cosa potrebbe essere migliorato.",
+ "plugin-review:error-empty": "Aggiungi un commento o scegli Mi piace.",
+ "plugin-review:unrated": "Non valutato"
}
diff --git a/src/lang/ja-jp.json b/src/lang/ja-jp.json
index 326b525fc2..9901ac78ac 100644
--- a/src/lang/ja-jp.json
+++ b/src/lang/ja-jp.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "リワード広告を1本視聴して、このアプリアイコンを適用しますか?",
"rewarded ad unavailable": "現在リワード広告を利用できません。もう一度お試しください。",
"rewarded ad failed": "広告を完了できませんでした。もう一度お試しください。",
- "rewarded ad incomplete": "報酬を獲得するには、広告を最後まで視聴してください。"
+ "rewarded ad incomplete": "報酬を獲得するには、広告を最後まで視聴してください。",
+ "plugin-review:dialog-label": "プラグインのレビュー",
+ "plugin-review:account-check-failed": "アカウントを確認できませんでした。もう一度お試しください。",
+ "plugin-review:sign-in": "ログインしてレビュー",
+ "plugin-review:edit": "レビューを編集",
+ "plugin-review:add": "レビューを追加…",
+ "plugin-review:placeholder": "使用した感想を共有…",
+ "plugin-review:input-label": "プラグインのレビュー",
+ "plugin-review:vote-group-label": "評価",
+ "plugin-review:thumbs-up": "高評価",
+ "plugin-review:thumbs-down": "低評価",
+ "plugin-review:delete": "レビューを削除",
+ "plugin-review:load-failed": "レビューを読み込めませんでした。",
+ "plugin-review:retry": "再試行",
+ "plugin-review:empty-title": "まだレビューはありません",
+ "plugin-review:empty-description": "最初のレビューを投稿しましょう。",
+ "plugin-review:yours": "あなたのレビュー",
+ "plugin-review:community": "コミュニティのレビュー",
+ "plugin-review:no-other-reviews": "ほかのレビューはまだありません。",
+ "plugin-review:login-incomplete": "ログインが完了しませんでした。",
+ "plugin-review:sign-in-failed": "ログインできませんでした。",
+ "plugin-review:session-expired-review": "セッションの有効期限が切れました。もう一度ログインしてレビューしてください。",
+ "plugin-review:save-failed": "レビューを保存できませんでした。",
+ "plugin-review:delete-confirmation": "レビューを削除しますか?この操作は元に戻せません。",
+ "plugin-review:session-expired-continue": "セッションの有効期限が切れました。続行するにはもう一度ログインしてください。",
+ "plugin-review:delete-failed": "レビューを削除できませんでした。",
+ "plugin-review:you": "あなた",
+ "plugin-review:edit-action": "レビューを編集",
+ "plugin-review:recommended": "このプラグインをおすすめしています",
+ "plugin-review:error-max-length": "レビューは {max} 文字以内で入力してください。",
+ "plugin-review:error-downvote-comment": "改善してほしい点を開発者に伝えてください。",
+ "plugin-review:error-empty": "コメントを追加するか、高評価を選んでください。",
+ "plugin-review:unrated": "未評価"
}
diff --git a/src/lang/ko-kr.json b/src/lang/ko-kr.json
index b24526e9f9..1e1a369da5 100644
--- a/src/lang/ko-kr.json
+++ b/src/lang/ko-kr.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "보상형 광고 한 편을 시청하고 이 앱 아이콘을 적용할까요?",
"rewarded ad unavailable": "현재 보상형 광고를 이용할 수 없습니다. 다시 시도해 주세요.",
"rewarded ad failed": "광고를 완료하지 못했습니다. 다시 시도해 주세요.",
- "rewarded ad incomplete": "보상을 받으려면 광고를 끝까지 시청하세요."
+ "rewarded ad incomplete": "보상을 받으려면 광고를 끝까지 시청하세요.",
+ "plugin-review:dialog-label": "플러그인 리뷰",
+ "plugin-review:account-check-failed": "계정을 확인할 수 없습니다. 다시 시도하세요.",
+ "plugin-review:sign-in": "로그인하고 리뷰 작성",
+ "plugin-review:edit": "내 리뷰 수정",
+ "plugin-review:add": "리뷰 추가...",
+ "plugin-review:placeholder": "사용 경험을 공유하세요...",
+ "plugin-review:input-label": "플러그인 리뷰",
+ "plugin-review:vote-group-label": "평가",
+ "plugin-review:thumbs-up": "좋아요",
+ "plugin-review:thumbs-down": "싫어요",
+ "plugin-review:delete": "리뷰 삭제",
+ "plugin-review:load-failed": "리뷰를 불러올 수 없습니다.",
+ "plugin-review:retry": "다시 시도",
+ "plugin-review:empty-title": "아직 리뷰가 없습니다",
+ "plugin-review:empty-description": "첫 번째로 사용 경험을 공유해 보세요.",
+ "plugin-review:yours": "내 리뷰",
+ "plugin-review:community": "커뮤니티 리뷰",
+ "plugin-review:no-other-reviews": "아직 다른 리뷰가 없습니다.",
+ "plugin-review:login-incomplete": "로그인이 완료되지 않았습니다.",
+ "plugin-review:sign-in-failed": "로그인할 수 없습니다.",
+ "plugin-review:session-expired-review": "세션이 만료되었습니다. 다시 로그인하고 리뷰를 작성하세요.",
+ "plugin-review:save-failed": "리뷰를 저장할 수 없습니다.",
+ "plugin-review:delete-confirmation": "리뷰를 삭제할까요? 이 작업은 되돌릴 수 없습니다.",
+ "plugin-review:session-expired-continue": "세션이 만료되었습니다. 계속하려면 다시 로그인하세요.",
+ "plugin-review:delete-failed": "리뷰를 삭제할 수 없습니다.",
+ "plugin-review:you": "나",
+ "plugin-review:edit-action": "리뷰 수정",
+ "plugin-review:recommended": "이 플러그인을 추천함",
+ "plugin-review:error-max-length": "리뷰는 {max}자 이하여야 합니다.",
+ "plugin-review:error-downvote-comment": "개발자에게 개선할 점을 알려 주세요.",
+ "plugin-review:error-empty": "댓글을 추가하거나 좋아요를 선택하세요.",
+ "plugin-review:unrated": "평가 없음"
}
diff --git a/src/lang/ln-ln.json b/src/lang/ln-ln.json
new file mode 100644
index 0000000000..b86fe9d345
--- /dev/null
+++ b/src/lang/ln-ln.json
@@ -0,0 +1,846 @@
+{
+ "lang": "Lingala",
+ "about": "Mpo na yango",
+ "active files": "Ba fichier efungwami",
+ "alert": "Likebisi",
+ "app theme": "Motó ya application",
+ "autocorrect": "Pesa nzela na bobongisi ya automatique ?",
+ "autosave": "Kobomba yango moko",
+ "cancel": "Tika",
+ "change language": "Bobongola monoko",
+ "choose color": "Pona langi moko",
+ "clear": "Longola",
+ "close app": "Kanga app ?",
+ "commit message": "Nsango ya commit",
+ "console": "Konsole",
+ "copy": "Kopi",
+ "create folder error": "Ekoki, te kosala dossier ya sika.",
+ "cut": "Kata",
+ "delete": "Longola",
+ "dependencies": "Ba dépendance",
+ "delay": "Ntango ya kozela na millisecondes",
+ "editor settings": "Paramɛtrɛ ya mobongisi",
+ "editor theme": "Motó ya mobongisi",
+ "enter file name": "Koma nkombo ya fichier",
+ "enter folder name": "Koma nkombo ya dossier",
+ "empty folder message": "Dossier ezali mpamba",
+ "enter line number": "Koma nimero ya ligne",
+ "error": "Libunga",
+ "failed": "Elongi te",
+ "file already exists": "Fichier ezali déjà",
+ "file already exists force": "Fichier ezali déjà. Kokoma lisusu?",
+ "file changed": " has been changed, reload file?",
+ "file deleted": "Fichier elongolami",
+ "file is not supported": "Fichier oyo esungami te",
+ "file not supported": "Lolenge ya fichier oyo esungami te.",
+ "file too large": "Fichier ezali monene mingi mpo na kosalela yango. Bonene ya likolo ezali {size}",
+ "file renamed": "Nkombo ya fichier ebongwani",
+ "file saved": "Fichier ebombami",
+ "folder added": "Dossier ebakisami",
+ "folder already added": "Dossier ebakisami déjà",
+ "font size": "Bonene ya makomi",
+ "goto": "Kende na ligne",
+ "icons definition": "Ndimbola ya bilembo",
+ "info": "Sango",
+ "invalid value": "Valeur ezali malamu te",
+ "language changed": "Monoko ebongwani malamu",
+ "linting": "Tala libunga ya syntaxe",
+ "logout": "Bima",
+ "loading": "Ezali kokɔtisa",
+ "my profile": "Profil na ngai",
+ "new file": "Fichier ya sika",
+ "new folder": "Dossier ya sika",
+ "no": "Te",
+ "no editor message": "Fungola to sala fichier mpe dossier ya sika na menu",
+ "not set": "Etamwisami te",
+ "unsaved files close app": "Ba fichiers mosusu ebombami nanu te. Kanga application?",
+ "notice": "Mayebisi",
+ "open file": "Fungola fichier",
+ "open files and folders": "Fungola ba fichiers mpe ba dossiers",
+ "open folder": "Fungola dossier",
+ "open recent": "Fungola oyo euti kosalelama sika",
+ "ok": "OK",
+ "overwrite": "Koma likolo",
+ "paste": "Kangisa",
+ "preview mode": "Mode ya botali liboso",
+ "read only file": "Ekoki te kobomba fichier ya kotanga kaka. Meká Bomba lokola",
+ "reload": "Zongisa",
+ "rename": "Pesa kombo mosusu",
+ "replace": "Zongisa na esika",
+ "required": "Esika oyo esengeli kotondisama",
+ "run your web app": "Tambwisa application web na yo",
+ "save": "Bomba",
+ "saving": "Ezali kobomba",
+ "save as": "Bomba lokola",
+ "save file to run": "Bomba fichier oyo liboso ya kotambwisa yango na navigateur",
+ "search": "Luka",
+ "see logs and errors": "Tala ba logs mpe mabunga",
+ "select folder": "Pona dossier",
+ "settings": "Paramɛtrɛ",
+ "settings saved": "Paramɛtrɛ ebombami",
+ "show line numbers": "Lakisa mituya ya ba lignes",
+ "show hidden files": "Lakisa ba fichiers oyo ebombami",
+ "show spaces": "Lakisa ba espaces",
+ "soft tab": "Tab ya pete",
+ "sort by name": "Tanda na kotalela kombo",
+ "success": "Esalemi malamu",
+ "tab size": "Bonene ya tab",
+ "text wrap": "Kokanga milongo ya makomi",
+ "theme": "Motema ya app",
+ "title-listfiles": "Tanga ba fichiers",
+ "Ekoki te kolongola fichier": "unable to delete file",
+ "unable to open file": "Limbisa, ekoki te kofungola fichier",
+ "unable to open folder": "Limbisa, ekoki te kofungola dossier",
+ "unable to save file": "Limbisa, ekoki te kobomba fichier",
+ "unable to rename": "Limbisa, ekoki te kobongola kombo",
+ "unsaved file": "Fichier oyo ebombami te, kanga yango kaka?",
+ "warning": "Likebisi",
+ "use emmet": "Salela Emmet",
+ "use quick tools": "Salela bisaleli ya mbangu",
+ "yes": "Iyo",
+ "encoding": "Encodage ya makomi",
+ "syntax highlighting": "Kopesa balangi na syntaxe",
+ "read only": "Kotanga kaka",
+ "select all": "Pona nyonso",
+ "select branch": "Pona branche",
+ "create new branch": "Sala branche ya sika",
+ "use branch": "Salela branche",
+ "new branch": "Branche ya sika",
+ "branch": "Branch",
+ "key bindings": "Ba raccourcis ya clavier",
+ "edit": "Bobongisi",
+ "reset": "Zongisa na ebandeli",
+ "color": "Langi",
+ "select word": "Pona liloba",
+ "quick tools": "Bisaleli ya mbangu",
+ "select": "Pona",
+ "editor font": "Police ya éditeur",
+ "new project": "Projet ya sika",
+ "format": "Lolenge",
+ "project name": "Kombo ya projet",
+ "unsupported device": "Appareil na yo endimi thème te.",
+ "vibrate on tap": "Vibrer ntango ozali kofina",
+ "copy command is not supported by ftp.": "Commande ya kopi esungami te na FTP.",
+ "support title": "Sunga Acode",
+ "fullscreen": "Ekran mobimba",
+ "animation": "Botambwisi",
+ "backup": "Kopi ya libateli",
+ "restore": "Zongisa",
+ "backup successful": "Backup esalemi malamu",
+ "invalid backup file": "Fichier ya backup ezali malamu te",
+ "add path": "Bakisa nzela",
+ "live autocompletion": "Autocomplétion ya mbala moko",
+ "file properties": "Bizaleli ya fichier",
+ "path": "Nzela",
+ "type": "Lolenge",
+ "word count": "Motango ya maloba",
+ "line count": "Motango ya milɔngɔ",
+ "last modified": "Ebongisami mbala ya nsuka",
+ "size": "Bonene",
+ "share": "Kabola",
+ "show print margin": "Lakisa marge ya impression",
+ "login": "Kota",
+ "scrollbar size": "Bonene ya barre ya kokitisa",
+ "cursor controller size": "Bonene ya contrôleur ya curseur",
+ "none": "Eloko moko te",
+ "small": "Moke",
+ "large": "Monene",
+ "confirm on exit": "Kondimisa liboso ya kobima",
+ "show console": "Lakisa console",
+ "image": "Elilingi",
+ "insert file": "Kotisa fichier",
+ "insert color": "Kotisa langi",
+ "powersave mode warning": "Kanga mode ya kobomba nguya mpo na kotala na navigateur ya libanda.",
+ "exit": "Bima",
+ "custom": "Ya moto",
+ "reset warning": "Oza na ntembe te ete olingi kozongisa thème na ebandeli?",
+ "theme type": "Lolenge ya thème",
+ "light": "Pole",
+ "dark": "Molili",
+ "file browser": "Navigateur ya ba fichiers",
+ "operation not permitted": "Opération epesami nzela te",
+ "no such file or directory": "Fichier to dossier yango ezali te",
+ "input/output error": "Libunga ya entrée/sortie",
+ "permission denied": "Ndingisa eboyami",
+ "bad address": "Adresse ezali malamu te",
+ "file exists": "Fichier ezali",
+ "not a directory": "Ezali dossier te",
+ "is a directory": "Ezali dossier",
+ "invalid argument": "Argument ezali malamu te",
+ "too many open files in system": "Ba fichiers mingi efungwami na système",
+ "too many open files": "Ba fichiers mingi efungwami",
+ "text file busy": "Fichier ya makomi ezali kosalelama",
+ "no space left on device": "Esika etikali te na appareil",
+ "read-only file system": "Système ya fichiers ya kotanga kaka",
+ "file name too long": "Kombo ya fichier ezali molai mingi",
+ "too many users": "Basaleli bazali mingi",
+ "connection timed out": "Ntango ya connexion esili",
+ "connection refused": "Connexion eboyami",
+ "owner died": "Nkolo akufi",
+ "an error occurred": "Libunga moko esalemi",
+ "add ftp": "Bakisa FTP",
+ "add sftp": "Bakisa SFTP",
+ "save file": "Bomba fichier",
+ "save file as": "Bomba fichier lokola",
+ "files": "Ba fichiers",
+ "help": "Lisungi",
+ "file has been deleted": "{file} has been deleted!",
+ "feature not available": "Makoki oyo ezali te.",
+ "feature available in paid version": "Makoki oyo ezali kaka na version ya kofuta ya application.",
+ "deleted file": "Fichier elongolami",
+ "line height": "Molai ya ligne",
+ "preview info": "Soki olingi kosala fichier oyo ezali kosala, finá mpe simbá elembo ya kobɛta.",
+ "manage all files": "Pesa Acode nzela ya kokamba ba fichiers nyonso na paramètres mpo na kobongisa ba fichiers na appareil na yo na pete.",
+ "close file": "Kanga fichier",
+ "reset connections": "Zongisa ba connexions",
+ "check file changes": "Tala mbongwana ya fichier",
+ "open in browser": "Fungola na navigateur",
+ "desktop mode": "Mode ordinateur",
+ "toggle console": "Bongola console",
+ "new line mode": "Mode ya ligne ya sika",
+ "add a storage": "Bakisa esika ya kobomba",
+ "rate acode": "Pesa Acode note",
+ "support": "Lisungi",
+ "downloading file": "Ezali kokitisa {file}",
+ "downloading...": "Ezali kokɔtisa...",
+ "folder name": "Kombo ya dossier",
+ "keyboard mode": "Mode ya clavier",
+ "normal": "Ya momesano",
+ "app settings": "Paramɛtrɛ ya application",
+ "disable in-app-browser caching": "Kanga cache ya navigateur ya kati ya application",
+ "copied to clipboard": "Ekopedami na presse-papier",
+ "clipboard not available": "Clipboard ezali te.",
+ "remember opened files": "Kanisa ba fichiers oyo efungwamaki",
+ "remember opened folders": "Kanisa ba dossiers oyo efungwamaki",
+ "no suggestions": "Ba suggestions ezali te",
+ "no suggestions aggressive": "Ba suggestions ya makasi ezali te",
+ "install": "Tia",
+ "installing": "Ezali kotia...",
+ "plugins": "Ba plugins",
+ "recently used": "Esalelami kala mingi te",
+ "update": "Bongisa",
+ "uninstall": "Longola",
+ "download acode pro": "Kokitisa Acode Pro",
+ "loading plugins": "Ezali kokɔtisa ba plugins",
+ "diagonal scrolling": "Kokita na diagonal",
+ "reverse scrolling": "Kokita na ngámbo ya inverse",
+ "formatter": "Formatter",
+ "format on save": "Sala format tango ya kobomba",
+ "remove ads": "Longola bapub",
+ "faqs": "Mituna oyo etunamaka mingi",
+ "feedback": "Makanisi",
+ "header": "Motó ya likoló",
+ "sidebar": "Barre ya pembeni",
+ "inapp": "Inapp",
+ "browser": "Navigateur",
+ "fast": "Nokí",
+ "slow": "Malɛmbɛ",
+ "scroll settings": "Paramɛtrɛ ya kokita",
+ "scroll speed": "Mbangu ya kokita",
+ "loading...": "Ezali kokɔtisa...",
+ "no plugins found": "Plugin moko te ezwami",
+ "name": "Kombo",
+ "username": "Kombo ya mosaleli",
+ "ekoki kozala te": "optional",
+ "hostname": "Hostname",
+ "password": "Liloba ya sekele",
+ "security type": "Lolenge ya libateli",
+ "connection mode": "Mode ya connexion",
+ "port": "Port",
+ "key file": "Fichier ya fungola",
+ "select key file": "Pona fichier ya fungola",
+ "passphrase": "Maloba ya sekele",
+ "connecting...": "Ezali kokangisa...",
+ "type filename": "Koma kombo ya fichier",
+ "unable to load files": "Ekoki te kokɔtisa ba fichiers",
+ "preview port": "Port ya botali liboso",
+ "find file": "Luka fichier",
+ "system": "Sistɛmi",
+ "please select a formatter": "Pona formatter moko",
+ "case sensitive": "Kotalela makomi minene mpe mike",
+ "regular expression": "Regular expression",
+ "whole word": "Liloba mobimba",
+ "edit with": "Bongisa na",
+ "open with": "Fungola na",
+ "no app found to handle this file": "Application moko te ezwami mpo na kofungola fichier oyo",
+ "restore default settings": "Zongisa ba paramɛtrɛ ya liboso",
+ "server port": "Port ya serveur",
+ "preview settings": "Ba paramɛtrɛ ya botali liboso",
+ "preview settings note": "Soki port ya preview mpe port ya serveur ekeseni, application ekobanda serveur te mpe ekofungola https://: na navigateur to navigateur ya kati ya application. Yango ezali na tina soki ozali kosalela serveur esika mosusu.",
+ "backup/restore note": "It will only backup your settings, custom theme, installed plugins and key bindings. It will not backup your FTP/SFTP or App state.",
+ "host": "Host",
+ "retry ftp/sftp when fail": "Meka FTP/SFTP lisusu soki elongi te",
+ "more": "Mosusu",
+ "thank you :)": "Matondi :)",
+ "Kosomba ezali kozela": "Kosomba ezali kozela",
+ "Ebengami": "Ebengami",
+ "local": "Ya mboka",
+ "remote": "Ya mosika",
+ "show console toggler": "Lakisa bouton ya console",
+ "binary file": "Fichier oyo ezali na ba données binaires, olingi kofungola yango?",
+ "relative line numbers": "Mituya ya ba lignes na kotalela ligne oyo ezali sikoyo",
+ "elastic tabstops": "Ba tab stops oyo ebongwanaka",
+ "line based rtl switching": "Kobongola RTL na kotalela ligne",
+ "hard wrap": "Kokanga ligne na makasi",
+ "spellcheck": "Kotala mabunga ya makomi",
+ "wrap method": "Lolenge ya kokanga milongo",
+ "use textarea for ime": "Salela textarea mpo na IME",
+ "invalid plugin": "Plugin ezali malamu te",
+ "type command": "Koma command",
+ "plugin": "Plugin",
+ "quicktools trigger mode": "Lolenge ya kofungola bisaleli ya mbangu",
+ "print margin": "Marge ya impression",
+ "touch move threshold": "Limite ya mouvement ya touch",
+ "info-retryremotefsafterfail": "Meka lisusu connexion FTP/SFTP soki elongi te.",
+ "info-fullscreen": "Bomba barre ya motó na écran ya ebandeli.",
+ "info-checkfiles": "Tala mbongwana ya ba fichiers ntango application ezali na nsima.",
+ "info-console": "Pona console ya JavaScript. Console Legacy ezali ya liboso, mpe Eruda ezali console ya bato mosusu.",
+ "info-keyboardmode": "Keyboard mode for text input, no suggestions will hide suggestions and auto correct. If no suggestions does not work, try to change value to no suggestions aggressive.",
+ "info-rememberfiles": "Kanisa ba fichiers oyo efungwami ntango application ekangami.",
+ "info-rememberfolders": "Kanisa ba dossiers oyo efungwami ntango application ekangami.",
+ "info-floatingbutton": "Lakisa to bomba bouton flottant ya bisaleli ya mbangu.",
+ "info-openfilelistpos": "Esika ya kolakisa liste ya ba fichiers oyo ezali kosala.",
+ "info-touchmovethreshold": "Soki sensibilite ya touch ya appareil na yo ezali makasi mingi, bakisa motuya oyo mpo na kopekisa mouvement ya touch oyo esalemi na libunga.",
+ "info-scroll-settings": "Ba paramɛtrɛ oyo ezali na ba paramètres ya kokita, bakisa mpe kokanga milongo ya makomi.",
+ "info-animation": "Soki application ezali kosala malɛmbɛ, kangá animation.",
+ "info-quicktoolstriggermode": "Soki bouton ya bisaleli ya mbangu ezali kosala te, meká kobongola motuya oyo.",
+ "info-checkForAppUpdates": "Tala automatiquement soki ba mises à jour ya application ezali.",
+ "info-quickTools": "Lakisa to bomba ba outils ya noki.",
+ "info-showHiddenFiles": "Lakisa ba fichiers mpe ba dossiers oyo ebombami. (Bandaka na .)",
+ "info-listFiles": "Tanga automatiquement ba fichiers nyonso ntango dossier efungwami",
+ "info-all_file_access": "Pesa terminal accès na /sdcard mpe /storage.",
+ "info-fontSize": "Bonene ya makomi oyo esalelamaka mpo na kolakisa makomi.",
+ "info-fontFamily": "Lolenge ya makomi oyo esalelamaka mpo na kolakisa makomi.",
+ "info-theme": "Motó ya couleur ya terminal.",
+ "info-cursorStyle": "Lolenge ya curseur ntango terminal ezali na focus.",
+ "info-cursorInactiveStyle": "Lolenge ya curseur ntango terminal ezali na focus te.",
+ "info-fontWeight": "Bonene ya makomi oyo esalelamaka mpo na makomi oyo ezali minene te.",
+ "info-cursorBlink": "Soki curseur ekoti mpe ebimi.",
+ "info-scrollback": "Motango ya milongo oyo ebombamaka na terminal ntango ozali kokita.",
+ "info-tabStopWidth": "Bonene ya ba tab stops na terminal.",
+ "info-letterSpacing": "Esika oyo ezali kati ya makomi.",
+ "info-imageSupport": "Soki terminal ekoki kosala na bililingi.",
+ "info-fontLigatures": "Soki ba ligatures ya makomi efungwami na terminal.",
+ "info-confirmTabClose": "Senga kondimisa liboso ya kokanga ba onglets ya terminal.",
+ "info-backup": "Sala backup ya terminal.",
+ "info-restore": "Zongisa backup ya terminal.",
+ "info-uninstall": "Longola terminal.",
+ "owned": "Ezali ya ngai",
+ "api_error": "Serveur ya API ezali kosala te, meká lisusu nsima ya mwa ntango.",
+ "installed": "Etyami",
+ "all": "Nyonso",
+ "medium": "Ya kati-kati",
+ "refund": "Kozongisa mbongo",
+ "product not available": "Produit ezali te",
+ "no-product-info": "Produit oyo ezali te na mboka na yo sikoyo, meká lisusu na nsima.",
+ "close": "Kanga",
+ "explore": "Tala makambo mosusu",
+ "key bindings updated": "Ba raccourcis ya clavier ebongwani",
+ "search in files": "Luka na kati ya ba fichiers",
+ "exclude files": "Longola ba fichiers",
+ "include files": "Bakisa ba fichiers",
+ "search result": "{matches} ba résultats na {files} ba fichiers.",
+ "invalid regex": "Regex ezali na libunga: {message}.",
+ "bottom": "Na nse",
+ "save all": "Bomba nyonso",
+ "close all": "Kanga nyonso",
+ "unsaved files warning": "Ba fichiers mosusu ebombami nanu te. Finá 'OK' pona kopona nini osala, to 'Cancel' pona kozonga.",
+ "save all warning": "Oza na ntembe te ete olingi kobomba ba fichiers nyonso mpe kokanga yango? Likambo oyo ekoki kozongisama nsima te.",
+ "save all changes warning": "Oza na ntembe te ete olingi kobomba mbongwana nyonso ya ba fichiers?",
+ "close all warning": "Oza na ntembe te ete olingi kokanga ba fichiers nyonso? Mbongwana oyo ebombami te ekobunga mpe likambo oyo ekoki kozongisama nsima te.",
+ "refresh": "Zongisa",
+ "shortcut buttons": "Ba boutons ya raccourci",
+ "no result": "Eyano ezali te",
+ "searching...": "Koluka...",
+ "quicktools:ctrl-key": "Fungola ya Control/Command",
+ "quicktools:tab-key": "Fungola tab",
+ "quicktools:shift-key": "Fungola Shift",
+ "quicktools:undo": "Zongisa nsima",
+ "quicktools:redo": "Zongisa lisusu",
+ "quicktools:search": "Luka na fichier",
+ "quicktools:save": "Bomba fichier",
+ "quicktools:esc-key": "Fungola Escape",
+ "quicktools:curlybracket": "Kotisa ba accolade",
+ "quicktools:squarebracket": "Kotisa ba parenthèses carrées",
+ "quicktools:parentheses": "Kotisa ba parenthèse",
+ "quicktools:anglebracket": "Kotisa ba parenthèses angulaires",
+ "quicktools:left-arrow-key": "Flèche ya mwasi",
+ "quicktools:right-arrow-key": "Flèche ya mobali",
+ "quicktools:up-arrow-key": "Flèche likolo",
+ "quicktools:down-arrow-key": "Flèche na nse",
+ "quicktools:moveline-up": "Tombola ligne likolo",
+ "quicktools:moveline-down": "Kitisa ligne na nse",
+ "quicktools:copyline-up": "Kopi ligne likolo",
+ "quicktools:copyline-down": "Kopi ligne na nse",
+ "quicktools:semicolon": "Kotisa elembo ya point-virgule",
+ "quicktools:quotation": "Kotisa elembo ya citation",
+ "quicktools:and": "Kotisa elembo ya mpe",
+ "quicktools:bar": "Kotisa elembo ya barre",
+ "quicktools:equal": "Kotisa elembo ya ekokani",
+ "quicktools:slash": "Kotisa elembo ya slash",
+ "quicktools:exclamation": "Kotisa elembo ya exclamation",
+ "quicktools:alt-key": "Alt",
+ "quicktools:meta-key": "Windows/Meta",
+ "quicktools:search-prev": "Match oyo eleki",
+ "quicktools:search-next": "Match oyo elandi",
+ "quicktools:search-settings": "Ba paramɛtrɛ ya boluki",
+ "quicktools:search-replace": "Zongisa",
+ "quicktools:search-replace-all": "Zongisa nyonso",
+ "info-quicktoolssettings": "Bongisa ba boutons ya shortcuts mpe ba touches ya clavier na esika ya Quicktools oyo ezali na nse ya éditeur mpo na kobongisa ndenge ya kosala code.",
+ "info-excludefolders": "Salelá modèle **/node_modules/** mpo na koboya ba fichiers nyonso ya dossier node_modules. Ba fichiers yango ekomonana te na liste mpe ekosala te na boluki ya ba fichiers.",
+ "missed files": "Ba fichiers {count} etalelami nsima ya kobanda boluki mpe ekotisami te na boluki.",
+ "remove": "Longola",
+ "quicktools:command-palette": "Palette ya mitindo",
+ "default file encoding": "Encodage ya fichier ya liboso",
+ "remove entry": "Oza na ntembe te ete olingi kolongola '{name}' na ba chemins oyo ebombami? Koboma chemin yango moko te.",
+ "delete entry": "Ndima koboma: '{name}'. Likambo oyo ekoki kozongisama nsima te. Olingi kokoba?",
+ "change encoding": "Fungola lisusu '{file}' na encodage '{encoding}'? Likambo oyo ekobungisa mbongwana nyonso oyo ebombami nanu te. Olingi kokoba?",
+ "reopen file": "Oza na ntembe te ete olingi kofungola lisusu '{file}'? Mbongwana nyonso oyo ebombami nanu te ekobunga.",
+ "plugin min version": "{name} ezali kaka na Acode - {v-code} mpe ba versions ya likolo. Finá awa mpo na kosala mbongwana.",
+ "color preview": "Botali liboso ya langi",
+ "confirm": "Kondimisa",
+ "problems": "Mikakatano",
+ "show side buttons": "Lakisa ba boutons ya pembeni",
+ "bug_report": "Tinda rapɔ́rɛ ya libunga",
+ "verified publisher": "Mobimisi oyo andimami",
+ "most_downloaded": "Ekitisami mingi",
+ "newly_added": "Ebakisami sika",
+ "top_rated": "Oyo etangami malamu mingi",
+ "rename not supported": "Kobongola kombo na dossier ya Termux yango esungami te",
+ "compress": "Kokitisa bonene",
+ "copy uri": "Kopi URI",
+ "delete entries": "Oza na ntembe te ete olingi kolongola biloko {count}?",
+ "deleting items": "Kolongola biloko {count}...",
+ "import project zip": "Kokɔtisa projet (zip)",
+ "changelog": "Mbongwana ya version",
+ "notifications": "Mayebisi",
+ "no_unread_notifications": "Ezali na ba notifications oyo etángami te te",
+ "should_use_current_file_for_preview": "Esengeli kosalela fichier oyo ezali sikoyo mpo na preview na esika ya index.html ya liboso.",
+ "fade fold widgets": "Kokitisa polele ba widgets ya fold",
+ "quicktools:home-key": "Home",
+ "quicktools:end-key": "End",
+ "quicktools:pageup-key": "PageUp",
+ "quicktools:pagedown-key": "PageDown",
+ "quicktools:delete-key": "Longola",
+ "quicktools:tilde": "Kotisa elembo ya tilde",
+ "quicktools:backtick": "Kotisa backtick",
+ "quicktools:hash": "Kotisa elembo ya hash",
+ "quicktools:dollar": "Kotisa elembo ya dollar",
+ "quicktools:modulo": "Kotisa elembo ya modulo/pourcentage",
+ "quicktools:caret": "Kotisa elembo ya caret",
+ "plugin_enabled": "Plugin efungwami",
+ "plugin_disabled": "Plugin ekangami",
+ "enable_plugin": "Fungola plugin oyo",
+ "disable_plugin": "Kanga plugin oyo",
+ "open_source": "Open source",
+ "terminal settings": "Paramɛtrɛ ya terminal",
+ "font ligatures": "Ba ligatures ya makomi",
+ "letter spacing": "Espace kati ya balɛ́tɛ́lɛ",
+ "terminal:tab stop width": "Bonene ya tab stop",
+ "terminal:scrollback": "Milongo ya scrollback",
+ "terminal:cursor blink": "Kongenga ya curseur",
+ "terminal:font weight": "Bonene ya makomi",
+ "terminal:cursor inactive style": "Lolenge ya curseur oyo ezali inactif",
+ "terminal:cursor style": "Lolenge ya curseur",
+ "terminal:font family": "Libota ya makomi",
+ "terminal:convert eol": "Bongola suka ya ligne",
+ "terminal:confirm tab close": "Ndima kokanga onglet ya terminal",
+ "terminal:image support": "Lisungi ya bililingi",
+ "terminal": "Terminal",
+ "terminal not installed prompt": "Terminal etyá te. Olingi kobanda yango sikawa ?",
+ "terminal first launch prompt": "Environnement ya terminal etyá te. Ezali kopesa yo nzela ya kosalela ba commands, SSH mpe ba scripts. Olingi kotya yango sikawa ?",
+ "allFileAccess": "Accès na ba fichiers nyonso",
+ "fonts": "Makomi",
+ "sponsor": "Kosalisa",
+ "downloads": "Ba téléchargements",
+ "reviews": "Ba avis",
+ "overview": "Botali ya mobimba",
+ "contributors": "Bato oyo basalisaki",
+ "quicktools:hyphen": "Kotisa trait d'union",
+ "check for app updates": "Tala ba mises à jour ya application",
+ "prompt update check consent message": "Acode ekoki kotala ba mises à jour ya application ntango ozali na internet. Olingi kofungola botali ya ba mises à jour?",
+ "keywords": "Maloba ya ntina",
+ "author": "Mokomi",
+ "filtered by": "Eponami na",
+ "clean install state": "Ezalela ya installation ya pamba",
+ "backup created": "Backup esalemi",
+ "restore completed": "Zongisi esili",
+ "restore will include": "Oyo ekozongisa",
+ "restore warning": "Likambo oyo ekoki kozongisama nsima te. Olingi kokoba?",
+ "reload to apply": "Zongisa mpo na kosalela mbongwana?",
+ "reload app": "Kozongisa application",
+ "preparing backup": "Kobongisa backup",
+ "collecting settings": "Kozwa ba paramɛtrɛ",
+ "collecting key bindings": "Kozwa ba raccourcis",
+ "collecting plugins": "Kozwa makambo ya ba plugin",
+ "creating backup": "Kosala fichier ya backup",
+ "validating backup": "Kotalela backup",
+ "restoring key bindings": "Kozongisa ba raccourcis",
+ "restoring plugins": "Kozongisa ba plugins",
+ "restoring settings": "Kozongisa ba paramɛtrɛ",
+ "legacy backup warning": "Oyo ezali format ya backup ya kala. Ba fonctionnalités mosusu ekoki kozala limitées.",
+ "checksum mismatch": "Makambo ya checksum ekokani te - fichier ya backup ekoki kozala ebongisami to ebebisami.",
+ "plugin not found": "Plugin ezwami te na registre",
+ "paid plugin skipped": "Plugin ya kofuta - kosomba ezwami te",
+ "source not found": "Fichier source ezali lisusu te",
+ "restored": "Ezongisami",
+ "skipped": "Eleki",
+ "backup not valid object": "Fichier ya backup ezali objet ya malamu te",
+ "backup no data": "Fichier ya backup ezali na ba données ya kozongisa te",
+ "backup legacy warning": "Oyo ezali format ya backup ya kala (v1). Ba fonctionnalités mosusu ekoki kozala limitées.",
+ "backup missing metadata": "Ba informations ya backup ezali te - makambo mosusu ekoki kozanga.",
+ "backup checksum mismatch": "Checksum ekokani te - fichier ya backup ekoki kozala ebongwani to ebebi. Keba liboso ya kokoba.",
+ "backup checksum verify failed": "Kotalisa checksum elongi te",
+ "backup invalid settings": "Format ya ba paramɛtrɛ ezali na libunga",
+ "backup invalid keybindings": "Format ya ba keyboard shortcuts ezali na libunga",
+ "backup invalid plugins": "Format ya ba plugins oyo etiemami ezali na libunga",
+ "issues found": "Mikakatano emonani",
+ "error details": "Makambo ya libunga",
+ "active tools": "Bisaleli oyo ezali kosala",
+ "available tools": "Ba outils oyo ezali",
+ "recent": "Ba fichiers ya sika",
+ "command palette": "Fungola menu ya ba commandes",
+ "change theme": "Bobongola motó",
+ "documentation": "Mikanda ya lisungi",
+ "open in terminal": "Fungola na terminal",
+ "developer mode": "Mode ya developer",
+ "info-developermode": "Fungola ba outils ya developer (Eruda) pona ko déboguer ba plugins mpe kotala ezalela ya application. Inspecteur ekofungwama tango application ebandi.",
+ "developer mode enabled": "Mode ya developer efungwami. Salela palette ya mitindo mpo na kofungola to kokanga inspecteur (Ctrl+Shift+I).",
+ "developer mode disabled": "Mode ya developer ekangami",
+ "copy relative path": "Kopi nzela relatif",
+ "shortcut request sent": "Bosengi ya raccourci etindami. Finá Ajouter mpo na kosilisa.",
+ "add to home screen": "Bakisa na écran d'accueil",
+ "pin shortcuts not supported": "Ba shortcuts ya écran d'accueil esimbami te na appareil oyo.",
+ "save file before home shortcut": "Bomba fichier liboso ya kobakisa yango na écran d'accueil.",
+ "terminal_required_message_for_lsp": "Terminal ezali installed te. Install terminal liboso mpo na kosalela ba serveurs LSP.",
+ "shift click selection": "Poná na Shift + click",
+ "earn ad-free time": "Zwa ntango kozanga bapub",
+ "indent guides": "Ba guide ya kokɔtisa molɔngɔ",
+ "language servers": "Ba serveurs ya monoko",
+ "lint gutter": "Lakisa ba erreurs ya lint",
+ "rainbow brackets": "Ba parenthèses ya balangi",
+ "lsp-add-custom-server": "Bakisa serveur personnalisé",
+ "lsp-binary-args": "Ba arguments ya binaire (JSON array)",
+ "lsp-binary-command": "Command ya binaire",
+ "lsp-binary-path-optional": "Nzela ya binaire (ekoki kozala te)",
+ "lsp-check-command-optional": "Command ya kotala (option ya kobongola)",
+ "lsp-checking-installation-status": "Kotala ezalela ya installation...",
+ "lsp-configured": "Ebongisami",
+ "lsp-custom-server-added": "Serveur personnalisé ebakisami",
+ "lsp-default": "Ya liboso",
+ "lsp-details-line": "Makambo: {details}",
+ "lsp-edit-initialization-options": "Bongola ba options ya kobanda",
+ "lsp-empty": "Ezali mpamba",
+ "lsp-enabled": "Efongwami",
+ "lsp-error-add-server-failed": "Ekoki te kobakisa serveur.",
+ "lsp-error-args-must-be-array": "Ba arguments esengeli kozala tableau ya JSON",
+ "lsp-error-binary-command-required": "Command binary esengeli",
+ "lsp-error-language-id-required": "Esengeli kozala na ID moko ya monoko ata moko",
+ "lsp-error-package-required": "Esengeli kozala na package ata moko",
+ "lsp-error-server-id-required": "ID ya serveur esengeli",
+ "lsp-feature-completion": "Kosilisa code automatiquement",
+ "lsp-feature-completion-info": "Fungola ba suggestions ya autocomplete oyo ewutaka na serveur.",
+ "lsp-feature-diagnostics": "Botali mabunga",
+ "lsp-feature-diagnostics-info": "Lakisa ba erreurs mpe ba avertissements oyo ewutaka na serveur ya langue.",
+ "lsp-feature-formatting": "Bobongisi format",
+ "lsp-feature-formatting-info": "Fungola formatage ya code oyo ewutaka na serveur ya langue.",
+ "lsp-feature-hover": "Makambo ya code",
+ "lsp-feature-hover-info": "Lakisa ba informations ya type mpe documentation tango ozali kosala hover.",
+ "lsp-feature-inlay-hints": "Bilembo ya lisungi",
+ "lsp-feature-inlay-hints-info": "Lakisa ba informations ya lolenge ya code na kati ya éditeur.",
+ "lsp-feature-signature": "Lisungi ya signature",
+ "lsp-feature-signature-info": "Lakisa ba indications ya ba paramɛtrɛ ya fonction tango ozali kokoma.",
+ "lsp-feature-state-toast": "{feature} {state}",
+ "lsp-initialization-options": "Ba options ya kobanda",
+ "lsp-initialization-options-json": "Ba options ya kobanda (JSON)",
+ "lsp-initialization-options-updated": "Ba options ya kobanda ebongwani",
+ "lsp-install-command": "Command ya installation",
+ "lsp-install-command-unavailable": "Command ya installation ezali te.",
+ "lsp-install-info-check-failed": "Acode ekoki te kotala soki installation esili malamu.",
+ "lsp-install-info-missing": "Serveur ya monoko etiemami te na environnement ya terminal.",
+ "lsp-install-info-ready": "Serveur ya monoko etiemami mpe ezali prêt.",
+ "lsp-install-info-unknown": "Ezalela ya installation ekoki kotala yango automatiquement te.",
+ "lsp-install-info-version-available": "Version {version} ezali.",
+ "lsp-install-notification": "{server} language server is not installed. Tap to install.",
+ "lsp-install-method-apk": "Package APK",
+ "lsp-install-method-cargo": "Package Cargo",
+ "lsp-install-method-manual": "Binaire ya mabɔkɔ",
+ "lsp-install-method-npm": "Package npm",
+ "lsp-install-method-pip": "Package pip",
+ "lsp-install-method-shell": "Shell personnalisé",
+ "lsp-install-method-title": "Lolenge ya installation",
+ "lsp-install-repair": "Kotia / kobongisa",
+ "lsp-installation-status": "Ezalela ya installation",
+ "lsp-installed": "Eteni",
+ "lsp-invalid-timeout": "Motuya ya timeout ezali na libunga",
+ "lsp-language-ids": "Ba ID ya monoko (ekabolami na virgule)",
+ "lsp-packages-prompt": "Ba packages {method} (ekabwani na virgule)",
+ "lsp-remove-installed-files": "Longola ba fichiers installés pona {server}?",
+ "lsp-server-disabled-toast": "Serveur ekangami",
+ "lsp-server-enabled-toast": "Serveur efungwami",
+ "lsp-server-id": "ID ya serveur",
+ "lsp-server-label": "Kombo ya serveur",
+ "lsp-server-not-found": "Serveur ezwami te",
+ "lsp-server-uninstalled": "Serveur elongolami",
+ "lsp-startup-timeout": "Ntango ya kozela na ebandeli",
+ "lsp-startup-timeout-ms": "Ntango ya kozela na ebandeli (millisecondes)",
+ "lsp-startup-timeout-set": "Ntango ya kozela etiamisami na {timeout} ms",
+ "lsp-state-disabled": "ekangami",
+ "lsp-state-enabled": "efungwami",
+ "lsp-status": "Ezalela",
+ "lsp-status-check-failed": "Kotalela elongi te",
+ "lsp-status-installed": "Eteni",
+ "lsp-status-installed-version": "Etyami ({version})",
+ "lsp-status-line": "Ezali: {status}",
+ "lsp-status-not-installed": "Etyami te",
+ "lsp-status-unknown": "Eyebani te",
+ "lsp-timeout-ms": "{timeout} ms",
+ "lsp-uninstall-command-unavailable": "Command ya kolongola ezali te",
+ "lsp-uninstall-notification": "Finá mpo na kolongola serveur ya monoko {server}.",
+ "lsp-uninstall-server": "Longola serveur",
+ "lsp-update-command-optional": "Command ya mbongwana (option ya kobongisa)",
+ "lsp-update-command-unavailable": "Command ya mbongwana ezali te.",
+ "lsp-update-server": "Mbongwana ya serveur",
+ "lsp-version-line": "Version: {version}",
+ "lsp-view-initialization-options": "Talá ba options ya kobanda",
+ "settings-category-about-acode": "Mpo na Acode",
+ "settings-category-discover-apps": "Tala ba applications mosusu",
+ "settings-category-advanced": "Ya likolo",
+ "settings-category-assistance": "Lisungi",
+ "settings-category-core": "Paramɛtrɛ ya moboko",
+ "settings-category-cursor": "Curseur",
+ "settings-category-cursor-selection": "Curseur mpe kopona",
+ "settings-category-custom-servers": "Ba serveurs oyo ebongisami na moto",
+ "settings-category-customization-tools": "Bobongisi mpe bisaleli",
+ "settings-category-display": "Emoniseli",
+ "settings-category-editing": "Bobongisi",
+ "settings-category-features": "Makoki",
+ "settings-category-files-sessions": "Ba fichiers mpe ba sessions",
+ "settings-category-fonts": "Makomi",
+ "settings-category-general": "Ya monene",
+ "settings-category-guides-indicators": "Ba guides mpe bilembo",
+ "settings-category-installation": "Botie",
+ "settings-category-interface": "Interface",
+ "settings-category-maintenance": "Bobongisi mpe bobateli",
+ "settings-category-permissions": "Ndingisa",
+ "settings-category-preview": "Botali liboso",
+ "settings-category-scrolling": "Kokita",
+ "settings-category-server": "Serveur",
+ "settings-category-servers": "Ba serveurs",
+ "settings-category-session": "Session",
+ "settings-category-support-acode": "Sunga Acode",
+ "settings-category-text-layout": "Bobongisi ya makomi",
+ "settings-info-app-animation": "Kamba ba animation ya transition na kati ya application nyonso.",
+ "settings-info-app-check-files": "Zongisa ba éditeur soki ba fichier ebongwani libanda ya Acode.",
+ "settings-info-app-clean-install-state": "Longola ezalela ya installation oyo ebombami mpo na setup.",
+ "settings-info-app-confirm-on-exit": "Senga kondimisa liboso ya kokanga application.",
+ "settings-info-app-console": "Pona console ya débogage oyo Acode esalela.",
+ "settings-info-app-default-file-encoding": "Encodage ya liboso tango ya kofungola to kosala ba fichier.",
+ "settings-info-app-exclude-folders": "Longola ba dossier mpe ba modèle tango ya koluka.",
+ "settings-info-app-floating-button": "Lakisa bouton flottant ya ba actions ya noki.",
+ "settings-info-app-font-manager": "Kotia, kokamba to kolongola ba polices ya application.",
+ "settings-info-app-fullscreen": "Bomba barre ya système ntango ozali kosalela Acode.",
+ "settings-info-app-keybindings": "Bongola fichier ya ba raccourcis to zongisa yango na ndenge ya liboso.",
+ "settings-info-app-keyboard-mode": "Pona ndenge clavier ya logiciel esalaka ntango ozali kobongisa code.",
+ "settings-info-app-language": "Pona monoko ya application mpe ba labels oyo ebongolami.",
+ "settings-info-app-open-file-list-position": "Pona esika liste ya ba fichiers actifs ekomonana.",
+ "settings-info-app-quick-tools-settings": "Bongola molongo mpe ndenge ya ba raccourcis ya ba outils ya mbangu.",
+ "settings-info-app-quick-tools-trigger-mode": "Pona ndenge ba outils ya noki efungwamaka na touche to na kosimba écran.",
+ "settings-info-app-remember-files": "Fungola lisusu ba fichiers oyo ezalaki ya kofungwama mbala ya suka.",
+ "settings-info-app-remember-folders": "Fungola lisusu ba dossiers ya session oyo eleki.",
+ "settings-info-app-retry-remote-fs": "Meka lisusu ba opérations ya fichiers distants nsima ya transfert oyo elongi te.",
+ "settings-info-app-side-buttons": "Lakisa ba boutons ya actions ya kobakisa pembeni ya éditeur.",
+ "settings-info-app-sponsor-sidebar": "Lakisa sponsor na sidebar.",
+ "settings-info-app-touch-move-threshold": "Mouvement moke oyo esengeli liboso ya koyeba déplacement ya touch.",
+ "settings-info-app-vibrate-on-tap": "Fungola vibration ya appareil tango ozali kosimba ba boutons mpe ba contrôles.",
+ "settings-info-editor-autosave": "Bomba mbongwana automatiquement nsima ya mwa ntango.",
+ "settings-info-editor-color-preview": "Tala ba valeur ya langi na kati ya éditeur.",
+ "settings-info-editor-fade-fold-widgets": "Kitisa pole ya bilembo ya fold soki esengeli te.",
+ "settings-info-editor-font-family": "Pona lolenge ya police oyo esalelami na éditeur.",
+ "settings-info-editor-font-size": "Bongola bonene ya makomi ya éditeur.",
+ "settings-info-editor-format-on-save": "Sala formatage tango nyonso fichier ebombami.",
+ "settings-info-editor-hard-wrap": "Kotisa ba saut ya ligne ya solo na esika ya kaka kokanga yango na komona.",
+ "settings-info-editor-indent-guides": "Lakisa ba lignes ya guide ya indentation.",
+ "settings-info-editor-line-height": "Bongola espace ya likolo mpe ya se kati ya ba ligne.",
+ "settings-info-editor-line-numbers": "Lakisa mituya ya ba lignes pembeni ya éditeur.",
+ "settings-info-editor-lint-gutter": "Lakisa ba erreurs, ba diagnostics mpe ba marqueurs ya lint pembeni ya éditeur.",
+ "settings-info-editor-live-autocomplete": "Lakisa ba suggestions ntango ozali kokoma.",
+ "settings-info-editor-rainbow-brackets": "Pesa balangisi ya langi na ba crochet oyo ekokani na profondeur.",
+ "settings-info-editor-relative-line-numbers": "Lakisa distance uta na ligne oyo ozali kosalela.",
+ "settings-info-editor-rtl-text": "Bongola ndenge ya kokoma droite na gauche mpo na ligne moko na moko.",
+ "settings-info-editor-scroll-settings": "Bongola bonene ya barre ya défilement, vitesse mpe ndenge ya kosalela yango.",
+ "settings-info-editor-shift-click-selection": "Bakisa sélection na Shift + kosimba to kofina.",
+ "settings-info-editor-show-spaces": "Lakisa bilembo oyo emonisaka ba espaces mpe ba saut ya ligne.",
+ "settings-info-editor-soft-tab": "Kotisa ba espaces na esika ya ba caractères tab.",
+ "settings-info-editor-tab-size": "Pona motango ya ba espaces oyo tab moko esalela.",
+ "settings-info-editor-teardrop-size": "Bongola bonene ya poignée ya curseur mpo na édition na touch.",
+ "settings-info-editor-text-wrap": "Kanga ba ligne milayi na kati ya éditeur.",
+ "settings-info-lsp-add-custom-server": "Bakisa serveur ya langue personnalisé na ba commandes ya installation, mbongwana mpe lancement.",
+ "settings-info-lsp-edit-init-options": "Bongola ba options ya kobanda lokola JSON.",
+ "settings-info-lsp-install-server": "Kotia to kobongisa serveur oyo ya langue.",
+ "settings-info-lsp-server-enabled": "Kofungola to kokanga serveur oyo ya monoko.",
+ "settings-info-lsp-startup-timeout": "Pona tango oyo Acode ekoki kozela mpo serveur ebanda.",
+ "settings-info-lsp-uninstall-server": "Longola ba paquets to ba fichiers exécutables oyo ebombami mpo na serveur oyo.",
+ "settings-info-lsp-update-server": "Kobongisa serveur oyo ya monoko soki lolenge ya kobongisa ezali.",
+ "settings-info-lsp-view-init-options": "Tala ba options ya kobanda oyo ezali kosala lokola JSON.",
+ "settings-info-main-ad-rewards": "Tala ba publicité mpo na kozwa accès sans publicité mpo na mwa tango.",
+ "settings-info-main-app-settings": "Monoko, ndenge application esalaka mpe ba outils ya accès rapide.",
+ "settings-info-main-backup-restore": "Bimisa ba paramɛtrɛ na backup to zongisa yango sima.",
+ "settings-info-main-changelog": "Tala ba mbongwana ya sika mpe ba notes ya version.",
+ "settings-info-main-edit-settings": "Bongola fichier settings.json brut directement.",
+ "settings-info-main-editor-settings": "Ba police, ba tabs, ba suggestions mpe ndenge éditeur emonanaka.",
+ "settings-info-main-formatter": "Pona formatter pona langage moko na moko oyo esungami.",
+ "settings-info-main-lsp-settings": "Bongisa ba serveur ya monoko mpe mayele ya éditeur.",
+ "settings-info-main-plugins": "Tambwisa ba plugins oyo etiemi mpe misala na yango.",
+ "settings-info-main-preview-settings": "Mode ya preview, ba port ya serveur mpe ndenge navigateur esalaka.",
+ "settings-info-main-rateapp": "Pesa Acode note na Google Play.",
+ "settings-info-main-remove-ads": "Fungola accès ya libela sans publicité.",
+ "settings-info-main-reset": "Zongisa Acode na ba paramètres ya liboso.",
+ "settings-info-main-sponsors": "Sunga bokoli ya Acode oyo ezali kokoba.",
+ "settings-info-main-terminal-settings": "Motó ya terminal, police, curseur mpe ndenge session esalaka.",
+ "settings-info-main-theme": "Motó ya application, contraste mpe ba langi oyo ebongisami.",
+ "settings-info-preview-disable-cache": "Zongisa ntango nyonso makambo ya sika na navigateur ya kati ya application.",
+ "settings-info-preview-host": "Nkombo ya hôte oyo esalelami ntango URL ya preview efungwami.",
+ "settings-info-preview-mode": "Pona esika preview ekofungwama ntango obandi yango.",
+ "settings-info-preview-preview-port": "Port oyo serveur ya preview na tango ya solo esalelaka.",
+ "settings-info-preview-server-port": "Port oyo serveur ya kati ya application esalelaka.",
+ "settings-info-preview-show-console-toggler": "Lakisa bouton ya console na preview.",
+ "settings-info-preview-use-current-file": "Pona liboso fichier oyo ezali sikoyo ntango obandi preview.",
+ "settings-info-terminal-convert-eol": "Bongola ba suka ya ba lignes ntango ozali kokanga to kolakisa makambo ya terminal.",
+ "settings-note-formatter-settings": "Pesa formatter na monoko moko na moko. Installer ba plugins ya formatter mpo na kozwa ba options mosusu.",
+ "settings-note-lsp-settings": "Ba serveurs ya langue ebakisaka autocomplete, diagnostics, ba informations ya hover mpe makambo mosusu. Esalaka malamu mingi na ba dossiers oyo terminal intégré ya Acode ekoki kokoma directement, lokola ba dossiers terminal/public. Ba emplacements SAF, externes mpe distants etikalamaka na libanda automatiquement mpo bakoki kosalela ba chemins ya cache to virtuels; activer option ya compatibilité kaka soki olingi komeka yango.",
+ "search result label singular": "mbano",
+ "search result label plural": "mbano",
+ "pin tab": "Kangisa onglet",
+ "unpin tab": "Longola onglet na biloko ekangami",
+ "pinned tab": "Onglet ekangami",
+ "unpin tab before closing": "Longola tab na pin liboso ya kokanga yango.",
+ "app font": "Makomi ya application",
+ "settings-info-app-font-family": "Pona police oyo esalelami na interface mobimba ya application.",
+ "lsp-transport-method-stdio": "STDIO (bandisa commande ya binaire)",
+ "lsp-transport-method-websocket": "WebSocket (kota na URL ws/wss)",
+ "lsp-websocket-url": "URL ya WebSocket",
+ "lsp-websocket-server-managed-externally": "Serveur oyo etambwisami libanda na nzela ya WebSocket.",
+ "lsp-error-websocket-url-invalid": "URL ya WebSocket esengeli kobanda na ws:// to wss://",
+ "lsp-error-websocket-url-required": "URL ya WebSocket esengeli",
+ "lsp-remove-custom-server": "Longola serveur personnalisé",
+ "lsp-remove-custom-server-confirm": "Longola serveur personnalisé ya langage {server}?",
+ "lsp-custom-server-removed": "Serveur personnalisé elongolami",
+ "settings-info-lsp-remove-custom-server": "Longola serveur ya langue personnalisé oyo na Acode.",
+ "unsaved selected tabs warning": "Ba tabs mosusu oyo oponi ebombami nanu te. Pona nini osengeli kosala.",
+ "save selected tabs": "Bomba ba onglets oyo oponi",
+ "close selected tabs": "Kanga ba onglets oyo oponi",
+ "save selected tabs warning": "Oza na ntembe te ete olingi kobomba mpe kokanga ba tabs oyo oponi?",
+ "close selected tabs warning": "Oza na ntembe te ete olingi kokanga ba tabs oyo oponi? Mbongwana oyo ebombami nanu te ekobunga mpe likambo oyo ekoki kozongisama te.",
+ "close tabs to right": "Kanga oyo ezali na droite",
+ "close tabs to left": "Kanga oyo ezali na gauche",
+ "close other tabs": "Kanga ba onglets mosusu",
+ "auto close tags": "Kanga ba tags automatiquement",
+ "settings-info-editor-auto-close-tags": "Kotisa automatiquement ba balises ya kokanga na HTML, XML, Vue, Angular mpe PHP.",
+ "ui zoom": "Zoom ya interface",
+ "settings-info-app-ui-zoom": "Bongola bonene ya makomi na interface mobimba ya Acode.",
+ "plugin-not-supported": "Plugin oyo endimami te",
+ "plugin-not-supported-info": "Plugin esalemaki pona version ya kala ya Acode.",
+ "login-to-view": "Kota na compte mpo na komona yango...",
+ "show share button": "Lakisa bouton ya kokabola",
+ "settings-info-editor-show-share-button": "Lakisa bouton ya partage na menu ya sélection.",
+ "iap-plugin-purchase-warning": "Ba plugins oyo osombi ebongisami te na compte na yo ya Acode. Salela compte Google moko na Play Store mpo na kozongisa bosombi na yo.",
+ "iap-pro-purchase-warning": "Bosombi oyo ekobongisama te na compte na yo ya Acode. Salela compte Google moko na Play Store mpo na kozongisa bosombi na yo.",
+ "confirm-login": "Okoti nanu te na Acode, olingi kokota sikoyo?",
+ "local word completion": "Bobongisi ya maloba ya fichier",
+ "language package completion": "Bobongisi ya package ya lokota",
+ "settings-info-editor-local-word-completion": "Pesa ba suggestions ya maloba oyo ezali na fichier oyo ozali kosalela.",
+ "settings-info-editor-language-completion": "Pesaka ba mots ya ntina, ba snippets mpe ba suggestions ya CodeMirror.",
+ "terminal:failsafe-info": "Bandisa terminal na shell ya système",
+ "auto rename tags": "Bongola kombo ya ba tags automatiquement",
+ "settings-info-editor-auto-rename-tags": "Bongola kombo ya balise oyo ekokani tango ozali kobongisa ba balise ya HTML.",
+ "copying items": "Kokopa biloko {count}...",
+ "cannot paste folder into itself": "Okoki te ko coller dossier na kati na yango moko",
+ "folder already exists": "Dossier ezali déjà",
+ "file already exists force named": "'{name}' ezali deja. Olingi kokoma likolo na yango?",
+ "lsp-allow-non-terminal-workspace": "Tika LSP esala na ba dossiers ya libanda",
+ "settings-info-lsp-allow-non-terminal-workspace": "Pesa nzela na ba serveur ya monoko mpo na SAF, bisika ya libanda mpe bisika ya mosika. LSP esalaka na terminal ya kati ya Acode, yango ekoki kosala ete makambo mosusu esalaka malamu te.",
+ "don't ask again": "Kotuna lisusu te",
+ "scrollbar height": "Molai ya barre ya bokitisaka",
+ "full": "Mobimba",
+ "scroll past end": "Koba kokita koleka suka",
+ "settings-info-scroll-past-end": "Bakisa esika ya pamba na nse ya éditeur mpo okoka komema molongo ya suka likolo.",
+ "compact": "Kokómisa mokuse",
+ "off": "Ekangami",
+ "quick tools height": "Molai ya bisaleli ya mbangu",
+ "quick tools toggler": "Bascule ya bisaleli ya mbangu",
+ "running processes": "Ba processus oyo ezali kosala",
+ "recommend extensions": "Tinda ba extensions",
+ "settings-info-editor-recommend-extensions": "Pesaka ba plugins tango fichier efungwami lokola texte pamba mpo na kozanga mode ya monoko.",
+ "extension recommendation title": "Ba extensions ezali mpo na {extension}",
+ "extension recommendation message": "Mode ya syntax etiemami te mpo na {extension}. Luka ba plugins mpo na \"{keyword}\".",
+ "extension request title": "Extension ezwamaki te mpo na {extension}",
+ "extension request message": "Senga plugin mpo Acode ekoka kolakisa lolenge oyo ya fichier.",
+ "search plugins": "Luka ba plugins",
+ "request plugin": "Senga plugin",
+ "terminal:block": "Bloc",
+ "terminal:underline": "Mokomi na nse",
+ "terminal:bar": "Barre",
+ "terminal:inactive block": "Bloc",
+ "terminal:inactive underline": "Mokomi na nse",
+ "terminal:inactive bar": "Barre",
+ "terminal:inactive none": "Eloko moko te",
+ "terminal:normal": "Ya momesano",
+ "terminal:bold": "Makomi minene",
+ "quicktools-trigger:click": "Finá",
+ "quicktools-trigger:touch": "Kosimba",
+ "settings-info-terminal-uninstall": "Oza na ntembe te ete olingi kolongola terminal?",
+ "terminal:inactive outline": "Ndelo",
+ "restored successfully": "Terminal ezongisami na elonga",
+ "uninstalled successfully": "Terminal elongolami na elonga",
+ "enter plugin source": "Kota source ya plugin",
+ "enter keywords": "Kota ba maloba ya ntina",
+ "enter author name": "Kota kombo ya mokomi",
+ "update available": "Mbongwana ya sika ezali",
+ "update available info": "Acode {version} ezali sikoyo! Finá awa mpo na kotala yango.",
+ "plugin updates": "Ba mbongwana ya ba plugins",
+ "plugin updates singular": "Plugin 1 ezali na version ya sika.",
+ "plugin updates plural": "Ba plugins {count} ezali na ba versions ya sika.",
+ "just now": "Sikawa kaka",
+ "day singular": "Eleki mokolo {count}",
+ "hour singular": "Eleki ngonga {count}",
+ "min singular": "Eleki miniti {count}",
+ "day plural": "Eleki mikolo {count}",
+ "hour plural": "Eleki bangonga {count}",
+ "min plural": "Eleki baminiti {count}",
+ "settings-category-builtin-servers": "Ba serveurs oyo etongami na kati",
+ "settings-category-plugin-servers": "Ba serveurs ya ba plugins",
+ "new name": "Kombo ya sika",
+ "enter new name": "Koma kombo ya sika",
+ "code actions": "Misala ya code",
+ "active processes": "Ba processus oyo ezali kosala",
+ "total memory": "Mémoire mobimba",
+ "uptime": "Ntango ya mosala",
+ "note": "Likebisi",
+ "acode main process": "Processus monene ya Acode",
+ "ppid parent": "PPID (Moboti)",
+ "unknown": "Eyebani te",
+ "just started": "Ebandi sikawa",
+ "diff days": "Eleki mikolo {days}, bangonga {hr}",
+ "diff hr": "Eleki {hr}h {min}m",
+ "diff min": "Eleki {min}m {sec}s",
+ "diff sec": "Eleki {sec}s",
+ "command": "Mitindo",
+ "managed": "Etambwisami",
+ "acode service": "Service ya Acode",
+ "info-terminal-show-scrollbar": "Lakisa scrollbar ya xterm pembeni ya terminal.",
+ "terminal:show scrollbar": "Lakisa barre ya défilement",
+ "apply exclusions when copying": "Salela ba exclusions ntango ozali kokopa",
+ "settings-info-app-use-file-operation-exclusions": "Pusa ba fichier mpe ba dossier oyo ekokani na ba règles ya exclusion tango ya kopiya mpe kokanga.",
+ "horizontal scroll margin": "Marge ya kokita na ngámbo",
+ "settings-info-horizontal-scroll-margin": "Bakisa esika ya pamba nsima ya ligne oyo eleki molai ntango retour à la ligne ezali kosalelama te. Tia motuya mobimba ya pixels oyo ezali négatif te.",
+ "conflict error": "Matata! Zela liboso ya kosala commit mosusu.",
+ "terminal:failsafe": "Mode FailSafe",
+ "app icon": "App icon",
+ "app icon changed": "App icon changed",
+ "settings-info-app-icon": "Choose the app icon displayed on your device.",
+ "confirm app icon reward": "Watch one rewarded ad to apply this app icon?",
+ "rewarded ad unavailable": "Rewarded ads are unavailable right now. Please try again.",
+ "rewarded ad failed": "The ad could not be completed. Please try again.",
+ "rewarded ad incomplete": "Finish watching the ad to earn the reward."
+}
diff --git a/src/lang/ml-in.json b/src/lang/ml-in.json
index cc44821d8f..d0f3823fea 100644
--- a/src/lang/ml-in.json
+++ b/src/lang/ml-in.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "ഈ ആപ്പ് ഐക്കൺ ഉപയോഗിക്കാൻ പ്രതിഫലമുള്ള ഒരു പരസ്യം കാണണോ?",
"rewarded ad unavailable": "പ്രതിഫലമുള്ള പരസ്യങ്ങൾ ഇപ്പോൾ ലഭ്യമല്ല. ദയവായി വീണ്ടും ശ്രമിക്കുക.",
"rewarded ad failed": "പരസ്യം പൂർത്തിയാക്കാനായില്ല. ദയവായി വീണ്ടും ശ്രമിക്കുക.",
- "rewarded ad incomplete": "പ്രതിഫലം ലഭിക്കാൻ പരസ്യം മുഴുവനായി കാണുക."
+ "rewarded ad incomplete": "പ്രതിഫലം ലഭിക്കാൻ പരസ്യം മുഴുവനായി കാണുക.",
+ "plugin-review:dialog-label": "പ്ലഗിൻ അവലോകനങ്ങൾ",
+ "plugin-review:account-check-failed": "നിങ്ങളുടെ അക്കൗണ്ട് പരിശോധിക്കാനായില്ല. വീണ്ടും ശ്രമിക്കുക.",
+ "plugin-review:sign-in": "അവലോകനം നൽകാൻ സൈൻ ഇൻ ചെയ്യുക",
+ "plugin-review:edit": "നിങ്ങളുടെ അവലോകനം തിരുത്തുക",
+ "plugin-review:add": "അവലോകനം ചേർക്കുക...",
+ "plugin-review:placeholder": "നിങ്ങളുടെ അനുഭവം പങ്കിടുക...",
+ "plugin-review:input-label": "പ്ലഗിൻ അവലോകനം",
+ "plugin-review:vote-group-label": "വോട്ട്",
+ "plugin-review:thumbs-up": "ഇഷ്ടപ്പെട്ടു",
+ "plugin-review:thumbs-down": "ഇഷ്ടപ്പെട്ടില്ല",
+ "plugin-review:delete": "അവലോകനം ഇല്ലാതാക്കുക",
+ "plugin-review:load-failed": "അവലോകനങ്ങൾ ലോഡ് ചെയ്യാനായില്ല.",
+ "plugin-review:retry": "വീണ്ടും ശ്രമിക്കുക",
+ "plugin-review:empty-title": "ഇതുവരെ അവലോകനങ്ങളൊന്നുമില്ല",
+ "plugin-review:empty-description": "നിങ്ങളുടെ അനുഭവം ആദ്യം പങ്കിടൂ.",
+ "plugin-review:yours": "നിങ്ങളുടെ അവലോകനം",
+ "plugin-review:community": "കമ്മ്യൂണിറ്റി അവലോകനങ്ങൾ",
+ "plugin-review:no-other-reviews": "മറ്റ് അവലോകനങ്ങളൊന്നും ഇതുവരെ ഇല്ല.",
+ "plugin-review:login-incomplete": "സൈൻ ഇൻ പൂർത്തിയായില്ല.",
+ "plugin-review:sign-in-failed": "സൈൻ ഇൻ ചെയ്യാനായില്ല.",
+ "plugin-review:session-expired-review": "നിങ്ങളുടെ സെഷൻ കാലഹരണപ്പെട്ടു. അവലോകനം നൽകാൻ വീണ്ടും സൈൻ ഇൻ ചെയ്യുക.",
+ "plugin-review:save-failed": "അവലോകനം സേവ് ചെയ്യാനായില്ല.",
+ "plugin-review:delete-confirmation": "നിങ്ങളുടെ അവലോകനം ഇല്ലാതാക്കണോ? ഇത് പഴയപടിയാക്കാനാകില്ല.",
+ "plugin-review:session-expired-continue": "നിങ്ങളുടെ സെഷൻ കാലഹരണപ്പെട്ടു. തുടരാൻ വീണ്ടും സൈൻ ഇൻ ചെയ്യുക.",
+ "plugin-review:delete-failed": "അവലോകനം ഇല്ലാതാക്കാനായില്ല.",
+ "plugin-review:you": "നിങ്ങൾ",
+ "plugin-review:edit-action": "അവലോകനം തിരുത്തുക",
+ "plugin-review:recommended": "ഈ പ്ലഗിൻ ശുപാർശ ചെയ്തു",
+ "plugin-review:error-max-length": "അവലോകനം {max} അക്ഷരങ്ങളോ അതിൽ കുറവോ ആയിരിക്കണം.",
+ "plugin-review:error-downvote-comment": "എന്താണ് മെച്ചപ്പെടുത്താനാകുന്നതെന്ന് ഡെവലപ്പറോട് പറയുക.",
+ "plugin-review:error-empty": "ഒരു അഭിപ്രായം ചേർക്കുക അല്ലെങ്കിൽ ഇഷ്ടപ്പെട്ടു തിരഞ്ഞെടുക്കുക.",
+ "plugin-review:unrated": "വിലയിരുത്തിയിട്ടില്ല"
}
diff --git a/src/lang/mm-unicode.json b/src/lang/mm-unicode.json
index 2c0ca208c0..9f67ac2983 100644
--- a/src/lang/mm-unicode.json
+++ b/src/lang/mm-unicode.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "ဤအက်ပ်အိုင်ကွန်ကို အသုံးပြုရန် ဆုရကြော်ငြာတစ်ခုကို ကြည့်မလား။",
"rewarded ad unavailable": "ဆုရကြော်ငြာများကို လောလောဆယ် မရနိုင်ပါ။ ထပ်မံကြိုးစားပါ။",
"rewarded ad failed": "ကြော်ငြာကို အဆုံးအထိ မပြသနိုင်ခဲ့ပါ။ ထပ်မံကြိုးစားပါ။",
- "rewarded ad incomplete": "ဆုရရှိရန် ကြော်ငြာကို အဆုံးအထိ ကြည့်ပါ။"
+ "rewarded ad incomplete": "ဆုရရှိရန် ကြော်ငြာကို အဆုံးအထိ ကြည့်ပါ။",
+ "plugin-review:dialog-label": "ပလပ်အင် သုံးသပ်ချက်များ",
+ "plugin-review:account-check-failed": "သင့်အကောင့်ကို စစ်ဆေး၍မရပါ။ ထပ်မံကြိုးစားပါ။",
+ "plugin-review:sign-in": "သုံးသပ်ချက်ရေးရန် အကောင့်ဝင်ပါ",
+ "plugin-review:edit": "သင့်သုံးသပ်ချက်ကို ပြင်ဆင်ပါ",
+ "plugin-review:add": "သုံးသပ်ချက် ထည့်ရန်...",
+ "plugin-review:placeholder": "သင့်အတွေ့အကြုံကို မျှဝေပါ...",
+ "plugin-review:input-label": "ပလပ်အင် သုံးသပ်ချက်",
+ "plugin-review:vote-group-label": "မဲ",
+ "plugin-review:thumbs-up": "ကြိုက်သည်",
+ "plugin-review:thumbs-down": "မကြိုက်ပါ",
+ "plugin-review:delete": "သုံးသပ်ချက် ဖျက်ရန်",
+ "plugin-review:load-failed": "သုံးသပ်ချက်များကို ဖွင့်၍မရပါ။",
+ "plugin-review:retry": "ထပ်မံကြိုးစားပါ",
+ "plugin-review:empty-title": "သုံးသပ်ချက် မရှိသေးပါ",
+ "plugin-review:empty-description": "သင့်အတွေ့အကြုံကို ပထမဆုံး မျှဝေပါ။",
+ "plugin-review:yours": "သင့်သုံးသပ်ချက်",
+ "plugin-review:community": "အသိုင်းအဝိုင်း သုံးသပ်ချက်များ",
+ "plugin-review:no-other-reviews": "အခြားသုံးသပ်ချက် မရှိသေးပါ။",
+ "plugin-review:login-incomplete": "အကောင့်ဝင်ခြင်း မပြီးဆုံးပါ။",
+ "plugin-review:sign-in-failed": "အကောင့်ဝင်၍မရပါ။",
+ "plugin-review:session-expired-review": "သင့်အသုံးပြုချိန် ကုန်ဆုံးသွားပါပြီ။ သုံးသပ်ချက်ရေးရန် ပြန်ဝင်ပါ။",
+ "plugin-review:save-failed": "သုံးသပ်ချက်ကို သိမ်း၍မရပါ။",
+ "plugin-review:delete-confirmation": "သင့်သုံးသပ်ချက်ကို ဖျက်မလား။ ပြန်ယူ၍မရပါ။",
+ "plugin-review:session-expired-continue": "သင့်အသုံးပြုချိန် ကုန်ဆုံးသွားပါပြီ။ ဆက်လုပ်ရန် ပြန်ဝင်ပါ။",
+ "plugin-review:delete-failed": "သုံးသပ်ချက်ကို ဖျက်၍မရပါ။",
+ "plugin-review:you": "သင်",
+ "plugin-review:edit-action": "သုံးသပ်ချက် ပြင်ဆင်ရန်",
+ "plugin-review:recommended": "ဤပလပ်အင်ကို အကြံပြုထားသည်",
+ "plugin-review:error-max-length": "သုံးသပ်ချက်သည် စာလုံးရေ {max} လုံး သို့မဟုတ် ထိုထက်နည်းရမည်။",
+ "plugin-review:error-downvote-comment": "မည်သည့်အရာကို ပိုကောင်းအောင်လုပ်နိုင်ကြောင်း developer ကို ပြောပါ။",
+ "plugin-review:error-empty": "မှတ်ချက်ထည့်ပါ သို့မဟုတ် ကြိုက်သည်ကို ရွေးပါ။",
+ "plugin-review:unrated": "အဆင့်မသတ်မှတ်ရသေးပါ"
}
diff --git a/src/lang/mm-zawgyi.json b/src/lang/mm-zawgyi.json
index 0e9f1b919e..de23b6e30c 100644
--- a/src/lang/mm-zawgyi.json
+++ b/src/lang/mm-zawgyi.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "ဤအက္ပ္အိုင္ကြန္ကို အသုံးျပဳရန္ ဆုရေၾကာ္ျငာတစ္ခုကို ၾကည့္မလား။",
"rewarded ad unavailable": "ဆုရေၾကာ္ျငာမ်ားကို ေလာေလာဆယ္ မရႏိုင္ပါ။ ထပ္မံႀကိဳးစားပါ။",
"rewarded ad failed": "ေၾကာ္ျငာကို အဆုံးအထိ မျပသႏိုင္ခဲ့ပါ။ ထပ္မံႀကိဳးစားပါ။",
- "rewarded ad incomplete": "ဆုရရွိရန္ ေၾကာ္ျငာကို အဆုံးအထိ ၾကည့္ပါ။"
+ "rewarded ad incomplete": "ဆုရရွိရန္ ေၾကာ္ျငာကို အဆုံးအထိ ၾကည့္ပါ။",
+ "plugin-review:dialog-label": "ပလပ္အင္ သုံးသပ္ခ်က္မ်ား",
+ "plugin-review:account-check-failed": "သင့္အေကာင့္ကို စစ္ေဆး၍မရပါ။ ထပ္မံႀကိဳးစားပါ။",
+ "plugin-review:sign-in": "သုံးသပ္ခ်က္ေရးရန္ အေကာင့္ဝင္ပါ",
+ "plugin-review:edit": "သင့္သုံးသပ္ခ်က္ကို ျပင္ဆင္ပါ",
+ "plugin-review:add": "သုံးသပ္ခ်က္ ထည့္ရန္...",
+ "plugin-review:placeholder": "သင့္အေတြ႕အႀကဳံကို မွ်ေဝပါ...",
+ "plugin-review:input-label": "ပလပ္အင္ သုံးသပ္ခ်က္",
+ "plugin-review:vote-group-label": "မဲ",
+ "plugin-review:thumbs-up": "ႀကိဳက္သည္",
+ "plugin-review:thumbs-down": "မႀကိဳက္ပါ",
+ "plugin-review:delete": "သုံးသပ္ခ်က္ ဖ်က္ရန္",
+ "plugin-review:load-failed": "သုံးသပ္ခ်က္မ်ားကို ဖြင့္၍မရပါ။",
+ "plugin-review:retry": "ထပ္မံႀကိဳးစားပါ",
+ "plugin-review:empty-title": "သုံးသပ္ခ်က္ မရွိေသးပါ",
+ "plugin-review:empty-description": "သင့္အေတြ႕အႀကဳံကို ပထမဆုံး မွ်ေဝပါ။",
+ "plugin-review:yours": "သင့္သုံးသပ္ခ်က္",
+ "plugin-review:community": "အသိုင္းအဝိုင္း သုံးသပ္ခ်က္မ်ား",
+ "plugin-review:no-other-reviews": "အျခားသုံးသပ္ခ်က္ မရွိေသးပါ။",
+ "plugin-review:login-incomplete": "အေကာင့္ဝင္ျခင္း မၿပီးဆုံးပါ။",
+ "plugin-review:sign-in-failed": "အေကာင့္ဝင္၍မရပါ။",
+ "plugin-review:session-expired-review": "သင့္အသုံးျပဳခ်ိန္ ကုန္ဆုံးသြားပါၿပီ။ သုံးသပ္ခ်က္ေရးရန္ ျပန္ဝင္ပါ။",
+ "plugin-review:save-failed": "သုံးသပ္ခ်က္ကို သိမ္း၍မရပါ။",
+ "plugin-review:delete-confirmation": "သင့္သုံးသပ္ခ်က္ကို ဖ်က္မလား။ ျပန္ယူ၍မရပါ။",
+ "plugin-review:session-expired-continue": "သင့္အသုံးျပဳခ်ိန္ ကုန္ဆုံးသြားပါၿပီ။ ဆက္လုပ္ရန္ ျပန္ဝင္ပါ။",
+ "plugin-review:delete-failed": "သုံးသပ္ခ်က္ကို ဖ်က္၍မရပါ။",
+ "plugin-review:you": "သင္",
+ "plugin-review:edit-action": "သုံးသပ္ခ်က္ ျပင္ဆင္ရန္",
+ "plugin-review:recommended": "ဤပလပ္အင္ကို အႀကံျပဳထားသည္",
+ "plugin-review:error-max-length": "သုံးသပ္ခ်က္သည္ စာလုံးေရ {max} လုံး သို႔မဟုတ္ ထိုထက္နည္းရမည္။",
+ "plugin-review:error-downvote-comment": "မည္သည့္အရာကို ပိုေကာင္းေအာင္လုပ္ႏိုင္ေၾကာင္း developer ကို ေျပာပါ။",
+ "plugin-review:error-empty": "မွတ္ခ်က္ထည့္ပါ သို႔မဟုတ္ ႀကိဳက္သည္ကို ေ႐ြးပါ။",
+ "plugin-review:unrated": "အဆင့္မသတ္မွတ္ရေသးပါ"
}
diff --git a/src/lang/pl-pl.json b/src/lang/pl-pl.json
index 843821641a..890c7082b7 100644
--- a/src/lang/pl-pl.json
+++ b/src/lang/pl-pl.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "Obejrzeć reklamę z nagrodą, aby zastosować tę ikonę aplikacji?",
"rewarded ad unavailable": "Reklamy z nagrodą są teraz niedostępne. Spróbuj ponownie.",
"rewarded ad failed": "Nie udało się ukończyć reklamy. Spróbuj ponownie.",
- "rewarded ad incomplete": "Obejrzyj reklamę do końca, aby otrzymać nagrodę."
+ "rewarded ad incomplete": "Obejrzyj reklamę do końca, aby otrzymać nagrodę.",
+ "plugin-review:dialog-label": "Opinie o wtyczce",
+ "plugin-review:account-check-failed": "Nie udało się sprawdzić Twojego konta. Spróbuj ponownie.",
+ "plugin-review:sign-in": "Zaloguj się, aby dodać opinię",
+ "plugin-review:edit": "Edytuj swoją opinię",
+ "plugin-review:add": "Dodaj opinię…",
+ "plugin-review:placeholder": "Podziel się swoim doświadczeniem…",
+ "plugin-review:input-label": "Opinia o wtyczce",
+ "plugin-review:vote-group-label": "Głos",
+ "plugin-review:thumbs-up": "Lubię",
+ "plugin-review:thumbs-down": "Nie lubię",
+ "plugin-review:delete": "Usuń opinię",
+ "plugin-review:load-failed": "Nie udało się wczytać opinii.",
+ "plugin-review:retry": "Spróbuj ponownie",
+ "plugin-review:empty-title": "Brak opinii",
+ "plugin-review:empty-description": "Podziel się swoim doświadczeniem jako pierwsza osoba.",
+ "plugin-review:yours": "Twoja opinia",
+ "plugin-review:community": "Opinie społeczności",
+ "plugin-review:no-other-reviews": "Nie ma jeszcze innych opinii.",
+ "plugin-review:login-incomplete": "Logowanie nie zostało ukończone.",
+ "plugin-review:sign-in-failed": "Nie udało się zalogować.",
+ "plugin-review:session-expired-review": "Twoja sesja wygasła. Zaloguj się ponownie, aby dodać opinię.",
+ "plugin-review:save-failed": "Nie udało się zapisać opinii.",
+ "plugin-review:delete-confirmation": "Usunąć Twoją opinię? Tej operacji nie można cofnąć.",
+ "plugin-review:session-expired-continue": "Twoja sesja wygasła. Zaloguj się ponownie, aby kontynuować.",
+ "plugin-review:delete-failed": "Nie udało się usunąć opinii.",
+ "plugin-review:you": "Ty",
+ "plugin-review:edit-action": "Edytuj opinię",
+ "plugin-review:recommended": "Poleca tę wtyczkę",
+ "plugin-review:error-max-length": "Opinia może mieć maksymalnie {max} znaków.",
+ "plugin-review:error-downvote-comment": "Powiedz deweloperowi, co można poprawić.",
+ "plugin-review:error-empty": "Dodaj komentarz lub wybierz „Lubię”.",
+ "plugin-review:unrated": "Bez oceny"
}
diff --git a/src/lang/pt-br.json b/src/lang/pt-br.json
index 6ac0faea49..09938cbf79 100644
--- a/src/lang/pt-br.json
+++ b/src/lang/pt-br.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "Assistir a um anúncio com recompensa para aplicar este ícone do aplicativo?",
"rewarded ad unavailable": "Os anúncios com recompensa estão indisponíveis no momento. Tente novamente.",
"rewarded ad failed": "Não foi possível concluir o anúncio. Tente novamente.",
- "rewarded ad incomplete": "Assista ao anúncio até o fim para receber a recompensa."
+ "rewarded ad incomplete": "Assista ao anúncio até o fim para receber a recompensa.",
+ "plugin-review:dialog-label": "Avaliações do plugin",
+ "plugin-review:account-check-failed": "Não foi possível verificar sua conta. Tente novamente.",
+ "plugin-review:sign-in": "Entre para avaliar",
+ "plugin-review:edit": "Editar sua avaliação",
+ "plugin-review:add": "Adicionar uma avaliação...",
+ "plugin-review:placeholder": "Compartilhe sua experiência...",
+ "plugin-review:input-label": "Avaliação do plugin",
+ "plugin-review:vote-group-label": "Voto",
+ "plugin-review:thumbs-up": "Gostei",
+ "plugin-review:thumbs-down": "Não gostei",
+ "plugin-review:delete": "Excluir avaliação",
+ "plugin-review:load-failed": "Não foi possível carregar as avaliações.",
+ "plugin-review:retry": "Tentar novamente",
+ "plugin-review:empty-title": "Ainda não há avaliações",
+ "plugin-review:empty-description": "Seja a primeira pessoa a compartilhar sua experiência.",
+ "plugin-review:yours": "Sua avaliação",
+ "plugin-review:community": "Avaliações da comunidade",
+ "plugin-review:no-other-reviews": "Ainda não há outras avaliações.",
+ "plugin-review:login-incomplete": "O login não foi concluído.",
+ "plugin-review:sign-in-failed": "Não foi possível entrar.",
+ "plugin-review:session-expired-review": "Sua sessão expirou. Entre novamente para avaliar.",
+ "plugin-review:save-failed": "Não foi possível salvar a avaliação.",
+ "plugin-review:delete-confirmation": "Excluir sua avaliação? Esta ação não pode ser desfeita.",
+ "plugin-review:session-expired-continue": "Sua sessão expirou. Entre novamente para continuar.",
+ "plugin-review:delete-failed": "Não foi possível excluir a avaliação.",
+ "plugin-review:you": "Você",
+ "plugin-review:edit-action": "Editar avaliação",
+ "plugin-review:recommended": "Recomendou este plugin",
+ "plugin-review:error-max-length": "A avaliação deve ter no máximo {max} caracteres.",
+ "plugin-review:error-downvote-comment": "Diga ao desenvolvedor o que pode ser melhorado.",
+ "plugin-review:error-empty": "Adicione um comentário ou escolha Gostei.",
+ "plugin-review:unrated": "Sem avaliação"
}
diff --git a/src/lang/pu-in.json b/src/lang/pu-in.json
index c0030f7bb2..7f29eb6f43 100644
--- a/src/lang/pu-in.json
+++ b/src/lang/pu-in.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "ਕੀ ਇਸ ਐਪ ਆਈਕਨ ਨੂੰ ਲਾਗੂ ਕਰਨ ਲਈ ਇੱਕ ਇਨਾਮ ਵਾਲਾ ਇਸ਼ਤਿਹਾਰ ਦੇਖਣਾ ਹੈ?",
"rewarded ad unavailable": "ਇਨਾਮ ਵਾਲੇ ਇਸ਼ਤਿਹਾਰ ਇਸ ਵੇਲੇ ਉਪਲਬਧ ਨਹੀਂ ਹਨ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।",
"rewarded ad failed": "ਇਸ਼ਤਿਹਾਰ ਪੂਰਾ ਨਹੀਂ ਹੋ ਸਕਿਆ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।",
- "rewarded ad incomplete": "ਇਨਾਮ ਪ੍ਰਾਪਤ ਕਰਨ ਲਈ ਇਸ਼ਤਿਹਾਰ ਪੂਰਾ ਦੇਖੋ।"
+ "rewarded ad incomplete": "ਇਨਾਮ ਪ੍ਰਾਪਤ ਕਰਨ ਲਈ ਇਸ਼ਤਿਹਾਰ ਪੂਰਾ ਦੇਖੋ।",
+ "plugin-review:dialog-label": "ਪਲੱਗਇਨ ਸਮੀਖਿਆਵਾਂ",
+ "plugin-review:account-check-failed": "ਤੁਹਾਡੇ ਖਾਤੇ ਦੀ ਜਾਂਚ ਨਹੀਂ ਹੋ ਸਕੀ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।",
+ "plugin-review:sign-in": "ਸਮੀਖਿਆ ਦੇਣ ਲਈ ਸਾਈਨ ਇਨ ਕਰੋ",
+ "plugin-review:edit": "ਆਪਣੀ ਸਮੀਖਿਆ ਸੋਧੋ",
+ "plugin-review:add": "ਸਮੀਖਿਆ ਸ਼ਾਮਲ ਕਰੋ...",
+ "plugin-review:placeholder": "ਆਪਣਾ ਅਨੁਭਵ ਸਾਂਝਾ ਕਰੋ...",
+ "plugin-review:input-label": "ਪਲੱਗਇਨ ਸਮੀਖਿਆ",
+ "plugin-review:vote-group-label": "ਵੋਟ",
+ "plugin-review:thumbs-up": "ਪਸੰਦ",
+ "plugin-review:thumbs-down": "ਨਾਪਸੰਦ",
+ "plugin-review:delete": "ਸਮੀਖਿਆ ਮਿਟਾਓ",
+ "plugin-review:load-failed": "ਸਮੀਖਿਆਵਾਂ ਲੋਡ ਨਹੀਂ ਹੋ ਸਕੀਆਂ।",
+ "plugin-review:retry": "ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ",
+ "plugin-review:empty-title": "ਹਾਲੇ ਕੋਈ ਸਮੀਖਿਆ ਨਹੀਂ",
+ "plugin-review:empty-description": "ਆਪਣਾ ਅਨੁਭਵ ਸਾਂਝਾ ਕਰਨ ਵਾਲੇ ਪਹਿਲੇ ਵਿਅਕਤੀ ਬਣੋ।",
+ "plugin-review:yours": "ਤੁਹਾਡੀ ਸਮੀਖਿਆ",
+ "plugin-review:community": "ਭਾਈਚਾਰੇ ਦੀਆਂ ਸਮੀਖਿਆਵਾਂ",
+ "plugin-review:no-other-reviews": "ਹਾਲੇ ਹੋਰ ਕੋਈ ਸਮੀਖਿਆ ਨਹੀਂ।",
+ "plugin-review:login-incomplete": "ਸਾਈਨ ਇਨ ਪੂਰਾ ਨਹੀਂ ਹੋਇਆ।",
+ "plugin-review:sign-in-failed": "ਸਾਈਨ ਇਨ ਨਹੀਂ ਹੋ ਸਕਿਆ।",
+ "plugin-review:session-expired-review": "ਤੁਹਾਡਾ ਸੈਸ਼ਨ ਖਤਮ ਹੋ ਗਿਆ। ਸਮੀਖਿਆ ਦੇਣ ਲਈ ਦੁਬਾਰਾ ਸਾਈਨ ਇਨ ਕਰੋ।",
+ "plugin-review:save-failed": "ਸਮੀਖਿਆ ਸੰਭਾਲੀ ਨਹੀਂ ਜਾ ਸਕੀ।",
+ "plugin-review:delete-confirmation": "ਆਪਣੀ ਸਮੀਖਿਆ ਮਿਟਾਉਣੀ ਹੈ? ਇਹ ਵਾਪਸ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ।",
+ "plugin-review:session-expired-continue": "ਤੁਹਾਡਾ ਸੈਸ਼ਨ ਖਤਮ ਹੋ ਗਿਆ। ਜਾਰੀ ਰੱਖਣ ਲਈ ਦੁਬਾਰਾ ਸਾਈਨ ਇਨ ਕਰੋ।",
+ "plugin-review:delete-failed": "ਸਮੀਖਿਆ ਮਿਟਾਈ ਨਹੀਂ ਜਾ ਸਕੀ।",
+ "plugin-review:you": "ਤੁਸੀਂ",
+ "plugin-review:edit-action": "ਸਮੀਖਿਆ ਸੋਧੋ",
+ "plugin-review:recommended": "ਇਸ ਪਲੱਗਇਨ ਦੀ ਸਿਫ਼ਾਰਸ਼ ਕੀਤੀ",
+ "plugin-review:error-max-length": "ਸਮੀਖਿਆ {max} ਅੱਖਰਾਂ ਜਾਂ ਇਸ ਤੋਂ ਘੱਟ ਦੀ ਹੋਣੀ ਚਾਹੀਦੀ ਹੈ।",
+ "plugin-review:error-downvote-comment": "ਡਿਵੈਲਪਰ ਨੂੰ ਦੱਸੋ ਕਿ ਕੀ ਸੁਧਾਰਿਆ ਜਾ ਸਕਦਾ ਹੈ।",
+ "plugin-review:error-empty": "ਟਿੱਪਣੀ ਸ਼ਾਮਲ ਕਰੋ ਜਾਂ ਪਸੰਦ ਚੁਣੋ।",
+ "plugin-review:unrated": "ਹਾਲੇ ਮੁਲਾਂਕਣ ਨਹੀਂ"
}
diff --git a/src/lang/ru-ru.json b/src/lang/ru-ru.json
index 3fa063c1db..0453983187 100644
--- a/src/lang/ru-ru.json
+++ b/src/lang/ru-ru.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "Посмотреть рекламу с вознаграждением, чтобы применить этот значок приложения?",
"rewarded ad unavailable": "Реклама с вознаграждением сейчас недоступна. Повторите попытку.",
"rewarded ad failed": "Не удалось завершить просмотр рекламы. Повторите попытку.",
- "rewarded ad incomplete": "Досмотрите рекламу до конца, чтобы получить награду."
+ "rewarded ad incomplete": "Досмотрите рекламу до конца, чтобы получить награду.",
+ "plugin-review:dialog-label": "Отзывы о плагине",
+ "plugin-review:account-check-failed": "Не удалось проверить вашу учётную запись. Повторите попытку.",
+ "plugin-review:sign-in": "Войти, чтобы оставить отзыв",
+ "plugin-review:edit": "Редактировать свой отзыв",
+ "plugin-review:add": "Добавить отзыв…",
+ "plugin-review:placeholder": "Поделитесь своим опытом…",
+ "plugin-review:input-label": "Отзыв о плагине",
+ "plugin-review:vote-group-label": "Оценка",
+ "plugin-review:thumbs-up": "Нравится",
+ "plugin-review:thumbs-down": "Не нравится",
+ "plugin-review:delete": "Удалить отзыв",
+ "plugin-review:load-failed": "Не удалось загрузить отзывы.",
+ "plugin-review:retry": "Повторить",
+ "plugin-review:empty-title": "Отзывов пока нет",
+ "plugin-review:empty-description": "Станьте первым, кто поделится своим опытом.",
+ "plugin-review:yours": "Ваш отзыв",
+ "plugin-review:community": "Отзывы сообщества",
+ "plugin-review:no-other-reviews": "Других отзывов пока нет.",
+ "plugin-review:login-incomplete": "Вход не был завершён.",
+ "plugin-review:sign-in-failed": "Не удалось войти.",
+ "plugin-review:session-expired-review": "Сеанс истёк. Войдите снова, чтобы оставить отзыв.",
+ "plugin-review:save-failed": "Не удалось сохранить отзыв.",
+ "plugin-review:delete-confirmation": "Удалить ваш отзыв? Это действие нельзя отменить.",
+ "plugin-review:session-expired-continue": "Сеанс истёк. Войдите снова, чтобы продолжить.",
+ "plugin-review:delete-failed": "Не удалось удалить отзыв.",
+ "plugin-review:you": "Вы",
+ "plugin-review:edit-action": "Редактировать отзыв",
+ "plugin-review:recommended": "Рекомендует этот плагин",
+ "plugin-review:error-max-length": "Отзыв должен содержать не более {max} символов.",
+ "plugin-review:error-downvote-comment": "Расскажите разработчику, что можно улучшить.",
+ "plugin-review:error-empty": "Добавьте комментарий или выберите «Нравится».",
+ "plugin-review:unrated": "Нет оценок"
}
diff --git a/src/lang/tl-ph.json b/src/lang/tl-ph.json
index 2d9d72f94c..3342744dec 100644
--- a/src/lang/tl-ph.json
+++ b/src/lang/tl-ph.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "Manood ng isang ad na may gantimpala upang gamitin ang icon na ito ng app?",
"rewarded ad unavailable": "Hindi available ngayon ang mga ad na may gantimpala. Pakisubukang muli.",
"rewarded ad failed": "Hindi nakumpleto ang ad. Pakisubukang muli.",
- "rewarded ad incomplete": "Tapusin ang panonood ng ad upang makuha ang gantimpala."
+ "rewarded ad incomplete": "Tapusin ang panonood ng ad upang makuha ang gantimpala.",
+ "plugin-review:dialog-label": "Mga review ng plugin",
+ "plugin-review:account-check-failed": "Hindi masuri ang iyong account. Subukan muli.",
+ "plugin-review:sign-in": "Mag-sign in para mag-review",
+ "plugin-review:edit": "I-edit ang iyong review",
+ "plugin-review:add": "Magdagdag ng review...",
+ "plugin-review:placeholder": "Ibahagi ang iyong karanasan...",
+ "plugin-review:input-label": "Review ng plugin",
+ "plugin-review:vote-group-label": "Boto",
+ "plugin-review:thumbs-up": "Gusto",
+ "plugin-review:thumbs-down": "Hindi gusto",
+ "plugin-review:delete": "I-delete ang review",
+ "plugin-review:load-failed": "Hindi ma-load ang mga review.",
+ "plugin-review:retry": "Subukan muli",
+ "plugin-review:empty-title": "Wala pang review",
+ "plugin-review:empty-description": "Mauna sa pagbabahagi ng iyong karanasan.",
+ "plugin-review:yours": "Iyong review",
+ "plugin-review:community": "Mga review ng komunidad",
+ "plugin-review:no-other-reviews": "Wala pang ibang review.",
+ "plugin-review:login-incomplete": "Hindi natapos ang pag-sign in.",
+ "plugin-review:sign-in-failed": "Hindi makapag-sign in.",
+ "plugin-review:session-expired-review": "Nag-expire ang iyong session. Mag-sign in muli para mag-review.",
+ "plugin-review:save-failed": "Hindi mai-save ang review.",
+ "plugin-review:delete-confirmation": "I-delete ang iyong review? Hindi na ito maibabalik.",
+ "plugin-review:session-expired-continue": "Nag-expire ang iyong session. Mag-sign in muli para magpatuloy.",
+ "plugin-review:delete-failed": "Hindi ma-delete ang review.",
+ "plugin-review:you": "Ikaw",
+ "plugin-review:edit-action": "I-edit ang review",
+ "plugin-review:recommended": "Inirerekomenda ang plugin na ito",
+ "plugin-review:error-max-length": "Dapat {max} character o mas kaunti ang review.",
+ "plugin-review:error-downvote-comment": "Sabihin sa developer kung ano ang maaaring mapabuti.",
+ "plugin-review:error-empty": "Magdagdag ng komento o piliin ang Gusto.",
+ "plugin-review:unrated": "Walang rating"
}
diff --git a/src/lang/tr-tr.json b/src/lang/tr-tr.json
index 407ca5a8dc..68bc5dafb7 100644
--- a/src/lang/tr-tr.json
+++ b/src/lang/tr-tr.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "Bu uygulama simgesini kullanmak için bir ödüllü reklam izlensin mi?",
"rewarded ad unavailable": "Ödüllü reklamlar şu anda kullanılamıyor. Lütfen tekrar deneyin.",
"rewarded ad failed": "Reklam tamamlanamadı. Lütfen tekrar deneyin.",
- "rewarded ad incomplete": "Ödülü kazanmak için reklamı sonuna kadar izleyin."
+ "rewarded ad incomplete": "Ödülü kazanmak için reklamı sonuna kadar izleyin.",
+ "plugin-review:dialog-label": "Eklenti değerlendirmeleri",
+ "plugin-review:account-check-failed": "Hesabınız kontrol edilemedi. Tekrar deneyin.",
+ "plugin-review:sign-in": "Değerlendirmek için oturum açın",
+ "plugin-review:edit": "Değerlendirmenizi düzenleyin",
+ "plugin-review:add": "Değerlendirme ekleyin...",
+ "plugin-review:placeholder": "Deneyiminizi paylaşın...",
+ "plugin-review:input-label": "Eklenti değerlendirmesi",
+ "plugin-review:vote-group-label": "Oy",
+ "plugin-review:thumbs-up": "Beğendim",
+ "plugin-review:thumbs-down": "Beğenmedim",
+ "plugin-review:delete": "Değerlendirmeyi sil",
+ "plugin-review:load-failed": "Değerlendirmeler yüklenemedi.",
+ "plugin-review:retry": "Tekrar dene",
+ "plugin-review:empty-title": "Henüz değerlendirme yok",
+ "plugin-review:empty-description": "Deneyiminizi ilk paylaşan siz olun.",
+ "plugin-review:yours": "Değerlendirmeniz",
+ "plugin-review:community": "Topluluk değerlendirmeleri",
+ "plugin-review:no-other-reviews": "Henüz başka değerlendirme yok.",
+ "plugin-review:login-incomplete": "Oturum açma tamamlanmadı.",
+ "plugin-review:sign-in-failed": "Oturum açılamadı.",
+ "plugin-review:session-expired-review": "Oturumunuzun süresi doldu. Değerlendirmek için tekrar oturum açın.",
+ "plugin-review:save-failed": "Değerlendirme kaydedilemedi.",
+ "plugin-review:delete-confirmation": "Değerlendirmeniz silinsin mi? Bu işlem geri alınamaz.",
+ "plugin-review:session-expired-continue": "Oturumunuzun süresi doldu. Devam etmek için tekrar oturum açın.",
+ "plugin-review:delete-failed": "Değerlendirme silinemedi.",
+ "plugin-review:you": "Siz",
+ "plugin-review:edit-action": "Değerlendirmeyi düzenle",
+ "plugin-review:recommended": "Bu eklentiyi önerdi",
+ "plugin-review:error-max-length": "Değerlendirme en fazla {max} karakter olmalıdır.",
+ "plugin-review:error-downvote-comment": "Geliştiriciye nelerin iyileştirilebileceğini söyleyin.",
+ "plugin-review:error-empty": "Yorum ekleyin veya Beğendim’i seçin.",
+ "plugin-review:unrated": "Değerlendirilmedi"
}
diff --git a/src/lang/uk-ua.json b/src/lang/uk-ua.json
index d4817eb12a..062101b415 100644
--- a/src/lang/uk-ua.json
+++ b/src/lang/uk-ua.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "Переглянути рекламу з винагородою, щоб застосувати цю піктограму застосунку?",
"rewarded ad unavailable": "Реклама з винагородою зараз недоступна. Спробуйте ще раз.",
"rewarded ad failed": "Не вдалося завершити перегляд реклами. Спробуйте ще раз.",
- "rewarded ad incomplete": "Додивіться рекламу до кінця, щоб отримати винагороду."
+ "rewarded ad incomplete": "Додивіться рекламу до кінця, щоб отримати винагороду.",
+ "plugin-review:dialog-label": "Відгуки про плагін",
+ "plugin-review:account-check-failed": "Не вдалося перевірити ваш обліковий запис. Спробуйте ще раз.",
+ "plugin-review:sign-in": "Увійти, щоб залишити відгук",
+ "plugin-review:edit": "Редагувати свій відгук",
+ "plugin-review:add": "Додати відгук…",
+ "plugin-review:placeholder": "Поділіться своїм досвідом…",
+ "plugin-review:input-label": "Відгук про плагін",
+ "plugin-review:vote-group-label": "Оцінка",
+ "plugin-review:thumbs-up": "Подобається",
+ "plugin-review:thumbs-down": "Не подобається",
+ "plugin-review:delete": "Видалити відгук",
+ "plugin-review:load-failed": "Не вдалося завантажити відгуки.",
+ "plugin-review:retry": "Спробувати ще раз",
+ "plugin-review:empty-title": "Відгуків ще немає",
+ "plugin-review:empty-description": "Поділіться своїм досвідом першими.",
+ "plugin-review:yours": "Ваш відгук",
+ "plugin-review:community": "Відгуки спільноти",
+ "plugin-review:no-other-reviews": "Інших відгуків ще немає.",
+ "plugin-review:login-incomplete": "Вхід не було завершено.",
+ "plugin-review:sign-in-failed": "Не вдалося ввійти.",
+ "plugin-review:session-expired-review": "Сеанс завершився. Увійдіть знову, щоб залишити відгук.",
+ "plugin-review:save-failed": "Не вдалося зберегти відгук.",
+ "plugin-review:delete-confirmation": "Видалити ваш відгук? Цю дію не можна скасувати.",
+ "plugin-review:session-expired-continue": "Сеанс завершився. Увійдіть знову, щоб продовжити.",
+ "plugin-review:delete-failed": "Не вдалося видалити відгук.",
+ "plugin-review:you": "Ви",
+ "plugin-review:edit-action": "Редагувати відгук",
+ "plugin-review:recommended": "Рекомендує цей плагін",
+ "plugin-review:error-max-length": "Відгук має містити не більше {max} символів.",
+ "plugin-review:error-downvote-comment": "Розкажіть розробнику, що можна покращити.",
+ "plugin-review:error-empty": "Додайте коментар або виберіть «Подобається».",
+ "plugin-review:unrated": "Без оцінки"
}
diff --git a/src/lang/uz-uz.json b/src/lang/uz-uz.json
index da3c2725e4..9b284ee11b 100644
--- a/src/lang/uz-uz.json
+++ b/src/lang/uz-uz.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "Ushbu ilova belgisini qo‘llash uchun bitta mukofotli reklamani ko‘rasizmi?",
"rewarded ad unavailable": "Mukofotli reklamalar hozir mavjud emas. Qayta urinib ko‘ring.",
"rewarded ad failed": "Reklamani yakunlab bo‘lmadi. Qayta urinib ko‘ring.",
- "rewarded ad incomplete": "Mukofotni olish uchun reklamani oxirigacha tomosha qiling."
+ "rewarded ad incomplete": "Mukofotni olish uchun reklamani oxirigacha tomosha qiling.",
+ "plugin-review:dialog-label": "Plagin sharhlari",
+ "plugin-review:account-check-failed": "Hisobingizni tekshirib bo‘lmadi. Qayta urinib ko‘ring.",
+ "plugin-review:sign-in": "Sharh qoldirish uchun kiring",
+ "plugin-review:edit": "Sharhingizni tahrirlash",
+ "plugin-review:add": "Sharh qo‘shish...",
+ "plugin-review:placeholder": "Tajribangizni ulashing...",
+ "plugin-review:input-label": "Plagin sharhi",
+ "plugin-review:vote-group-label": "Ovoz",
+ "plugin-review:thumbs-up": "Yoqdi",
+ "plugin-review:thumbs-down": "Yoqmadi",
+ "plugin-review:delete": "Sharhni o‘chirish",
+ "plugin-review:load-failed": "Sharhlarni yuklab bo‘lmadi.",
+ "plugin-review:retry": "Qayta urinish",
+ "plugin-review:empty-title": "Hozircha sharhlar yo‘q",
+ "plugin-review:empty-description": "Tajribangizni birinchi bo‘lib ulashing.",
+ "plugin-review:yours": "Sharhingiz",
+ "plugin-review:community": "Hamjamiyat sharhlari",
+ "plugin-review:no-other-reviews": "Hozircha boshqa sharhlar yo‘q.",
+ "plugin-review:login-incomplete": "Kirish yakunlanmadi.",
+ "plugin-review:sign-in-failed": "Tizimga kirib bo‘lmadi.",
+ "plugin-review:session-expired-review": "Seans muddati tugadi. Sharh qoldirish uchun qayta kiring.",
+ "plugin-review:save-failed": "Sharhni saqlab bo‘lmadi.",
+ "plugin-review:delete-confirmation": "Sharhingiz o‘chirilsinmi? Buni ortga qaytarib bo‘lmaydi.",
+ "plugin-review:session-expired-continue": "Seans muddati tugadi. Davom etish uchun qayta kiring.",
+ "plugin-review:delete-failed": "Sharhni o‘chirib bo‘lmadi.",
+ "plugin-review:you": "Siz",
+ "plugin-review:edit-action": "Sharhni tahrirlash",
+ "plugin-review:recommended": "Bu plaginni tavsiya qildi",
+ "plugin-review:error-max-length": "Sharh {max} ta yoki undan kam belgidan iborat bo‘lishi kerak.",
+ "plugin-review:error-downvote-comment": "Dasturchiga nimani yaxshilash mumkinligini ayting.",
+ "plugin-review:error-empty": "Izoh qo‘shing yoki “Yoqdi”ni tanlang.",
+ "plugin-review:unrated": "Baholanmagan"
}
diff --git a/src/lang/vi-vn.json b/src/lang/vi-vn.json
index 69f567b7ac..131cb3fe91 100644
--- a/src/lang/vi-vn.json
+++ b/src/lang/vi-vn.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "Xem một quảng cáo có thưởng để áp dụng biểu tượng ứng dụng này?",
"rewarded ad unavailable": "Quảng cáo có thưởng hiện không khả dụng. Vui lòng thử lại.",
"rewarded ad failed": "Không thể hoàn tất quảng cáo. Vui lòng thử lại.",
- "rewarded ad incomplete": "Xem hết quảng cáo để nhận phần thưởng."
+ "rewarded ad incomplete": "Xem hết quảng cáo để nhận phần thưởng.",
+ "plugin-review:dialog-label": "Đánh giá plugin",
+ "plugin-review:account-check-failed": "Không thể kiểm tra tài khoản của bạn. Hãy thử lại.",
+ "plugin-review:sign-in": "Đăng nhập để đánh giá",
+ "plugin-review:edit": "Chỉnh sửa đánh giá của bạn",
+ "plugin-review:add": "Thêm đánh giá...",
+ "plugin-review:placeholder": "Chia sẻ trải nghiệm của bạn...",
+ "plugin-review:input-label": "Đánh giá plugin",
+ "plugin-review:vote-group-label": "Bình chọn",
+ "plugin-review:thumbs-up": "Thích",
+ "plugin-review:thumbs-down": "Không thích",
+ "plugin-review:delete": "Xóa đánh giá",
+ "plugin-review:load-failed": "Không thể tải các đánh giá.",
+ "plugin-review:retry": "Thử lại",
+ "plugin-review:empty-title": "Chưa có đánh giá",
+ "plugin-review:empty-description": "Hãy là người đầu tiên chia sẻ trải nghiệm.",
+ "plugin-review:yours": "Đánh giá của bạn",
+ "plugin-review:community": "Đánh giá từ cộng đồng",
+ "plugin-review:no-other-reviews": "Chưa có đánh giá nào khác.",
+ "plugin-review:login-incomplete": "Quá trình đăng nhập chưa hoàn tất.",
+ "plugin-review:sign-in-failed": "Không thể đăng nhập.",
+ "plugin-review:session-expired-review": "Phiên của bạn đã hết hạn. Hãy đăng nhập lại để đánh giá.",
+ "plugin-review:save-failed": "Không thể lưu đánh giá.",
+ "plugin-review:delete-confirmation": "Xóa đánh giá của bạn? Bạn không thể hoàn tác thao tác này.",
+ "plugin-review:session-expired-continue": "Phiên của bạn đã hết hạn. Hãy đăng nhập lại để tiếp tục.",
+ "plugin-review:delete-failed": "Không thể xóa đánh giá.",
+ "plugin-review:you": "Bạn",
+ "plugin-review:edit-action": "Chỉnh sửa đánh giá",
+ "plugin-review:recommended": "Đã đề xuất plugin này",
+ "plugin-review:error-max-length": "Đánh giá phải có tối đa {max} ký tự.",
+ "plugin-review:error-downvote-comment": "Hãy cho nhà phát triển biết điều gì có thể được cải thiện.",
+ "plugin-review:error-empty": "Thêm bình luận hoặc chọn Thích.",
+ "plugin-review:unrated": "Chưa đánh giá"
}
diff --git a/src/lang/zh-cn.json b/src/lang/zh-cn.json
index aaf2d0813f..b5eb3008b8 100644
--- a/src/lang/zh-cn.json
+++ b/src/lang/zh-cn.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "观看一条激励广告以应用此应用图标?",
"rewarded ad unavailable": "激励广告暂时不可用,请重试。",
"rewarded ad failed": "广告未能完成,请重试。",
- "rewarded ad incomplete": "请完整观看广告以获得奖励。"
+ "rewarded ad incomplete": "请完整观看广告以获得奖励。",
+ "plugin-review:dialog-label": "插件评价",
+ "plugin-review:account-check-failed": "无法检查你的账户,请重试。",
+ "plugin-review:sign-in": "登录后评价",
+ "plugin-review:edit": "编辑你的评价",
+ "plugin-review:add": "添加评价…",
+ "plugin-review:placeholder": "分享你的使用体验…",
+ "plugin-review:input-label": "插件评价",
+ "plugin-review:vote-group-label": "投票",
+ "plugin-review:thumbs-up": "赞",
+ "plugin-review:thumbs-down": "踩",
+ "plugin-review:delete": "删除评价",
+ "plugin-review:load-failed": "无法加载评价。",
+ "plugin-review:retry": "重试",
+ "plugin-review:empty-title": "暂无评价",
+ "plugin-review:empty-description": "成为第一个分享使用体验的人。",
+ "plugin-review:yours": "你的评价",
+ "plugin-review:community": "社区评价",
+ "plugin-review:no-other-reviews": "暂无其他评价。",
+ "plugin-review:login-incomplete": "登录未完成。",
+ "plugin-review:sign-in-failed": "无法登录。",
+ "plugin-review:session-expired-review": "会话已过期,请重新登录后评价。",
+ "plugin-review:save-failed": "无法保存评价。",
+ "plugin-review:delete-confirmation": "要删除你的评价吗?此操作无法撤销。",
+ "plugin-review:session-expired-continue": "会话已过期,请重新登录后继续。",
+ "plugin-review:delete-failed": "无法删除评价。",
+ "plugin-review:you": "你",
+ "plugin-review:edit-action": "编辑评价",
+ "plugin-review:recommended": "推荐了此插件",
+ "plugin-review:error-max-length": "评价不能超过 {max} 个字符。",
+ "plugin-review:error-downvote-comment": "告诉开发者哪些地方可以改进。",
+ "plugin-review:error-empty": "添加评论或选择“赞”。",
+ "plugin-review:unrated": "暂无评分"
}
diff --git a/src/lang/zh-hant.json b/src/lang/zh-hant.json
index bf2ac76f22..5de4315970 100644
--- a/src/lang/zh-hant.json
+++ b/src/lang/zh-hant.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "觀看一則獎勵廣告以套用此應用程式圖示?",
"rewarded ad unavailable": "獎勵廣告暫時無法使用,請再試一次。",
"rewarded ad failed": "廣告未能完成,請再試一次。",
- "rewarded ad incomplete": "請完整觀看廣告以獲得獎勵。"
+ "rewarded ad incomplete": "請完整觀看廣告以獲得獎勵。",
+ "plugin-review:dialog-label": "外掛評論",
+ "plugin-review:account-check-failed": "無法檢查你的帳戶,請再試一次。",
+ "plugin-review:sign-in": "登入以撰寫評論",
+ "plugin-review:edit": "編輯你的評論",
+ "plugin-review:add": "新增評論…",
+ "plugin-review:placeholder": "分享你的使用體驗…",
+ "plugin-review:input-label": "外掛評論",
+ "plugin-review:vote-group-label": "投票",
+ "plugin-review:thumbs-up": "讚",
+ "plugin-review:thumbs-down": "倒讚",
+ "plugin-review:delete": "刪除評論",
+ "plugin-review:load-failed": "無法載入評論。",
+ "plugin-review:retry": "重試",
+ "plugin-review:empty-title": "尚無評論",
+ "plugin-review:empty-description": "成為第一個分享使用體驗的人。",
+ "plugin-review:yours": "你的評論",
+ "plugin-review:community": "社群評論",
+ "plugin-review:no-other-reviews": "尚無其他評論。",
+ "plugin-review:login-incomplete": "登入未完成。",
+ "plugin-review:sign-in-failed": "無法登入。",
+ "plugin-review:session-expired-review": "工作階段已過期,請重新登入以撰寫評論。",
+ "plugin-review:save-failed": "無法儲存評論。",
+ "plugin-review:delete-confirmation": "要刪除你的評論嗎?此操作無法復原。",
+ "plugin-review:session-expired-continue": "工作階段已過期,請重新登入以繼續。",
+ "plugin-review:delete-failed": "無法刪除評論。",
+ "plugin-review:you": "你",
+ "plugin-review:edit-action": "編輯評論",
+ "plugin-review:recommended": "推薦了此外掛",
+ "plugin-review:error-max-length": "評論不得超過 {max} 個字元。",
+ "plugin-review:error-downvote-comment": "告訴開發者哪些地方可以改進。",
+ "plugin-review:error-empty": "新增留言或選擇「讚」。",
+ "plugin-review:unrated": "尚未評分"
}
diff --git a/src/lang/zh-tw.json b/src/lang/zh-tw.json
index 1204930d69..1fa59224d3 100644
--- a/src/lang/zh-tw.json
+++ b/src/lang/zh-tw.json
@@ -842,5 +842,37 @@
"confirm app icon reward": "觀看一則獎勵廣告以套用此應用程式圖示?",
"rewarded ad unavailable": "獎勵廣告目前無法使用,請再試一次。",
"rewarded ad failed": "廣告未能完成,請再試一次。",
- "rewarded ad incomplete": "請完整觀看廣告以獲得獎勵。"
+ "rewarded ad incomplete": "請完整觀看廣告以獲得獎勵。",
+ "plugin-review:dialog-label": "外掛評論",
+ "plugin-review:account-check-failed": "無法檢查你的帳號,請再試一次。",
+ "plugin-review:sign-in": "登入以撰寫評論",
+ "plugin-review:edit": "編輯你的評論",
+ "plugin-review:add": "新增評論…",
+ "plugin-review:placeholder": "分享你的使用心得…",
+ "plugin-review:input-label": "外掛評論",
+ "plugin-review:vote-group-label": "評分",
+ "plugin-review:thumbs-up": "讚",
+ "plugin-review:thumbs-down": "倒讚",
+ "plugin-review:delete": "刪除評論",
+ "plugin-review:load-failed": "無法載入評論。",
+ "plugin-review:retry": "重試",
+ "plugin-review:empty-title": "目前沒有評論",
+ "plugin-review:empty-description": "成為第一個分享使用心得的人。",
+ "plugin-review:yours": "你的評論",
+ "plugin-review:community": "社群評論",
+ "plugin-review:no-other-reviews": "目前沒有其他評論。",
+ "plugin-review:login-incomplete": "登入未完成。",
+ "plugin-review:sign-in-failed": "無法登入。",
+ "plugin-review:session-expired-review": "工作階段已過期,請重新登入以撰寫評論。",
+ "plugin-review:save-failed": "無法儲存評論。",
+ "plugin-review:delete-confirmation": "要刪除你的評論嗎?此動作無法復原。",
+ "plugin-review:session-expired-continue": "工作階段已過期,請重新登入以繼續。",
+ "plugin-review:delete-failed": "無法刪除評論。",
+ "plugin-review:you": "你",
+ "plugin-review:edit-action": "編輯評論",
+ "plugin-review:recommended": "推薦這個外掛",
+ "plugin-review:error-max-length": "評論不得超過 {max} 個字元。",
+ "plugin-review:error-downvote-comment": "告訴開發者哪些地方可以改進。",
+ "plugin-review:error-empty": "新增留言或選擇「讚」。",
+ "plugin-review:unrated": "尚未評分"
}
diff --git a/src/lib/acode.js b/src/lib/acode.js
index 6d9310d245..d5a0f2de62 100644
--- a/src/lib/acode.js
+++ b/src/lib/acode.js
@@ -718,7 +718,7 @@ class Acode {
}
get exitAppMessage() {
- const numFiles = editorManager.hasUnsavedFiles();
+ const numFiles = editorManager?.hasUnsavedFiles?.() ?? 0;
if (numFiles) {
return strings["unsaved files close app"];
}
diff --git a/src/lib/adConsentCoordinator.mjs b/src/lib/adConsentCoordinator.mjs
index 5a23de1737..4391e22aac 100644
--- a/src/lib/adConsentCoordinator.mjs
+++ b/src/lib/adConsentCoordinator.mjs
@@ -35,6 +35,7 @@ export class AdConsentCoordinator {
#state = EMPTY_PRIVACY_STATE;
#consentPromise;
#adStartPromise;
+ #privacyOptionsPromise;
#listeners = new Set();
constructor({ privacy, initializeAds, onError = console.error }) {
@@ -51,7 +52,14 @@ export class AdConsentCoordinator {
return (this.#consentPromise ??= this.#gatherAndStart());
}
- async showPrivacyOptions() {
+ showPrivacyOptions() {
+ this.#privacyOptionsPromise ??= this.#showPrivacyOptions().finally(() => {
+ this.#privacyOptionsPromise = undefined;
+ });
+ return this.#privacyOptionsPromise;
+ }
+
+ async #showPrivacyOptions() {
const state = await this.#privacy.showOptions();
this.#setState(state);
await this.#startAdsIfAllowed();
diff --git a/src/lib/bannerVisibilityController.mjs b/src/lib/bannerVisibilityController.mjs
index c02df5b80b..517e914d02 100644
--- a/src/lib/bannerVisibilityController.mjs
+++ b/src/lib/bannerVisibilityController.mjs
@@ -10,6 +10,9 @@ export const BANNER_SUPPRESSION_REASON = Object.freeze({
REWARDED_PASS: "rewarded-pass",
});
+const DEFAULT_RETRY_DELAY_MS = 500;
+const TRANSIENT_LOAD_ERROR_CODES = new Set([0, 2, 3, 9]);
+
export class BannerVisibilityController {
#banner = null;
#registeredPages = new WeakSet();
@@ -20,9 +23,13 @@ export class BannerVisibilityController {
#suppressions = new Set();
#nativeVisible = false;
#scheduledVisible = false;
+ #desiredVisible = false;
#operation = Promise.resolve();
#revision = 0;
#onError;
+ #retryTimer = null;
+ #retryUsed = false;
+ #stopBannerListeners = [];
constructor({
getActivePage,
@@ -35,9 +42,13 @@ export class BannerVisibilityController {
}
setBanner(banner) {
+ this.#stopListeningToBanner();
+ this.#resetRetry();
+ this.#revision++;
this.#banner = banner;
this.#nativeVisible = false;
this.#scheduledVisible = false;
+ this.#listenToBanner(banner);
this.reconcile();
}
@@ -83,6 +94,12 @@ export class BannerVisibilityController {
activePage !== null &&
this.#registeredPages.has(activePage);
const shouldShow = pageRequestsBanner && !this.#keyboardVisible;
+ const eligibilityChanged = shouldShow !== this.#desiredVisible;
+ this.#desiredVisible = shouldShow;
+
+ if (!shouldShow || eligibilityChanged) {
+ this.#resetRetry();
+ }
if (this.#banner) {
this.#banner.active = pageRequestsBanner;
@@ -98,7 +115,12 @@ export class BannerVisibilityController {
dispose() {
this.#stopObserving?.();
this.#stopObserving = null;
+ this.#stopListeningToBanner();
+ this.#resetRetry();
this.#banner = null;
+ this.#desiredVisible = false;
+ this.#nativeVisible = false;
+ this.#scheduledVisible = false;
this.#revision++;
}
@@ -107,9 +129,16 @@ export class BannerVisibilityController {
this.#stopObserving = this.#observePageChanges(() => this.reconcile());
}
- #queueNativeVisibility(shouldShow) {
+ #queueNativeVisibility(shouldShow, isRetry = false) {
const banner = this.#banner;
- if (!banner || shouldShow === this.#scheduledVisible) return;
+ if (
+ !banner ||
+ shouldShow === this.#scheduledVisible ||
+ (shouldShow &&
+ (this.#retryTimer !== null || (this.#retryUsed && !isRetry)))
+ ) {
+ return;
+ }
this.#scheduledVisible = shouldShow;
const revision = ++this.#revision;
@@ -124,14 +153,80 @@ export class BannerVisibilityController {
} else {
await banner.hide?.();
}
+ if (revision !== this.#revision || banner !== this.#banner) return;
this.#nativeVisible = shouldShow;
} catch (error) {
+ if (revision !== this.#revision || banner !== this.#banner) return;
this.#nativeVisible = !shouldShow;
this.#scheduledVisible = !shouldShow;
this.#onError(error);
+ if (shouldShow) this.#scheduleRetry();
}
});
}
+
+ #listenToBanner(banner) {
+ if (typeof banner?.on !== "function") return;
+
+ for (const [eventName, listener] of [
+ ["load", () => this.#handleBannerLoad()],
+ ["loadfail", (event) => this.#handleBannerLoadFailure(event)],
+ ]) {
+ const stopListening = banner.on(eventName, listener);
+ if (typeof stopListening === "function") {
+ this.#stopBannerListeners.push(stopListening);
+ }
+ }
+ }
+
+ #stopListeningToBanner() {
+ for (const stopListening of this.#stopBannerListeners.splice(0)) {
+ stopListening();
+ }
+ }
+
+ #handleBannerLoad() {
+ this.#resetRetry();
+ if (!this.#desiredVisible) return;
+
+ this.#nativeVisible = true;
+ this.#scheduledVisible = true;
+ }
+
+ #handleBannerLoadFailure(event) {
+ this.#nativeVisible = false;
+ this.#scheduledVisible = false;
+ this.#onError(event);
+
+ const errorCode = Number(event?.code);
+ if (TRANSIENT_LOAD_ERROR_CODES.has(errorCode)) {
+ this.#scheduleRetry();
+ } else {
+ this.#retryUsed = true;
+ }
+ }
+
+ #scheduleRetry() {
+ if (!this.#desiredVisible || this.#retryTimer !== null || this.#retryUsed) {
+ return;
+ }
+
+ this.#retryUsed = true;
+ const banner = this.#banner;
+ this.#retryTimer = setTimeout(() => {
+ this.#retryTimer = null;
+ if (!this.#desiredVisible || banner !== this.#banner) return;
+ this.#queueNativeVisibility(true, true);
+ }, DEFAULT_RETRY_DELAY_MS);
+ }
+
+ #resetRetry() {
+ if (this.#retryTimer !== null) {
+ clearTimeout(this.#retryTimer);
+ this.#retryTimer = null;
+ }
+ this.#retryUsed = false;
+ }
}
function getActivePage() {
diff --git a/src/lib/console.js b/src/lib/console.js
index 3e10948585..35a32cb2b9 100644
--- a/src/lib/console.js
+++ b/src/lib/console.js
@@ -1,24 +1,112 @@
import "core-js/stable";
import "html-tag-js/dist/polyfill";
import { parse } from "acorn";
+import { VariableVirtualList } from "components/virtualList";
import css from "styles/console.m.scss";
import loadPolyFill from "utils/polyfill";
+import ConsoleExecutor, {
+ applyConsoleViewport,
+ executeConsoleCommand,
+ executeConsoleScript,
+ resolveConsoleExecutionContext,
+} from "./consoleRuntime";
(function () {
loadPolyFill.apply(window);
let consoleVisible = false;
+ let isFocused = false;
+ let isExecuting = false;
+ let viewportFrame = null;
+ let viewportObserver = null;
+ let themeSyncTimer = null;
+ let themeSyncPending = false;
+ let themeSignature = null;
+ const isStandaloneConsole = sessionStorage.getItem("__mode") === "console";
+ const themeEndpoint = document.querySelector(
+ 'meta[name="acode-console-theme-endpoint"]',
+ )?.content;
+ const startupScriptUrl = document.querySelector(
+ 'meta[name="acode-console-executing-script"]',
+ )?.content;
const originalConsole = console;
const $input = tag("textarea", {
id: "__c-input",
+ attr: {
+ rows: "1",
+ placeholder: "Run JavaScript…",
+ "aria-label": "JavaScript console input",
+ spellcheck: "false",
+ autocomplete: "off",
+ autocapitalize: "off",
+ },
+ oninput: resizeInput,
+ onfocus() {
+ isFocused = true;
+ virtualMessages.scrollToBottom();
+ },
onblur() {
setTimeout(() => {
isFocused = false;
}, 0);
},
});
+ const $stopExecution = tag("button", {
+ className: "__c-action __c-action-danger",
+ textContent: "Stop",
+ attr: {
+ type: "button",
+ "aria-label": "Stop JavaScript execution",
+ },
+ onclick() {
+ executor.cancel();
+ },
+ });
+ $stopExecution.hidden = true;
+ const $executionContext = tag("select", {
+ className: "__c-context",
+ attr: {
+ "aria-label": "JavaScript execution context",
+ title: "Choose isolated Worker execution or live page access",
+ },
+ children: [
+ tag("option", {
+ textContent: "Worker",
+ attr: { value: "worker" },
+ }),
+ tag("option", {
+ textContent: "Page (unsafe)",
+ attr: { value: "page" },
+ }),
+ ],
+ onchange() {
+ if (this.value !== "page") return;
+ log(
+ "warn",
+ {},
+ "Page mode can access window and document, but it runs on the preview thread and cannot stop infinite code.",
+ );
+ },
+ });
+ const $output = tag("c-output", {
+ attr: {
+ role: "region",
+ "aria-label": "JavaScript console",
+ },
+ });
const $inputContainer = tag("c-input", {
- child: $input,
+ children: [
+ $input,
+ tag("c-input-actions", {
+ children: [
+ ...(isStandaloneConsole ? [] : [$executionContext]),
+ $stopExecution,
+ ],
+ }),
+ ],
+ });
+ const virtualMessages = new VariableVirtualList($output, {
+ footer: $inputContainer,
});
const $toggler = tag("c-toggler", {
style: {
@@ -46,9 +134,13 @@ import loadPolyFill from "utils/polyfill";
},
});
const $console = tag("c-console", {
- child: $inputContainer,
+ child: $output,
+ attr: {
+ role: "dialog",
+ "aria-label": "JavaScript console",
+ },
onclick(e) {
- const el = e.target;
+ const el = e.target.closest?.("[action]") || e.target;
const action = el.getAttribute("action");
switch (action) {
@@ -64,9 +156,26 @@ import loadPolyFill from "utils/polyfill";
}
},
});
+ if (isStandaloneConsole) {
+ $console.setAttribute("standalone", "");
+ document.documentElement.setAttribute("console-only", "");
+ startThemeSync();
+ window.addEventListener("pagehide", stopThemeSync, {
+ once: true,
+ });
+ }
const counter = {};
const timers = {};
- let isFocused = false;
+ const executor = new ConsoleExecutor({
+ workerUrl: window.__consoleWorkerScript || "build/consoleWorker.js",
+ onConsole(message) {
+ if (message.action === "clear") {
+ window.console.clear();
+ return;
+ }
+ log(message.level, {}, ...message.args);
+ },
+ });
if (!window.__objs) window.__objs = {};
@@ -77,18 +186,76 @@ import loadPolyFill from "utils/polyfill";
window.addEventListener("error", onError);
assignCustomConsole();
- if (sessionStorage.getItem("__mode") === "console") {
+ if (isStandaloneConsole) {
showConsole();
+ void runStartupScript();
return;
}
tag.get("html").append($toggler);
- $console.setAttribute("title", "Console");
sessionStorage.setItem("__console_available", true);
document.addEventListener("showconsole", showConsole);
document.addEventListener("hideconsole", hideConsole);
}
+ function startThemeSync() {
+ if (!themeEndpoint || themeSyncTimer !== null) return;
+ void syncTheme();
+ themeSyncTimer = setInterval(syncTheme, 1000);
+ }
+
+ function stopThemeSync() {
+ if (themeSyncTimer === null) return;
+ clearInterval(themeSyncTimer);
+ themeSyncTimer = null;
+ }
+
+ async function runStartupScript() {
+ if (!startupScriptUrl) return;
+
+ setExecutionState(true);
+ const result = await executeConsoleScript({
+ scriptUrl: startupScriptUrl,
+ workerExecutor: executor,
+ });
+ setExecutionState(false);
+
+ if (result?.type === "error") {
+ log("error", getStack(new Error()), result.value);
+ }
+ }
+
+ async function syncTheme() {
+ if (themeSyncPending) return;
+ themeSyncPending = true;
+
+ try {
+ const response = await fetch(themeEndpoint, { cache: "no-store" });
+ if (!response.ok) return;
+ const snapshot = await response.json();
+ if (typeof snapshot.css !== "string") return;
+
+ const signature = JSON.stringify([snapshot.type, snapshot.css]);
+ if (signature === themeSignature) return;
+
+ let $theme = document.getElementById("console-live-theme");
+ if (!$theme) {
+ $theme = tag("style", { id: "console-live-theme" });
+ document.head.append($theme);
+ }
+ $theme.textContent = snapshot.css;
+ document.documentElement.setAttribute(
+ "theme-type",
+ snapshot.type === "light" ? "light" : "dark",
+ );
+ themeSignature = signature;
+ } catch {
+ // Keep the last valid theme if the local endpoint is briefly unavailable.
+ } finally {
+ themeSyncPending = false;
+ }
+ }
+
function touchmove(e) {
e.preventDefault();
$toggler.style.transform = "translate("
@@ -105,10 +272,7 @@ import loadPolyFill from "utils/polyfill";
}
},
clear() {
- originalConsole.clear();
- if (isFocused) $input.focus();
- $console.textContent = "";
- $console.appendChild($inputContainer);
+ clearConsole();
},
count(hash = "default") {
originalConsole.count(hash);
@@ -207,35 +371,104 @@ import loadPolyFill from "utils/polyfill";
function showConsole() {
tag.get("html").append($console);
$input.addEventListener("keydown", onCodeInput);
+ if (!isStandaloneConsole) {
+ bindViewportListeners();
+ updateConsoleViewport();
+ }
+ virtualMessages.invalidate();
}
function hideConsole() {
$console.remove();
$input.removeEventListener("keydown", onCodeInput);
+ unbindViewportListeners();
+ }
+
+ function bindViewportListeners() {
+ window.addEventListener("resize", updateConsoleViewport);
+ window.visualViewport?.addEventListener("resize", updateConsoleViewport);
+ window.visualViewport?.addEventListener("scroll", updateConsoleViewport);
+ if (typeof ResizeObserver === "function") {
+ viewportObserver = new ResizeObserver(updateConsoleViewport);
+ viewportObserver.observe(document.documentElement);
+ }
+ }
+
+ function unbindViewportListeners() {
+ window.removeEventListener("resize", updateConsoleViewport);
+ window.visualViewport?.removeEventListener("resize", updateConsoleViewport);
+ window.visualViewport?.removeEventListener("scroll", updateConsoleViewport);
+ viewportObserver?.disconnect();
+ viewportObserver = null;
+ if (viewportFrame !== null) cancelAnimationFrame(viewportFrame);
+ viewportFrame = null;
+ }
+
+ function updateConsoleViewport() {
+ if (viewportFrame !== null) cancelAnimationFrame(viewportFrame);
+ viewportFrame = requestAnimationFrame(() => {
+ viewportFrame = null;
+ applyConsoleViewport($console);
+ virtualMessages.invalidate();
+ });
}
function onCodeInput(e) {
- const key = e.key;
isFocused = true;
- if (key === "Enter") {
- const regex = /[\[|{\(\)\}\]]/g;
- let code = this.value.trim();
- let isOdd = (code.length - code.replace(regex, "").length) % 2;
-
- if (!code || isOdd) return;
- e.preventDefault();
- e.stopPropagation();
- e.stopImmediatePropagation();
-
- log("code", {}, code);
- $input.value = "";
- const res = execute(code);
- if (res.type === "error") {
- log("error", getStack(new Error()), res.value);
- } else {
- log("log", getStack(new Error()), res.value);
- }
+ if (e.key !== "Enter" || e.shiftKey) return;
+
+ const code = $input.value.trim();
+ const brackets = /[\[|{\(\)\}\]]/g;
+ const isIncomplete =
+ (code.length - code.replace(brackets, "").length) % 2 !== 0;
+ if (!code || isIncomplete) return;
+
+ e.preventDefault();
+ e.stopPropagation();
+ e.stopImmediatePropagation();
+ runInputCode();
+ }
+
+ async function runInputCode() {
+ const code = $input.value.trim();
+ if (!code) return;
+ if (isExecuting) {
+ log("warn", {}, "Another console command is still running.");
+ return;
}
+
+ log("code", {}, code);
+ $input.value = "";
+ resizeInput();
+ setExecutionState(true);
+ const res = await executeCommand(code);
+ setExecutionState(false);
+
+ if (res.type === "error") {
+ log("error", getStack(new Error()), res.value);
+ } else {
+ log("log", getStack(new Error()), res.value);
+ }
+ $input.focus();
+ }
+
+ function setExecutionState(running) {
+ isExecuting = running;
+ $console.toggleAttribute("running", running);
+ $stopExecution.hidden = !running || $executionContext.value !== "worker";
+ $input.disabled = running;
+ $executionContext.disabled = running;
+ }
+
+ function resizeInput() {
+ $input.style.height = "0px";
+ $input.style.height = `${Math.min(120, Math.max(38, $input.scrollHeight))}px`;
+ }
+
+ function clearConsole() {
+ originalConsole.clear();
+ virtualMessages.clear();
+ if (isFocused) $input.focus();
}
function getBody(obj, ...keys) {
@@ -454,7 +687,7 @@ import loadPolyFill from "utils/polyfill";
let $msg;
if (mode === "code") {
$msg = tag("c-code");
- $msg.textContent = arg.length > 50 ? arg.substring(0, 50) + "..." : arg;
+ $msg.textContent = arg;
$msg.setAttribute("data-code", arg);
$msg.setAttribute("action", "use code");
} else {
@@ -486,11 +719,7 @@ import loadPolyFill from "utils/polyfill";
$messages.appendChild($stack);
}
- $console.insertBefore($messages, $inputContainer);
-
- while ($console.childElementCount > 100) {
- $console.firstElementChild.remove();
- }
+ virtualMessages.append($messages);
}
/**
@@ -634,6 +863,18 @@ import loadPolyFill from "utils/polyfill";
};
}
+ function executeCommand(code) {
+ return executeConsoleCommand({
+ context: resolveConsoleExecutionContext(
+ isStandaloneConsole,
+ $executionContext.value,
+ ),
+ code,
+ workerExecutor: executor,
+ pageExecutor: execute,
+ });
+ }
+
function execute(code) {
let res = null;
try {
diff --git a/src/lib/consoleRuntime.js b/src/lib/consoleRuntime.js
new file mode 100644
index 0000000000..5e45e25236
--- /dev/null
+++ b/src/lib/consoleRuntime.js
@@ -0,0 +1,217 @@
+export const DEFAULT_CONSOLE_TIMEOUT = 30000;
+
+/**
+ * Runs console commands in a worker so user code can never block the page UI.
+ */
+export default class ConsoleExecutor {
+ constructor({
+ workerUrl,
+ timeout = DEFAULT_CONSOLE_TIMEOUT,
+ onConsole = () => {},
+ WorkerClass = globalThis.Worker,
+ } = {}) {
+ this.workerUrl = workerUrl;
+ this.timeout = timeout;
+ this.onConsole = onConsole;
+ this.WorkerClass = WorkerClass;
+ this.worker = null;
+ this.pending = null;
+ this.nextId = 0;
+ }
+
+ execute(code) {
+ if (this.pending) {
+ return Promise.resolve({
+ type: "error",
+ value: new Error("Another console command is still running."),
+ });
+ }
+
+ if (!this.WorkerClass) {
+ return Promise.resolve({
+ type: "error",
+ value: new Error(
+ "This WebView does not support isolated console execution.",
+ ),
+ });
+ }
+
+ let worker;
+ try {
+ worker = this.getWorker();
+ } catch (error) {
+ return Promise.resolve({ type: "error", value: error });
+ }
+ const id = ++this.nextId;
+
+ return new Promise((resolve) => {
+ const timer = setTimeout(() => {
+ this.finish(id, {
+ type: "error",
+ value: new Error(
+ `Execution stopped after ${this.timeout / 1000} seconds.`,
+ ),
+ });
+ this.resetWorker();
+ }, this.timeout);
+
+ this.pending = { id, resolve, timer };
+ try {
+ worker.postMessage({ id, code });
+ } catch (error) {
+ this.finish(id, { type: "error", value: error });
+ this.resetWorker();
+ }
+ });
+ }
+
+ getWorker() {
+ if (this.worker) return this.worker;
+
+ const worker = new this.WorkerClass(this.workerUrl);
+ worker.onmessage = ({ data }) => this.handleMessage(data);
+ worker.onerror = (event) => {
+ const error = new Error(event.message || "Console worker failed.");
+ this.finish(this.pending?.id, { type: "error", value: error });
+ this.resetWorker();
+ };
+ this.worker = worker;
+ return worker;
+ }
+
+ handleMessage(message) {
+ if (message.type === "console") {
+ this.onConsole(message);
+ return;
+ }
+
+ if (message.type === "result") {
+ this.finish(message.id, { type: "result", value: message.value });
+ return;
+ }
+
+ if (message.type === "error") {
+ const error = new Error(
+ message.error?.message || "Console command failed.",
+ );
+ error.name = message.error?.name || "Error";
+ if (message.error?.stack) error.stack = message.error.stack;
+ this.finish(message.id, { type: "error", value: error });
+ }
+ }
+
+ finish(id, result) {
+ if (!this.pending || this.pending.id !== id) return;
+
+ const { resolve, timer } = this.pending;
+ this.pending = null;
+ clearTimeout(timer);
+ resolve(result);
+ }
+
+ resetWorker() {
+ this.worker?.terminate();
+ this.worker = null;
+ }
+
+ cancel() {
+ if (!this.pending) return false;
+
+ this.finish(this.pending.id, {
+ type: "error",
+ value: new Error("Execution stopped."),
+ });
+ this.resetWorker();
+ return true;
+ }
+
+ destroy() {
+ if (this.pending) {
+ this.finish(this.pending.id, {
+ type: "error",
+ value: new Error("Console execution was cancelled."),
+ });
+ }
+ this.resetWorker();
+ }
+}
+
+/**
+ * Returns the actually visible browser rectangle. On mobile this shrinks with
+ * the software keyboard even when the layout viewport remains full height.
+ */
+export function getConsoleViewportRect(windowObject = window) {
+ const viewport = windowObject.visualViewport;
+ const documentHeight = windowObject.document?.documentElement?.clientHeight;
+ const visibleHeights = [
+ viewport?.height,
+ windowObject.innerHeight,
+ documentHeight,
+ ].filter((height) => Number.isFinite(height) && height > 0);
+ return {
+ height: Math.round(Math.min(...visibleHeights)),
+ width: Math.round(viewport?.width || windowObject.innerWidth),
+ top: Math.round(viewport?.offsetTop || 0),
+ left: Math.round(viewport?.offsetLeft || 0),
+ };
+}
+
+export function applyConsoleViewport(element, windowObject = window) {
+ const { height, width, top, left } = getConsoleViewportRect(windowObject);
+ element.style.setProperty("--console-viewport-height", `${height}px`);
+ element.style.setProperty("--console-viewport-width", `${width}px`);
+ element.style.setProperty("--console-viewport-top", `${top}px`);
+ element.style.setProperty("--console-viewport-left", `${left}px`);
+}
+
+export function resolveConsoleExecutionContext(
+ isStandaloneConsole,
+ selectedContext,
+) {
+ return isStandaloneConsole ? "worker" : selectedContext;
+}
+
+/**
+ * Routes a console command to the isolated worker or the live preview page.
+ * Page execution is deliberately opt-in because it runs on the preview thread.
+ */
+export function executeConsoleCommand({
+ context,
+ code,
+ workerExecutor,
+ pageExecutor,
+}) {
+ if (context === "page") return Promise.resolve(pageExecutor(code));
+ return workerExecutor.execute(code);
+}
+
+/**
+ * Loads a standalone JavaScript file and executes it in the isolated console
+ * worker. The file is fetched first so it is never inserted as a page script.
+ */
+export async function executeConsoleScript({
+ scriptUrl,
+ workerExecutor,
+ fetchScript = globalThis.fetch,
+}) {
+ if (!scriptUrl) return null;
+
+ try {
+ if (typeof fetchScript !== "function") {
+ throw new Error("This WebView cannot load the JavaScript file.");
+ }
+
+ const response = await fetchScript(scriptUrl, { cache: "no-store" });
+ if (!response.ok) {
+ const status = response.status ? ` (${response.status})` : "";
+ throw new Error(`Failed to load JavaScript file${status}.`);
+ }
+
+ return workerExecutor.execute(await response.text());
+ } catch (error) {
+ return {
+ type: "error",
+ value: error instanceof Error ? error : new Error(String(error)),
+ };
+ }
+}
diff --git a/src/lib/consoleWorker.js b/src/lib/consoleWorker.js
new file mode 100644
index 0000000000..c5d911fe8c
--- /dev/null
+++ b/src/lib/consoleWorker.js
@@ -0,0 +1,168 @@
+const MAX_MESSAGES_PER_SECOND = 100;
+const MESSAGE_WINDOW_MS = 1000;
+const MAX_PROPERTIES = 100;
+const MAX_DEPTH = 4;
+const MAX_SNAPSHOT_VALUES = 500;
+
+let activeCommandId = 0;
+let messageWindowStartedAt = 0;
+let emittedInWindow = 0;
+let suppressedInWindow = 0;
+const counts = new Map();
+const timers = new Map();
+
+function snapshot(
+ value,
+ depth = 0,
+ seen = new WeakSet(),
+ budget = { remaining: MAX_SNAPSHOT_VALUES },
+) {
+ const type = typeof value;
+
+ if (
+ value === null ||
+ ["boolean", "number", "string", "undefined"].includes(type)
+ ) {
+ return value;
+ }
+ if (type === "bigint") return `${value}n`;
+ if (type === "symbol") return value.toString();
+ if (type === "function")
+ return `[Function${value.name ? `: ${value.name}` : ""}]`;
+ if (budget.remaining-- <= 0) return "[Truncated]";
+ if (value instanceof Error) return snapshotError(value);
+ if (value instanceof Date) return value.toISOString();
+ if (value instanceof RegExp) return value.toString();
+ if (value instanceof Promise) return "Promise { }";
+ if (depth >= MAX_DEPTH) return `[${value.constructor?.name || "Object"}]`;
+ if (seen.has(value)) return "[Circular]";
+
+ seen.add(value);
+ if (Array.isArray(value)) {
+ const result = value
+ .slice(0, MAX_PROPERTIES)
+ .map((item) => snapshot(item, depth + 1, seen, budget));
+ if (value.length > MAX_PROPERTIES) result.push("…");
+ return result;
+ }
+
+ const result = {};
+ let keys;
+ try {
+ keys = Reflect.ownKeys(value).slice(0, MAX_PROPERTIES);
+ } catch (error) {
+ return `[Uninspectable: ${error.message}]`;
+ }
+
+ for (const key of keys) {
+ const outputKey = typeof key === "symbol" ? key.toString() : key;
+ try {
+ result[outputKey] = snapshot(value[key], depth + 1, seen, budget);
+ } catch (error) {
+ result[outputKey] = `[Thrown: ${error.message}]`;
+ }
+ }
+ if (Reflect.ownKeys(value).length > MAX_PROPERTIES) result["…"] = "…";
+ return result;
+}
+
+function snapshotError(error) {
+ return {
+ name: error?.name || "Error",
+ message: error?.message || String(error),
+ stack: error?.stack || "",
+ };
+}
+
+function discardSuppressedMessages() {
+ suppressedInWindow = 0;
+}
+
+function emitMessage(message) {
+ const now = performance.now();
+ if (now - messageWindowStartedAt >= MESSAGE_WINDOW_MS) {
+ discardSuppressedMessages();
+ messageWindowStartedAt = now;
+ emittedInWindow = 0;
+ }
+
+ if (emittedInWindow >= MAX_MESSAGES_PER_SECOND) {
+ suppressedInWindow++;
+ return;
+ }
+
+ emittedInWindow++;
+ self.postMessage({ type: "console", id: activeCommandId, ...message });
+}
+
+function emit(level, args) {
+ emitMessage({
+ level,
+ args: args.map((value) => snapshot(value)),
+ });
+}
+
+self.console = {
+ assert(condition, ...args) {
+ if (!condition) emit("error", args.length ? args : ["Assertion failed"]);
+ },
+ clear() {
+ emitMessage({ action: "clear" });
+ },
+ count(label = "default") {
+ const value = (counts.get(label) || 0) + 1;
+ counts.set(label, value);
+ emit("log", [`${label}: ${value}`]);
+ },
+ countReset(label = "default") {
+ counts.delete(label);
+ },
+ debug: (...args) => emit("log", args),
+ dir: (...args) => emit("log", args),
+ dirxml: (...args) => emit("log", args),
+ error: (...args) => emit("error", args),
+ group: (...args) => emit("log", args),
+ groupCollapsed: (...args) => emit("log", args),
+ groupEnd() {},
+ info: (...args) => emit("info", args),
+ log: (...args) => emit("log", args),
+ table: (...args) => emit("table", args),
+ time(label = "default") {
+ timers.set(label, performance.now());
+ },
+ timeEnd(label = "default") {
+ if (!timers.has(label)) return emit("warn", [`No such label: ${label}`]);
+ emit("log", [
+ `${label}: ${(performance.now() - timers.get(label)).toFixed(2)}ms`,
+ ]);
+ timers.delete(label);
+ },
+ timeLog(label = "default") {
+ if (!timers.has(label)) return emit("warn", [`No such label: ${label}`]);
+ emit("log", [
+ `${label}: ${(performance.now() - timers.get(label)).toFixed(2)}ms`,
+ ]);
+ },
+ trace(...args) {
+ emit("trace", [...args, new Error().stack]);
+ },
+ warn: (...args) => emit("warn", args),
+};
+
+self.onmessage = ({ data: { id, code } }) => {
+ activeCommandId = id;
+ messageWindowStartedAt = performance.now();
+ emittedInWindow = 0;
+ suppressedInWindow = 0;
+
+ try {
+ // Intentional: this local REPL runs the command in its isolated worker.
+ // codeql[js/code-injection]
+ const value = (0, eval)(code);
+ discardSuppressedMessages();
+ self.postMessage({ type: "result", id, value: snapshot(value) });
+ } catch (error) {
+ discardSuppressedMessages();
+ self.postMessage({ type: "error", id, error: snapshotError(error) });
+ }
+};
diff --git a/src/lib/editorFile.js b/src/lib/editorFile.js
index 2aee9b500f..e638cdb84b 100644
--- a/src/lib/editorFile.js
+++ b/src/lib/editorFile.js
@@ -1,17 +1,11 @@
import fsOperation from "fileSystem";
// CodeMirror imports for document state management
-import { EditorState } from "@codemirror/state";
+import { EditorSelection, EditorState } from "@codemirror/state";
import {
focusEditorIfEditable,
reconfigureEditorReadOnly,
} from "cm/editorReadOnly";
-import {
- clearSelection,
- getDocText,
- restoreFolds,
- restoreSelection,
- setScrollPosition,
-} from "cm/editorUtils";
+import { clearSelection, getDocText } from "cm/editorUtils";
import { getMode, getModeForPath } from "cm/modelist";
import quickTools from "components/quickTools";
import Sidebar from "components/sidebar";
@@ -37,6 +31,25 @@ import appSettings from "./settings";
let mainCSSStyleSheet = null;
+function restoreSessionSelection(state, selection) {
+ if (!selection?.ranges?.length) return state;
+
+ const docLength = state.doc.length;
+ const ranges = selection.ranges.map((range) => {
+ const from = Math.max(0, Math.min(docLength, range.from | 0));
+ const to = Math.max(0, Math.min(docLength, range.to | 0));
+ return EditorSelection.range(from, to);
+ });
+ const mainIndex =
+ selection.mainIndex >= 0 && selection.mainIndex < ranges.length
+ ? selection.mainIndex
+ : 0;
+
+ return state.update({
+ selection: EditorSelection.create(ranges, mainIndex),
+ }).state;
+}
+
function getMainCSSStyleSheet() {
if (mainCSSStyleSheet) return mainCSSStyleSheet;
for (const sheet of document.styleSheets) {
@@ -330,6 +343,7 @@ function maybeRecommendLanguageModeExtension(file, modeInfo) {
* @property {string} [paneId] target editor pane id
* @property {object} [pane] target editor pane
* @property {boolean} [isPanePlaceholder] temporary empty tab for an empty pane
+ * @property {boolean} [persistInSession] restore the tab in a future app session
* @property {boolean} [highlightStyles] adopt static CodeMirror highlight CSS into the custom tab shadow root
*/
@@ -445,6 +459,7 @@ export default class EditorFile {
* contains information about cursor position, scroll left, scroll top, folds.
*/
#loadOptions;
+ #loadPromise = null;
/**
* Weather file is changed and needs to be saved
* @type {boolean}
@@ -500,6 +515,11 @@ export default class EditorFile {
diskMtime = null;
hasDiskConflict = false;
isPanePlaceholder = false;
+ persistInSession = true;
+ lastScrollTop = 0;
+ lastScrollLeft = 0;
+ restoredSelection = null;
+ restoredFolds = null;
/**
*
@@ -513,6 +533,7 @@ export default class EditorFile {
this.hideQuickTools = options?.hideQuickTools || false;
this.paneId = options?.paneId || options?.pane?.id || null;
this.isPanePlaceholder = !!options?.isPanePlaceholder;
+ this.persistInSession = options?.persistInSession !== false;
// if options are passed
if (options) {
@@ -699,6 +720,14 @@ export default class EditorFile {
folds: options?.folds,
editable,
};
+ this.lastScrollTop = Number.isFinite(options?.scrollTop)
+ ? options.scrollTop
+ : 0;
+ this.lastScrollLeft = Number.isFinite(options?.scrollLeft)
+ ? options.scrollLeft
+ : 0;
+ this.restoredSelection = options?.cursorPos || null;
+ this.restoredFolds = options?.folds || null;
}
this.#onFilePosChange = () => {
@@ -1554,8 +1583,8 @@ export default class EditorFile {
this.#tab.classList.add("active");
this.#tab.scrollIntoView();
- if (this.type === "editor" && !this.loaded && !this.loading) {
- this.#loadText();
+ if (this.type === "editor" && !this.loaded) {
+ void this.load();
}
syncQuickToolsVisibility(this);
@@ -1637,6 +1666,20 @@ export default class EditorFile {
}
}
+ /**
+ * Load this file's document into its stored editor session.
+ * Reuses an in-flight load so session restoration can safely preload tabs.
+ */
+ load() {
+ if (this.type !== "editor" || this.loaded) return Promise.resolve(this);
+ if (this.#loadPromise) return this.#loadPromise;
+
+ this.#loadPromise = this.#loadText().finally(() => {
+ this.#loadPromise = null;
+ });
+ return this.#loadPromise;
+ }
+
/**
* Add event listener
* @param {string} event
@@ -1778,9 +1821,7 @@ export default class EditorFile {
const protocol = this.uri ? Url.getProtocol(this.uri) : "";
const isRemoteFile = protocol === "ftp:" || protocol === "sftp:";
- const { cursorPos, scrollLeft, scrollTop, folds, editable } =
- this.#loadOptions;
- const { editor } = editorManager;
+ const { cursorPos, editable } = this.#loadOptions;
this.#loadOptions = null;
@@ -1852,7 +1893,11 @@ export default class EditorFile {
const isUnsaved = this.isUnsaved;
this.markChanged = false;
- this.session = EditorState.create({ doc: value });
+ this.session = restoreSessionSelection(
+ EditorState.create({ doc: value }),
+ cursorPos,
+ );
+ this.restoredSelection = null;
this.__cmSessionReady = false;
this.__cmLanguageReady = false;
this.__cmLanguageSignature = null;
@@ -1871,13 +1916,6 @@ export default class EditorFile {
setTimeout(() => {
this.#emit("load", createFileEvent(this));
- if (cursorPos) {
- restoreSelection(editor, cursorPos);
- }
- if (scrollTop || scrollLeft) {
- setScrollPosition(editor, scrollTop, scrollLeft);
- }
- restoreFolds(editor, folds);
}, 0);
} catch (error) {
this.#emit("loaderror", createFileEvent(this));
diff --git a/src/lib/editorManager.js b/src/lib/editorManager.js
index d719add426..3ce9068465 100644
--- a/src/lib/editorManager.js
+++ b/src/lib/editorManager.js
@@ -1850,13 +1850,7 @@ async function EditorManager($header, $body) {
const col = Math.max(0, Math.min(targetColumn, docLine.length));
const pos = docLine.from + col;
- // Move cursor and scroll into view
- editor.dispatch({
- selection: { anchor: pos, head: pos },
- effects: EditorView.scrollIntoView(pos, { y: "center" }),
- });
- focusEditorIfEditable(editor);
- return true;
+ return revealEditorRange(editor, pos);
} catch (error) {
console.error("Error in gotoLine:", error);
return false;
@@ -2181,12 +2175,7 @@ async function EditorManager($header, $body) {
const col = Math.max(0, Math.min(targetColumn, docLine.length));
const pos = docLine.from + col;
- targetEditor.dispatch({
- selection: { anchor: pos, head: pos },
- effects: EditorView.scrollIntoView(pos, { y: "center" }),
- });
- focusEditorIfEditable(targetEditor);
- return true;
+ return revealEditorRange(targetEditor, pos);
} catch (error) {
console.error("Error in gotoLine:", error);
return false;
@@ -3018,9 +3007,19 @@ async function EditorManager($header, $body) {
// Restore folds from previous state if available
try {
const folds = prevState ? getAllFolds(prevState) : [];
+ const canConsumeRestoredFolds = file.loaded && !file.loading;
+ if (
+ !folds.length &&
+ canConsumeRestoredFolds &&
+ file.restoredFolds?.length
+ ) {
+ folds.push(...file.restoredFolds);
+ }
if (folds && folds.length) {
restoreFolds(editor, folds);
+ file.session = editor.state;
}
+ if (canConsumeRestoredFolds) file.restoredFolds = null;
} catch (error) {
warnRecoverable(
"Failed to restore folded regions from previous session state.",
@@ -3182,6 +3181,9 @@ async function EditorManager($header, $body) {
hasUnsavedFiles,
getEditorHeight,
getEditorWidth,
+ revealRange(from, to = from, options) {
+ return revealEditorRange(manager.editor, from, to, options);
+ },
header: $header,
openPreviousEditorFromHistory,
openNextEditorFromHistory,
@@ -3442,6 +3444,45 @@ async function EditorManager($header, $body) {
applyFileToEditor(file, { forceRecreate: true });
}
+ /**
+ * Reveal an editor range after a file switch.
+ *
+ * File activation restores the tab's saved viewport over two animation
+ * frames and a short timeout. Explicit navigation must cancel that work or
+ * it can overwrite CodeMirror's scrollIntoView effect while leaving the new
+ * selection in place.
+ */
+ function revealEditorRange(
+ targetEditor,
+ from,
+ to = from,
+ { y = "center", userEvent = "select.reveal" } = {},
+ ) {
+ if (!targetEditor) return false;
+
+ try {
+ const length = targetEditor.state.doc.length;
+ const anchor = Math.max(0, Math.min(Number(from) || 0, length));
+ const head = Math.max(0, Math.min(Number(to) || 0, length));
+
+ if (targetEditor === editor) {
+ cancelPendingScrollRestore();
+ clearScrollbarScrollLock();
+ }
+
+ targetEditor.dispatch({
+ selection: { anchor, head },
+ effects: EditorView.scrollIntoView(anchor, { y }),
+ userEvent,
+ });
+ focusEditorIfEditable(targetEditor);
+ return true;
+ } catch (error) {
+ console.error("Error revealing editor range:", error);
+ return false;
+ }
+ }
+
appSettings.on("update:tabSize", function () {
updateEditorIndentationSettings();
});
diff --git a/src/lib/fileSessionPersistence.js b/src/lib/fileSessionPersistence.js
new file mode 100644
index 0000000000..e14c639402
--- /dev/null
+++ b/src/lib/fileSessionPersistence.js
@@ -0,0 +1,13 @@
+/**
+ * Promote an open file to durable session persistence when a later open source
+ * proves that its URI will remain accessible. Less durable sources, such as
+ * external intents, must not revoke an existing durable grant.
+ *
+ * @param {{persistInSession?: boolean}} file
+ * @param {boolean | undefined} requestedPersistence
+ */
+export function promoteSessionPersistence(file, requestedPersistence) {
+ if (requestedPersistence === true) {
+ file.persistInSession = true;
+ }
+}
diff --git a/src/lib/keyBindings.js b/src/lib/keyBindings.js
index b252139621..db48a80185 100644
--- a/src/lib/keyBindings.js
+++ b/src/lib/keyBindings.js
@@ -714,6 +714,12 @@ const APP_BINDING_CONFIG = [
readOnly: true,
editorOnly: true,
},
+ {
+ name: "acode:showWelcome",
+ description: "Show Welcome",
+ key: "Ctrl-Shift-W",
+ action: "welcome",
+ },
];
const APP_KEY_BINDINGS = buildAppBindings(APP_BINDING_CONFIG);
diff --git a/src/lib/lang.js b/src/lib/lang.js
index b8a2966ab5..b4477e9629 100644
--- a/src/lib/lang.js
+++ b/src/lib/lang.js
@@ -185,7 +185,41 @@ const langMap = {
return await import("../lang/he-il.json");
},
},
+ "ln-ln": {
+ name: "Lingála",
+ async strings() {
+ return await import("../lang/ln-ln.json");
+ },
+ },
+};
+
+const intlLocaleOverrides = {
+ "ir-fa": "fa-IR",
+ "mm-unicode": "my-MM",
+ "mm-zawgyi": "my-MM",
+ "pu-in": "pa-IN",
};
+const rtlLanguages = new Set(["ar", "fa", "he"]);
+
+export function getIntlLocale(code) {
+ const normalizedCode = code?.toLowerCase();
+ const locale =
+ intlLocaleOverrides[normalizedCode] ||
+ (normalizedCode in langMap
+ ? normalizedCode
+ : globalThis.navigator?.language || "en-US");
+
+ try {
+ return Intl.getCanonicalLocales(locale)[0];
+ } catch {
+ return "en-US";
+ }
+}
+
+export function getLocaleDirection(locale) {
+ const language = locale?.split("-")[0]?.toLowerCase();
+ return rtlLanguages.has(language) ? "rtl" : "ltr";
+}
export default {
async set(code) {
diff --git a/src/lib/loadPlugin.js b/src/lib/loadPlugin.js
index 75656082bf..2272163ec8 100644
--- a/src/lib/loadPlugin.js
+++ b/src/lib/loadPlugin.js
@@ -3,8 +3,16 @@ import Page from "components/page";
import helpers from "utils/helpers";
import Url from "utils/Url";
import actionStack from "./actionStack";
+import generatePluginContext, { connect } from "./pluginContext";
export default async function loadPlugin(pluginId, justInstalled = false) {
+ // Establish the trusted native session BEFORE any plugin script is appended
+ // and run. Plugin main.js runs as soon as its
-
-
-
+
+
+
-
-
-