Translate app UI from Turkish to English
Translates string resources, hardcoded layout text and user-facing strings in Java sources (toasts, dialogs, status labels, upload log). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -100,7 +100,7 @@ public class AbrpUploadService extends Service {
|
||||
FIRST_UPLOAD_DELAY_SEC, UPLOAD_INTERVAL_SEC, TimeUnit.SECONDS);
|
||||
|
||||
uploadLog.record(new UploadLog.Entry(System.currentTimeMillis(), 0, true,
|
||||
"Tüketim servisi başlatıldı"));
|
||||
"Consumption service started"));
|
||||
Log.i(TAG, "Service started, consumption tracking armed");
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ public class AbrpUploadService extends Service {
|
||||
wifi.ensureConnected(false);
|
||||
}
|
||||
|
||||
updateNotification("Tüketim takibi aktif");
|
||||
updateNotification("Consumption tracking active");
|
||||
}
|
||||
|
||||
// ---------- Notification ----------
|
||||
|
||||
@@ -33,13 +33,13 @@ public final class ChargingGraphView extends View {
|
||||
invalidate();
|
||||
}
|
||||
synchronized String tableText() {
|
||||
StringBuilder out = new StringBuilder("SOC Şarj gücü\n");
|
||||
StringBuilder out = new StringBuilder("SOC Charge power\n");
|
||||
boolean found = false;
|
||||
for (int soc=0; soc<=100; soc++) if (!Float.isNaN(socPower[soc])) {
|
||||
found = true;
|
||||
out.append(String.format(Locale.getDefault(), "%3d %% %6.1f kW\n", soc, socPower[soc]));
|
||||
}
|
||||
return found ? out.toString().trim() : "Henüz şarj ölçümü yok";
|
||||
return found ? out.toString().trim() : "No charging measurements yet";
|
||||
}
|
||||
@Override protected synchronized void onDraw(Canvas c) {
|
||||
super.onDraw(c); float left=58, right=getWidth()-12, top=12, bottom=getHeight()-38;
|
||||
|
||||
@@ -79,7 +79,7 @@ final class ConsumptionCloudClient {
|
||||
* Every 30 minutes, takes a delta chunk from the tracker and sends it. Chunks that fail
|
||||
* to send (offline, server error) accumulate in a local cache and are retried on the
|
||||
* next cycle — so a drive through a dead-signal area still reaches the cloud once the
|
||||
* head unit is back on the hotspot. Every attempt is logged to the in-app "Kayıtlar" tab.
|
||||
* head unit is back on the hotspot. Every attempt is logged to the in-app "Logs" tab.
|
||||
*
|
||||
* @param nowMs wall clock, recorded with the payload — the throttle below runs on a
|
||||
* monotonic clock instead, so a backwards NTP correction cannot stall
|
||||
@@ -96,7 +96,7 @@ final class ConsumptionCloudClient {
|
||||
// Drain any cached chunks first — a backlog from an offline period has priority.
|
||||
int cached = drainChunkCache();
|
||||
if (cached > 0) {
|
||||
logEvent(true, 200, "Cache boşaltıldı: " + cached + " chunk gönderildi");
|
||||
logEvent(true, 200, "Cache drained: " + cached + " chunk(s) sent");
|
||||
invalidateHistory();
|
||||
}
|
||||
|
||||
@@ -115,14 +115,14 @@ final class ConsumptionCloudClient {
|
||||
try {
|
||||
JSONObject body = consumptionBody(chunk, nowMs);
|
||||
if (send("/v1/consumption/daily", "PUT", body)) {
|
||||
logEvent(true, 200, "Chunk " + chunk.date + " gönderildi (+"
|
||||
logEvent(true, 200, "Chunk " + chunk.date + " sent (+"
|
||||
+ String.format("%.1f", chunk.day.km) + "km, +"
|
||||
+ String.format("%.2f", chunk.day.kwh) + "kWh)");
|
||||
invalidateHistory();
|
||||
} else {
|
||||
cacheChunk(body);
|
||||
int pending = pendingChunkCount();
|
||||
logEvent(false, 0, "Chunk gönderilemedi — cache'de bekliyor (" + pending + " chunk)");
|
||||
logEvent(false, 0, "Chunk not sent — waiting in cache (" + pending + " chunk(s))");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Network failure: cache the chunk for the next cycle.
|
||||
@@ -131,7 +131,7 @@ final class ConsumptionCloudClient {
|
||||
cacheChunk(body);
|
||||
} catch (Exception ignored) { }
|
||||
int pending = pendingChunkCount();
|
||||
logEvent(false, 0, "Çevrimdışı — cache'de bekliyor (" + pending + " chunk): " + e.getMessage());
|
||||
logEvent(false, 0, "Offline — waiting in cache (" + pending + " chunk(s)): " + e.getMessage());
|
||||
Log.w(TAG, "Chunk sync failed, cached: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
@@ -190,7 +190,7 @@ final class ConsumptionCloudClient {
|
||||
return loadChunkCache().length();
|
||||
}
|
||||
|
||||
/** Records a cloud-sync attempt to the in-app log (the "Kayıtlar" tab). */
|
||||
/** Records a cloud-sync attempt to the in-app log (the "Logs" tab). */
|
||||
private void logEvent(boolean success, int httpStatus, String detail) {
|
||||
UploadLog log = AbrpUploadService.log();
|
||||
if (log == null) return;
|
||||
@@ -220,7 +220,7 @@ final class ConsumptionCloudClient {
|
||||
try {
|
||||
syncPendingCharges(charges, pending);
|
||||
} catch (Exception e) {
|
||||
logEvent(false, 0, "Şarj session sync hatası: " + e.getMessage());
|
||||
logEvent(false, 0, "Charging session sync error: " + e.getMessage());
|
||||
Log.w(TAG, "Charging-session sync unavailable: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
@@ -235,10 +235,10 @@ final class ConsumptionCloudClient {
|
||||
Log.i(TAG, "Uploading charge session: " + id);
|
||||
if (send("/v1/charging-sessions/" + id, "PUT", body)) {
|
||||
charges.markUploaded(id);
|
||||
logEvent(true, 200, "Şarj session gönderildi: " + id);
|
||||
logEvent(true, 200, "Charging session sent: " + id);
|
||||
Log.i(TAG, "Successfully uploaded charge session: " + id);
|
||||
} else {
|
||||
logEvent(false, 0, "Şarj session gönderilemedi: " + id);
|
||||
logEvent(false, 0, "Charging session not sent: " + id);
|
||||
Log.w(TAG, "Failed to upload charge session: " + id);
|
||||
return;
|
||||
}
|
||||
@@ -310,11 +310,11 @@ final class ConsumptionCloudClient {
|
||||
List<DayRecord> fresh = fetchHistory();
|
||||
if (!fresh.isEmpty()) cachedHistory = fresh;
|
||||
Log.i(TAG, "Fetched " + fresh.size() + " history records from cloud");
|
||||
logEvent(true, 200, "History çekildi: " + fresh.size() + " gün");
|
||||
logEvent(true, 200, "History fetched: " + fresh.size() + " day(s)");
|
||||
} catch (Exception e) {
|
||||
String msg = e.getMessage() == null ? e.getClass().getSimpleName() : e.getMessage();
|
||||
Log.w(TAG, "History fetch unavailable: " + msg);
|
||||
logEvent(false, 0, "History fetch hatası: " + msg);
|
||||
logEvent(false, 0, "History fetch error: " + msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,11 +325,11 @@ final class ConsumptionCloudClient {
|
||||
|
||||
/**
|
||||
* Immediately attempts to send every cached chunk and take a fresh one, ignoring the
|
||||
* 2-minute throttle. Called from the UI "Şimdi yükle" button. Returns a one-line
|
||||
* 2-minute throttle. Called from the UI "Upload now" button. Returns a one-line
|
||||
* status for the log.
|
||||
*/
|
||||
String flushNow(ConsumptionTracker tracker, long nowMs) {
|
||||
if (endpoint.isEmpty() || token.isEmpty()) return "API yapılandırılmamış";
|
||||
if (endpoint.isEmpty() || token.isEmpty()) return "API not configured";
|
||||
int cached = drainChunkCache();
|
||||
ConsumptionTracker.CloudSnapshot chunk = tracker.takeChunkDelta();
|
||||
int total = cached;
|
||||
@@ -348,9 +348,9 @@ final class ConsumptionCloudClient {
|
||||
}
|
||||
int pending = pendingChunkCount();
|
||||
String msg = total > 0
|
||||
? total + " chunk yüklendi" + (pending > 0 ? ", " + pending + " hâlâ bekliyor" : "")
|
||||
: (pending > 0 ? pending + " chunk yüklenemedi (internet?)" : "Yüklenecek yeni veri yok");
|
||||
logEvent(total > 0, total > 0 ? 200 : 0, "Manuel sync: " + msg);
|
||||
? total + " chunk(s) uploaded" + (pending > 0 ? ", " + pending + " still pending" : "")
|
||||
: (pending > 0 ? pending + " chunk(s) could not be uploaded (internet?)" : "No new data to upload");
|
||||
logEvent(total > 0, total > 0 ? 200 : 0, "Manual sync: " + msg);
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
@@ -363,9 +363,9 @@ public class MainActivity extends AppCompatActivity {
|
||||
String ssid = wifi.currentSsid();
|
||||
wifiSsid.setText(ssid == null ? getString(R.string.wifi_not_connected) : ssid);
|
||||
if (ssid != null) {
|
||||
wifiState.setText("Bağlı ♥");
|
||||
wifiState.setText("Connected ♥");
|
||||
} else if (!wifi.isWifiEnabled()) {
|
||||
wifiState.setText("Wi-Fi kapalı");
|
||||
wifiState.setText("Wi-Fi off");
|
||||
}
|
||||
// Left alone otherwise: a message the button just set says more about what is
|
||||
// happening than "not connected" would.
|
||||
@@ -458,10 +458,10 @@ public class MainActivity extends AppCompatActivity {
|
||||
consumptionReset.setOnClickListener(v -> {
|
||||
if (consumptionPeriod != ConsumptionTracker.Period.TRIP_A && consumptionPeriod != ConsumptionTracker.Period.TRIP_B) return;
|
||||
String name = consumptionPeriod == ConsumptionTracker.Period.TRIP_A ? "Trip A" : "Trip B";
|
||||
new MaterialAlertDialogBuilder(this).setTitle(name + " sıfırlansın mı?")
|
||||
.setMessage("Bu sayacın kayıtlı tüketim geçmişi kalıcı olarak silinir.")
|
||||
.setNegativeButton("Vazgeç", null)
|
||||
.setPositiveButton("Sıfırla", (d, w) -> {
|
||||
new MaterialAlertDialogBuilder(this).setTitle("Reset " + name + "?")
|
||||
.setMessage("This counter's recorded consumption history will be permanently deleted.")
|
||||
.setNegativeButton("Cancel", null)
|
||||
.setPositiveButton("Reset", (d, w) -> {
|
||||
consumptionTracker.reset(consumptionPeriod);
|
||||
refreshConsumption();
|
||||
}).show();
|
||||
@@ -475,9 +475,9 @@ public class MainActivity extends AppCompatActivity {
|
||||
if (!consumptionTracker.setSohPercent(value)) throw new NumberFormatException();
|
||||
consumptionSohLayout.setError(null);
|
||||
consumptionSohInput.setText(String.format(java.util.Locale.US, "%.1f", value));
|
||||
Toast.makeText(this, "SoH kaydedildi", Toast.LENGTH_SHORT).show();
|
||||
Toast.makeText(this, "SoH saved", Toast.LENGTH_SHORT).show();
|
||||
} catch (NumberFormatException e) {
|
||||
consumptionSohLayout.setError("1 ile 100 arasında bir değer girin");
|
||||
consumptionSohLayout.setError("Enter a value between 1 and 100");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -533,9 +533,9 @@ public class MainActivity extends AppCompatActivity {
|
||||
if (!chargeSessionTracker.setPricePerKwh(value)) throw new NumberFormatException();
|
||||
chargePriceLayout.setError(null);
|
||||
chargePriceInput.setText(String.format(java.util.Locale.US, "%.2f", value));
|
||||
Toast.makeText(this, "Şarj fiyatı kaydedildi", Toast.LENGTH_SHORT).show();
|
||||
Toast.makeText(this, "Charging price saved", Toast.LENGTH_SHORT).show();
|
||||
} catch (NumberFormatException e) {
|
||||
chargePriceLayout.setError("Geçerli bir ₺/kWh değeri girin");
|
||||
chargePriceLayout.setError("Enter a valid ₺/kWh value");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -550,9 +550,9 @@ public class MainActivity extends AppCompatActivity {
|
||||
// below — which then describe the previous DC session — be read as this charge.
|
||||
boolean dc = ChargingState.isDcCharging(
|
||||
code, s.getChargePortConnected(), s.getBatteryPowerKw(), s.getSpeedKmh());
|
||||
chargeStatus.setText(dc ? "DC hızlı şarj"
|
||||
: charging ? "AC şarj (ölçülmüyor)"
|
||||
: (session.startedAtMs > 0 ? "Son şarj" : "Şarj yok"));
|
||||
chargeStatus.setText(dc ? "DC fast charging"
|
||||
: charging ? "AC charging (not metered)"
|
||||
: (session.startedAtMs > 0 ? "Last charge" : "Not charging"));
|
||||
chargeSoc.setText(fmt(s.getSocPercent(), "%.1f %%"));
|
||||
chargeStartSoc.setText(fmt(session.startSocPercent, "%.1f %%"));
|
||||
chargeVoltage.setText(fmt(s.getBatteryVoltageV(), "%.1f V"));
|
||||
@@ -586,20 +586,20 @@ public class MainActivity extends AppCompatActivity {
|
||||
consumptionSpeed.setText(t.hours <= 0 ? "—" : String.format(java.util.Locale.getDefault(),
|
||||
"%.1f km/h", t.km / t.hours));
|
||||
long minutes = Math.round(t.hours * 60d);
|
||||
consumptionTime.setText(String.format(java.util.Locale.getDefault(), "%d sa %02d dk",
|
||||
consumptionTime.setText(String.format(java.util.Locale.getDefault(), "%d h %02d min",
|
||||
minutes / 60, minutes % 60));
|
||||
consumptionSoc.setText(String.format(java.util.Locale.getDefault(), "%.1f %%", t.soc));
|
||||
// Daily history: cloud first, local fallback for today (not yet uploaded).
|
||||
ConsumptionTracker.Totals day = cloudDay(selectedConsumptionDate);
|
||||
if (day == null) day = consumptionTracker.totalsForDay(selectedConsumptionDate);
|
||||
if (day.km == 0 && day.kwh == 0 && day.hours == 0 && day.soc == 0) {
|
||||
consumptionDailyHistory.setText("Bu tarih için kayıt yok");
|
||||
consumptionDailyHistory.setText("No records for this date");
|
||||
} else {
|
||||
String average = day.km < 0.1 ? "—" : String.format(java.util.Locale.getDefault(),
|
||||
"%.1f kWh/100 km", day.kwh * 100d / day.km);
|
||||
long dayMinutes = Math.round(day.hours * 60d);
|
||||
consumptionDailyHistory.setText(String.format(java.util.Locale.getDefault(),
|
||||
"Mesafe %.1f km\nEnerji %.2f kWh\nOrtalama %s\nSüre %d sa %02d dk\nSOC farkı %.1f %%",
|
||||
"Distance %.1f km\nEnergy %.2f kWh\nAverage %s\nDuration %d h %02d min\nSOC change %.1f %%",
|
||||
day.km, day.kwh, average, dayMinutes / 60, dayMinutes % 60, day.soc));
|
||||
}
|
||||
}
|
||||
@@ -666,17 +666,17 @@ public class MainActivity extends AppCompatActivity {
|
||||
Integer status = s.getChargingStatus();
|
||||
if (status != null) {
|
||||
switch (status) {
|
||||
case 1: return "AC şarj ♥";
|
||||
case 10: return "DC hızlı şarj ♥";
|
||||
case 5: return "Bağlanıyor…";
|
||||
case 7: return "Kabloda, şarj yok";
|
||||
case 8: return "Durduruldu";
|
||||
case 0: return "Şarj yok";
|
||||
default: return "Durum " + status;
|
||||
case 1: return "AC charging ♥";
|
||||
case 10: return "DC fast charging ♥";
|
||||
case 5: return "Connecting…";
|
||||
case 7: return "Plugged in, not charging";
|
||||
case 8: return "Stopped";
|
||||
case 0: return "Not charging";
|
||||
default: return "Status " + status;
|
||||
}
|
||||
}
|
||||
Boolean plugged = s.getChargePortConnected();
|
||||
if (plugged != null) return plugged ? "Bağlı ♥" : "Bağlı değil";
|
||||
if (plugged != null) return plugged ? "Connected ♥" : "Not connected";
|
||||
return "—";
|
||||
}
|
||||
|
||||
@@ -689,13 +689,13 @@ public class MainActivity extends AppCompatActivity {
|
||||
// ---------- Call log ----------
|
||||
|
||||
/**
|
||||
* "Şimdi yükle" button — forces a cache drain + fresh chunk on a background thread,
|
||||
* ignoring the 2-minute throttle. The result lands in the upload log (Kayıtlar tab).
|
||||
* "Upload now" button — forces a cache drain + fresh chunk on a background thread,
|
||||
* ignoring the 2-minute throttle. The result lands in the upload log (Logs tab).
|
||||
*/
|
||||
private void manualFlush() {
|
||||
if (consumptionCloudClient == null || consumptionTracker == null) return;
|
||||
AbrpUploadService.log().record(new UploadLog.Entry(
|
||||
System.currentTimeMillis(), 0, true, "Manuel sync başlatıldı…"));
|
||||
System.currentTimeMillis(), 0, true, "Manual sync started…"));
|
||||
new Thread(() -> {
|
||||
String result = consumptionCloudClient.flushNow(
|
||||
consumptionTracker, System.currentTimeMillis());
|
||||
@@ -704,19 +704,19 @@ public class MainActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tüketim sekmesi "Yenile" button — sends cached chunks + fresh delta, invalidates the
|
||||
* Consumption tab "Refresh" button — sends cached chunks + fresh delta, invalidates the
|
||||
* history cache so the next poll fetches fresh data from the cloud, then refreshes the UI.
|
||||
*/
|
||||
private void refreshFromCloud() {
|
||||
if (consumptionCloudClient == null || consumptionTracker == null) return;
|
||||
AbrpUploadService.log().record(new UploadLog.Entry(
|
||||
System.currentTimeMillis(), 0, true, "Tüketim yenileniyor…"));
|
||||
System.currentTimeMillis(), 0, true, "Refreshing consumption…"));
|
||||
new Thread(() -> {
|
||||
consumptionCloudClient.flushNow(consumptionTracker, System.currentTimeMillis());
|
||||
consumptionCloudClient.invalidateHistory();
|
||||
runOnUiThread(() -> {
|
||||
refreshConsumption();
|
||||
Toast.makeText(this, "Tüketim yenilendi", Toast.LENGTH_SHORT).show();
|
||||
Toast.makeText(this, "Consumption refreshed", Toast.LENGTH_SHORT).show();
|
||||
});
|
||||
}, "cloud-refresh").start();
|
||||
}
|
||||
@@ -764,7 +764,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
break;
|
||||
case RUNNING:
|
||||
case STARTING:
|
||||
statusText.setText("Tüketim takibi aktif");
|
||||
statusText.setText("Consumption tracking active");
|
||||
statusText.setTextColor(COLOR_OK);
|
||||
break;
|
||||
case STOPPED:
|
||||
|
||||
@@ -150,14 +150,14 @@ final class WifiAutoConnect {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
static Result alreadyOn(String ssid) { return new Result(true, ssid, "Bağlı: " + ssid); }
|
||||
static Result attempting(String ssid) { return new Result(false, ssid, "Bağlanılıyor: " + ssid); }
|
||||
static Result alreadyOn(String ssid) { return new Result(true, ssid, "Connected: " + ssid); }
|
||||
static Result attempting(String ssid) { return new Result(false, ssid, "Connecting: " + ssid); }
|
||||
|
||||
static final Result UNSUPPORTED = new Result(false, null, "Wi-Fi yönetilemiyor");
|
||||
static final Result UNSUPPORTED = new Result(false, null, "Wi-Fi cannot be managed");
|
||||
static final Result WAITING = new Result(false, null, "Bekleniyor…");
|
||||
static final Result ENABLING = new Result(false, null, "Wi-Fi açılıyor…");
|
||||
static final Result CANNOT_ENABLE = new Result(false, null, "Wi-Fi açılamadı");
|
||||
static final Result NO_SAVED_NETWORKS = new Result(false, null, "Kayıtlı ağ yok");
|
||||
static final Result ENABLING = new Result(false, null, "Turning Wi-Fi on…");
|
||||
static final Result CANNOT_ENABLE = new Result(false, null, "Could not turn Wi-Fi on");
|
||||
static final Result NO_SAVED_NETWORKS = new Result(false, null, "No saved networks");
|
||||
static final Result REFUSED = new Result(false, null, "Sistem izin vermedi");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user