diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 97100cc..1958b52 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -36,6 +36,13 @@ jobs:
- name: Fat-jar derle + test
run: mvn -B -ntp clean verify
+ - name: Installer araclari (best-effort)
+ continue-on-error: true
+ shell: bash
+ run: |
+ if [ "${{ runner.os }}" = "Windows" ]; then choco install wixtoolset -y --no-progress || true; fi
+ if [ "${{ runner.os }}" = "Linux" ]; then sudo apt-get update && sudo apt-get install -y fakeroot || true; fi
+
- name: jpackage app-image (JRE gomulu)
shell: bash
run: |
@@ -53,16 +60,48 @@ jobs:
zip -r "../AutoClicker-${{ runner.os }}.zip" AutoClicker* >/dev/null
fi
- - name: Release'e OS paketini yukle
- uses: softprops/action-gh-release@v2
- with:
- prerelease: true
- generate_release_notes: true
- files: AutoClicker-${{ runner.os }}.zip
+ - name: jpackage native installer (msi/dmg/deb) - best-effort
+ id: installer
+ continue-on-error: true
+ shell: bash
+ run: |
+ case "${{ runner.os }}" in
+ Windows) T=msi ;;
+ macOS) T=dmg ;;
+ Linux) T=deb ;;
+ esac
+ jpackage --type "$T" --input target --main-jar autoclicker.jar \
+ --name AutoClicker --app-version "${{ steps.ver.outputs.v }}" --dest installer \
+ --java-options "-Dfile.encoding=UTF-8"
- - name: Release'e fat-jar yukle (yalnizca Linux)
- if: runner.os == 'Linux'
+ - name: Yayim dosyalari + SHA-256 checksum
+ shell: bash
+ run: |
+ mkdir -p out
+ cp "AutoClicker-${{ runner.os }}.zip" out/ 2>/dev/null || true
+ if [ -d installer ]; then cp installer/* out/ 2>/dev/null || true; fi
+ if [ "${{ runner.os }}" = "Linux" ]; then cp target/autoclicker.jar out/ 2>/dev/null || true; fi
+ cd out
+ for f in *; do
+ [ -f "$f" ] || continue
+ if command -v sha256sum >/dev/null 2>&1; then sha256sum "$f" > "$f.sha256"; else shasum -a 256 "$f" > "$f.sha256"; fi
+ done
+ ls -la
+
+ # ---- KOD IMZALAMA (opsiyonel - SERTIFIKA gerektirir) ----
+ # Ucretsiz yol: yukaridaki SHA-256 checksum'lar butunluk dogrulamasi saglar (imza degil).
+ # Imzalamak icin repo Settings > Secrets'a sertifikalari ekleyip asagidaki adimlari etkinlestirin:
+ # Windows: WIN_CERT_BASE64 (.pfx -> base64), WIN_CERT_PASSWORD
+ # - name: Windows imzala (jsign)
+ # if: runner.os == 'Windows'
+ # shell: bash
+ # run: |
+ # echo "${{ secrets.WIN_CERT_BASE64 }}" | base64 -d > cert.pfx
+ # for f in out/*.msi; do jsign --storetype PKCS12 --keystore cert.pfx --storepass "${{ secrets.WIN_CERT_PASSWORD }}" "$f"; done
+ # macOS: APPLE_DEV_ID sertifikasi import + codesign + 'xcrun notarytool submit --wait' ile imzala/notarize.
+ - name: Release'e yukle
uses: softprops/action-gh-release@v2
with:
prerelease: true
- files: target/autoclicker.jar
+ generate_release_notes: true
+ files: out/*
diff --git a/.gitignore b/.gitignore
index 17a9e56..be215d3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,6 +19,8 @@ dist/
*.properties
# Maven wrapper properties'i *.properties'e ragmen izlenmeli
!.mvn/wrapper/maven-wrapper.properties
+# i18n ceviri kaynaklari *.properties'e ragmen izlenmeli
+!src/main/resources/i18n/messages*.properties
# ────────────────────────────────────────
# IDE dosyaları
diff --git a/README.md b/README.md
index d72dc95..6b6315d 100644
--- a/README.md
+++ b/README.md
@@ -125,6 +125,26 @@ com.ohualtex.autoclicker
---
+## 🔒 Güvenlik & Doğrulama
+
+Release dosyaları **kod imzalı değildir** (ücretsiz dağıtım); bunun yerine her dosya için **SHA-256 checksum** (`*.sha256`) yayınlanır.
+
+**Bütünlüğü doğrula:**
+```bash
+# Linux/macOS
+shasum -a 256 -c AutoClicker-Linux.zip.sha256
+# Windows (PowerShell)
+(Get-FileHash AutoClicker-Windows.zip -Algorithm SHA256).Hash
+```
+
+**İşletim sistemi uyarısını aşma** (imzasız olduğu için normaldir):
+- **Windows SmartScreen:** *"Daha fazla bilgi" → "Yine de çalıştır"*
+- **macOS Gatekeeper:** *Sistem Ayarları → Gizlilik ve Güvenlik → "Yine de Aç"*, veya `xattr -dr com.apple.quarantine AutoClicker.app`
+
+İlk çalıştırmada uygulama bir **sorumlu-kullanım onayı** ister ve **GitHub'dan yeni sürüm** olup olmadığını arka planda kontrol eder (config'de `checkUpdates=false` ile kapatılabilir).
+
+---
+
## 📌 Notlar & Uyumluluk
- **Ayar konumu:** Ayarlar `%APPDATA%\AutoClicker\config.properties` (Windows) veya `~/.autoclicker/` (macOS/Linux) altında saklanır; installer ile kurulumda bile yazılabilir.
diff --git a/pom.xml b/pom.xml
index 21dd630..2b05531 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
com.ohualtex
autoclicker
- 7.5
+ 8.5
jar
AutoClicker Ultimate
diff --git a/src/main/java/com/ohualtex/autoclicker/AutoClicker.java b/src/main/java/com/ohualtex/autoclicker/AutoClicker.java
index 8f784d0..9b986d4 100644
--- a/src/main/java/com/ohualtex/autoclicker/AutoClicker.java
+++ b/src/main/java/com/ohualtex/autoclicker/AutoClicker.java
@@ -8,6 +8,7 @@
import com.ohualtex.autoclicker.model.ActionType;
import com.ohualtex.autoclicker.model.MacroAction;
import com.ohualtex.autoclicker.ui.Icons;
+import com.ohualtex.autoclicker.ui.Widgets;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
@@ -149,6 +150,66 @@ public void windowClosing(WindowEvent e) {
saveConfig();
}
});
+
+ checkConsent(); // ilk calistirmada sorumlu-kullanim onayi (kabul edilmezse cikar)
+ checkForUpdate(); // arka planda surum kontrolu (best-effort, sessiz)
+ }
+
+ // Ilk calistirmada sorumlu-kullanim/yasal sorumluluk reddi onayi; bir kez gosterilir
+ private void checkConsent() {
+ if (Boolean.parseBoolean(props.getProperty("consentAccepted", "false"))) return;
+ int r = JOptionPane.showConfirmDialog(this, Lang.get("consent_msg"), Lang.get("consent_title"),
+ JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);
+ if (r != JOptionPane.OK_OPTION) { System.exit(0); }
+ props.setProperty("consentAccepted", "true");
+ saveConfig();
+ }
+
+ // GitHub Releases'i kontrol eder; daha yeni surum varsa kullaniciya bildirir (arka plan, best-effort)
+ private void checkForUpdate() {
+ if (!Boolean.parseBoolean(props.getProperty("checkUpdates", "true"))) return;
+ Thread t = new Thread(() -> {
+ try {
+ java.net.http.HttpClient c = java.net.http.HttpClient.newHttpClient();
+ java.net.http.HttpRequest req = java.net.http.HttpRequest.newBuilder()
+ .uri(java.net.URI.create("https://api.github.com/repos/Ohualtex/Auto_Clicker/releases/latest"))
+ .header("Accept", "application/vnd.github+json")
+ .timeout(java.time.Duration.ofSeconds(6)).build();
+ String body = c.send(req, java.net.http.HttpResponse.BodyHandlers.ofString()).body();
+ String tag = new com.google.gson.JsonParser().parse(body).getAsJsonObject().get("tag_name").getAsString();
+ String latest = tag.startsWith("v") ? tag.substring(1) : tag;
+ if (isNewer(latest, appVersion())) {
+ SwingUtilities.invokeLater(() -> {
+ int r = JOptionPane.showConfirmDialog(this,
+ String.format(Lang.get("update_msg"), latest, appVersion()),
+ Lang.get("update_title"), JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE);
+ if (r == JOptionPane.YES_OPTION) openReleasesPage();
+ });
+ }
+ } catch (Exception ignore) { /* ag/parse hatasi: sessiz */ }
+ }, "AutoClicker-UpdateCheck");
+ t.setDaemon(true);
+ t.start();
+ }
+
+ // "8.10" > "8.9" gibi sayisal-parcali surum karsilastirmasi
+ static boolean isNewer(String latest, String current) {
+ try {
+ String[] a = latest.split("\\."), b = current.split("\\.");
+ int n = Math.max(a.length, b.length);
+ for (int i = 0; i < n; i++) {
+ int x = i < a.length ? Integer.parseInt(a[i].trim()) : 0;
+ int y = i < b.length ? Integer.parseInt(b[i].trim()) : 0;
+ if (x != y) return x > y;
+ }
+ return false;
+ } catch (Exception e) { return false; }
+ }
+
+ private void openReleasesPage() {
+ try {
+ Desktop.getDesktop().browse(java.net.URI.create("https://github.com/Ohualtex/Auto_Clicker/releases/latest"));
+ } catch (Exception ignore) {}
}
// Sistem tepsisi ikonu: simge durumuna kuculunce gizle, tray menusunden goster/baslat-durdur/cikis
@@ -226,15 +287,7 @@ private void rebuildUI() {
}
private JButton createInfoButton(String tooltipKey) {
- JButton btn = new JButton(new Icons.InfoIcon());
- btn.setMargin(new Insets(0,0,0,0));
- btn.setBorderPainted(false);
- btn.setContentAreaFilled(false);
- btn.setFocusPainted(false);
- btn.setCursor(new Cursor(Cursor.HAND_CURSOR));
- btn.setToolTipText("
" + Lang.get(tooltipKey) + "
");
- btn.addActionListener(e -> JOptionPane.showMessageDialog(this, Lang.get(tooltipKey), Lang.get("info_title"), JOptionPane.INFORMATION_MESSAGE));
- return btn;
+ return Widgets.infoButton(this, tooltipKey);
}
private void applyColorsRecursively(Component c, Color color) {
@@ -882,11 +935,14 @@ public void keyPressed(KeyEvent ev) {
int t = typeBox.getSelectedIndex();
if(t==0) {
int mIdx = mouseBox.getSelectedIndex();
- int mask = InputEvent.BUTTON1_DOWN_MASK;
- if(mIdx==1) mask = InputEvent.BUTTON3_DOWN_MASK;
- else if(mIdx==2) mask = InputEvent.BUTTON2_DOWN_MASK;
- else if(mIdx==3) mask = MacroAction.DOUBLE_CLICK;
- chainModel.addElement(new MacroAction(ActionType.MOUSE_CLICK, mask, 0));
+ if (mIdx == 3) {
+ chainModel.addElement(new MacroAction(ActionType.MOUSE_DOUBLE_CLICK, 0, 0));
+ } else {
+ int mask = InputEvent.BUTTON1_DOWN_MASK;
+ if(mIdx==1) mask = InputEvent.BUTTON3_DOWN_MASK;
+ else if(mIdx==2) mask = InputEvent.BUTTON2_DOWN_MASK;
+ chainModel.addElement(new MacroAction(ActionType.MOUSE_CLICK, mask, 0));
+ }
} else if(t==1) {
chainModel.addElement(new MacroAction(ActionType.KEY_PRESS, selectedActKey[0], 0));
} else if(t==2) {
@@ -1088,37 +1144,7 @@ private JPanel buildSettingsPanel() {
}
private JPanel createCpsPanel(String title, String defaultVal, int max, String infoKey, java.util.function.Consumer setSlider) {
- JPanel panel = new JPanel();
- panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
- panel.setBorder(BorderFactory.createTitledBorder(title));
-
- JPanel inputPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
- JSlider slider = new JSlider(1, max, Integer.parseInt(defaultVal));
- JTextField field = new JTextField(defaultVal, 5);
-
- slider.addChangeListener(e -> field.setText(String.valueOf(slider.getValue())));
- field.addKeyListener(new KeyAdapter() {
- public void keyReleased(KeyEvent e) {
- boolean ok = false;
- try {
- int val = Integer.parseInt(field.getText().trim());
- if (val >= slider.getMinimum() && val <= max) { slider.setValue(val); ok = true; }
- } catch (Exception ex) { }
- // Bos alan notr; gecersiz/araliga sigmayan deger kirmizi cerceve
- field.putClientProperty("JComponent.outline", (ok || field.getText().trim().isEmpty()) ? null : "error");
- field.repaint();
- }
- });
-
- setSlider.accept(slider);
-
- inputPanel.add(slider);
- inputPanel.add(field);
- if (infoKey != null) {
- inputPanel.add(createInfoButton(infoKey));
- }
- panel.add(inputPanel);
- return panel;
+ return Widgets.cpsPanel(this, title, defaultVal, max, infoKey, setSlider);
}
private void initJNativeHook() {
@@ -1437,13 +1463,12 @@ private boolean startChainMacro() {
SwingUtilities.invokeLater(() -> chainList.setSelectedIndex(idx));
switch (action.type) {
case MOUSE_CLICK:
- if (action.p1 == MacroAction.DOUBLE_CLICK) {
- doMouseClick(InputEvent.BUTTON1_DOWN_MASK);
- robot.delay(40);
- doMouseClick(InputEvent.BUTTON1_DOWN_MASK);
- } else {
- doMouseClick(action.p1);
- }
+ doMouseClick(action.p1);
+ break;
+ case MOUSE_DOUBLE_CLICK:
+ doMouseClick(InputEvent.BUTTON1_DOWN_MASK);
+ robot.delay(40);
+ doMouseClick(InputEvent.BUTTON1_DOWN_MASK);
break;
case KEY_PRESS:
robot.keyPress(action.p1);
diff --git a/src/main/java/com/ohualtex/autoclicker/i18n/Lang.java b/src/main/java/com/ohualtex/autoclicker/i18n/Lang.java
index 0e324a5..295696f 100644
--- a/src/main/java/com/ohualtex/autoclicker/i18n/Lang.java
+++ b/src/main/java/com/ohualtex/autoclicker/i18n/Lang.java
@@ -1,114 +1,28 @@
package com.ohualtex.autoclicker.i18n;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+/**
+ * 6 dilli yerellestirme. Metinler src/main/resources/i18n/messages_<lang>.properties
+ * dosyalarinda tutulur (UTF-8; Java 9+ ResourceBundle bunlari UTF-8 okur).
+ */
public final class Lang {
- public static int L = 0; // 0=TR, 1=EN, 2=DE, 3=FR, 4=IT, 5=RU
- static java.util.Map d = new java.util.HashMap<>();
- static {
- d.put("st_idle", new String[]{"DURUM: BEKLIYOR", "STATUS: IDLE", "STATUS: BEREIT", "STATUT: EN ATTENTE", "STATO: IN ATTESA", "СТАТУС: ОЖИДАНИЕ"});
- d.put("st_run", new String[]{"DURUM: CALISIYOR", "STATUS: RUNNING", "STATUS: LÄUFT", "STATUT: EN COURS", "STATO: IN ESECUZIONE", "СТАТУС: РАБОТАЕТ"});
- d.put("st_lim", new String[]{"DURUM: LIMIT YENDI", "STATUS: LIMIT HIT", "STATUS: LIMIT ERREICHT", "STATUT: LIMITE", "STATO: LIMITE RAGGIUNTO", "СТАТУС: ЛИМИТ"});
- d.put("hook_fail", new String[]{"DURUM: KISAYOL DINLENEMIYOR", "STATUS: HOTKEY UNAVAILABLE", "STATUS: HOTKEY NICHT VERFUGBAR", "STATUT: RACCOURCI INDISPONIBLE", "STATO: HOTKEY NON DISPONIBILE", "СТАТУС: ГОРЯЧАЯ КЛАВИША НЕДОСТУПНА"});
-
- d.put("t_mouse", new String[]{"Fare", "Mouse", "Maus", "Souris", "Mouse", "Мышь"});
- d.put("t_key", new String[]{"Klavye", "Keyboard", "Tastatur", "Clavier", "Tastiera", "Клавиатура"});
- d.put("t_chain", new String[]{"Zincir", "Chain", "Kette", "Chaîne", "Catena", "Цепь"});
- d.put("t_px", new String[]{"Piksel", "Pixel", "Pixel", "Pixel", "Pixel", "Пиксель"});
- d.put("t_set", new String[]{"Ayarlar", "Settings", "Einstellungen", "Paramètres", "Impostazioni", "Настройки"});
-
- d.put("c_type", new String[]{"Tiklama Tipi: ", "Click Type: ", "Klick-Typ: ", "Type de clic: ", "Tipo di clic: ", "Тип клика: "});
- d.put("l_click", new String[]{"Sol Tik", "Left Click", "Linksklick", "Clic Gauche", "Clic Sinistro", "Левый Клик"});
- d.put("r_click", new String[]{"Sag Tik", "Right Click", "Rechtsklick", "Clic Droit", "Clic Destro", "Правый Клик"});
- d.put("m_click", new String[]{"Orta Tik", "Mid Click", "Mittelklick", "Clic Milieu", "Clic Centrale", "Средний Клик"});
- d.put("d_click", new String[]{"Cift Sol Tik", "Double Click", "Doppelklick", "Double Clic", "Doppio Clic", "Двойной Клик"});
-
- d.put("fix_loc", new String[]{"Sabit Konuma Tikla", "Click Fixed Loc", "Feste Position", "Bouton Fixe", "Pos. Fissa", "Фикс. Место"});
- d.put("pick_loc", new String[]{"Konum Sec", "Pick Loc", "Wählen", "Choisir", "Seleziona", "Выбрать"});
- d.put("wait_mid", new String[]{"Bekliyor (Orta Tik)", "Waiting (Mid Click)", "Wartet (Mittelklick)", "Attente (Milieu)", "Attesa (Centrale)", "Ожидание (Ср. клик)"});
-
- d.put("anti_ban", new String[]{"Insan Modu (Rastgele Gecikme)", "Humanizer (Random Delay)", "Menschenmodus (Zufall)", "Mode Humain (Délais Aléat.)", "Modalità Umana (Ritardo)", "Анти-Бан (случайная задержка)"});
- d.put("cps", new String[]{"Fare Hizi (CPS):", "Mouse Speed (CPS):", "Maus-Geschw. (CPS):", "Vitesse Souris (CPS):", "Velocità Mouse (CPS):", "Скорость Мыши (CPS):"});
- d.put("key_cps", new String[]{"Klavye Hizi (Saniyede):", "Key Speed (/sec):", "Tasten-Geschw. (/s):", "Vitesse Touche (/s):", "Velocità Tasto (/s):", "Скор. Клавиатуры (/с):"});
-
- d.put("key_trg", new String[]{"Basilacak Tus:", "Target Key:", "Zieltaste:", "Touche Cible:", "Tasto Obiettivo:", "Целевая Клавиша:"});
- d.put("set_k", new String[]{"Tus Ata", "Set Key", "Setzen", "Définir", "Assegna", "Назначить"});
- d.put("press_k", new String[]{"Basin...", "Press...", "Drücken...", "Appuyez...", "Premi...", "Нажмите..."});
-
- d.put("add_act", new String[]{"(+) Eylem Ekle", "(+) Add Action", "(+) Aktion", "(+) Ajouter", "(+) Aggiungi", "(+) Добавить"});
- d.put("del_act", new String[]{"(-) Secileni Sil", "(-) Remove", "(-) Löschen", "(-) Supprimer", "(-) Rimuovi", "(-) Удалить"});
- d.put("clr_act", new String[]{"(x) Temizle", "(x) Clear", "(x) Leeren", "(x) Effacer", "(x) Pulisci", "(x) Очистить"});
-
- d.put("act_typ", new String[]{"Eylem Turu:", "Action Type:", "Aktionsart:", "Type d'action:", "Tipo di Azione:", "Тип Действия:"});
- d.put("ms_delay", new String[]{"Milisaniye (Gecikme):", "Delay (ms):", "Verzögerung (ms):", "Délai (ms):", "Ritardo (ms):", "Задержка (мс):"});
- d.put("list_add", new String[]{"[v] Listeye Ekle", "[v] Add to List", "[v] Hinzufügen", "[v] Ajouter", "[v] Aggiungi", "[v] Добавить"});
- d.put("tnt_mouse", new String[]{"Fare Tiklamasi", "Mouse Click", "Mausklick", "Clic Souris", "Clic Mouse", "Клик Мыши"});
- d.put("tnt_key", new String[]{"Klavye Tusu", "Key Press", "Taste Drücken", "Appui Touche", "Pressione Tasto", "Нажатие Клавиши"});
- d.put("tnt_move", new String[]{"Fareyi Tasi", "Move Mouse", "Maus Bewegen", "Bouger Souris", "Sposta Mouse", "Сдвинуть Мышь"});
-
- d.put("px_1", new String[]{"1. Gozetlenecek Piksel", "1. Target Pixel", "1. Zielpixel", "1. Pixel Cible", "1. Pixel Obiettivo", "1. Цель Пиксель"});
- d.put("px_clr", new String[]{"Renk:", "Color:", "Farbe:", "Couleur:", "Colore:", "Цвет:"});
- d.put("px_2", new String[]{"2. Tetiklenme Sartlari", "2. Conditions", "2. Bedingungen", "2. Conditions", "2. Condizioni", "2. Условия"});
- d.put("px_cond1", new String[]{"Renk ESLESTIGINDE", "When Color MATCHES", "Farbe ÜBEREINSTIMMT", "Couleur CORRESPOND", "Colore CORRISPONDE", "Когда совпадает"});
- d.put("px_cond2", new String[]{"Renk DEGISTIGINDE", "When Color CHANGES", "Farbe WECHSELT", "Couleur CHANGE", "Colore CAMBIA", "Когда меняется"});
- d.put("px_tol", new String[]{"Tolerans Payi (%):", "Tolerance (%):", "Toleranz (%):", "Tolérance (%):", "Tolleranza (%):", "Допуск (%):"});
- d.put("px_3", new String[]{"3. Gerceklesecek Tepki", "3. Reaction Action", "3. Reaktion", "3. Réaction", "3. Reazione", "3. Реакция"});
- d.put("px_act3", new String[]{"Ozel Tusa Bas", "Press Custom Key", "Zieltaste drücken", "Appuyer Touche", "Premi Tasto", "Своя Клавиша"});
- d.put("px_act4", new String[]{"Sadece Zili Cal", "Only Beep", "Nur Piepen", "Bip Sonore", "Suona Solo", "Только Звук"});
- d.put("px_rate", new String[]{"Tarama Hizi (Ms):", "Scanner Rate (Ms):", "Scanrate (Ms):", "Vitesse Scan (Ms):", "Velocità Scan (Ms):", "Скорость (Мс):"});
-
- d.put("set_hk", new String[]{"Kisayol Tusu (Baslat/Durdur):", "Start/Stop Hotkey:", "Start/Stopp Hotkey:", "Raccourci Start/Stop:", "Tasto Avvio/Arresto:", "Горячая Клавиша:"});
- d.put("lim_title", new String[]{"Otomatik Durdurma Sinirlari", "Auto Stop Limiters", "Auto-Stopp Begrenzungen", "Limites Arrêt Auto", "Limiti Arresto Auto", "Лимиты Автоостановки"});
- d.put("lim_use", new String[]{"Limitoru Aktif Et", "Enable Limiter", "Limiter aktivieren", "Activer Limiteur", "Abilita Limitatore", "Вкл. Лимитер"});
- d.put("lim_after", new String[]{"Sinir:", "Limit:", "Limit:", "Dans:", "Dopo:", "Лимит:"});
- d.put("lim_min", new String[]{"Dakika Sonra", "Minutes Later", "Minuten", "Minutes", "Minuti", "Минут"});
- d.put("lim_iter", new String[]{"Dongu Sonra", "Iterations Later", "Iterationen", "Itérations", "Iterazioni", "Итераций"});
- d.put("lim_stop", new String[]{"Sadece Makroyu Durdur", "Just Stop Macro", "Makro stoppen", "Arrêter Macro", "Ferma Macro", "Только стоп"});
- d.put("lim_shut", new String[]{"Bilgisayari Kapat", "Shutdown PC", "PC herunterfahren", "Éteindre le PC", "Spegni PC", "Выкл ПК"});
-
- d.put("style", new String[]{"(O) Gorunum Ozellestirme", "(O) UI Customization", "(O) UI Anpassung", "(O) Apparence UI", "(O) Aspetto UI", "(O) Дизайн UI"});
- d.put("theme", new String[]{"Ana Tema:", "Main Theme:", "Hauptthema:", "Thème:", "Tema Principale:", "Тема:"});
- d.put("theme_d", new String[]{"Karanlik Mod", "Dark Mode", "Dunkler Modus", "Sombre", "Modo Scuro", "Темный"});
- d.put("theme_l", new String[]{"Aydinlik Mod", "Light Mode", "Heller Modus", "Clair", "Modo Chiaro", "Светлый"});
- d.put("txt_size", new String[]{"Yazi Boyutu:", "Text Size:", "Textgröße:", "Taille:", "Dimensione:", "Размер:"});
- d.put("txt_col", new String[]{"Metin Rengi:", "Text Color:", "Textfarbe:", "Couleur Texte:", "Colore Testo:", "Цвет Текста:"});
- d.put("col_pick", new String[]{"Renk Sec", "Pick Color", "Farbe", "Choisir", "Seleziona", "Выбрать Цвет"});
- d.put("apply_s", new String[]{"Uygula/Kaydet", "Apply/Save", "Anwenden", "Appliquer", "Applica", "Применить"});
- d.put("lang_title", new String[]{"(L) Dil (Language)", "(L) Language", "(L) Sprache", "(L) Langue", "(L) Lingua", "(L) Язык"});
-
- d.put("info_hum", new String[]{"Anti-Ban: Robotik tiklamalari saptirmak icin gecikmelere minik sapmalar ekler.", "Anti-Ban: Adds random fluctuations to delays to simulate human behavior and evade detection.", "Anti-Ban: Fügt den Verzögerungen zufällige Schwankungen hinzu.", "Anti-Ban: Ajoute des fluctuations aléatoires aux délais.", "Anti-Ban: Aggiunge fluttuazioni casuali ai ritardi.", "Анти-Бан: Добавляет случайные колебания к задержкам."});
- d.put("info_lim", new String[]{"Otomasyonu belirli bir sure sonra kapatir.", "Stops the automation automatically after a set time or cycle count. Ideal for AFK macros.", "Stoppt die Automatisierung automatisch nach einer Weile.", "Arrête automatiquement l'automatisation.", "Ferma l'automazione in base a limiti.", "Останавливает автоматизацию при достижении лимита."});
- d.put("info_px", new String[]{"Renk Toleransi: Ufak golge farkliliklarinin renk algisini bozmasini engeller.", "Color Tolerance: Prevents minor in-game shading/lighting shifts from ruining detection.", "Farbtoleranz: Verhindert kleine Schattenfehler.", "Tolérance: Empêche les petits changements de lumière de fausser la détection.", "Tolleranza: Evita che l'illuminazione rompa l'algoritmo.", "Допуск: Игнорирует изменения освещения."});
- d.put("info_cps", new String[]{"Saniyedeki tiklama hizini belirler (Click Per Second).", "Sets the click speed per second (CPS).", "Legt die Klicks pro Sekunde fest.", "Définit la vitesse de clic (CPS).", "Imposta i clic al secondo (CPS).", "Устанавливает кликов в секунду (CPS)."});
- d.put("info_px_cond", new String[]{"Eslestiginde: Renk gorundugunde tepki verir.\nDegistiginde: Renk kayboldugunda tepki verir.", "Matches: Reacts when color appears.\nChanges: Reacts when color disappears.", "Stimmt überein: Reagiert, wenn die Farbe erscheint.", "Correspond: Agit quand la couleur apparait.", "Corrisponde: Agisce quando il colore appare.", "Совпадает: Реагирует на появление цвета."});
- d.put("info_px_rate", new String[]{"Tarama Hizi: Ekranin ne siklikla kontrol edilecegini belirler (Milisaniye).", "Scan Rate: How often to check the screen (Milliseconds).", "Scanrate: Wie oft der Bildschirm überprüft wird (ms).", "Taux de scan: Fréquence de vérification (ms).", "Velocità scan: Frequenza di controllo schermo (ms).", "Скорость: Частота проверки экрана (мс)."});
- d.put("info_title", new String[]{"Bilgi", "Info", "Info", "Info", "Info", "Информация"});
- d.put("reset", new String[]{"Sifirla", "Reset", "Zurücksetzen", "Réinit.", "Reimposta", "Сброс"});
- d.put("shut_ok", new String[]{"Limit asildi! Bilgisayar %s icinde kapatilacak.", "Limit reached! PC will shut down in %s.", "Limit erreicht! PC fährt in %s herunter.", "Limite atteinte! Le PC s'eteindra dans %s.", "Limite raggiunto! Il PC si spegnera tra %s.", "Лимит достигнут! ПК выключится через %s."});
- d.put("shut_title", new String[]{"Bilgisayar Kapatiliyor", "Shutting Down", "Herunterfahren", "Arret du PC", "Spegnimento PC", "Выключение ПК"});
- d.put("shut_pending", new String[]{"Limit asildi! Bilgisayar %s icinde kapanacak.\nVazgecmek icin asagidaki butona basin.", "Limit reached! PC shuts down in %s.\nPress the button below to cancel.", "Limit erreicht! PC fährt in %s herunter.\nZum Abbrechen unten klicken.", "Limite atteinte! Arret dans %s.\nCliquez ci-dessous pour annuler.", "Limite raggiunto! Spegnimento tra %s.\nPremi sotto per annullare.", "Лимит достигнут! Выключение через %s.\nНажмите ниже для отмены."});
- d.put("shut_cancel_btn", new String[]{"Kapatmayi Iptal Et", "Cancel Shutdown", "Abbrechen", "Annuler l'arret", "Annulla spegnimento", "Отменить выключение"});
- d.put("shut_cancelled", new String[]{"Bilgisayar kapatma iptal edildi.", "Shutdown cancelled.", "Herunterfahren abgebrochen.", "Arret annule.", "Spegnimento annullato.", "Выключение отменено."});
- d.put("lim_invalid", new String[]{"DURUM: GECERSIZ LIMIT DEGERI", "STATUS: INVALID LIMIT VALUE", "STATUS: UNGULTIGER LIMITWERT", "STATUT: LIMITE INVALIDE", "STATO: LIMITE NON VALIDO", "СТАТУС: НЕВЕРНЫЙ ЛИМИТ"});
- d.put("sched_title", new String[]{"(Z) Zamanlayici", "(Z) Scheduler", "(Z) Zeitplaner", "(Z) Planificateur", "(Z) Pianificatore", "(Z) Планировщик"});
- d.put("sched_use", new String[]{"Gecikmeli baslat", "Delayed start", "Verzögerter Start", "Démarrage différé", "Avvio ritardato", "Запуск с задержкой"});
- d.put("sched_sec", new String[]{"saniye sonra", "seconds later", "Sekunden später", "secondes après", "secondi dopo", "секунд спустя"});
- d.put("sched_countdown", new String[]{"DURUM: BASLIYOR (%d sn)", "STATUS: STARTING (%d s)", "STATUS: START IN (%d s)", "STATUT: DEBUT (%d s)", "STATO: AVVIO (%d s)", "СТАТУС: СТАРТ (%d с)"});
- d.put("tray_show", new String[]{"Goster", "Show", "Anzeigen", "Afficher", "Mostra", "Показать"});
- d.put("tray_toggle", new String[]{"Baslat / Durdur", "Start / Stop", "Start / Stopp", "Demarrer / Arreter", "Avvia / Ferma", "Старт / Стоп"});
- d.put("tray_exit", new String[]{"Cikis", "Exit", "Beenden", "Quitter", "Esci", "Выход"});
- d.put("tabhk_title", new String[]{"(K) Sekme Kisayollari", "(K) Per-Tab Hotkeys", "(K) Tab-Hotkeys", "(K) Raccourcis par onglet", "(K) Tasti per scheda", "(K) Горячие клавиши вкладок"});
- d.put("io_export", new String[]{"Disa Aktar (JSON)", "Export (JSON)", "Export (JSON)", "Exporter (JSON)", "Esporta (JSON)", "Экспорт (JSON)"});
- d.put("io_import", new String[]{"Ice Aktar (JSON)", "Import (JSON)", "Import (JSON)", "Importer (JSON)", "Importa (JSON)", "Импорт (JSON)"});
- d.put("io_fail", new String[]{"Dosya islemi basarisiz: ", "File operation failed: ", "Dateioperation fehlgeschlagen: ", "Echec du fichier: ", "Operazione file fallita: ", "Сбой работы с файлом: "});
- d.put("prof_title", new String[]{"(P) Profiller", "(P) Profiles", "(P) Profile", "(P) Profils", "(P) Profili", "(P) Профили"});
- d.put("prof_save", new String[]{"Kaydet", "Save", "Speichern", "Enregistrer", "Salva", "Сохранить"});
- d.put("prof_load", new String[]{"Yukle", "Load", "Laden", "Charger", "Carica", "Загрузить"});
- d.put("prof_del", new String[]{"Sil", "Delete", "Löschen", "Supprimer", "Elimina", "Удалить"});
- d.put("rec_start", new String[]{"● Kaydet", "● Record", "● Aufnehmen", "● Enregistrer", "● Registra", "● Запись"});
- d.put("rec_stop", new String[]{"■ Durdur (ESC)", "■ Stop (ESC)", "■ Stopp (ESC)", "■ Arreter (ESC)", "■ Ferma (ESC)", "■ Стоп (ESC)"});
- d.put("rec_status", new String[]{"DURUM: KAYDEDILIYOR (ESC=dur)", "STATUS: RECORDING (ESC=stop)", "STATUS: AUFNAHME (ESC=stopp)", "STATUT: ENREGISTREMENT (ESC)", "STATO: REGISTRAZIONE (ESC)", "СТАТУС: ЗАПИСЬ (ESC=стоп)"});
- d.put("shut_fail", new String[]{"Kapatma komutu basarisiz oldu: ", "Shutdown command failed: ", "Herunterfahren fehlgeschlagen: ", "Echec de la commande d'arret: ", "Comando di spegnimento fallito: ", "Сбой команды выключения: "});
- d.put("shut_unsup", new String[]{"Bu isletim sisteminde otomatik kapatma desteklenmiyor: ", "Automatic shutdown not supported on this OS: ", "Automatisches Herunterfahren auf diesem OS nicht unterstützt: ", "Arret automatique non supporte sur cet OS: ", "Spegnimento automatico non supportato su questo OS: ", "Автовыключение не поддерживается в этой ОС: "});
+ private Lang() {}
+
+ // 0=TR 1=EN 2=DE 3=FR 4=IT 5=RU
+ private static final String[] LOCALES = {"tr", "en", "de", "fr", "it", "ru"};
+
+ /** Aktif dil indeksi (langBox tarafindan ayarlanir). */
+ public static int L = 0;
+
+ public static String get(String key) {
+ try {
+ int idx = (L >= 0 && L < LOCALES.length) ? L : 0;
+ return ResourceBundle.getBundle("i18n.messages", new Locale(LOCALES[idx])).getString(key);
+ } catch (Exception e) {
+ return key; // anahtar/dosya bulunamazsa anahtarin kendisi (eski davranis)
+ }
}
- public static String get(String key) { return d.containsKey(key) ? d.get(key)[L] : key; }
}
diff --git a/src/main/java/com/ohualtex/autoclicker/model/ActionType.java b/src/main/java/com/ohualtex/autoclicker/model/ActionType.java
index c92a5da..bcee4cc 100644
--- a/src/main/java/com/ohualtex/autoclicker/model/ActionType.java
+++ b/src/main/java/com/ohualtex/autoclicker/model/ActionType.java
@@ -1,4 +1,4 @@
package com.ohualtex.autoclicker.model;
/** Zincir makro adim turleri. */
-public enum ActionType { MOUSE_CLICK, KEY_PRESS, MOUSE_MOVE, DELAY }
+public enum ActionType { MOUSE_CLICK, MOUSE_DOUBLE_CLICK, KEY_PRESS, MOUSE_MOVE, DELAY }
diff --git a/src/main/java/com/ohualtex/autoclicker/model/MacroAction.java b/src/main/java/com/ohualtex/autoclicker/model/MacroAction.java
index deee6d1..9e5c5dd 100644
--- a/src/main/java/com/ohualtex/autoclicker/model/MacroAction.java
+++ b/src/main/java/com/ohualtex/autoclicker/model/MacroAction.java
@@ -7,8 +7,8 @@
/** Zincir makrosundaki tek bir adim (tur + iki parametre). Listede toString ile gosterilir, serialize ile saklanir. */
public class MacroAction {
- /** MOUSE_CLICK adiminda p1 bu degerse "cift sol tik" demektir (sentinel/isaret degeri). */
- public static final int DOUBLE_CLICK = 999;
+ // Eski configlerde cift-tik "MOUSE_CLICK:999" olarak saklaniyordu; geriye uyum icin tutulur.
+ private static final int LEGACY_DOUBLE_CLICK = 999;
public ActionType type;
public int p1, p2;
@@ -17,7 +17,8 @@ public class MacroAction {
public String toString() {
switch(type) {
- case MOUSE_CLICK: return Lang.get("tnt_mouse") + ": " + (p1==InputEvent.BUTTON1_DOWN_MASK ? Lang.get("l_click") : p1==InputEvent.BUTTON3_DOWN_MASK ? Lang.get("r_click") : p1==DOUBLE_CLICK ? Lang.get("d_click") : Lang.get("m_click"));
+ case MOUSE_CLICK: return Lang.get("tnt_mouse") + ": " + (p1==InputEvent.BUTTON1_DOWN_MASK ? Lang.get("l_click") : p1==InputEvent.BUTTON3_DOWN_MASK ? Lang.get("r_click") : Lang.get("m_click"));
+ case MOUSE_DOUBLE_CLICK: return Lang.get("tnt_mouse") + ": " + Lang.get("d_click");
case KEY_PRESS: return Lang.get("tnt_key") + ": " + KeyEvent.getKeyText(p1);
case MOUSE_MOVE: return Lang.get("tnt_move") + ": X=" + p1 + ", Y=" + p2;
case DELAY: return Lang.get("ms_delay") + " " + p1;
@@ -29,6 +30,13 @@ public String toString() {
public static MacroAction deserialize(String s) {
String[] parts = s.split(":");
- return new MacroAction(ActionType.valueOf(parts[0]), Integer.parseInt(parts[1]), Integer.parseInt(parts[2]));
+ ActionType t = ActionType.valueOf(parts[0]);
+ int p1 = Integer.parseInt(parts[1]);
+ int p2 = Integer.parseInt(parts[2]);
+ // Geriye uyum: eski "MOUSE_CLICK:999" -> MOUSE_DOUBLE_CLICK
+ if (t == ActionType.MOUSE_CLICK && p1 == LEGACY_DOUBLE_CLICK) {
+ return new MacroAction(ActionType.MOUSE_DOUBLE_CLICK, 0, 0);
+ }
+ return new MacroAction(t, p1, p2);
}
}
diff --git a/src/main/java/com/ohualtex/autoclicker/ui/Widgets.java b/src/main/java/com/ohualtex/autoclicker/ui/Widgets.java
new file mode 100644
index 0000000..601178e
--- /dev/null
+++ b/src/main/java/com/ohualtex/autoclicker/ui/Widgets.java
@@ -0,0 +1,60 @@
+package com.ohualtex.autoclicker.ui;
+
+import com.ohualtex.autoclicker.i18n.Lang;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.util.function.Consumer;
+
+/** Durum-bagimsiz, yeniden kullanilabilir Swing widget kuruculari (bilgi butonu, CPS/sayisal panel). */
+public final class Widgets {
+
+ private Widgets() {}
+
+ /** Yaninda info ikonu olan, tiklayinca aciklama gosteren buton. */
+ public static JButton infoButton(Component parent, String tooltipKey) {
+ JButton btn = new JButton(new Icons.InfoIcon());
+ btn.setMargin(new Insets(0, 0, 0, 0));
+ btn.setBorderPainted(false);
+ btn.setContentAreaFilled(false);
+ btn.setFocusPainted(false);
+ btn.setCursor(new Cursor(Cursor.HAND_CURSOR));
+ btn.setToolTipText("" + Lang.get(tooltipKey) + "
");
+ btn.addActionListener(e -> JOptionPane.showMessageDialog(parent, Lang.get(tooltipKey), Lang.get("info_title"), JOptionPane.INFORMATION_MESSAGE));
+ return btn;
+ }
+
+ /** Baslikli kenarlik + slider + senkron metin alani (gecersiz girdide kirmizi cerceve) + opsiyonel info butonu. */
+ public static JPanel cpsPanel(Component parent, String title, String defaultVal, int max, String infoKey,
+ Consumer setSlider) {
+ JPanel panel = new JPanel();
+ panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
+ panel.setBorder(BorderFactory.createTitledBorder(title));
+
+ JPanel inputPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
+ JSlider slider = new JSlider(1, max, Integer.parseInt(defaultVal));
+ JTextField field = new JTextField(defaultVal, 5);
+
+ slider.addChangeListener(e -> field.setText(String.valueOf(slider.getValue())));
+ field.addKeyListener(new KeyAdapter() {
+ public void keyReleased(KeyEvent e) {
+ boolean ok = false;
+ try {
+ int val = Integer.parseInt(field.getText().trim());
+ if (val >= slider.getMinimum() && val <= max) { slider.setValue(val); ok = true; }
+ } catch (Exception ex) { }
+ field.putClientProperty("JComponent.outline", (ok || field.getText().trim().isEmpty()) ? null : "error");
+ field.repaint();
+ }
+ });
+
+ setSlider.accept(slider);
+ inputPanel.add(slider);
+ inputPanel.add(field);
+ if (infoKey != null) inputPanel.add(infoButton(parent, infoKey));
+ panel.add(inputPanel);
+ return panel;
+ }
+}
diff --git a/src/main/resources/i18n/messages.properties b/src/main/resources/i18n/messages.properties
new file mode 100644
index 0000000..a3d2b60
--- /dev/null
+++ b/src/main/resources/i18n/messages.properties
@@ -0,0 +1,100 @@
+#AutoClicker i18n - default(en)
+#Sun Jun 21 15:07:13 GMT+03:00 2026
+act_typ=Action Type\:
+add_act=(+) Add Action
+anti_ban=Humanizer (Random Delay)
+apply_s=Apply/Save
+c_type=Click Type\:
+clr_act=(x) Clear
+col_pick=Pick Color
+cps=Mouse Speed (CPS)\:
+d_click=Double Click
+del_act=(-) Remove
+fix_loc=Click Fixed Loc
+hook_fail=STATUS\: HOTKEY UNAVAILABLE
+info_cps=Sets the click speed per second (CPS).
+info_hum=Anti-Ban\: Adds random fluctuations to delays to simulate human behavior and evade detection.
+info_lim=Stops the automation automatically after a set time or cycle count. Ideal for AFK macros.
+info_px=Color Tolerance\: Prevents minor in-game shading/lighting shifts from ruining detection.
+info_px_cond=Matches\: Reacts when color appears.\nChanges\: Reacts when color disappears.
+info_px_rate=Scan Rate\: How often to check the screen (Milliseconds).
+info_title=Info
+io_export=Export (JSON)
+io_fail=File operation failed\:
+io_import=Import (JSON)
+key_cps=Key Speed (/sec)\:
+key_trg=Target Key\:
+l_click=Left Click
+lang_title=(L) Language
+lim_after=Limit\:
+lim_invalid=STATUS\: INVALID LIMIT VALUE
+lim_iter=Iterations Later
+lim_min=Minutes Later
+lim_shut=Shutdown PC
+lim_stop=Just Stop Macro
+lim_title=Auto Stop Limiters
+lim_use=Enable Limiter
+list_add=[v] Add to List
+m_click=Mid Click
+ms_delay=Delay (ms)\:
+pick_loc=Pick Loc
+press_k=Press...
+prof_del=Delete
+prof_load=Load
+prof_save=Save
+prof_title=(P) Profiles
+px_1=1. Target Pixel
+px_2=2. Conditions
+px_3=3. Reaction Action
+px_act3=Press Custom Key
+px_act4=Only Beep
+px_clr=Color\:
+px_cond1=When Color MATCHES
+px_cond2=When Color CHANGES
+px_rate=Scanner Rate (Ms)\:
+px_tol=Tolerance (%)\:
+r_click=Right Click
+rec_start=● Record
+rec_status=STATUS\: RECORDING (ESC\=stop)
+rec_stop=■ Stop (ESC)
+reset=Reset
+sched_countdown=STATUS\: STARTING (%d s)
+sched_sec=seconds later
+sched_title=(Z) Scheduler
+sched_use=Delayed start
+set_hk=Start/Stop Hotkey\:
+set_k=Set Key
+shut_cancel_btn=Cancel Shutdown
+shut_cancelled=Shutdown cancelled.
+shut_fail=Shutdown command failed\:
+shut_ok=Limit reached\! PC will shut down in %s.
+shut_pending=Limit reached\! PC shuts down in %s.\nPress the button below to cancel.
+shut_title=Shutting Down
+shut_unsup=Automatic shutdown not supported on this OS\:
+st_idle=STATUS\: IDLE
+st_lim=STATUS\: LIMIT HIT
+st_run=STATUS\: RUNNING
+style=(O) UI Customization
+t_chain=Chain
+t_key=Keyboard
+t_mouse=Mouse
+t_px=Pixel
+t_set=Settings
+tabhk_title=(K) Per-Tab Hotkeys
+theme=Main Theme\:
+theme_d=Dark Mode
+theme_l=Light Mode
+tnt_key=Key Press
+tnt_mouse=Mouse Click
+tnt_move=Move Mouse
+tray_exit=Exit
+tray_show=Show
+tray_toggle=Start / Stop
+txt_col=Text Color\:
+txt_size=Text Size\:
+wait_mid=Waiting (Mid Click)
+
+consent_title=Responsible Use Agreement
+consent_msg=This tool is for learning and productivity. Using it in anti-cheat protected games risks account bans; you are responsible. Do you accept?
+update_title=Update Available
+update_msg=New version %s is available (you have %s). Open the download page?
diff --git a/src/main/resources/i18n/messages_de.properties b/src/main/resources/i18n/messages_de.properties
new file mode 100644
index 0000000..16ab18d
--- /dev/null
+++ b/src/main/resources/i18n/messages_de.properties
@@ -0,0 +1,100 @@
+#AutoClicker i18n - de
+#Sun Jun 21 15:07:13 GMT+03:00 2026
+act_typ=Aktionsart\:
+add_act=(+) Aktion
+anti_ban=Menschenmodus (Zufall)
+apply_s=Anwenden
+c_type=Klick-Typ\:
+clr_act=(x) Leeren
+col_pick=Farbe
+cps=Maus-Geschw. (CPS)\:
+d_click=Doppelklick
+del_act=(-) Löschen
+fix_loc=Feste Position
+hook_fail=STATUS\: HOTKEY NICHT VERFUGBAR
+info_cps=Legt die Klicks pro Sekunde fest.
+info_hum=Anti-Ban\: Fügt den Verzögerungen zufällige Schwankungen hinzu.
+info_lim=Stoppt die Automatisierung automatisch nach einer Weile.
+info_px=Farbtoleranz\: Verhindert kleine Schattenfehler.
+info_px_cond=Stimmt überein\: Reagiert, wenn die Farbe erscheint.
+info_px_rate=Scanrate\: Wie oft der Bildschirm überprüft wird (ms).
+info_title=Info
+io_export=Export (JSON)
+io_fail=Dateioperation fehlgeschlagen\:
+io_import=Import (JSON)
+key_cps=Tasten-Geschw. (/s)\:
+key_trg=Zieltaste\:
+l_click=Linksklick
+lang_title=(L) Sprache
+lim_after=Limit\:
+lim_invalid=STATUS\: UNGULTIGER LIMITWERT
+lim_iter=Iterationen
+lim_min=Minuten
+lim_shut=PC herunterfahren
+lim_stop=Makro stoppen
+lim_title=Auto-Stopp Begrenzungen
+lim_use=Limiter aktivieren
+list_add=[v] Hinzufügen
+m_click=Mittelklick
+ms_delay=Verzögerung (ms)\:
+pick_loc=Wählen
+press_k=Drücken...
+prof_del=Löschen
+prof_load=Laden
+prof_save=Speichern
+prof_title=(P) Profile
+px_1=1. Zielpixel
+px_2=2. Bedingungen
+px_3=3. Reaktion
+px_act3=Zieltaste drücken
+px_act4=Nur Piepen
+px_clr=Farbe\:
+px_cond1=Farbe ÜBEREINSTIMMT
+px_cond2=Farbe WECHSELT
+px_rate=Scanrate (Ms)\:
+px_tol=Toleranz (%)\:
+r_click=Rechtsklick
+rec_start=● Aufnehmen
+rec_status=STATUS\: AUFNAHME (ESC\=stopp)
+rec_stop=■ Stopp (ESC)
+reset=Zurücksetzen
+sched_countdown=STATUS\: START IN (%d s)
+sched_sec=Sekunden später
+sched_title=(Z) Zeitplaner
+sched_use=Verzögerter Start
+set_hk=Start/Stopp Hotkey\:
+set_k=Setzen
+shut_cancel_btn=Abbrechen
+shut_cancelled=Herunterfahren abgebrochen.
+shut_fail=Herunterfahren fehlgeschlagen\:
+shut_ok=Limit erreicht\! PC fährt in %s herunter.
+shut_pending=Limit erreicht\! PC fährt in %s herunter.\nZum Abbrechen unten klicken.
+shut_title=Herunterfahren
+shut_unsup=Automatisches Herunterfahren auf diesem OS nicht unterstützt\:
+st_idle=STATUS\: BEREIT
+st_lim=STATUS\: LIMIT ERREICHT
+st_run=STATUS\: LÄUFT
+style=(O) UI Anpassung
+t_chain=Kette
+t_key=Tastatur
+t_mouse=Maus
+t_px=Pixel
+t_set=Einstellungen
+tabhk_title=(K) Tab-Hotkeys
+theme=Hauptthema\:
+theme_d=Dunkler Modus
+theme_l=Heller Modus
+tnt_key=Taste Drücken
+tnt_mouse=Mausklick
+tnt_move=Maus Bewegen
+tray_exit=Beenden
+tray_show=Anzeigen
+tray_toggle=Start / Stopp
+txt_col=Textfarbe\:
+txt_size=Textgröße\:
+wait_mid=Wartet (Mittelklick)
+
+consent_title=Nutzungsvereinbarung
+consent_msg=Dieses Tool dient dem Lernen und der Produktivitaet. Nutzung in Anti-Cheat-Spielen birgt Sperrrisiken; Sie sind verantwortlich. Akzeptieren Sie?
+update_title=Update verfuegbar
+update_msg=Neue Version %s verfuegbar (aktuell %s). Download-Seite oeffnen?
diff --git a/src/main/resources/i18n/messages_en.properties b/src/main/resources/i18n/messages_en.properties
new file mode 100644
index 0000000..1a9c64a
--- /dev/null
+++ b/src/main/resources/i18n/messages_en.properties
@@ -0,0 +1,100 @@
+#AutoClicker i18n - en
+#Sun Jun 21 15:07:13 GMT+03:00 2026
+act_typ=Action Type\:
+add_act=(+) Add Action
+anti_ban=Humanizer (Random Delay)
+apply_s=Apply/Save
+c_type=Click Type\:
+clr_act=(x) Clear
+col_pick=Pick Color
+cps=Mouse Speed (CPS)\:
+d_click=Double Click
+del_act=(-) Remove
+fix_loc=Click Fixed Loc
+hook_fail=STATUS\: HOTKEY UNAVAILABLE
+info_cps=Sets the click speed per second (CPS).
+info_hum=Anti-Ban\: Adds random fluctuations to delays to simulate human behavior and evade detection.
+info_lim=Stops the automation automatically after a set time or cycle count. Ideal for AFK macros.
+info_px=Color Tolerance\: Prevents minor in-game shading/lighting shifts from ruining detection.
+info_px_cond=Matches\: Reacts when color appears.\nChanges\: Reacts when color disappears.
+info_px_rate=Scan Rate\: How often to check the screen (Milliseconds).
+info_title=Info
+io_export=Export (JSON)
+io_fail=File operation failed\:
+io_import=Import (JSON)
+key_cps=Key Speed (/sec)\:
+key_trg=Target Key\:
+l_click=Left Click
+lang_title=(L) Language
+lim_after=Limit\:
+lim_invalid=STATUS\: INVALID LIMIT VALUE
+lim_iter=Iterations Later
+lim_min=Minutes Later
+lim_shut=Shutdown PC
+lim_stop=Just Stop Macro
+lim_title=Auto Stop Limiters
+lim_use=Enable Limiter
+list_add=[v] Add to List
+m_click=Mid Click
+ms_delay=Delay (ms)\:
+pick_loc=Pick Loc
+press_k=Press...
+prof_del=Delete
+prof_load=Load
+prof_save=Save
+prof_title=(P) Profiles
+px_1=1. Target Pixel
+px_2=2. Conditions
+px_3=3. Reaction Action
+px_act3=Press Custom Key
+px_act4=Only Beep
+px_clr=Color\:
+px_cond1=When Color MATCHES
+px_cond2=When Color CHANGES
+px_rate=Scanner Rate (Ms)\:
+px_tol=Tolerance (%)\:
+r_click=Right Click
+rec_start=● Record
+rec_status=STATUS\: RECORDING (ESC\=stop)
+rec_stop=■ Stop (ESC)
+reset=Reset
+sched_countdown=STATUS\: STARTING (%d s)
+sched_sec=seconds later
+sched_title=(Z) Scheduler
+sched_use=Delayed start
+set_hk=Start/Stop Hotkey\:
+set_k=Set Key
+shut_cancel_btn=Cancel Shutdown
+shut_cancelled=Shutdown cancelled.
+shut_fail=Shutdown command failed\:
+shut_ok=Limit reached\! PC will shut down in %s.
+shut_pending=Limit reached\! PC shuts down in %s.\nPress the button below to cancel.
+shut_title=Shutting Down
+shut_unsup=Automatic shutdown not supported on this OS\:
+st_idle=STATUS\: IDLE
+st_lim=STATUS\: LIMIT HIT
+st_run=STATUS\: RUNNING
+style=(O) UI Customization
+t_chain=Chain
+t_key=Keyboard
+t_mouse=Mouse
+t_px=Pixel
+t_set=Settings
+tabhk_title=(K) Per-Tab Hotkeys
+theme=Main Theme\:
+theme_d=Dark Mode
+theme_l=Light Mode
+tnt_key=Key Press
+tnt_mouse=Mouse Click
+tnt_move=Move Mouse
+tray_exit=Exit
+tray_show=Show
+tray_toggle=Start / Stop
+txt_col=Text Color\:
+txt_size=Text Size\:
+wait_mid=Waiting (Mid Click)
+
+consent_title=Responsible Use Agreement
+consent_msg=This tool is for learning and productivity. Using it in anti-cheat protected games risks account bans; you are responsible. Do you accept?
+update_title=Update Available
+update_msg=New version %s is available (you have %s). Open the download page?
diff --git a/src/main/resources/i18n/messages_fr.properties b/src/main/resources/i18n/messages_fr.properties
new file mode 100644
index 0000000..4312832
--- /dev/null
+++ b/src/main/resources/i18n/messages_fr.properties
@@ -0,0 +1,100 @@
+#AutoClicker i18n - fr
+#Sun Jun 21 15:07:13 GMT+03:00 2026
+act_typ=Type d'action\:
+add_act=(+) Ajouter
+anti_ban=Mode Humain (Délais Aléat.)
+apply_s=Appliquer
+c_type=Type de clic\:
+clr_act=(x) Effacer
+col_pick=Choisir
+cps=Vitesse Souris (CPS)\:
+d_click=Double Clic
+del_act=(-) Supprimer
+fix_loc=Bouton Fixe
+hook_fail=STATUT\: RACCOURCI INDISPONIBLE
+info_cps=Définit la vitesse de clic (CPS).
+info_hum=Anti-Ban\: Ajoute des fluctuations aléatoires aux délais.
+info_lim=Arrête automatiquement l'automatisation.
+info_px=Tolérance\: Empêche les petits changements de lumière de fausser la détection.
+info_px_cond=Correspond\: Agit quand la couleur apparait.
+info_px_rate=Taux de scan\: Fréquence de vérification (ms).
+info_title=Info
+io_export=Exporter (JSON)
+io_fail=Echec du fichier\:
+io_import=Importer (JSON)
+key_cps=Vitesse Touche (/s)\:
+key_trg=Touche Cible\:
+l_click=Clic Gauche
+lang_title=(L) Langue
+lim_after=Dans\:
+lim_invalid=STATUT\: LIMITE INVALIDE
+lim_iter=Itérations
+lim_min=Minutes
+lim_shut=Éteindre le PC
+lim_stop=Arrêter Macro
+lim_title=Limites Arrêt Auto
+lim_use=Activer Limiteur
+list_add=[v] Ajouter
+m_click=Clic Milieu
+ms_delay=Délai (ms)\:
+pick_loc=Choisir
+press_k=Appuyez...
+prof_del=Supprimer
+prof_load=Charger
+prof_save=Enregistrer
+prof_title=(P) Profils
+px_1=1. Pixel Cible
+px_2=2. Conditions
+px_3=3. Réaction
+px_act3=Appuyer Touche
+px_act4=Bip Sonore
+px_clr=Couleur\:
+px_cond1=Couleur CORRESPOND
+px_cond2=Couleur CHANGE
+px_rate=Vitesse Scan (Ms)\:
+px_tol=Tolérance (%)\:
+r_click=Clic Droit
+rec_start=● Enregistrer
+rec_status=STATUT\: ENREGISTREMENT (ESC)
+rec_stop=■ Arreter (ESC)
+reset=Réinit.
+sched_countdown=STATUT\: DEBUT (%d s)
+sched_sec=secondes après
+sched_title=(Z) Planificateur
+sched_use=Démarrage différé
+set_hk=Raccourci Start/Stop\:
+set_k=Définir
+shut_cancel_btn=Annuler l'arret
+shut_cancelled=Arret annule.
+shut_fail=Echec de la commande d'arret\:
+shut_ok=Limite atteinte\! Le PC s'eteindra dans %s.
+shut_pending=Limite atteinte\! Arret dans %s.\nCliquez ci-dessous pour annuler.
+shut_title=Arret du PC
+shut_unsup=Arret automatique non supporte sur cet OS\:
+st_idle=STATUT\: EN ATTENTE
+st_lim=STATUT\: LIMITE
+st_run=STATUT\: EN COURS
+style=(O) Apparence UI
+t_chain=Chaîne
+t_key=Clavier
+t_mouse=Souris
+t_px=Pixel
+t_set=Paramètres
+tabhk_title=(K) Raccourcis par onglet
+theme=Thème\:
+theme_d=Sombre
+theme_l=Clair
+tnt_key=Appui Touche
+tnt_mouse=Clic Souris
+tnt_move=Bouger Souris
+tray_exit=Quitter
+tray_show=Afficher
+tray_toggle=Demarrer / Arreter
+txt_col=Couleur Texte\:
+txt_size=Taille\:
+wait_mid=Attente (Milieu)
+
+consent_title=Accord d'utilisation responsable
+consent_msg=Cet outil sert a l'apprentissage et la productivite. Son usage dans des jeux anti-triche risque le bannissement; vous etes responsable. Acceptez-vous?
+update_title=Mise a jour disponible
+update_msg=Nouvelle version %s disponible (actuelle %s). Ouvrir la page de telechargement?
diff --git a/src/main/resources/i18n/messages_it.properties b/src/main/resources/i18n/messages_it.properties
new file mode 100644
index 0000000..b9409e3
--- /dev/null
+++ b/src/main/resources/i18n/messages_it.properties
@@ -0,0 +1,100 @@
+#AutoClicker i18n - it
+#Sun Jun 21 15:07:13 GMT+03:00 2026
+act_typ=Tipo di Azione\:
+add_act=(+) Aggiungi
+anti_ban=Modalità Umana (Ritardo)
+apply_s=Applica
+c_type=Tipo di clic\:
+clr_act=(x) Pulisci
+col_pick=Seleziona
+cps=Velocità Mouse (CPS)\:
+d_click=Doppio Clic
+del_act=(-) Rimuovi
+fix_loc=Pos. Fissa
+hook_fail=STATO\: HOTKEY NON DISPONIBILE
+info_cps=Imposta i clic al secondo (CPS).
+info_hum=Anti-Ban\: Aggiunge fluttuazioni casuali ai ritardi.
+info_lim=Ferma l'automazione in base a limiti.
+info_px=Tolleranza\: Evita che l'illuminazione rompa l'algoritmo.
+info_px_cond=Corrisponde\: Agisce quando il colore appare.
+info_px_rate=Velocità scan\: Frequenza di controllo schermo (ms).
+info_title=Info
+io_export=Esporta (JSON)
+io_fail=Operazione file fallita\:
+io_import=Importa (JSON)
+key_cps=Velocità Tasto (/s)\:
+key_trg=Tasto Obiettivo\:
+l_click=Clic Sinistro
+lang_title=(L) Lingua
+lim_after=Dopo\:
+lim_invalid=STATO\: LIMITE NON VALIDO
+lim_iter=Iterazioni
+lim_min=Minuti
+lim_shut=Spegni PC
+lim_stop=Ferma Macro
+lim_title=Limiti Arresto Auto
+lim_use=Abilita Limitatore
+list_add=[v] Aggiungi
+m_click=Clic Centrale
+ms_delay=Ritardo (ms)\:
+pick_loc=Seleziona
+press_k=Premi...
+prof_del=Elimina
+prof_load=Carica
+prof_save=Salva
+prof_title=(P) Profili
+px_1=1. Pixel Obiettivo
+px_2=2. Condizioni
+px_3=3. Reazione
+px_act3=Premi Tasto
+px_act4=Suona Solo
+px_clr=Colore\:
+px_cond1=Colore CORRISPONDE
+px_cond2=Colore CAMBIA
+px_rate=Velocità Scan (Ms)\:
+px_tol=Tolleranza (%)\:
+r_click=Clic Destro
+rec_start=● Registra
+rec_status=STATO\: REGISTRAZIONE (ESC)
+rec_stop=■ Ferma (ESC)
+reset=Reimposta
+sched_countdown=STATO\: AVVIO (%d s)
+sched_sec=secondi dopo
+sched_title=(Z) Pianificatore
+sched_use=Avvio ritardato
+set_hk=Tasto Avvio/Arresto\:
+set_k=Assegna
+shut_cancel_btn=Annulla spegnimento
+shut_cancelled=Spegnimento annullato.
+shut_fail=Comando di spegnimento fallito\:
+shut_ok=Limite raggiunto\! Il PC si spegnera tra %s.
+shut_pending=Limite raggiunto\! Spegnimento tra %s.\nPremi sotto per annullare.
+shut_title=Spegnimento PC
+shut_unsup=Spegnimento automatico non supportato su questo OS\:
+st_idle=STATO\: IN ATTESA
+st_lim=STATO\: LIMITE RAGGIUNTO
+st_run=STATO\: IN ESECUZIONE
+style=(O) Aspetto UI
+t_chain=Catena
+t_key=Tastiera
+t_mouse=Mouse
+t_px=Pixel
+t_set=Impostazioni
+tabhk_title=(K) Tasti per scheda
+theme=Tema Principale\:
+theme_d=Modo Scuro
+theme_l=Modo Chiaro
+tnt_key=Pressione Tasto
+tnt_mouse=Clic Mouse
+tnt_move=Sposta Mouse
+tray_exit=Esci
+tray_show=Mostra
+tray_toggle=Avvia / Ferma
+txt_col=Colore Testo\:
+txt_size=Dimensione\:
+wait_mid=Attesa (Centrale)
+
+consent_title=Accordo di uso responsabile
+consent_msg=Questo strumento e per apprendimento e produttivita. Uso in giochi con anti-cheat rischia il ban; sei responsabile. Accetti?
+update_title=Aggiornamento disponibile
+update_msg=Nuova versione %s disponibile (attuale %s). Aprire la pagina di download?
diff --git a/src/main/resources/i18n/messages_ru.properties b/src/main/resources/i18n/messages_ru.properties
new file mode 100644
index 0000000..11d2e6b
--- /dev/null
+++ b/src/main/resources/i18n/messages_ru.properties
@@ -0,0 +1,100 @@
+#AutoClicker i18n - ru
+#Sun Jun 21 15:07:13 GMT+03:00 2026
+act_typ=Тип Действия\:
+add_act=(+) Добавить
+anti_ban=Анти-Бан (случайная задержка)
+apply_s=Применить
+c_type=Тип клика\:
+clr_act=(x) Очистить
+col_pick=Выбрать Цвет
+cps=Скорость Мыши (CPS)\:
+d_click=Двойной Клик
+del_act=(-) Удалить
+fix_loc=Фикс. Место
+hook_fail=СТАТУС\: ГОРЯЧАЯ КЛАВИША НЕДОСТУПНА
+info_cps=Устанавливает кликов в секунду (CPS).
+info_hum=Анти-Бан\: Добавляет случайные колебания к задержкам.
+info_lim=Останавливает автоматизацию при достижении лимита.
+info_px=Допуск\: Игнорирует изменения освещения.
+info_px_cond=Совпадает\: Реагирует на появление цвета.
+info_px_rate=Скорость\: Частота проверки экрана (мс).
+info_title=Информация
+io_export=Экспорт (JSON)
+io_fail=Сбой работы с файлом\:
+io_import=Импорт (JSON)
+key_cps=Скор. Клавиатуры (/с)\:
+key_trg=Целевая Клавиша\:
+l_click=Левый Клик
+lang_title=(L) Язык
+lim_after=Лимит\:
+lim_invalid=СТАТУС\: НЕВЕРНЫЙ ЛИМИТ
+lim_iter=Итераций
+lim_min=Минут
+lim_shut=Выкл ПК
+lim_stop=Только стоп
+lim_title=Лимиты Автоостановки
+lim_use=Вкл. Лимитер
+list_add=[v] Добавить
+m_click=Средний Клик
+ms_delay=Задержка (мс)\:
+pick_loc=Выбрать
+press_k=Нажмите...
+prof_del=Удалить
+prof_load=Загрузить
+prof_save=Сохранить
+prof_title=(P) Профили
+px_1=1. Цель Пиксель
+px_2=2. Условия
+px_3=3. Реакция
+px_act3=Своя Клавиша
+px_act4=Только Звук
+px_clr=Цвет\:
+px_cond1=Когда совпадает
+px_cond2=Когда меняется
+px_rate=Скорость (Мс)\:
+px_tol=Допуск (%)\:
+r_click=Правый Клик
+rec_start=● Запись
+rec_status=СТАТУС\: ЗАПИСЬ (ESC\=стоп)
+rec_stop=■ Стоп (ESC)
+reset=Сброс
+sched_countdown=СТАТУС\: СТАРТ (%d с)
+sched_sec=секунд спустя
+sched_title=(Z) Планировщик
+sched_use=Запуск с задержкой
+set_hk=Горячая Клавиша\:
+set_k=Назначить
+shut_cancel_btn=Отменить выключение
+shut_cancelled=Выключение отменено.
+shut_fail=Сбой команды выключения\:
+shut_ok=Лимит достигнут\! ПК выключится через %s.
+shut_pending=Лимит достигнут\! Выключение через %s.\nНажмите ниже для отмены.
+shut_title=Выключение ПК
+shut_unsup=Автовыключение не поддерживается в этой ОС\:
+st_idle=СТАТУС\: ОЖИДАНИЕ
+st_lim=СТАТУС\: ЛИМИТ
+st_run=СТАТУС\: РАБОТАЕТ
+style=(O) Дизайн UI
+t_chain=Цепь
+t_key=Клавиатура
+t_mouse=Мышь
+t_px=Пиксель
+t_set=Настройки
+tabhk_title=(K) Горячие клавиши вкладок
+theme=Тема\:
+theme_d=Темный
+theme_l=Светлый
+tnt_key=Нажатие Клавиши
+tnt_mouse=Клик Мыши
+tnt_move=Сдвинуть Мышь
+tray_exit=Выход
+tray_show=Показать
+tray_toggle=Старт / Стоп
+txt_col=Цвет Текста\:
+txt_size=Размер\:
+wait_mid=Ожидание (Ср. клик)
+
+consent_title=Соглашение об ответственном использовании
+consent_msg=Этот инструмент для обучения и продуктивности. Использование в играх с анти-читом грозит баном; ответственность на вас. Принимаете?
+update_title=Доступно обновление
+update_msg=Доступна новая версия %s (у вас %s). Открыть страницу загрузки?
diff --git a/src/main/resources/i18n/messages_tr.properties b/src/main/resources/i18n/messages_tr.properties
new file mode 100644
index 0000000..7b994ef
--- /dev/null
+++ b/src/main/resources/i18n/messages_tr.properties
@@ -0,0 +1,100 @@
+#AutoClicker i18n - tr
+#Sun Jun 21 15:07:13 GMT+03:00 2026
+act_typ=Eylem Turu\:
+add_act=(+) Eylem Ekle
+anti_ban=Insan Modu (Rastgele Gecikme)
+apply_s=Uygula/Kaydet
+c_type=Tiklama Tipi\:
+clr_act=(x) Temizle
+col_pick=Renk Sec
+cps=Fare Hizi (CPS)\:
+d_click=Cift Sol Tik
+del_act=(-) Secileni Sil
+fix_loc=Sabit Konuma Tikla
+hook_fail=DURUM\: KISAYOL DINLENEMIYOR
+info_cps=Saniyedeki tiklama hizini belirler (Click Per Second).
+info_hum=Anti-Ban\: Robotik tiklamalari saptirmak icin gecikmelere minik sapmalar ekler.
+info_lim=Otomasyonu belirli bir sure sonra kapatir.
+info_px=Renk Toleransi\: Ufak golge farkliliklarinin renk algisini bozmasini engeller.
+info_px_cond=Eslestiginde\: Renk gorundugunde tepki verir.\nDegistiginde\: Renk kayboldugunda tepki verir.
+info_px_rate=Tarama Hizi\: Ekranin ne siklikla kontrol edilecegini belirler (Milisaniye).
+info_title=Bilgi
+io_export=Disa Aktar (JSON)
+io_fail=Dosya islemi basarisiz\:
+io_import=Ice Aktar (JSON)
+key_cps=Klavye Hizi (Saniyede)\:
+key_trg=Basilacak Tus\:
+l_click=Sol Tik
+lang_title=(L) Dil (Language)
+lim_after=Sinir\:
+lim_invalid=DURUM\: GECERSIZ LIMIT DEGERI
+lim_iter=Dongu Sonra
+lim_min=Dakika Sonra
+lim_shut=Bilgisayari Kapat
+lim_stop=Sadece Makroyu Durdur
+lim_title=Otomatik Durdurma Sinirlari
+lim_use=Limitoru Aktif Et
+list_add=[v] Listeye Ekle
+m_click=Orta Tik
+ms_delay=Milisaniye (Gecikme)\:
+pick_loc=Konum Sec
+press_k=Basin...
+prof_del=Sil
+prof_load=Yukle
+prof_save=Kaydet
+prof_title=(P) Profiller
+px_1=1. Gozetlenecek Piksel
+px_2=2. Tetiklenme Sartlari
+px_3=3. Gerceklesecek Tepki
+px_act3=Ozel Tusa Bas
+px_act4=Sadece Zili Cal
+px_clr=Renk\:
+px_cond1=Renk ESLESTIGINDE
+px_cond2=Renk DEGISTIGINDE
+px_rate=Tarama Hizi (Ms)\:
+px_tol=Tolerans Payi (%)\:
+r_click=Sag Tik
+rec_start=● Kaydet
+rec_status=DURUM\: KAYDEDILIYOR (ESC\=dur)
+rec_stop=■ Durdur (ESC)
+reset=Sifirla
+sched_countdown=DURUM\: BASLIYOR (%d sn)
+sched_sec=saniye sonra
+sched_title=(Z) Zamanlayici
+sched_use=Gecikmeli baslat
+set_hk=Kisayol Tusu (Baslat/Durdur)\:
+set_k=Tus Ata
+shut_cancel_btn=Kapatmayi Iptal Et
+shut_cancelled=Bilgisayar kapatma iptal edildi.
+shut_fail=Kapatma komutu basarisiz oldu\:
+shut_ok=Limit asildi\! Bilgisayar %s icinde kapatilacak.
+shut_pending=Limit asildi\! Bilgisayar %s icinde kapanacak.\nVazgecmek icin asagidaki butona basin.
+shut_title=Bilgisayar Kapatiliyor
+shut_unsup=Bu isletim sisteminde otomatik kapatma desteklenmiyor\:
+st_idle=DURUM\: BEKLIYOR
+st_lim=DURUM\: LIMIT YENDI
+st_run=DURUM\: CALISIYOR
+style=(O) Gorunum Ozellestirme
+t_chain=Zincir
+t_key=Klavye
+t_mouse=Fare
+t_px=Piksel
+t_set=Ayarlar
+tabhk_title=(K) Sekme Kisayollari
+theme=Ana Tema\:
+theme_d=Karanlik Mod
+theme_l=Aydinlik Mod
+tnt_key=Klavye Tusu
+tnt_mouse=Fare Tiklamasi
+tnt_move=Fareyi Tasi
+tray_exit=Cikis
+tray_show=Goster
+tray_toggle=Baslat / Durdur
+txt_col=Metin Rengi\:
+txt_size=Yazi Boyutu\:
+wait_mid=Bekliyor (Orta Tik)
+
+consent_title=Sorumlu Kullanim Onayi
+consent_msg=Bu arac ogrenme ve verimlilik icindir. Anti-cheat korumali oyunlarda kullanmak hesap yasaklanmasi riski tasir; sorumluluk size aittir. Kabul ediyor musunuz?
+update_title=Guncelleme Mevcut
+update_msg=Yeni surum %s yayinlandi (su an %s). Indirme sayfasini acalim mi?
diff --git a/src/test/java/com/ohualtex/autoclicker/VersionCompareTest.java b/src/test/java/com/ohualtex/autoclicker/VersionCompareTest.java
new file mode 100644
index 0000000..8e9b7f1
--- /dev/null
+++ b/src/test/java/com/ohualtex/autoclicker/VersionCompareTest.java
@@ -0,0 +1,38 @@
+package com.ohualtex.autoclicker;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/** AutoClicker.isNewer surum karsilastirmasi (oto-guncelleme kontrolu icin). */
+class VersionCompareTest {
+
+ @Test
+ void newerMajorAndMinor() {
+ assertTrue(AutoClicker.isNewer("9.0", "8.5"));
+ assertTrue(AutoClicker.isNewer("8.6", "8.5"));
+ }
+
+ @Test
+ void numericNotLexical() {
+ // "8.10" lexical olarak "8.9"dan kucuk gorunur ama sayisal olarak buyuktur
+ assertTrue(AutoClicker.isNewer("8.10", "8.9"));
+ }
+
+ @Test
+ void sameOrOlderIsNotNewer() {
+ assertFalse(AutoClicker.isNewer("8.5", "8.5"));
+ assertFalse(AutoClicker.isNewer("8.4", "8.5"));
+ }
+
+ @Test
+ void differingSegmentCounts() {
+ assertTrue(AutoClicker.isNewer("8.5.1", "8.5"));
+ assertFalse(AutoClicker.isNewer("8.5", "8.5.1"));
+ }
+
+ @Test
+ void malformedIsNotNewer() {
+ assertFalse(AutoClicker.isNewer("dev", "8.5"));
+ }
+}
diff --git a/src/test/java/com/ohualtex/autoclicker/i18n/LangTest.java b/src/test/java/com/ohualtex/autoclicker/i18n/LangTest.java
new file mode 100644
index 0000000..26df8c2
--- /dev/null
+++ b/src/test/java/com/ohualtex/autoclicker/i18n/LangTest.java
@@ -0,0 +1,36 @@
+package com.ohualtex.autoclicker.i18n;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class LangTest {
+
+ @AfterEach
+ void reset() { Lang.L = 0; }
+
+ @Test
+ void returnsTurkishByDefault() {
+ Lang.L = 0;
+ assertEquals("Fare", Lang.get("t_mouse"));
+ }
+
+ @Test
+ void switchesLanguagePerIndex() {
+ Lang.L = 1; assertEquals("Mouse", Lang.get("t_mouse")); // EN
+ Lang.L = 5; assertEquals("Мышь", Lang.get("t_mouse")); // RU (UTF-8 dogrulama)
+ }
+
+ @Test
+ void unknownKeyReturnsKeyItself() {
+ Lang.L = 0;
+ assertEquals("nonexistent_key_xyz", Lang.get("nonexistent_key_xyz"));
+ }
+
+ @Test
+ void outOfRangeIndexFallsBackToFirst() {
+ Lang.L = 99;
+ assertEquals("Fare", Lang.get("t_mouse"));
+ }
+}