MiniABS 1.2: Galician interface, larger text and touch targets

- Translate the interface to Galician (tools/translate_gl.py), including
  Galician month abbreviations for dates, which Android 2.3 lacks
- Resize for the Galaxy Mini's 240x320 screen: larger text, rows, tabs and
  buttons; all sizes now live in res/values/dimens.xml
- Redraw play/pause/refresh icons for every density; slightly brighter
  secondary text colours

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
xockoandClaude Opus 5.5 committed 2026-10-14 21:29:17 +02:00
1 parent b7e43d7d61
commit 275bee3c11
51 files changed
+704 -372

No files matched your search

+260
View File
@@ -0,0 +1,260 @@
"""One-off: translates MiniABS's interface strings to Galician in place.
Each (file, old, new) must match at least once, so nothing is silently missed."""
import os
import re
import sys
ROOT = os.path.join(os.path.dirname(__file__), "..")
S = "src/com/miniabs/"
R = [
# ---------------- layouts / xml
("res/layout/activity_login.xml", 'android:text="Audiobookshelf podcasts"', 'android:text="Podcasts de Audiobookshelf"'),
("res/layout/activity_login.xml", 'android:text="Server address"', 'android:text="Enderezo do servidor"'),
("res/layout/activity_login.xml", 'android:text="Username"', 'android:text="Usuario"'),
("res/layout/activity_login.xml", 'android:text="Password"', 'android:text="Contrasinal"'),
("res/layout/activity_login.xml", 'android:text="Use an API key instead"', 'android:text="Usar unha chave da API"'),
("res/layout/activity_login.xml", 'android:text="Connect"', 'android:text="Conectar"'),
("res/layout/activity_login.xml",
"android:text=\"At home, use your server's local http:// address. For https://, Android 2.3 needs the server to offer TLS 1.0 on a separate port (see README). If the certificate isn't recognised, you'll be shown its fingerprint to check.\"",
'android:text="Na casa, usa o enderezo local http:// do servidor. Para https://, Android 2.3 precisa que o servidor ofreza TLS 1.0 nun porto á parte (ve o README). Se o certificado non se recoñece, amosaráseche a súa pegada dixital para que a comprobes."'),
("res/layout/activity_home.xml", 'android:text="Latest"', 'android:text="Últimos"'),
("res/layout/activity_home.xml", 'android:text="Shows"', 'android:text="Programas"'),
("res/layout/activity_home.xml", 'android:text="Saved"', 'android:text="Gardados"'),
("res/xml/settings.xml", 'android:title="Playback"', 'android:title="Reprodución"'),
("res/xml/settings.xml", 'android:title="Skip back"', 'android:title="Retroceder"'),
("res/xml/settings.xml", 'android:title="Skip forward"', 'android:title="Avanzar"'),
("res/xml/settings.xml", 'android:title="Downloads"', 'android:title="Descargas"'),
("res/xml/settings.xml", 'android:title="Download on Wi-Fi only"', 'android:title="Descargar só con wifi"'),
("res/xml/settings.xml", 'android:summary="Saves your mobile data"', 'android:summary="Aforra datos móbiles"'),
("res/xml/settings.xml", 'android:title="Delete all downloads"', 'android:title="Eliminar todas as descargas"'),
("res/xml/settings.xml", 'android:title="Display"', 'android:title="Aparencia"'),
("res/xml/settings.xml", 'android:title="Show cover art"', 'android:title="Amosar portadas"'),
("res/xml/settings.xml", 'android:summary="Turn off to save data and memory"', 'android:summary="Desactívao para aforrar datos e memoria"'),
("res/xml/settings.xml", 'android:title="Account"', 'android:title="Conta"'),
("res/xml/settings.xml", 'android:title="Signed in"', 'android:title="Sesión iniciada"'),
("res/xml/settings.xml", 'android:title="Certificates you trusted"', 'android:title="Certificados nos que confías"'),
("res/xml/settings.xml", 'android:title="Log out"', 'android:title="Pechar sesión"'),
("res/xml/settings.xml", 'android:title="About"', 'android:title="Acerca de"'),
("res/xml/settings.xml", 'android:summary="A tiny Audiobookshelf podcast client for Android 2.2+"',
'android:summary="Un pequeno cliente de podcasts de Audiobookshelf para Android 2.2+"'),
("res/values/arrays.xml", " seconds</item>", " segundos</item>"),
("AndroidManifest.xml", 'android:label="Settings"', 'android:label="Axustes"'),
# ---------------- Api / Json / Trust (errors)
(S + "Api.java", '"Unexpected reply from server"', '"Resposta inesperada do servidor"'),
(S + "Json.java", '"Unexpected reply from server"', '"Resposta inesperada do servidor"'),
(S + "Json.java", '"Reply was cut off"', '"A resposta chegou incompleta"'),
(S + "Api.java", '"Your sign-in has expired. Please log in again."', '"A túa sesión caducou. Inicia sesión de novo."'),
(S + "Api.java", '"The server redirected; check the address in Settings."', '"O servidor redirixiu a petición; comproba o enderezo do servidor."'),
(S + "Api.java", '"Please log in."', '"Inicia sesión."'),
(S + "Api.java", '"No Audiobookshelf server at this address."', '"Non hai ningún servidor de Audiobookshelf neste enderezo."'),
(S + "Api.java", "\"This server hasn't been set up yet. Finish setup in a browser first.\"",
'"Este servidor aínda non está configurado. Remata a configuración nun navegador."'),
(S + "Api.java", '"Wrong username or password."', '"Usuario ou contrasinal incorrectos."'),
(S + "Api.java", '"Too many attempts. Wait a minute and try again."', '"Demasiados intentos. Agarda un minuto e téntao de novo."'),
(S + "Api.java", "\"The server didn't return a sign-in token.\"", '"O servidor non devolveu ningún token de sesión."'),
(S + "Api.java", "\"That API key wasn't accepted.\"", '"Non se aceptou esa chave da API."'),
(S + "Api.java", "\"Certificate doesn't match \"", '"O certificado non corresponde a "'),
(S + "Trust.java", "\"Secure connections aren't available: \"", '"As conexións seguras non están dispoñibles: "'),
(S + "Trust.java", '"This phone doesn\'t recognise the certificate of "', '"Este teléfono non recoñece o certificado de "'),
(S + "Trust.java", '"Issued to: "', '"Emitido para: "'),
(S + "Trust.java", '"Issued by: "', '"Emitido por: "'),
(S + "Trust.java", '"Valid until: "', '"Válido ata: "'),
(S + "Trust.java", '"SHA-256 fingerprint:\\n"', '"Pegada dixital SHA-256:\\n"'),
(S + "Trust.java", "\"Only continue if this matches the fingerprint your computer's browser shows for the site.\"",
'"Continúa só se coincide coa pegada que amosa o navegador do teu ordenador para este sitio."'),
(S + "Trust.java", '"\\n\\nMiniABS will then trust certificates issued by \\""', '"\\n\\nMiniABS confiará desde agora nos certificados emitidos por «"'),
(S + "Trust.java", '.append("\\".");', '.append("».");'),
(S + "Trust.java", "DateFormat.getDateInstance().format(leaf.getNotAfter())", "Util.date(leaf.getNotAfter().getTime(), true)"),
(S + "Trust.java", "import java.text.DateFormat;\n", ""),
(S + "TrustPrompt.java", '"the server"', '"o servidor"'),
(S + "TrustPrompt.java", '"Check this certificate"', '"Comproba este certificado"'),
(S + "TrustPrompt.java", '"Trust"', '"Confiar"'),
(S + "TrustPrompt.java", '"Cancel"', '"Cancelar"'),
# ---------------- Util
(S + "Util.java", '"Not signed in. Please log in again."', '"Non iniciaches sesión. Inicia sesión de novo."'),
(S + "Util.java", "\"Your account isn't allowed to do that.\"", '"A túa conta non ten permiso para facer iso."'),
(S + "Util.java", '"Not found on the server."', '"Non se atopou no servidor."'),
(S + "Util.java", '"Server error "', '"Erro do servidor "'),
(S + "Util.java", '"Server not found. Check the address and your connection."', '"Non se atopou o servidor. Comproba o enderezo e a conexión."'),
(S + "Util.java", '"The server took too long to answer."', '"O servidor tardou demasiado en responder."'),
(S + "Util.java", "\"Can't connect to the server. Is it running and reachable?\"",
'"Non se pode conectar co servidor. Está en marcha e accesible?"'),
(S + "Util.java", "\"The server's certificate has expired, or the phone's date is wrong.\"",
'"O certificado do servidor caducou ou a data do teléfono é incorrecta."'),
(S + "Util.java", "\"This phone doesn't recognise the server's certificate.\"", '"Este teléfono non recoñece o certificado do servidor."'),
(S + "Util.java", "\"Couldn't set up a secure connection. Android 2.3 only speaks TLS 1.0, so the server needs \"\n + \"a legacy HTTPS port (see README). On your home network, the http:// address works too.\"",
'"Non se puido establecer unha conexión segura. Android 2.3 só admite TLS 1.0, así que o servidor "\n + "precisa un porto HTTPS antigo (ve o README). Na rede da casa tamén funciona o enderezo http://."'),
(S + "Util.java", '"Connection dropped. Check your network."', '"Cortouse a conexión. Comproba a rede."'),
(S + "Util.java", "\"The server's certificate is for a different address.\"", '"O certificado do servidor é doutro enderezo."'),
# ---------------- Downloads / DownloadService
(S + "Downloads.java", '"No SD card available. Insert or unmount it from USB to download."',
'"Non hai tarxeta SD dispoñible. Insírea ou desconéctaa do USB para descargar."'),
(S + "Downloads.java", "\"Can't use the SD card.\"", '"Non se pode usar a tarxeta SD."'),
(S + "Downloads.java", "\"Can't create a folder on the SD card.\"", '"Non se pode crear un cartafol na tarxeta SD."'),
(S + "DownloadService.java", '"Download failed: "', '"Fallou a descarga: "'),
(S + "DownloadService.java", '"not on Wi-Fi (Settings: Download on Wi-Fi only)"', '"non hai wifi (Axustes: Descargar só con wifi)"'),
(S + "DownloadService.java", '"this episode has no audio file"', '"este episodio non ten ficheiro de audio"'),
(S + "DownloadService.java", '"sign-in expired; log in again"', '"a sesión caducou; inicia sesión de novo"'),
(S + "DownloadService.java", "\"your account isn't allowed to download\"", '"a túa conta non ten permiso para descargar"'),
(S + "DownloadService.java", "\"couldn't save the file\"", '"non se puido gardar o ficheiro"'),
(S + "DownloadService.java", '"Downloading " + pct + "%"', '"Descargando " + pct + " %"'),
(S + "DownloadService.java", '" more queued"', '" máis na cola"'),
# ---------------- BaseActivity
(S + "BaseActivity.java", '"Certificate trusted. Try again."', '"Certificado aceptado. Téntao de novo."'),
(S + "BaseActivity.java", 'Util.clock(dur - pos) + " left"', '"quedan " + Util.clock(dur - pos)'),
(S + "BaseActivity.java", '"Paused"', '"En pausa"'),
(S + "BaseActivity.java", '"Play"', '"Reproducir"'),
(S + "BaseActivity.java", '"Cancel download"', '"Cancelar descarga"'),
(S + "BaseActivity.java", '"Delete download"', '"Eliminar descarga"'),
(S + "BaseActivity.java", '"Download"', '"Descargar"'),
(S + "BaseActivity.java", '"Mark as unplayed"', '"Marcar como non escoitado"'),
(S + "BaseActivity.java", '"Mark as played"', '"Marcar como escoitado"'),
(S + "BaseActivity.java", '"Go to show"', '"Ir ao programa"'),
(S + "BaseActivity.java", "\"You're not on Wi-Fi. Download over mobile data this time?\"",
'"Non estás nunha wifi. Descargar con datos móbiles esta vez?"'),
(S + "BaseActivity.java", '"Downloading. Wi-Fi-only is now off (change it in Settings)."',
'"Descargando. Desactivouse «só con wifi» (podes cambialo en Axustes)."'),
(S + "BaseActivity.java", '"Cancel"', '"Cancelar"'),
(S + "BaseActivity.java", '"Downloading…"', '"Descargando…"'),
(S + "BaseActivity.java", '"Download cancelled"', '"Descarga cancelada"'),
(S + "BaseActivity.java", '"Download deleted"', '"Descarga eliminada"'),
(S + "BaseActivity.java", '"Marked as played"', '"Marcado como escoitado"'),
(S + "BaseActivity.java", '"Marked as unplayed"', '"Marcado como non escoitado"'),
# ---------------- HomeActivity
(S + "HomeActivity.java", '"Synced offline progress"', '"Sincronizouse o progreso gardado sen conexión"'),
(S + "HomeActivity.java", '"This server has no podcast libraries."', '"Este servidor non ten bibliotecas de podcasts."'),
(S + "HomeActivity.java", '"CONTINUE LISTENING"', '"CONTINUAR ESCOITANDO"'),
(S + "HomeActivity.java", '"LATEST EPISODES"', '"ÚLTIMOS EPISODIOS"'),
(S + "HomeActivity.java", '"Load more"', '"Cargar máis"'),
(S + "HomeActivity.java", '"No episodes yet."', '"Aínda non hai episodios."'),
(S + "HomeActivity.java", '"\\n\\nTap refresh to try again."', '"\\n\\nToca actualizar para tentalo de novo."'),
(S + "HomeActivity.java", '"No podcasts in this library."', '"Non hai podcasts nesta biblioteca."'),
(S + "HomeActivity.java", "\"Can't reach the server. Showing saved episodes.\"",
'"Non se pode acceder ao servidor. Amósanse os episodios gardados."'),
(S + "HomeActivity.java", '"DOWNLOADING"', '"DESCARGANDO"'),
(S + "HomeActivity.java", '"SAVED ON SD CARD ("', '"GARDADOS NA TARXETA SD ("'),
(S + "HomeActivity.java", '"Nothing saved yet.\\n\\nLong-press an episode and choose Download to listen offline."',
'"Aínda non gardaches nada.\\n\\nMantén premido un episodio e escolle Descargar para escoitalo sen conexión."'),
(S + "HomeActivity.java", '"Loading…"', '"Cargando…"'),
(S + "HomeActivity.java", '"Still loading libraries…"', '"Aínda se están cargando as bibliotecas…"'),
(S + "HomeActivity.java", '"This is your only podcast library."', '"Esta é a túa única biblioteca de podcasts."'),
(S + "HomeActivity.java", '"Podcast library"', '"Biblioteca de podcasts"'),
(S + "HomeActivity.java", '"Refresh"', '"Actualizar"'),
(S + "HomeActivity.java", '"Library"', '"Biblioteca"'),
(S + "HomeActivity.java", '"Now playing"', '"En reprodución"'),
(S + "HomeActivity.java", '"Settings"', '"Axustes"'),
# ---------------- LoginActivity
(S + "LoginActivity.java", '"API key"', '"Chave da API"'),
(S + "LoginActivity.java", '"Password"', '"Contrasinal"'),
(S + "LoginActivity.java", '"Enter your server address."', '"Escribe o enderezo do servidor."'),
(S + "LoginActivity.java", '"Paste your API key."', '"Pega a túa chave da API."'),
(S + "LoginActivity.java", '"Enter your username."', '"Escribe o teu usuario."'),
(S + "LoginActivity.java", '"Connecting…"', '"Conectando…"'),
# ---------------- PlayerActivity
(S + "PlayerActivity.java", '"Nothing playing"', '"Non se está a reproducir nada"'),
(S + "PlayerActivity.java", '"Pick an episode from the list."', '"Escolle un episodio da lista."'),
(S + "PlayerActivity.java", '"Sleep at end"', '"Pausa ao final do episodio"'),
(S + "PlayerActivity.java", '"Sleep in "', '"Pausa en "'),
(S + "PlayerActivity.java", '"Connecting…"', '"Conectando…"'),
(S + "PlayerActivity.java", '"Saved on SD card"', '"Gardado na tarxeta SD"'),
(S + "PlayerActivity.java", '"Sleep timer"', '"Temporizador de pausa"'),
(S + "PlayerActivity.java", '"Mark as played"', '"Marcar como escoitado"'),
(S + "PlayerActivity.java", '"Cancel download"', '"Cancelar descarga"'),
(S + "PlayerActivity.java", '"Delete download"', '"Eliminar descarga"'),
(S + "PlayerActivity.java", '"Download"', '"Descargar"'),
(S + "PlayerActivity.java", '"Go to show"', '"Ir ao programa"'),
(S + "PlayerActivity.java", '"Stop"', '"Deter"'),
(S + "PlayerActivity.java", '"Marked as played"', '"Marcado como escoitado"'),
(S + "PlayerActivity.java", '"Off"', '"Desactivado"'),
(S + "PlayerActivity.java", ' minutes"', ' minutos"'),
(S + "PlayerActivity.java", '"1 hour"', '"1 hora"'),
(S + "PlayerActivity.java", '"End of episode"', '"Ao final do episodio"'),
(S + "PlayerActivity.java", '"Sleep timer off"', '"Temporizador desactivado"'),
(S + "PlayerActivity.java", '"Sleep timer set"', '"Temporizador activado"'),
# ---------------- PlayerService
(S + "PlayerService.java", '"Paused"', '"En pausa"'),
(S + "PlayerService.java", '"Marked as played"', '"Marcado como escoitado"'),
(S + "PlayerService.java", '"Connecting…"', '"Conectando…"'),
(S + "PlayerService.java", '"The server sent no audio for this episode."', '"O servidor non enviou audio para este episodio."'),
(S + "PlayerService.java", "\"This episode needs transcoding, which Android 2.x can't play. Try downloading it.\"",
'"Este episodio precisa transcodificación, que Android 2.x non pode reproducir. Proba a descargalo."'),
(S + "PlayerService.java", '"Offline · progress will sync later"', '"Sen conexión · o progreso sincronizarase despois"'),
(S + "PlayerService.java", '"Opening saved file…"', '"Abrindo o ficheiro gardado…"'),
(S + "PlayerService.java", '"Buffering…"', '"Cargando…"'),
(S + "PlayerService.java", "\"Can't open the audio: \"", '"Non se pode abrir o audio: "'),
(S + "PlayerService.java", '"Playback failed: "', '"Fallou a reprodución: "'),
(S + "PlayerService.java", '"Saved file · offline"', '"Ficheiro gardado · sen conexión"'),
(S + "PlayerService.java", '"Saved file"', '"Ficheiro gardado"'),
(S + "PlayerService.java", '"Streaming"', '"Reproducindo en liña"'),
(S + "PlayerService.java", '"Connection lost, reconnecting…"', '"Perdeuse a conexión, reconectando…"'),
(S + "PlayerService.java", '"Finished"', '"Rematado"'),
(S + "PlayerService.java", '"Playback error ("', '"Erro de reprodución ("'),
(S + "PlayerService.java", '"Lost connection to the server. Press play to try again."',
'"Perdeuse a conexión co servidor. Preme reproducir para tentalo de novo."'),
(S + "PlayerService.java", '"Sleep timer: paused"', '"Temporizador: en pausa"'),
(S + "PlayerService.java", '"Playing"', '"Reproducindo"'),
(S + "PlayerService.java", '"Loading…"', '"Cargando…"'),
(S + "PlayerService.java", '"Stopped: tap to retry"', '"Detido: toca para tentalo de novo"'),
# ---------------- PodcastActivity
(S + "PodcastActivity.java", '"1 episode"', '"1 episodio"'),
(S + "PodcastActivity.java", '" episodes"', '" episodios"'),
(S + "PodcastActivity.java", '" PLAYED EPISODES HIDDEN"', '" EPISODIOS ESCOITADOS OCULTOS"'),
(S + "PodcastActivity.java", '"No episodes."', '"Non hai episodios."'),
(S + "PodcastActivity.java", '"Newest first"', '"Máis recentes primeiro"'),
(S + "PodcastActivity.java", '"Oldest first"', '"Máis antigos primeiro"'),
(S + "PodcastActivity.java", '"Show played"', '"Amosar escoitados"'),
(S + "PodcastActivity.java", '"Hide played"', '"Ocultar escoitados"'),
(S + "PodcastActivity.java", '"Refresh"', '"Actualizar"'),
(S + "PodcastActivity.java", '"Now playing"', '"En reprodución"'),
# ---------------- Rows
(S + "Rows.java", '"1 episode"', '"1 episodio"'),
(S + "Rows.java", '" episodes"', '" episodios"'),
(S + "Rows.java", '"Played"', '"Escoitado"'),
(S + "Rows.java", 'Util.duration(Math.max(0, dur - cur)) + " left"', '"quedan " + Util.duration(Math.max(0, dur - cur))'),
(S + "Rows.java", '"Saving "', '"Gardando "'),
(S + "Rows.java", '"Queued"', '"Na cola"'),
(S + "Rows.java", '"Saved"', '"Gardado"'),
(S + "Rows.java", '"Now playing"', '"En reprodución"'),
# ---------------- SettingsActivity
(S + "SettingsActivity.java", '" seconds"', '" segundos"'),
(S + "SettingsActivity.java", '"API key"', '"Chave da API"'),
(S + "SettingsActivity.java", '"Delete every downloaded episode from the SD card?"',
'"Eliminar todos os episodios descargados da tarxeta SD?"'),
(S + "SettingsActivity.java", '"Delete"', '"Eliminar"'),
(S + "SettingsActivity.java", '" deleted"', '" eliminados"'),
(S + "SettingsActivity.java", '"Cancel"', '"Cancelar"'),
(S + "SettingsActivity.java", '"None"', '"Ningún"'),
(S + "SettingsActivity.java", '" (tap to forget)"', '" (toca para esquecelos)"'),
(S + "SettingsActivity.java", "\"Forget the certificates you chose to trust? You'll be asked again next time.\"",
'"Esquecer os certificados nos que decidiches confiar? Volverase preguntar a próxima vez."'),
(S + "SettingsActivity.java", '"Forget"', '"Esquecer"'),
(S + "SettingsActivity.java", '"Log out of "', '"Pechar sesión en "'),
(S + "SettingsActivity.java", '"? Downloads stay on the SD card."', '"? As descargas quedan na tarxeta SD."'),
(S + "SettingsActivity.java", '"Log out"', '"Pechar sesión"'),
]
missing = []
for f, old, new in R:
p = os.path.join(ROOT, f)
s = open(p, encoding="utf-8").read()
if old not in s:
missing.append((f, old[:70]))
continue
open(p, "w", encoding="utf-8").write(s.replace(old, new))
if missing:
for m in missing:
print("NOT FOUND", m)
sys.exit(1)
print(len(R), "replacements applied")