Compare commits

..
32 Commits
Author SHA1 Message Date
ShanaiaBot 53cc4a59ec chore: bump version to 1.1.53+58 [ci skip] 2026-07-26 00:18:31 +02:00
FreeTLab b551c85edb feat(i18n): draw the Catalan and Basque flags in the language picker
Build & Deploy Farolero / Análisis de código (push) Successful in 11s
Build & Deploy Farolero / Build APK + AAB release (push) Successful in 1m18s
Every language showed its flag except those two, which fell back to a plain
black flag. Unicode does define subdivision sequences for both, but outside
England, Scotland and Wales they are not in the recommended set, so almost
no system renders them.

Both flags are simple geometry, so they are painted rather than shipped as
images: crisp at any size, no new assets, no licensing question. The senyera
is nine equal stripes; the ikurriña is the green saltire under the white
cross on red. The rest keep their emoji, now boxed to the same size so the
list lines up.

Not seen on a device: verified by build and analysis only.
2026-07-26 00:18:06 +02:00
ShanaiaBot 0a6ac6cba0 chore: bump version to 1.1.52+57 [ci skip] 2026-07-26 00:00:22 +02:00
FreeTLab 56f07364c2 feat: confirm before leaving a game, and fix untranslated strings
Build & Deploy Farolero / Análisis de código (push) Successful in 13s
Build & Deploy Farolero / Build APK + AAB release (push) Successful in 1m22s
Exit confirmation
- A dialog in the app's own style now guards every in-game screen. The safe
  action is the prominent one, so a stray tap keeps you in the game.
- Eleven screens covered, against both the system back gesture and the close
  buttons. The message adapts: a single-device game is lost, a host ends it
  for everyone, a client can rejoin.
- The two screens the host also opens from the manager take a flag so that
  back there just closes them instead of offering to quit.

Translations
- 21 keys were still holding the English text in Arabic, Basque, Hindi,
  Japanese, Korean, Dutch, Polish, Russian, Turkish and both Chinese
  variants: 231 strings, covering the whole multi-device flow, permissions
  and the mode picker. Nothing failed, the app just showed English.
- The permissions dialog was hardcoded in Spanish; it is localized now.
- Portuguese used Spanish gerunds where pt-PT takes "a + infinitive".

Checked what looked untranslated but is not: Animals and Notes are correct
Catalan, Configuration and Vibration correct French, Version correct German.
Those are whitelisted in the new test rather than silently rewritten.

l10n_cobertura_test guards all of it: no missing or orphan keys, no empty
values, no English left outside the whitelist, and placeholders preserved.
2026-07-25 23:59:57 +02:00
ShanaiaBot d98ca66793 chore: bump version to 1.1.51+56 [ci skip] 2026-07-25 23:27:07 +02:00
FreeTLab 586b60ae78 fix(android): move MainActivity to the package the manifest looks for
Build & Deploy Farolero / Análisis de código (push) Successful in 14s
Build & Deploy Farolero / Build APK + AAB release (push) Successful in 1m28s
The app crashed on launch with ClassNotFoundException for
es.freetimelab.farolero.game.MainActivity: 374c6ae added the .game suffix to
namespace and applicationId but left the Kotlin source in
es.freetimelab.farolero, so the manifest asked for a class that was never
compiled under that name. Every release built since then died on startup,
including the one already published to internal testing.

Also requests edge-to-edge explicitly now that the app targets 35, rather
than relying on the Flutter default.

Verified on a physical device running Android 16: installs, launches and
stays alive with no crash, and the bottom action buttons sit clear of the
navigation bar.
2026-07-25 23:26:32 +02:00
ShanaiaBot c15a5e31cb chore: bump version to 1.1.50+55 [ci skip] 2026-07-25 22:29:12 +02:00
FreeTLab ae0d55c00f fix(android): target API level 35 as required by Google Play
Build & Deploy Farolero / Análisis de código (push) Successful in 14s
Build & Deploy Farolero / Build APK + AAB release (push) Successful in 1m16s
Play rejected version code 54 for still targeting 34.

From API 35 Android forces edge-to-edge: content is drawn behind the system
bars and it is up to each screen to keep clear of them. Seven screens had no
SafeArea and their bottom action button would have ended up under the
gesture bar, so FondoFarolero gains a respetarBarras flag that insets the
content while the background still paints full bleed. The seventeen screens
that already handle it are untouched.

The navigation bar colour is ignored under edge-to-edge, so its icons are
now forced light to stay visible over the dark background.

Verified on the merged manifest: targetSdkVersion 35, and the release bundle
builds. The visual result has not been checked on a device.
2026-07-25 22:27:28 +02:00
ShanaiaBot a890abd9ed chore: bump version to 1.1.49+54 [ci skip] 2026-07-25 22:15:06 +02:00
ShanaiaBot d43e5b58f5 chore: bump version to 1.1.48+53 [ci skip] 2026-07-25 22:13:18 +02:00
ShanaiaBot dfd00c71bb fix(ci): read key.properties for release signing with Kotlin imports
Build & Deploy Farolero / Análisis de código (push) Successful in 11s
Build & Deploy Farolero / Build APK + AAB release (push) Successful in 1m10s
2026-07-25 22:12:56 +02:00
ShanaiaBot 56ff48a576 chore: bump version to 1.1.47+52 [ci skip] 2026-07-25 21:56:15 +02:00
ShanaiaBot 252c91d781 fix(ci): simplify build.gradle.kts, signing handled by CI key.properties
Build & Deploy Farolero / Análisis de código (push) Successful in 10s
Build & Deploy Farolero / Build APK + AAB release (push) Successful in 1m10s
2026-07-25 21:55:55 +02:00
ShanaiaBot 89635af518 chore: bump version to 1.1.46+51 [ci skip] 2026-07-25 21:54:37 +02:00
ShanaiaBot 7d96673edb fix(ci): use Kotlin DSL syntax instead of Groovy in build.gradle.kts
Build & Deploy Farolero / Análisis de código (push) Successful in 10s
Build & Deploy Farolero / Build APK + AAB release (push) Failing after 11s
2026-07-25 21:54:15 +02:00
ShanaiaBot 9b73c08bbc chore: bump version to 1.1.45+50 [ci skip] 2026-07-25 21:37:18 +02:00
ShanaiaBot c52d8af1e6 fix(ci): fix YAML syntax errors in keystore secret and SSH key references
Build & Deploy Farolero / Análisis de código (push) Successful in 11s
Build & Deploy Farolero / Build APK + AAB release (push) Failing after 10s
2026-07-25 21:36:55 +02:00
ShanaiaBot 8f9d1dd298 chore: cleanup analysis_options 2026-07-25 21:33:51 +02:00
ShanaiaBot 26f9acb789 feat(ci): add workflow_dispatch trigger for manual runs 2026-07-25 21:31:22 +02:00
ShanaiaBot 82ae03d4f7 chore: verify production signing CI 2026-07-25 21:29:43 +02:00
ShanaiaBot e1c14a43e8 chore: trigger CI for production signing verification 2026-07-25 21:28:10 +02:00
ShanaiaBot 42d79eed5d chore: trigger CI for production signing verification 2026-07-25 21:26:50 +02:00
ShanaiaBot 374c6aef36 feat: change applicationId to es.freetimelab.farolero.game with production signing config 2026-07-25 21:22:56 +02:00
ShanaiaBot 3430238067 feat(ci): add keystore signing step for production release builds 2026-07-25 21:20:45 +02:00
ShanaiaBot 7c5544afd1 chore: bump version to 1.1.44+49 [ci skip] 2026-07-25 21:00:27 +02:00
ShanaiaBot 17f9813de5 chore(ci): remove Telegram notification step
Build & Deploy Farolero / Análisis de código (push) Successful in 11s
Build & Deploy Farolero / Build APK + AAB release (push) Successful in 2m10s
2026-07-25 21:00:02 +02:00
ShanaiaBot 212e56bc6d chore: bump version to 1.1.43+48 [ci skip] 2026-07-25 21:00:00 +02:00
ShanaiaBot b3823fecd1 fix(ci): use curly braces in BOT_TOKEN var to avoid bash parsing issues
Build & Deploy Farolero / Análisis de código (push) Successful in 11s
Build & Deploy Farolero / Build APK + AAB release (push) Failing after 1m27s
2026-07-25 20:59:39 +02:00
ShanaiaBot d37a231240 chore: bump version to 1.1.42+47 [ci skip] 2026-07-25 20:57:20 +02:00
ShanaiaBot 87958c1622 fix(ci): add explicit PATH with homebrew so flutter is found by bash --norc
Build & Deploy Farolero / Análisis de código (push) Successful in 10s
Build & Deploy Farolero / Build APK + AAB release (push) Failing after 1m38s
2026-07-25 20:57:03 +02:00
ShanaiaBot 862ff12bbd fix(ci): remove broken --unshallow (clone is full) and fix Telegram notify syntax
Build & Deploy Farolero / Análisis de código (push) Failing after 3s
Build & Deploy Farolero / Build APK + AAB release (push) Skipped
2026-07-25 20:55:19 +02:00
ShanaiaBot cc069f1c39 fix(ci): replace actions/checkout@v4 with git clone (no Node.js on runner)
Build & Deploy Farolero / Análisis de código (push) Successful in 12s
Build & Deploy Farolero / Build APK + AAB release (push) Failing after 3s
2026-07-25 20:52:50 +02:00
61 changed files with 2541 additions and 882 deletions
+32 -21
View File
@@ -3,16 +3,25 @@ name: Build & Deploy Farolero
on:
push:
branches: [main]
workflow_dispatch:
env:
PATH: /opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
ANDROID_HOME: /Users/freetlab/Library/Android/sdk
KEYSTORE_PATH: /Users/freetlab/.openclaw/workspace/.secure/farolero/farolero-upload.jks
KEYSTORE_ALIAS: upload
jobs:
analizar:
name: Análisis de código
runs-on: [self-hosted, macos, arm64, flutter]
steps:
- uses: actions/checkout@v4
- name: Clonar repositorio
run: |
git clone https://ShanaiaBot:${{ secrets.GITEA_TOKEN }}@git.freetimelab.es/FreeTLab/farolero.git .
git fetch origin main
git checkout main
- name: Verificar Flutter
run: |
which flutter
@@ -30,18 +39,35 @@ jobs:
needs: analizar
if: ${{ gitea.ref == 'refs/heads/main' }}
steps:
- uses: actions/checkout@v4
- name: Clonar repositorio
run: |
git clone https://ShanaiaBot:${{ secrets.GITEA_TOKEN }}@git.freetimelab.es/FreeTLab/farolero.git .
git fetch origin main
git checkout main
- name: Verificar Flutter
run: |
which flutter
flutter --version
- name: Fetch completo + Bump versión patch + commit
- name: Configurar keystore de firma
env:
KEYSTORE_PASSWORD: ${{ secrets.FAROLERO_KEYSTORE_PASSWORD }}
run: |
if [ ! -f "$KEYSTORE_PATH" ]; then
echo "ERROR: Keystore no encontrado en $KEYSTORE_PATH"
exit 1
fi
echo "storeFile=$KEYSTORE_PATH" > android/key.properties
echo "storePassword=$KEYSTORE_PASSWORD" >> android/key.properties
echo "keyAlias=$KEYSTORE_ALIAS" >> android/key.properties
echo "keyPassword=$KEYSTORE_PASSWORD" >> android/key.properties
echo "✅ Keystore configurado"
- name: Bump versión patch + commit
run: |
git config user.name "ShanaiaBot"
git config user.email "shanaia@freetimelab.es"
# Fetch completo para tener todo el historial y poder push
git fetch --unshallow origin main
CURRENT=$(grep '^version:' pubspec.yaml | awk '{print $2}')
SEMVER=$(echo $CURRENT | cut -d'+' -f1)
BUILD=$(echo $CURRENT | cut -d'+' -f2)
@@ -92,19 +118,4 @@ jobs:
build/app/outputs/bundle/release/app-release.aab \
"ShanaiaBot@192.168.0.33:${DESTINO}/${AAB_NOMBRE}"
echo "✅ APK: builds.freetimelab.es → farolero → v${VERSION}"
echo "✅ AAB: builds.freetimelab.es → farolero → v${VERSION}"
- name: Notificar Telegram
if: always()
run: |
VERSION="${{ steps.version.outputs.version }}"
COMMIT="${{ steps.version.outputs.commit }}"
BOT_TOKEN=$(plutil -extract 'EnvironmentVariables:TELEGRAM_BOT_TOKEN' raw /Users/freetlab/Library/LaunchAgents/ai.openclaw.gateway.plist 2>/dev/null || echo "")
if [ -z "$BOT_TOKEN" ]; then exit 0; fi
if [ "${{ job.status }}" = "success" ]; then
MSG="✅ *Farolero* v${VERSION} build OK · ${COMMIT}%0AAPK + AAB en builds.freetimelab.es"
else
MSG="❌ *Farolero* v${VERSION} build FAILED · ${COMMIT}"
fi
curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
-d "chat_id=221721467" -d "parse_mode=Markdown" -d "text=${MSG}" || true
echo "✅ AAB: builds.freetimelab.es → farolero → v${VERSION}"
+32 -5
View File
@@ -1,11 +1,20 @@
import java.util.Properties
import java.io.FileInputStream
plugins {
id("com.android.application")
id("kotlin-android")
id("dev.flutter.flutter-gradle-plugin")
}
val keystorePropertiesFile = rootProject.file("key.properties")
val keystoreProperties = Properties()
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(FileInputStream(keystorePropertiesFile))
}
android {
namespace = "es.freetimelab.farolero"
namespace = "es.freetimelab.farolero.game"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
@@ -19,20 +28,38 @@ android {
}
defaultConfig {
applicationId = "es.freetimelab.farolero"
applicationId = "es.freetimelab.farolero.game"
minSdk = 24
targetSdk = 34
// Google Play exige 35 como mínimo. A partir de aquí Android impone el
// dibujado de borde a borde: el contenido va detrás de las barras del
// sistema y son las pantallas las que deben apartarse.
targetSdk = 35
versionCode = flutter.versionCode
versionName = flutter.versionName
}
signingConfigs {
if (keystorePropertiesFile.exists()) {
create("release") {
keyAlias = keystoreProperties.getProperty("keyAlias") ?: ""
keyPassword = keystoreProperties.getProperty("keyPassword") ?: ""
storeFile = keystoreProperties.getProperty("storeFile")?.let { file(it) }
storePassword = keystoreProperties.getProperty("storePassword") ?: ""
}
}
}
buildTypes {
release {
signingConfig = signingConfigs.getByName("debug")
signingConfig = if (keystorePropertiesFile.exists()) {
signingConfigs.getByName("release")
} else {
signingConfigs.getByName("debug")
}
}
}
}
flutter {
source = "../.."
}
}
@@ -1,4 +1,4 @@
package es.freetimelab.farolero
package es.freetimelab.farolero.game
import io.flutter.embedding.android.FlutterActivity
+36 -22
View File
@@ -246,28 +246,28 @@
"release": "تحرير",
"select": "اختيار",
"delete": "حذف",
"selectAtLeastThreeUsersToStart": "Select at least 3 users to start.",
"hostPhoneMustSelectUser": "The host phone must select at least one user.",
"roomNoLongerInLobby": "The room is no longer in the lobby.",
"completeUserSelectionToStart": "Complete user selection to start.",
"preparingSecureRoom": "Preparing the secure room",
"searchingNearbyBluetoothGames": "Searching nearby games over Bluetooth",
"tapToJoin": "Tap to join",
"bluetoothLocationPermissionsRequired": "Bluetooth and location permissions are required to search for games.",
"bluetoothLocationPermissionsShort": "Bluetooth and location permissions are required",
"couldNotStartSearch": "Could not start the search. Check Bluetooth and location.",
"couldNotConnectToHost": "Could not connect to {host}",
"selectAtLeastThreeUsersToStart": "اختر 3 مستخدمين على الأقل للبدء.",
"hostPhoneMustSelectUser": "يجب أن يختار هاتف المضيف مستخدمًا واحدًا على الأقل.",
"roomNoLongerInLobby": "لم تعد الغرفة في ردهة الانتظار.",
"completeUserSelectionToStart": "أكمل اختيار المستخدمين للبدء.",
"preparingSecureRoom": "جارٍ تجهيز الغرفة الآمنة",
"searchingNearbyBluetoothGames": "البحث عن جولات قريبة عبر البلوتوث",
"tapToJoin": "اضغط للانضمام",
"bluetoothLocationPermissionsRequired": "يلزم إذنا البلوتوث والموقع للبحث عن جولات.",
"bluetoothLocationPermissionsShort": "يلزم إذنا البلوتوث والموقع",
"couldNotStartSearch": "تعذّر بدء البحث. تحقق من البلوتوث والموقع.",
"couldNotConnectToHost": "تعذّر الاتصال بـ {host}",
"room": "غرفة",
"singleDeviceSubtitle": "Game on this device",
"singleDeviceDescription": "Ideal for playing together by passing the phone around. Fast, direct setup.",
"multiDeviceSubtitle": "Each player on their phone",
"multiDeviceDescription": "Create a premium room, share the QR code and manage users from the lobby.",
"singleDeviceGameLabel": "Game on this device",
"multiDeviceGameLabel": "Multi-device game",
"mainDeviceUser": "Main device user",
"couldNotCreateRoom": "Could not create the room. Check Bluetooth.",
"cannotStartWithReason": "Cannot start: {reason}",
"invalidRoom": "invalid room",
"singleDeviceSubtitle": "اللعب على هذا الجهاز",
"singleDeviceDescription": "مثالي للعب معًا بتمرير الهاتف. إعداد سريع ومباشر.",
"multiDeviceSubtitle": "كل لاعب على هاتفه",
"multiDeviceDescription": "أنشئ غرفة مميزة، وشارك رمز QR، وأدر المستخدمين من ردهة الانتظار.",
"singleDeviceGameLabel": "اللعب على هذا الجهاز",
"multiDeviceGameLabel": "لعب متعدد الأجهزة",
"mainDeviceUser": "المستخدم الرئيسي للجهاز",
"couldNotCreateRoom": "تعذّر إنشاء الغرفة. تحقق من البلوتوث.",
"cannotStartWithReason": "تعذّر البدء: {reason}",
"invalidRoom": "غرفة غير صالحة",
"defaultPlayerName": "لاعب",
"play": "العب",
"history": "السجل",
@@ -368,5 +368,19 @@
"reconnecting": "جارٍ إعادة الاتصال...",
"reconnectingHint": "انقطع الاتصال بالمضيف. مكانك في الجولة محفوظ.",
"leaveGame": "مغادرة الجولة",
"playerRejoined": "عاد {name} إلى الجولة"
"playerRejoined": "عاد {name} إلى الجولة",
"leaveGameTitle": "هل تريد مغادرة الجولة؟",
"leaveGameSingleDevice": "ستفقد الجولة الجارية ولن يمكن استعادتها.",
"leaveGameHost": "أنت المضيف: إذا غادرت ستنتهي الجولة لجميع اللاعبين.",
"leaveGameClient": "ستغادر الجولة. يمكنك العودة ما دام المضيف يبقيها مفتوحة.",
"stayInGame": "متابعة اللعب",
"permissionsNeededTitle": "أذونات مطلوبة",
"permissionsNeededBody": "لوضع اللعب الجماعي نحتاج إلى:",
"openAppSettingsQuestion": "هل تريد فتح إعدادات التطبيق؟",
"openSettings": "فتح الإعدادات",
"permissionLocation": "الموقع",
"permissionBluetoothAdvertise": "بلوتوث (الإعلان)",
"permissionBluetoothConnect": "بلوتوث (الاتصال)",
"permissionBluetoothScan": "بلوتوث (المسح)",
"permissionNearbyWifi": "واي فاي قريب"
}
+15 -1
View File
@@ -368,5 +368,19 @@
"reconnecting": "Reconnectant...",
"reconnectingHint": "S'ha perdut la connexió amb l'amfitrió. El teu lloc a la partida es manté.",
"leaveGame": "Sortir de la partida",
"playerRejoined": "{name} ha tornat a la partida"
"playerRejoined": "{name} ha tornat a la partida",
"leaveGameTitle": "Vols sortir de la partida?",
"leaveGameSingleDevice": "Es perdrà la partida en curs i no la podràs recuperar.",
"leaveGameHost": "Ets l'amfitrió: si surts, la partida s'acaba per a tots els jugadors.",
"leaveGameClient": "Sortiràs de la partida. Hi podràs tornar mentre l'amfitrió la mantingui oberta.",
"stayInGame": "Continuar jugant",
"permissionsNeededTitle": "Permisos necessaris",
"permissionsNeededBody": "Per al mode multijugador necessitem:",
"openAppSettingsQuestion": "Vols obrir la configuració de l'aplicació?",
"openSettings": "Obrir configuració",
"permissionLocation": "Ubicació",
"permissionBluetoothAdvertise": "Bluetooth (anunciar)",
"permissionBluetoothConnect": "Bluetooth (connectar)",
"permissionBluetoothScan": "Bluetooth (escanejar)",
"permissionNearbyWifi": "Wi-Fi proper"
}
+15 -1
View File
@@ -368,5 +368,19 @@
"reconnecting": "Verbindung wird wiederhergestellt ...",
"reconnectingHint": "Verbindung zum Host verloren. Dein Platz im Spiel bleibt reserviert.",
"leaveGame": "Spiel verlassen",
"playerRejoined": "{name} ist zurück im Spiel"
"playerRejoined": "{name} ist zurück im Spiel",
"leaveGameTitle": "Spiel wirklich verlassen?",
"leaveGameSingleDevice": "Das laufende Spiel geht verloren und lässt sich nicht wiederherstellen.",
"leaveGameHost": "Du bist der Host: Wenn du gehst, endet das Spiel für alle.",
"leaveGameClient": "Du verlässt das Spiel. Du kannst zurückkommen, solange der Host es offen hält.",
"stayInGame": "Weiterspielen",
"permissionsNeededTitle": "Berechtigungen erforderlich",
"permissionsNeededBody": "Für den Mehrspielermodus brauchen wir:",
"openAppSettingsQuestion": "Die App-Einstellungen öffnen?",
"openSettings": "Einstellungen öffnen",
"permissionLocation": "Standort",
"permissionBluetoothAdvertise": "Bluetooth (sichtbar machen)",
"permissionBluetoothConnect": "Bluetooth (verbinden)",
"permissionBluetoothScan": "Bluetooth (suchen)",
"permissionNearbyWifi": "Wi-Fi in der Nähe"
}
+15 -1
View File
@@ -375,5 +375,19 @@
"reconnecting": "Reconnecting...",
"reconnectingHint": "Lost connection to the host. Your place in the game is being held.",
"leaveGame": "Leave the game",
"playerRejoined": "{name} has rejoined the game"
"playerRejoined": "{name} has rejoined the game",
"leaveGameTitle": "Leave the game?",
"leaveGameSingleDevice": "The game in progress will be lost and cannot be recovered.",
"leaveGameHost": "You are the host: if you leave, the game ends for everyone.",
"leaveGameClient": "You will leave the game. You can rejoin while the host keeps it open.",
"stayInGame": "Keep playing",
"permissionsNeededTitle": "Permissions needed",
"permissionsNeededBody": "For multiplayer mode we need:",
"openAppSettingsQuestion": "Open the app settings?",
"openSettings": "Open settings",
"permissionLocation": "Location",
"permissionBluetoothAdvertise": "Bluetooth (advertise)",
"permissionBluetoothConnect": "Bluetooth (connect)",
"permissionBluetoothScan": "Bluetooth (scan)",
"permissionNearbyWifi": "Nearby Wi-Fi"
}
+15 -1
View File
@@ -417,5 +417,19 @@
"type": "String"
}
}
}
},
"leaveGameTitle": "¿Salir de la partida?",
"leaveGameSingleDevice": "Se perderá la partida en curso y no podrás recuperarla.",
"leaveGameHost": "Eres el anfitrión: si sales, la partida termina para todos los jugadores.",
"leaveGameClient": "Saldrás de la partida. Podrás volver mientras el anfitrión la mantenga abierta.",
"stayInGame": "Seguir jugando",
"permissionsNeededTitle": "Permisos necesarios",
"permissionsNeededBody": "Para el modo multijugador necesitamos:",
"openAppSettingsQuestion": "¿Abrir la configuración de la app?",
"openSettings": "Abrir configuración",
"permissionLocation": "Ubicación",
"permissionBluetoothAdvertise": "Bluetooth (anunciar)",
"permissionBluetoothConnect": "Bluetooth (conectar)",
"permissionBluetoothScan": "Bluetooth (escanear)",
"permissionNearbyWifi": "Wi-Fi cercano"
}
+36 -22
View File
@@ -246,28 +246,28 @@
"release": "Askatu",
"select": "Hautatu",
"delete": "Ezabatu",
"selectAtLeastThreeUsersToStart": "Select at least 3 users to start.",
"hostPhoneMustSelectUser": "The host phone must select at least one user.",
"roomNoLongerInLobby": "The room is no longer in the lobby.",
"completeUserSelectionToStart": "Complete user selection to start.",
"preparingSecureRoom": "Preparing the secure room",
"searchingNearbyBluetoothGames": "Searching nearby games over Bluetooth",
"tapToJoin": "Tap to join",
"bluetoothLocationPermissionsRequired": "Bluetooth and location permissions are required to search for games.",
"bluetoothLocationPermissionsShort": "Bluetooth and location permissions are required",
"couldNotStartSearch": "Could not start the search. Check Bluetooth and location.",
"couldNotConnectToHost": "Could not connect to {host}",
"selectAtLeastThreeUsersToStart": "Hautatu gutxienez 3 erabiltzaile hasteko.",
"hostPhoneMustSelectUser": "Ostalariaren mugikorrak gutxienez erabiltzaile bat hautatu behar du.",
"roomNoLongerInLobby": "Gela jada ez dago lobbyan.",
"completeUserSelectionToStart": "Osatu erabiltzaileen hautaketa hasteko.",
"preparingSecureRoom": "Gela segurua prestatzen",
"searchingNearbyBluetoothGames": "Inguruko partidak bilatzen Bluetooth bidez",
"tapToJoin": "Sakatu batzeko",
"bluetoothLocationPermissionsRequired": "Bluetooth eta kokapen baimenak behar dira partidak bilatzeko.",
"bluetoothLocationPermissionsShort": "Bluetooth eta kokapen baimenak behar dira",
"couldNotStartSearch": "Ezin izan da bilaketa hasi. Egiaztatu Bluetooth eta kokapena.",
"couldNotConnectToHost": "Ezin izan da {host}(e)ra konektatu",
"room": "Gela",
"singleDeviceSubtitle": "Game on this device",
"singleDeviceDescription": "Ideal for playing together by passing the phone around. Fast, direct setup.",
"multiDeviceSubtitle": "Each player on their phone",
"multiDeviceDescription": "Create a premium room, share the QR code and manage users from the lobby.",
"singleDeviceGameLabel": "Game on this device",
"multiDeviceGameLabel": "Multi-device game",
"mainDeviceUser": "Main device user",
"couldNotCreateRoom": "Could not create the room. Check Bluetooth.",
"cannotStartWithReason": "Cannot start: {reason}",
"invalidRoom": "invalid room",
"singleDeviceSubtitle": "Partida gailu honetan",
"singleDeviceDescription": "Ezin hobea denok elkarrekin jokatzeko mugikorra pasatuz. Konfigurazio azkarra eta zuzena.",
"multiDeviceSubtitle": "Jokalari bakoitza bere mugikorrean",
"multiDeviceDescription": "Sortu gela premium bat, partekatu QR kodea eta kudeatu erabiltzaileak lobbytik.",
"singleDeviceGameLabel": "Partida gailu honetan",
"multiDeviceGameLabel": "Gailu anitzeko partida",
"mainDeviceUser": "Gailuaren erabiltzaile nagusia",
"couldNotCreateRoom": "Ezin izan da gela sortu. Egiaztatu Bluetooth.",
"cannotStartWithReason": "Ezin da hasi: {reason}",
"invalidRoom": "gela baliogabea",
"defaultPlayerName": "Jokalaria",
"play": "Jokatu",
"history": "Historia",
@@ -368,5 +368,19 @@
"reconnecting": "Berriz konektatzen...",
"reconnectingHint": "Ostalariarekiko konexioa galdu da. Partidan duzun lekua gordeta dago.",
"leaveGame": "Partidatik irten",
"playerRejoined": "{name} partidara itzuli da"
"playerRejoined": "{name} partidara itzuli da",
"leaveGameTitle": "Partidatik irten nahi duzu?",
"leaveGameSingleDevice": "Abian den partida galduko da eta ezin izango duzu berreskuratu.",
"leaveGameHost": "Zu zara ostalaria: irtenez gero, partida jokalari guztientzat amaituko da.",
"leaveGameClient": "Partidatik aterako zara. Itzuli ahal izango zara ostalariak zabalik mantentzen duen bitartean.",
"stayInGame": "Jokatzen jarraitu",
"permissionsNeededTitle": "Baimenak behar dira",
"permissionsNeededBody": "Jokalari anitzeko modurako hau behar dugu:",
"openAppSettingsQuestion": "Aplikazioaren ezarpenak ireki nahi dituzu?",
"openSettings": "Ireki ezarpenak",
"permissionLocation": "Kokapena",
"permissionBluetoothAdvertise": "Bluetooth (iragarri)",
"permissionBluetoothConnect": "Bluetooth (konektatu)",
"permissionBluetoothScan": "Bluetooth (eskaneatu)",
"permissionNearbyWifi": "Inguruko Wi-Fi"
}
+15 -1
View File
@@ -368,5 +368,19 @@
"reconnecting": "Reconnexion...",
"reconnectingHint": "Connexion à l'hôte perdue. Votre place dans la partie est conservée.",
"leaveGame": "Quitter la partie",
"playerRejoined": "{name} a rejoint la partie"
"playerRejoined": "{name} a rejoint la partie",
"leaveGameTitle": "Quitter la partie ?",
"leaveGameSingleDevice": "La partie en cours sera perdue et ne pourra pas être récupérée.",
"leaveGameHost": "Vous êtes l'hôte : si vous partez, la partie se termine pour tout le monde.",
"leaveGameClient": "Vous quitterez la partie. Vous pourrez revenir tant que l'hôte la laisse ouverte.",
"stayInGame": "Continuer à jouer",
"permissionsNeededTitle": "Autorisations nécessaires",
"permissionsNeededBody": "Pour le mode multijoueur, nous avons besoin de :",
"openAppSettingsQuestion": "Ouvrir les paramètres de l'application ?",
"openSettings": "Ouvrir les paramètres",
"permissionLocation": "Localisation",
"permissionBluetoothAdvertise": "Bluetooth (diffusion)",
"permissionBluetoothConnect": "Bluetooth (connexion)",
"permissionBluetoothScan": "Bluetooth (recherche)",
"permissionNearbyWifi": "Wi-Fi à proximité"
}
+36 -22
View File
@@ -246,28 +246,28 @@
"release": "छोड़ें",
"select": "चुनें",
"delete": "हटाएँ",
"selectAtLeastThreeUsersToStart": "Select at least 3 users to start.",
"hostPhoneMustSelectUser": "The host phone must select at least one user.",
"roomNoLongerInLobby": "The room is no longer in the lobby.",
"completeUserSelectionToStart": "Complete user selection to start.",
"preparingSecureRoom": "Preparing the secure room",
"searchingNearbyBluetoothGames": "Searching nearby games over Bluetooth",
"tapToJoin": "Tap to join",
"bluetoothLocationPermissionsRequired": "Bluetooth and location permissions are required to search for games.",
"bluetoothLocationPermissionsShort": "Bluetooth and location permissions are required",
"couldNotStartSearch": "Could not start the search. Check Bluetooth and location.",
"couldNotConnectToHost": "Could not connect to {host}",
"selectAtLeastThreeUsersToStart": "शुरू करने के लिए कम से कम 3 उपयोगकर्ता चुनें।",
"hostPhoneMustSelectUser": "होस्ट फ़ोन को कम से कम एक उपयोगकर्ता चुनना होगा।",
"roomNoLongerInLobby": "कमरा अब लॉबी में नहीं है।",
"completeUserSelectionToStart": "शुरू करने के लिए उपयोगकर्ताओं का चयन पूरा करें।",
"preparingSecureRoom": "सुरक्षित कमरा तैयार किया जा रहा है",
"searchingNearbyBluetoothGames": "ब्लूटूथ से आस-पास के गेम खोजे जा रहे हैं",
"tapToJoin": "शामिल होने के लिए टैप करें",
"bluetoothLocationPermissionsRequired": "गेम खोजने के लिए ब्लूटूथ और लोकेशन की अनुमति चाहिए।",
"bluetoothLocationPermissionsShort": "ब्लूटूथ और लोकेशन की अनुमति चाहिए",
"couldNotStartSearch": "खोज शुरू नहीं हो सकी। ब्लूटूथ और लोकेशन जाँचें।",
"couldNotConnectToHost": "{host} से कनेक्ट नहीं हो सका",
"room": "कक्ष",
"singleDeviceSubtitle": "Game on this device",
"singleDeviceDescription": "Ideal for playing together by passing the phone around. Fast, direct setup.",
"multiDeviceSubtitle": "Each player on their phone",
"multiDeviceDescription": "Create a premium room, share the QR code and manage users from the lobby.",
"singleDeviceGameLabel": "Game on this device",
"multiDeviceGameLabel": "Multi-device game",
"mainDeviceUser": "Main device user",
"couldNotCreateRoom": "Could not create the room. Check Bluetooth.",
"cannotStartWithReason": "Cannot start: {reason}",
"invalidRoom": "invalid room",
"singleDeviceSubtitle": "इसी डिवाइस पर खेल",
"singleDeviceDescription": "फ़ोन एक-दूसरे को देकर साथ खेलने के लिए बढ़िया। सेटअप तेज़ और सीधा।",
"multiDeviceSubtitle": "हर खिलाड़ी अपने फ़ोन पर",
"multiDeviceDescription": "एक प्रीमियम कमरा बनाएँ, QR साझा करें और लॉबी से उपयोगकर्ता संभालें।",
"singleDeviceGameLabel": "इसी डिवाइस पर खेल",
"multiDeviceGameLabel": "मल्टी-डिवाइस खेल",
"mainDeviceUser": "डिवाइस का मुख्य उपयोगकर्ता",
"couldNotCreateRoom": "कमरा नहीं बन सका। ब्लूटूथ जाँचें।",
"cannotStartWithReason": "शुरू नहीं हो सकता: {reason}",
"invalidRoom": "अमान्य कमरा",
"defaultPlayerName": "खिलाड़ी",
"play": "खेलें",
"history": "इतिहास",
@@ -368,5 +368,19 @@
"reconnecting": "फिर से कनेक्ट हो रहा है...",
"reconnectingHint": "होस्ट से कनेक्शन टूट गया। खेल में आपकी जगह सुरक्षित है।",
"leaveGame": "खेल छोड़ें",
"playerRejoined": "{name} खेल में वापस आ गए"
"playerRejoined": "{name} खेल में वापस आ गए",
"leaveGameTitle": "खेल छोड़ना है?",
"leaveGameSingleDevice": "चल रहा खेल ख़त्म हो जाएगा और वापस नहीं मिलेगा।",
"leaveGameHost": "आप होस्ट हैं: आपके जाने पर सभी खिलाड़ियों का खेल ख़त्म हो जाएगा।",
"leaveGameClient": "आप खेल से बाहर निकल जाएँगे। जब तक होस्ट इसे खुला रखे, आप लौट सकते हैं।",
"stayInGame": "खेलते रहें",
"permissionsNeededTitle": "अनुमतियाँ चाहिए",
"permissionsNeededBody": "मल्टीप्लेयर मोड के लिए हमें चाहिए:",
"openAppSettingsQuestion": "क्या ऐप की सेटिंग खोलें?",
"openSettings": "सेटिंग खोलें",
"permissionLocation": "लोकेशन",
"permissionBluetoothAdvertise": "ब्लूटूथ (प्रसारण)",
"permissionBluetoothConnect": "ब्लूटूथ (कनेक्ट)",
"permissionBluetoothScan": "ब्लूटूथ (स्कैन)",
"permissionNearbyWifi": "आस-पास का वाई-फ़ाई"
}
+15 -1
View File
@@ -368,5 +368,19 @@
"reconnecting": "Riconnessione...",
"reconnectingHint": "Connessione con l'host persa. Il tuo posto nella partita resta riservato.",
"leaveGame": "Esci dalla partita",
"playerRejoined": "{name} è tornato in partita"
"playerRejoined": "{name} è tornato in partita",
"leaveGameTitle": "Vuoi uscire dalla partita?",
"leaveGameSingleDevice": "La partita in corso andrà persa e non potrà essere recuperata.",
"leaveGameHost": "Sei l'host: se esci, la partita finisce per tutti i giocatori.",
"leaveGameClient": "Uscirai dalla partita. Potrai rientrare finché l'host la tiene aperta.",
"stayInGame": "Continua a giocare",
"permissionsNeededTitle": "Autorizzazioni necessarie",
"permissionsNeededBody": "Per la modalità multigiocatore servono:",
"openAppSettingsQuestion": "Vuoi aprire le impostazioni dell'app?",
"openSettings": "Apri impostazioni",
"permissionLocation": "Posizione",
"permissionBluetoothAdvertise": "Bluetooth (annuncio)",
"permissionBluetoothConnect": "Bluetooth (connessione)",
"permissionBluetoothScan": "Bluetooth (scansione)",
"permissionNearbyWifi": "Wi-Fi nelle vicinanze"
}
+36 -22
View File
@@ -246,28 +246,28 @@
"release": "解除",
"select": "選択",
"delete": "削除",
"selectAtLeastThreeUsersToStart": "Select at least 3 users to start.",
"hostPhoneMustSelectUser": "The host phone must select at least one user.",
"roomNoLongerInLobby": "The room is no longer in the lobby.",
"completeUserSelectionToStart": "Complete user selection to start.",
"preparingSecureRoom": "Preparing the secure room",
"searchingNearbyBluetoothGames": "Searching nearby games over Bluetooth",
"tapToJoin": "Tap to join",
"bluetoothLocationPermissionsRequired": "Bluetooth and location permissions are required to search for games.",
"bluetoothLocationPermissionsShort": "Bluetooth and location permissions are required",
"couldNotStartSearch": "Could not start the search. Check Bluetooth and location.",
"couldNotConnectToHost": "Could not connect to {host}",
"selectAtLeastThreeUsersToStart": "開始するには3人以上のユーザーを選んでください。",
"hostPhoneMustSelectUser": "ホストの端末は少なくとも1人のユーザーを選ぶ必要があります。",
"roomNoLongerInLobby": "ルームはすでにロビーにありません。",
"completeUserSelectionToStart": "開始するにはユーザーの選択を完了してください。",
"preparingSecureRoom": "安全なルームを準備しています",
"searchingNearbyBluetoothGames": "Bluetoothで近くのゲームを検索しています",
"tapToJoin": "タップして参加",
"bluetoothLocationPermissionsRequired": "ゲームを検索するにはBluetoothと位置情報の許可が必要です。",
"bluetoothLocationPermissionsShort": "Bluetoothと位置情報の許可が必要です",
"couldNotStartSearch": "検索を開始できませんでした。Bluetoothと位置情報を確認してください。",
"couldNotConnectToHost": "{host} に接続できませんでした",
"room": "ルーム",
"singleDeviceSubtitle": "Game on this device",
"singleDeviceDescription": "Ideal for playing together by passing the phone around. Fast, direct setup.",
"multiDeviceSubtitle": "Each player on their phone",
"multiDeviceDescription": "Create a premium room, share the QR code and manage users from the lobby.",
"singleDeviceGameLabel": "Game on this device",
"multiDeviceGameLabel": "Multi-device game",
"mainDeviceUser": "Main device user",
"couldNotCreateRoom": "Could not create the room. Check Bluetooth.",
"cannotStartWithReason": "Cannot start: {reason}",
"invalidRoom": "invalid room",
"singleDeviceSubtitle": "この端末でプレイ",
"singleDeviceDescription": "端末を回しながらみんなで遊ぶのに最適。設定はすばやく簡単。",
"multiDeviceSubtitle": "プレイヤーごとに自分の端末で",
"multiDeviceDescription": "プレミアムなルームを作り、QRコードを共有し、ロビーからユーザーを管理します。",
"singleDeviceGameLabel": "この端末でのゲーム",
"multiDeviceGameLabel": "マルチデバイスのゲーム",
"mainDeviceUser": "この端末のメインユーザー",
"couldNotCreateRoom": "ルームを作成できませんでした。Bluetoothを確認してください。",
"cannotStartWithReason": "開始できません: {reason}",
"invalidRoom": "無効なルーム",
"defaultPlayerName": "プレイヤー",
"play": "プレイ",
"history": "履歴",
@@ -368,5 +368,19 @@
"reconnecting": "再接続しています...",
"reconnectingHint": "ホストとの接続が切れました。ゲーム内のあなたの席は確保されています。",
"leaveGame": "ゲームから退出",
"playerRejoined": "{name} がゲームに復帰しました"
"playerRejoined": "{name} がゲームに復帰しました",
"leaveGameTitle": "ゲームから退出しますか?",
"leaveGameSingleDevice": "進行中のゲームは失われ、元に戻せません。",
"leaveGameHost": "あなたはホストです。退出すると全員のゲームが終了します。",
"leaveGameClient": "ゲームから退出します。ホストが開いている間は戻れます。",
"stayInGame": "ゲームを続ける",
"permissionsNeededTitle": "必要な権限",
"permissionsNeededBody": "マルチプレイには次の権限が必要です:",
"openAppSettingsQuestion": "アプリの設定を開きますか?",
"openSettings": "設定を開く",
"permissionLocation": "位置情報",
"permissionBluetoothAdvertise": "Bluetooth(アドバタイズ)",
"permissionBluetoothConnect": "Bluetooth(接続)",
"permissionBluetoothScan": "Bluetooth(スキャン)",
"permissionNearbyWifi": "近くのWi-Fi"
}
+36 -22
View File
@@ -246,28 +246,28 @@
"release": "해제",
"select": "선택",
"delete": "삭제",
"selectAtLeastThreeUsersToStart": "Select at least 3 users to start.",
"hostPhoneMustSelectUser": "The host phone must select at least one user.",
"roomNoLongerInLobby": "The room is no longer in the lobby.",
"completeUserSelectionToStart": "Complete user selection to start.",
"preparingSecureRoom": "Preparing the secure room",
"searchingNearbyBluetoothGames": "Searching nearby games over Bluetooth",
"tapToJoin": "Tap to join",
"bluetoothLocationPermissionsRequired": "Bluetooth and location permissions are required to search for games.",
"bluetoothLocationPermissionsShort": "Bluetooth and location permissions are required",
"couldNotStartSearch": "Could not start the search. Check Bluetooth and location.",
"couldNotConnectToHost": "Could not connect to {host}",
"selectAtLeastThreeUsersToStart": "시작하려면 사용자를 3명 이상 선택하세요.",
"hostPhoneMustSelectUser": "호스트 기기는 사용자를 최소 한 명 선택해야 합니다.",
"roomNoLongerInLobby": "방이 더 이상 대기실에 없습니다.",
"completeUserSelectionToStart": "시작하려면 사용자 선택을 마치세요.",
"preparingSecureRoom": "보안 방을 준비하는 중",
"searchingNearbyBluetoothGames": "블루투스로 근처 게임을 찾는 중",
"tapToJoin": "눌러서 참여하기",
"bluetoothLocationPermissionsRequired": "게임을 찾으려면 블루투스와 위치 권한이 필요합니다.",
"bluetoothLocationPermissionsShort": "블루투스와 위치 권한이 필요합니다",
"couldNotStartSearch": "검색을 시작할 수 없습니다. 블루투스와 위치를 확인하세요.",
"couldNotConnectToHost": "{host}에 연결할 수 없습니다",
"room": "방",
"singleDeviceSubtitle": "Game on this device",
"singleDeviceDescription": "Ideal for playing together by passing the phone around. Fast, direct setup.",
"multiDeviceSubtitle": "Each player on their phone",
"multiDeviceDescription": "Create a premium room, share the QR code and manage users from the lobby.",
"singleDeviceGameLabel": "Game on this device",
"multiDeviceGameLabel": "Multi-device game",
"mainDeviceUser": "Main device user",
"couldNotCreateRoom": "Could not create the room. Check Bluetooth.",
"cannotStartWithReason": "Cannot start: {reason}",
"invalidRoom": "invalid room",
"singleDeviceSubtitle": "이 기기에서 진행",
"singleDeviceDescription": "휴대전화를 돌려 가며 함께 놀기에 좋습니다. 설정이 빠르고 간단합니다.",
"multiDeviceSubtitle": "각자 자기 휴대전화로",
"multiDeviceDescription": "프리미엄 방을 만들고 QR 코드를 공유하며 대기실에서 사용자를 관리하세요.",
"singleDeviceGameLabel": "이 기기에서 하는 게임",
"multiDeviceGameLabel": "여러 기기로 하는 게임",
"mainDeviceUser": "이 기기의 주 사용자",
"couldNotCreateRoom": "방을 만들 수 없습니다. 블루투스를 확인하세요.",
"cannotStartWithReason": "시작할 수 없습니다: {reason}",
"invalidRoom": "잘못된 방",
"defaultPlayerName": "플레이어",
"play": "플레이",
"history": "기록",
@@ -368,5 +368,19 @@
"reconnecting": "다시 연결하는 중...",
"reconnectingHint": "호스트와의 연결이 끊겼습니다. 게임 내 자리는 유지됩니다.",
"leaveGame": "게임 나가기",
"playerRejoined": "{name} 님이 게임에 복귀했습니다"
"playerRejoined": "{name} 님이 게임에 복귀했습니다",
"leaveGameTitle": "게임에서 나갈까요?",
"leaveGameSingleDevice": "진행 중인 게임이 사라지며 되돌릴 수 없습니다.",
"leaveGameHost": "당신은 호스트입니다. 나가면 모두의 게임이 끝납니다.",
"leaveGameClient": "게임에서 나갑니다. 호스트가 열어 두는 동안에는 다시 들어올 수 있습니다.",
"stayInGame": "계속 하기",
"permissionsNeededTitle": "필요한 권한",
"permissionsNeededBody": "멀티플레이 모드에는 다음 권한이 필요합니다:",
"openAppSettingsQuestion": "앱 설정을 열까요?",
"openSettings": "설정 열기",
"permissionLocation": "위치",
"permissionBluetoothAdvertise": "블루투스(광고)",
"permissionBluetoothConnect": "블루투스(연결)",
"permissionBluetoothScan": "블루투스(검색)",
"permissionNearbyWifi": "근처 Wi-Fi"
}
+36 -22
View File
@@ -246,28 +246,28 @@
"release": "Vrijgeven",
"select": "Selecteren",
"delete": "Verwijderen",
"selectAtLeastThreeUsersToStart": "Select at least 3 users to start.",
"hostPhoneMustSelectUser": "The host phone must select at least one user.",
"roomNoLongerInLobby": "The room is no longer in the lobby.",
"completeUserSelectionToStart": "Complete user selection to start.",
"preparingSecureRoom": "Preparing the secure room",
"searchingNearbyBluetoothGames": "Searching nearby games over Bluetooth",
"tapToJoin": "Tap to join",
"bluetoothLocationPermissionsRequired": "Bluetooth and location permissions are required to search for games.",
"bluetoothLocationPermissionsShort": "Bluetooth and location permissions are required",
"couldNotStartSearch": "Could not start the search. Check Bluetooth and location.",
"couldNotConnectToHost": "Could not connect to {host}",
"selectAtLeastThreeUsersToStart": "Selecteer minstens 3 gebruikers om te starten.",
"hostPhoneMustSelectUser": "De host-telefoon moet minstens één gebruiker selecteren.",
"roomNoLongerInLobby": "De ruimte is niet meer in de lobby.",
"completeUserSelectionToStart": "Voltooi de gebruikersselectie om te starten.",
"preparingSecureRoom": "Beveiligde ruimte voorbereiden",
"searchingNearbyBluetoothGames": "Zoeken naar spellen in de buurt via Bluetooth",
"tapToJoin": "Tik om deel te nemen",
"bluetoothLocationPermissionsRequired": "Bluetooth- en locatietoestemming zijn nodig om spellen te zoeken.",
"bluetoothLocationPermissionsShort": "Bluetooth- en locatietoestemming zijn nodig",
"couldNotStartSearch": "Kon het zoeken niet starten. Controleer Bluetooth en locatie.",
"couldNotConnectToHost": "Kon geen verbinding maken met {host}",
"room": "Kamer",
"singleDeviceSubtitle": "Game on this device",
"singleDeviceDescription": "Ideal for playing together by passing the phone around. Fast, direct setup.",
"multiDeviceSubtitle": "Each player on their phone",
"multiDeviceDescription": "Create a premium room, share the QR code and manage users from the lobby.",
"singleDeviceGameLabel": "Game on this device",
"multiDeviceGameLabel": "Multi-device game",
"mainDeviceUser": "Main device user",
"couldNotCreateRoom": "Could not create the room. Check Bluetooth.",
"cannotStartWithReason": "Cannot start: {reason}",
"invalidRoom": "invalid room",
"singleDeviceSubtitle": "Spel op dit toestel",
"singleDeviceDescription": "Ideaal om samen te spelen door de telefoon door te geven. Snel en direct ingesteld.",
"multiDeviceSubtitle": "Elke speler op zijn eigen telefoon",
"multiDeviceDescription": "Maak een premium ruimte, deel de QR-code en beheer gebruikers vanuit de lobby.",
"singleDeviceGameLabel": "Spel op dit toestel",
"multiDeviceGameLabel": "Spel met meerdere toestellen",
"mainDeviceUser": "Hoofdgebruiker van dit toestel",
"couldNotCreateRoom": "Kon de ruimte niet aanmaken. Controleer Bluetooth.",
"cannotStartWithReason": "Kan niet starten: {reason}",
"invalidRoom": "ongeldige ruimte",
"defaultPlayerName": "Speler",
"play": "Spelen",
"history": "Geschiedenis",
@@ -368,5 +368,19 @@
"reconnecting": "Opnieuw verbinden...",
"reconnectingHint": "Verbinding met de host verbroken. Je plek in het spel blijft behouden.",
"leaveGame": "Spel verlaten",
"playerRejoined": "{name} is terug in het spel"
"playerRejoined": "{name} is terug in het spel",
"leaveGameTitle": "Het spel verlaten?",
"leaveGameSingleDevice": "Het lopende spel gaat verloren en kan niet worden hersteld.",
"leaveGameHost": "Jij bent de host: als je weggaat, eindigt het spel voor iedereen.",
"leaveGameClient": "Je verlaat het spel. Je kunt terugkomen zolang de host het openhoudt.",
"stayInGame": "Verder spelen",
"permissionsNeededTitle": "Toestemmingen nodig",
"permissionsNeededBody": "Voor de multiplayermodus hebben we nodig:",
"openAppSettingsQuestion": "De app-instellingen openen?",
"openSettings": "Instellingen openen",
"permissionLocation": "Locatie",
"permissionBluetoothAdvertise": "Bluetooth (zichtbaar maken)",
"permissionBluetoothConnect": "Bluetooth (verbinden)",
"permissionBluetoothScan": "Bluetooth (scannen)",
"permissionNearbyWifi": "Wi-Fi in de buurt"
}
+36 -22
View File
@@ -246,28 +246,28 @@
"release": "Zwolnij",
"select": "Wybierz",
"delete": "Usuń",
"selectAtLeastThreeUsersToStart": "Select at least 3 users to start.",
"hostPhoneMustSelectUser": "The host phone must select at least one user.",
"roomNoLongerInLobby": "The room is no longer in the lobby.",
"completeUserSelectionToStart": "Complete user selection to start.",
"preparingSecureRoom": "Preparing the secure room",
"searchingNearbyBluetoothGames": "Searching nearby games over Bluetooth",
"tapToJoin": "Tap to join",
"bluetoothLocationPermissionsRequired": "Bluetooth and location permissions are required to search for games.",
"bluetoothLocationPermissionsShort": "Bluetooth and location permissions are required",
"couldNotStartSearch": "Could not start the search. Check Bluetooth and location.",
"couldNotConnectToHost": "Could not connect to {host}",
"selectAtLeastThreeUsersToStart": "Wybierz co najmniej 3 użytkowników, aby rozpocząć.",
"hostPhoneMustSelectUser": "Telefon gospodarza musi wybrać przynajmniej jednego użytkownika.",
"roomNoLongerInLobby": "Pokój nie jest już w poczekalni.",
"completeUserSelectionToStart": "Dokończ wybór użytkowników, aby rozpocząć.",
"preparingSecureRoom": "Przygotowywanie bezpiecznego pokoju",
"searchingNearbyBluetoothGames": "Szukanie gier w pobliżu przez Bluetooth",
"tapToJoin": "Dotknij, aby dołączyć",
"bluetoothLocationPermissionsRequired": "Do wyszukiwania gier potrzebne są uprawnienia Bluetooth i lokalizacji.",
"bluetoothLocationPermissionsShort": "Potrzebne są uprawnienia Bluetooth i lokalizacji",
"couldNotStartSearch": "Nie udało się rozpocząć wyszukiwania. Sprawdź Bluetooth i lokalizację.",
"couldNotConnectToHost": "Nie udało się połączyć z {host}",
"room": "Pokój",
"singleDeviceSubtitle": "Game on this device",
"singleDeviceDescription": "Ideal for playing together by passing the phone around. Fast, direct setup.",
"multiDeviceSubtitle": "Each player on their phone",
"multiDeviceDescription": "Create a premium room, share the QR code and manage users from the lobby.",
"singleDeviceGameLabel": "Game on this device",
"multiDeviceGameLabel": "Multi-device game",
"mainDeviceUser": "Main device user",
"couldNotCreateRoom": "Could not create the room. Check Bluetooth.",
"cannotStartWithReason": "Cannot start: {reason}",
"invalidRoom": "invalid room",
"singleDeviceSubtitle": "Gra na tym urządzeniu",
"singleDeviceDescription": "Idealne do wspólnej gry, podając telefon dalej. Szybka i prosta konfiguracja.",
"multiDeviceSubtitle": "Każdy gracz na swoim telefonie",
"multiDeviceDescription": "Utwórz pokój premium, udostępnij kod QR i zarządzaj graczami z poczekalni.",
"singleDeviceGameLabel": "Gra na tym urządzeniu",
"multiDeviceGameLabel": "Gra na wielu urządzeniach",
"mainDeviceUser": "Główny użytkownik urządzenia",
"couldNotCreateRoom": "Nie udało się utworzyć pokoju. Sprawdź Bluetooth.",
"cannotStartWithReason": "Nie można rozpocząć: {reason}",
"invalidRoom": "nieprawidłowy pokój",
"defaultPlayerName": "Gracz",
"play": "Graj",
"history": "Historia",
@@ -368,5 +368,19 @@
"reconnecting": "Ponowne łączenie...",
"reconnectingHint": "Utracono połączenie z gospodarzem. Twoje miejsce w grze jest zachowane.",
"leaveGame": "Opuść grę",
"playerRejoined": "{name} wrócił(a) do gry"
"playerRejoined": "{name} wrócił(a) do gry",
"leaveGameTitle": "Opuścić grę?",
"leaveGameSingleDevice": "Trwająca gra zostanie utracona i nie da się jej odzyskać.",
"leaveGameHost": "Jesteś gospodarzem: jeśli wyjdziesz, gra kończy się dla wszystkich.",
"leaveGameClient": "Opuścisz grę. Możesz wrócić, dopóki gospodarz jej nie zamknie.",
"stayInGame": "Graj dalej",
"permissionsNeededTitle": "Wymagane uprawnienia",
"permissionsNeededBody": "Do trybu wieloosobowego potrzebujemy:",
"openAppSettingsQuestion": "Otworzyć ustawienia aplikacji?",
"openSettings": "Otwórz ustawienia",
"permissionLocation": "Lokalizacja",
"permissionBluetoothAdvertise": "Bluetooth (rozgłaszanie)",
"permissionBluetoothConnect": "Bluetooth (łączenie)",
"permissionBluetoothScan": "Bluetooth (skanowanie)",
"permissionNearbyWifi": "Wi-Fi w pobliżu"
}
+18 -4
View File
@@ -6,7 +6,7 @@
"matchRewards": "Recompensas da partida",
"newMedals": "Novas medalhas",
"noNewMedalsKeepFire": "Sem medalhas novas desta vez. Continua a acumular fogo.",
"calculatingRewards": "Calculando recompensas...",
"calculatingRewards": "A calcular recompensas...",
"fireLabel": "Fogo",
"playersRange": "3-20 jogadores • Sem internet",
"createGame": "Criar partida",
@@ -85,7 +85,7 @@
},
"holdToSeeWord": "Mantenha pressionado para ver sua palavra",
"makeSureNoOneLooks": "Certifique-se de que ninguém mais está olhando",
"showingWord": "👁️ Mostrando...",
"showingWord": "👁️ A mostrar...",
"holdToSee": "👆 Mantenha pressionado para ver",
"seenMyWord": "Já vi minha palavra",
"debateRound": "Debate - Rodada {round}",
@@ -133,7 +133,7 @@
"tapToReveal": "Toque para revelar o resultado",
"revealResult": "Revelar resultado",
"result": "Resultado",
"revealing": "Revelando...",
"revealing": "A revelar...",
"wasImpostor": "Era IMPOSTOR! 🎉",
"wasInnocent": "Era INOCENTE 😱",
"votesThisRound": "Votos desta rodada",
@@ -368,5 +368,19 @@
"reconnecting": "A religar...",
"reconnectingHint": "Perdeu-se a ligação ao anfitrião. O teu lugar no jogo mantém-se.",
"leaveGame": "Sair do jogo",
"playerRejoined": "{name} voltou ao jogo"
"playerRejoined": "{name} voltou ao jogo",
"leaveGameTitle": "Sair do jogo?",
"leaveGameSingleDevice": "O jogo em curso perde-se e não poderá ser recuperado.",
"leaveGameHost": "És o anfitrião: se saíres, o jogo termina para todos os jogadores.",
"leaveGameClient": "Vais sair do jogo. Podes voltar enquanto o anfitrião o mantiver aberto.",
"stayInGame": "Continuar a jogar",
"permissionsNeededTitle": "Permissões necessárias",
"permissionsNeededBody": "Para o modo multijogador precisamos de:",
"openAppSettingsQuestion": "Abrir as definições da aplicação?",
"openSettings": "Abrir definições",
"permissionLocation": "Localização",
"permissionBluetoothAdvertise": "Bluetooth (anunciar)",
"permissionBluetoothConnect": "Bluetooth (ligar)",
"permissionBluetoothScan": "Bluetooth (procurar)",
"permissionNearbyWifi": "Wi-Fi por perto"
}
+36 -22
View File
@@ -246,28 +246,28 @@
"release": "Освободить",
"select": "Выбрать",
"delete": "Удалить",
"selectAtLeastThreeUsersToStart": "Select at least 3 users to start.",
"hostPhoneMustSelectUser": "The host phone must select at least one user.",
"roomNoLongerInLobby": "The room is no longer in the lobby.",
"completeUserSelectionToStart": "Complete user selection to start.",
"preparingSecureRoom": "Preparing the secure room",
"searchingNearbyBluetoothGames": "Searching nearby games over Bluetooth",
"tapToJoin": "Tap to join",
"bluetoothLocationPermissionsRequired": "Bluetooth and location permissions are required to search for games.",
"bluetoothLocationPermissionsShort": "Bluetooth and location permissions are required",
"couldNotStartSearch": "Could not start the search. Check Bluetooth and location.",
"couldNotConnectToHost": "Could not connect to {host}",
"selectAtLeastThreeUsersToStart": "Выберите не менее 3 пользователей, чтобы начать.",
"hostPhoneMustSelectUser": "Телефон ведущего должен выбрать хотя бы одного пользователя.",
"roomNoLongerInLobby": "Комната больше не в лобби.",
"completeUserSelectionToStart": "Завершите выбор пользователей, чтобы начать.",
"preparingSecureRoom": "Подготовка защищённой комнаты",
"searchingNearbyBluetoothGames": "Поиск игр поблизости через Bluetooth",
"tapToJoin": "Нажмите, чтобы присоединиться",
"bluetoothLocationPermissionsRequired": "Для поиска игр нужны разрешения Bluetooth и геолокации.",
"bluetoothLocationPermissionsShort": "Нужны разрешения Bluetooth и геолокации",
"couldNotStartSearch": "Не удалось начать поиск. Проверьте Bluetooth и геолокацию.",
"couldNotConnectToHost": "Не удалось подключиться к {host}",
"room": "Комната",
"singleDeviceSubtitle": "Game on this device",
"singleDeviceDescription": "Ideal for playing together by passing the phone around. Fast, direct setup.",
"multiDeviceSubtitle": "Each player on their phone",
"multiDeviceDescription": "Create a premium room, share the QR code and manage users from the lobby.",
"singleDeviceGameLabel": "Game on this device",
"multiDeviceGameLabel": "Multi-device game",
"mainDeviceUser": "Main device user",
"couldNotCreateRoom": "Could not create the room. Check Bluetooth.",
"cannotStartWithReason": "Cannot start: {reason}",
"invalidRoom": "invalid room",
"singleDeviceSubtitle": "Игра на этом устройстве",
"singleDeviceDescription": "Идеально, чтобы играть вместе, передавая телефон. Быстрая и простая настройка.",
"multiDeviceSubtitle": "Каждый игрок на своём телефоне",
"multiDeviceDescription": "Создайте премиум-комнату, поделитесь QR-кодом и управляйте игроками из лобби.",
"singleDeviceGameLabel": "Игра на этом устройстве",
"multiDeviceGameLabel": "Игра на нескольких устройствах",
"mainDeviceUser": "Основной пользователь устройства",
"couldNotCreateRoom": "Не удалось создать комнату. Проверьте Bluetooth.",
"cannotStartWithReason": "Невозможно начать: {reason}",
"invalidRoom": "недопустимая комната",
"defaultPlayerName": "Игрок",
"play": "Играть",
"history": "История",
@@ -368,5 +368,19 @@
"reconnecting": "Переподключение...",
"reconnectingHint": "Соединение с ведущим потеряно. Ваше место в игре сохраняется.",
"leaveGame": "Выйти из игры",
"playerRejoined": "{name} вернулся в игру"
"playerRejoined": "{name} вернулся в игру",
"leaveGameTitle": "Выйти из игры?",
"leaveGameSingleDevice": "Текущая партия будет потеряна без возможности восстановления.",
"leaveGameHost": "Вы ведущий: если вы выйдете, игра закончится для всех.",
"leaveGameClient": "Вы выйдете из игры. Вы сможете вернуться, пока ведущий её не закрыл.",
"stayInGame": "Продолжить игру",
"permissionsNeededTitle": "Нужны разрешения",
"permissionsNeededBody": "Для многопользовательского режима нужны:",
"openAppSettingsQuestion": "Открыть настройки приложения?",
"openSettings": "Открыть настройки",
"permissionLocation": "Геолокация",
"permissionBluetoothAdvertise": "Bluetooth (объявление)",
"permissionBluetoothConnect": "Bluetooth (подключение)",
"permissionBluetoothScan": "Bluetooth (сканирование)",
"permissionNearbyWifi": "Wi-Fi поблизости"
}
+36 -22
View File
@@ -246,28 +246,28 @@
"release": "Bırak",
"select": "Seç",
"delete": "Sil",
"selectAtLeastThreeUsersToStart": "Select at least 3 users to start.",
"hostPhoneMustSelectUser": "The host phone must select at least one user.",
"roomNoLongerInLobby": "The room is no longer in the lobby.",
"completeUserSelectionToStart": "Complete user selection to start.",
"preparingSecureRoom": "Preparing the secure room",
"searchingNearbyBluetoothGames": "Searching nearby games over Bluetooth",
"tapToJoin": "Tap to join",
"bluetoothLocationPermissionsRequired": "Bluetooth and location permissions are required to search for games.",
"bluetoothLocationPermissionsShort": "Bluetooth and location permissions are required",
"couldNotStartSearch": "Could not start the search. Check Bluetooth and location.",
"couldNotConnectToHost": "Could not connect to {host}",
"selectAtLeastThreeUsersToStart": "Başlamak için en az 3 kullanıcı seç.",
"hostPhoneMustSelectUser": "Sunucu telefonu en az bir kullanıcı seçmeli.",
"roomNoLongerInLobby": "Oda artık lobide değil.",
"completeUserSelectionToStart": "Başlamak için kullanıcı seçimini tamamla.",
"preparingSecureRoom": "Güvenli oda hazırlanıyor",
"searchingNearbyBluetoothGames": "Bluetooth ile yakındaki oyunlar aranıyor",
"tapToJoin": "Katılmak için dokun",
"bluetoothLocationPermissionsRequired": "Oyun aramak için Bluetooth ve konum izinleri gerekli.",
"bluetoothLocationPermissionsShort": "Bluetooth ve konum izinleri gerekli",
"couldNotStartSearch": "Arama başlatılamadı. Bluetooth ve konumu kontrol et.",
"couldNotConnectToHost": "{host} bağlantısı kurulamadı",
"room": "Oda",
"singleDeviceSubtitle": "Game on this device",
"singleDeviceDescription": "Ideal for playing together by passing the phone around. Fast, direct setup.",
"multiDeviceSubtitle": "Each player on their phone",
"multiDeviceDescription": "Create a premium room, share the QR code and manage users from the lobby.",
"singleDeviceGameLabel": "Game on this device",
"multiDeviceGameLabel": "Multi-device game",
"mainDeviceUser": "Main device user",
"couldNotCreateRoom": "Could not create the room. Check Bluetooth.",
"cannotStartWithReason": "Cannot start: {reason}",
"invalidRoom": "invalid room",
"singleDeviceSubtitle": "Bu cihazda oyun",
"singleDeviceDescription": "Telefonu elden ele dolaştırarak birlikte oynamak için ideal. Hızlı ve doğrudan kurulum.",
"multiDeviceSubtitle": "Her oyuncu kendi telefonunda",
"multiDeviceDescription": "Premium bir oda oluştur, QR kodu paylaş ve kullanıcıları lobiden yönet.",
"singleDeviceGameLabel": "Bu cihazda oyun",
"multiDeviceGameLabel": "Çok cihazlı oyun",
"mainDeviceUser": "Cihazın ana kullanıcısı",
"couldNotCreateRoom": "Oda oluşturulamadı. Bluetooth'u kontrol et.",
"cannotStartWithReason": "Başlatılamıyor: {reason}",
"invalidRoom": "geçersiz oda",
"defaultPlayerName": "Oyuncu",
"play": "Oyna",
"history": "Geçmiş",
@@ -368,5 +368,19 @@
"reconnecting": "Yeniden bağlanılıyor...",
"reconnectingHint": "Sunucuyla bağlantı koptu. Oyundaki yerin korunuyor.",
"leaveGame": "Oyundan ayrıl",
"playerRejoined": "{name} oyuna geri döndü"
"playerRejoined": "{name} oyuna geri döndü",
"leaveGameTitle": "Oyundan çıkılsın mı?",
"leaveGameSingleDevice": "Devam eden oyun kaybolur ve geri getirilemez.",
"leaveGameHost": "Sunucu sensin: çıkarsan oyun herkes için biter.",
"leaveGameClient": "Oyundan çıkacaksın. Sunucu odayı açık tuttuğu sürece geri dönebilirsin.",
"stayInGame": "Oynamaya devam et",
"permissionsNeededTitle": "Gerekli izinler",
"permissionsNeededBody": "Çok oyunculu mod için şunlar gerekli:",
"openAppSettingsQuestion": "Uygulama ayarları açılsın mı?",
"openSettings": "Ayarları aç",
"permissionLocation": "Konum",
"permissionBluetoothAdvertise": "Bluetooth (yayın)",
"permissionBluetoothConnect": "Bluetooth (bağlanma)",
"permissionBluetoothScan": "Bluetooth (tarama)",
"permissionNearbyWifi": "Yakındaki Wi-Fi"
}
+36 -22
View File
@@ -246,28 +246,28 @@
"release": "释放",
"select": "选择",
"delete": "删除",
"selectAtLeastThreeUsersToStart": "Select at least 3 users to start.",
"hostPhoneMustSelectUser": "The host phone must select at least one user.",
"roomNoLongerInLobby": "The room is no longer in the lobby.",
"completeUserSelectionToStart": "Complete user selection to start.",
"preparingSecureRoom": "Preparing the secure room",
"searchingNearbyBluetoothGames": "Searching nearby games over Bluetooth",
"tapToJoin": "Tap to join",
"bluetoothLocationPermissionsRequired": "Bluetooth and location permissions are required to search for games.",
"bluetoothLocationPermissionsShort": "Bluetooth and location permissions are required",
"couldNotStartSearch": "Could not start the search. Check Bluetooth and location.",
"couldNotConnectToHost": "Could not connect to {host}",
"selectAtLeastThreeUsersToStart": "至少选择 3 名用户才能开始。",
"hostPhoneMustSelectUser": "房主的手机必须至少选择一名用户。",
"roomNoLongerInLobby": "房间已不在等候大厅。",
"completeUserSelectionToStart": "完成用户选择后才能开始。",
"preparingSecureRoom": "正在准备安全房间",
"searchingNearbyBluetoothGames": "正在通过蓝牙搜索附近的游戏",
"tapToJoin": "点击加入",
"bluetoothLocationPermissionsRequired": "搜索游戏需要蓝牙和定位权限。",
"bluetoothLocationPermissionsShort": "需要蓝牙和定位权限",
"couldNotStartSearch": "无法开始搜索。请检查蓝牙和定位。",
"couldNotConnectToHost": "无法连接到 {host}",
"room": "房间",
"singleDeviceSubtitle": "Game on this device",
"singleDeviceDescription": "Ideal for playing together by passing the phone around. Fast, direct setup.",
"multiDeviceSubtitle": "Each player on their phone",
"multiDeviceDescription": "Create a premium room, share the QR code and manage users from the lobby.",
"singleDeviceGameLabel": "Game on this device",
"multiDeviceGameLabel": "Multi-device game",
"mainDeviceUser": "Main device user",
"couldNotCreateRoom": "Could not create the room. Check Bluetooth.",
"cannotStartWithReason": "Cannot start: {reason}",
"invalidRoom": "invalid room",
"singleDeviceSubtitle": "在这台设备上游戏",
"singleDeviceDescription": "适合大家传着手机一起玩。设置快速直接。",
"multiDeviceSubtitle": "每位玩家用自己的手机",
"multiDeviceDescription": "创建高级房间,分享二维码,并在大厅管理用户。",
"singleDeviceGameLabel": "本机游戏",
"multiDeviceGameLabel": "多设备游戏",
"mainDeviceUser": "本机主用户",
"couldNotCreateRoom": "无法创建房间。请检查蓝牙。",
"cannotStartWithReason": "无法开始:{reason}",
"invalidRoom": "无效的房间",
"defaultPlayerName": "玩家",
"play": "开始",
"history": "历史",
@@ -368,5 +368,19 @@
"reconnecting": "正在重新连接…",
"reconnectingHint": "与房主的连接已断开。你在游戏中的位置仍为你保留。",
"leaveGame": "退出游戏",
"playerRejoined": "{name} 已重新加入游戏"
"playerRejoined": "{name} 已重新加入游戏",
"leaveGameTitle": "要退出游戏吗?",
"leaveGameSingleDevice": "正在进行的游戏将会丢失,且无法恢复。",
"leaveGameHost": "你是房主:一旦退出,所有玩家的游戏都会结束。",
"leaveGameClient": "你将退出这局游戏。只要房主还开着,你随时可以回来。",
"stayInGame": "继续游戏",
"permissionsNeededTitle": "需要权限",
"permissionsNeededBody": "多人游戏模式需要以下权限:",
"openAppSettingsQuestion": "要打开应用设置吗?",
"openSettings": "打开设置",
"permissionLocation": "定位",
"permissionBluetoothAdvertise": "蓝牙(广播)",
"permissionBluetoothConnect": "蓝牙(连接)",
"permissionBluetoothScan": "蓝牙(扫描)",
"permissionNearbyWifi": "附近的 Wi-Fi"
}
+36 -22
View File
@@ -246,28 +246,28 @@
"release": "释放",
"select": "选择",
"delete": "删除",
"selectAtLeastThreeUsersToStart": "Select at least 3 users to start.",
"hostPhoneMustSelectUser": "The host phone must select at least one user.",
"roomNoLongerInLobby": "The room is no longer in the lobby.",
"completeUserSelectionToStart": "Complete user selection to start.",
"preparingSecureRoom": "Preparing the secure room",
"searchingNearbyBluetoothGames": "Searching nearby games over Bluetooth",
"tapToJoin": "Tap to join",
"bluetoothLocationPermissionsRequired": "Bluetooth and location permissions are required to search for games.",
"bluetoothLocationPermissionsShort": "Bluetooth and location permissions are required",
"couldNotStartSearch": "Could not start the search. Check Bluetooth and location.",
"couldNotConnectToHost": "Could not connect to {host}",
"selectAtLeastThreeUsersToStart": "至少選擇 3 名使用者才能開始。",
"hostPhoneMustSelectUser": "房主的手機必須至少選擇一名使用者。",
"roomNoLongerInLobby": "房間已不在等候大廳。",
"completeUserSelectionToStart": "完成使用者選擇後才能開始。",
"preparingSecureRoom": "正在準備安全房間",
"searchingNearbyBluetoothGames": "正在透過藍牙搜尋附近的遊戲",
"tapToJoin": "點擊加入",
"bluetoothLocationPermissionsRequired": "搜尋遊戲需要藍牙和定位權限。",
"bluetoothLocationPermissionsShort": "需要藍牙和定位權限",
"couldNotStartSearch": "無法開始搜尋。請檢查藍牙和定位。",
"couldNotConnectToHost": "無法連線到 {host}",
"room": "房间",
"singleDeviceSubtitle": "Game on this device",
"singleDeviceDescription": "Ideal for playing together by passing the phone around. Fast, direct setup.",
"multiDeviceSubtitle": "Each player on their phone",
"multiDeviceDescription": "Create a premium room, share the QR code and manage users from the lobby.",
"singleDeviceGameLabel": "Game on this device",
"multiDeviceGameLabel": "Multi-device game",
"mainDeviceUser": "Main device user",
"couldNotCreateRoom": "Could not create the room. Check Bluetooth.",
"cannotStartWithReason": "Cannot start: {reason}",
"invalidRoom": "invalid room",
"singleDeviceSubtitle": "在這台裝置上遊戲",
"singleDeviceDescription": "適合大家傳著手機一起玩。設定快速直接。",
"multiDeviceSubtitle": "每位玩家用自己的手機",
"multiDeviceDescription": "建立高級房間,分享 QR Code,並在大廳管理使用者。",
"singleDeviceGameLabel": "本機遊戲",
"multiDeviceGameLabel": "多裝置遊戲",
"mainDeviceUser": "本機主要使用者",
"couldNotCreateRoom": "無法建立房間。請檢查藍牙。",
"cannotStartWithReason": "無法開始:{reason}",
"invalidRoom": "無效的房間",
"defaultPlayerName": "玩家",
"play": "開始",
"history": "紀錄",
@@ -368,5 +368,19 @@
"reconnecting": "正在重新連線…",
"reconnectingHint": "與房主的連線已中斷。你在遊戲中的位置仍為你保留。",
"leaveGame": "退出遊戲",
"playerRejoined": "{name} 已重新加入遊戲"
"playerRejoined": "{name} 已重新加入遊戲",
"leaveGameTitle": "要退出遊戲嗎?",
"leaveGameSingleDevice": "正在進行的遊戲將會遺失,且無法復原。",
"leaveGameHost": "你是房主:一旦退出,所有玩家的遊戲都會結束。",
"leaveGameClient": "你將退出這局遊戲。只要房主還開著,你隨時可以回來。",
"stayInGame": "繼續遊戲",
"permissionsNeededTitle": "需要權限",
"permissionsNeededBody": "多人遊戲模式需要以下權限:",
"openAppSettingsQuestion": "要開啟應用程式設定嗎?",
"openSettings": "開啟設定",
"permissionLocation": "定位",
"permissionBluetoothAdvertise": "藍牙(廣播)",
"permissionBluetoothConnect": "藍牙(連線)",
"permissionBluetoothScan": "藍牙(掃描)",
"permissionNearbyWifi": "附近的 Wi-Fi"
}
+84
View File
@@ -1634,6 +1634,90 @@ abstract class AppLocalizations {
/// In es, this message translates to:
/// **'{name} ha vuelto a la partida'**
String playerRejoined(String name);
/// No description provided for @leaveGameTitle.
///
/// In es, this message translates to:
/// **'¿Salir de la partida?'**
String get leaveGameTitle;
/// No description provided for @leaveGameSingleDevice.
///
/// In es, this message translates to:
/// **'Se perderá la partida en curso y no podrás recuperarla.'**
String get leaveGameSingleDevice;
/// No description provided for @leaveGameHost.
///
/// In es, this message translates to:
/// **'Eres el anfitrión: si sales, la partida termina para todos los jugadores.'**
String get leaveGameHost;
/// No description provided for @leaveGameClient.
///
/// In es, this message translates to:
/// **'Saldrás de la partida. Podrás volver mientras el anfitrión la mantenga abierta.'**
String get leaveGameClient;
/// No description provided for @stayInGame.
///
/// In es, this message translates to:
/// **'Seguir jugando'**
String get stayInGame;
/// No description provided for @permissionsNeededTitle.
///
/// In es, this message translates to:
/// **'Permisos necesarios'**
String get permissionsNeededTitle;
/// No description provided for @permissionsNeededBody.
///
/// In es, this message translates to:
/// **'Para el modo multijugador necesitamos:'**
String get permissionsNeededBody;
/// No description provided for @openAppSettingsQuestion.
///
/// In es, this message translates to:
/// **'¿Abrir la configuración de la app?'**
String get openAppSettingsQuestion;
/// No description provided for @openSettings.
///
/// In es, this message translates to:
/// **'Abrir configuración'**
String get openSettings;
/// No description provided for @permissionLocation.
///
/// In es, this message translates to:
/// **'Ubicación'**
String get permissionLocation;
/// No description provided for @permissionBluetoothAdvertise.
///
/// In es, this message translates to:
/// **'Bluetooth (anunciar)'**
String get permissionBluetoothAdvertise;
/// No description provided for @permissionBluetoothConnect.
///
/// In es, this message translates to:
/// **'Bluetooth (conectar)'**
String get permissionBluetoothConnect;
/// No description provided for @permissionBluetoothScan.
///
/// In es, this message translates to:
/// **'Bluetooth (escanear)'**
String get permissionBluetoothScan;
/// No description provided for @permissionNearbyWifi.
///
/// In es, this message translates to:
/// **'Wi-Fi cercano'**
String get permissionNearbyWifi;
}
class _AppLocalizationsDelegate
+66 -24
View File
@@ -647,83 +647,80 @@ class AppLocalizationsAr extends AppLocalizations {
@override
String get selectAtLeastThreeUsersToStart =>
'Select at least 3 users to start.';
'اختر 3 مستخدمين على الأقل للبدء.';
@override
String get hostPhoneMustSelectUser =>
'The host phone must select at least one user.';
'يجب أن يختار هاتف المضيف مستخدمًا واحدًا على الأقل.';
@override
String get roomNoLongerInLobby => 'The room is no longer in the lobby.';
String get roomNoLongerInLobby => 'لم تعد الغرفة في ردهة الانتظار.';
@override
String get completeUserSelectionToStart =>
'Complete user selection to start.';
String get completeUserSelectionToStart => 'أكمل اختيار المستخدمين للبدء.';
@override
String get preparingSecureRoom => 'Preparing the secure room';
String get preparingSecureRoom => 'جارٍ تجهيز الغرفة الآمنة';
@override
String get searchingNearbyBluetoothGames =>
'Searching nearby games over Bluetooth';
'البحث عن جولات قريبة عبر البلوتوث';
@override
String get tapToJoin => 'Tap to join';
String get tapToJoin => 'اضغط للانضمام';
@override
String get bluetoothLocationPermissionsRequired =>
'Bluetooth and location permissions are required to search for games.';
'يلزم إذنا البلوتوث والموقع للبحث عن جولات.';
@override
String get bluetoothLocationPermissionsShort =>
'Bluetooth and location permissions are required';
String get bluetoothLocationPermissionsShort => 'يلزم إذنا البلوتوث والموقع';
@override
String get couldNotStartSearch =>
'Could not start the search. Check Bluetooth and location.';
'تعذّر بدء البحث. تحقق من البلوتوث والموقع.';
@override
String couldNotConnectToHost(String host) {
return 'Could not connect to $host';
return 'تعذّر الاتصال بـ $host';
}
@override
String get room => 'غرفة';
@override
String get singleDeviceSubtitle => 'Game on this device';
String get singleDeviceSubtitle => 'اللعب على هذا الجهاز';
@override
String get singleDeviceDescription =>
'Ideal for playing together by passing the phone around. Fast, direct setup.';
'مثالي للعب معًا بتمرير الهاتف. إعداد سريع ومباشر.';
@override
String get multiDeviceSubtitle => 'Each player on their phone';
String get multiDeviceSubtitle => 'كل لاعب على هاتفه';
@override
String get multiDeviceDescription =>
'Create a premium room, share the QR code and manage users from the lobby.';
'أنشئ غرفة مميزة، وشارك رمز QR، وأدر المستخدمين من ردهة الانتظار.';
@override
String get singleDeviceGameLabel => 'Game on this device';
String get singleDeviceGameLabel => 'اللعب على هذا الجهاز';
@override
String get multiDeviceGameLabel => 'Multi-device game';
String get multiDeviceGameLabel => 'لعب متعدد الأجهزة';
@override
String get mainDeviceUser => 'Main device user';
String get mainDeviceUser => 'المستخدم الرئيسي للجهاز';
@override
String get couldNotCreateRoom =>
'Could not create the room. Check Bluetooth.';
String get couldNotCreateRoom => 'تعذّر إنشاء الغرفة. تحقق من البلوتوث.';
@override
String cannotStartWithReason(String reason) {
return 'Cannot start: $reason';
return 'تعذّر البدء: $reason';
}
@override
String get invalidRoom => 'invalid room';
String get invalidRoom => 'غرفة غير صالحة';
@override
String get defaultPlayerName => 'لاعب';
@@ -834,4 +831,49 @@ class AppLocalizationsAr extends AppLocalizations {
String playerRejoined(String name) {
return 'عاد $name إلى الجولة';
}
@override
String get leaveGameTitle => 'هل تريد مغادرة الجولة؟';
@override
String get leaveGameSingleDevice =>
'ستفقد الجولة الجارية ولن يمكن استعادتها.';
@override
String get leaveGameHost =>
'أنت المضيف: إذا غادرت ستنتهي الجولة لجميع اللاعبين.';
@override
String get leaveGameClient =>
'ستغادر الجولة. يمكنك العودة ما دام المضيف يبقيها مفتوحة.';
@override
String get stayInGame => 'متابعة اللعب';
@override
String get permissionsNeededTitle => 'أذونات مطلوبة';
@override
String get permissionsNeededBody => 'لوضع اللعب الجماعي نحتاج إلى:';
@override
String get openAppSettingsQuestion => 'هل تريد فتح إعدادات التطبيق؟';
@override
String get openSettings => 'فتح الإعدادات';
@override
String get permissionLocation => 'الموقع';
@override
String get permissionBluetoothAdvertise => 'بلوتوث (الإعلان)';
@override
String get permissionBluetoothConnect => 'بلوتوث (الاتصال)';
@override
String get permissionBluetoothScan => 'بلوتوث (المسح)';
@override
String get permissionNearbyWifi => 'واي فاي قريب';
}
@@ -844,4 +844,50 @@ class AppLocalizationsCa extends AppLocalizations {
String playerRejoined(String name) {
return '$name ha tornat a la partida';
}
@override
String get leaveGameTitle => 'Vols sortir de la partida?';
@override
String get leaveGameSingleDevice =>
'Es perdrà la partida en curs i no la podràs recuperar.';
@override
String get leaveGameHost =>
'Ets l\'amfitrió: si surts, la partida s\'acaba per a tots els jugadors.';
@override
String get leaveGameClient =>
'Sortiràs de la partida. Hi podràs tornar mentre l\'amfitrió la mantingui oberta.';
@override
String get stayInGame => 'Continuar jugant';
@override
String get permissionsNeededTitle => 'Permisos necessaris';
@override
String get permissionsNeededBody => 'Per al mode multijugador necessitem:';
@override
String get openAppSettingsQuestion =>
'Vols obrir la configuració de l\'aplicació?';
@override
String get openSettings => 'Obrir configuració';
@override
String get permissionLocation => 'Ubicació';
@override
String get permissionBluetoothAdvertise => 'Bluetooth (anunciar)';
@override
String get permissionBluetoothConnect => 'Bluetooth (connectar)';
@override
String get permissionBluetoothScan => 'Bluetooth (escanejar)';
@override
String get permissionNearbyWifi => 'Wi-Fi proper';
}
@@ -847,4 +847,49 @@ class AppLocalizationsDe extends AppLocalizations {
String playerRejoined(String name) {
return '$name ist zurück im Spiel';
}
@override
String get leaveGameTitle => 'Spiel wirklich verlassen?';
@override
String get leaveGameSingleDevice =>
'Das laufende Spiel geht verloren und lässt sich nicht wiederherstellen.';
@override
String get leaveGameHost =>
'Du bist der Host: Wenn du gehst, endet das Spiel für alle.';
@override
String get leaveGameClient =>
'Du verlässt das Spiel. Du kannst zurückkommen, solange der Host es offen hält.';
@override
String get stayInGame => 'Weiterspielen';
@override
String get permissionsNeededTitle => 'Berechtigungen erforderlich';
@override
String get permissionsNeededBody => 'Für den Mehrspielermodus brauchen wir:';
@override
String get openAppSettingsQuestion => 'Die App-Einstellungen öffnen?';
@override
String get openSettings => 'Einstellungen öffnen';
@override
String get permissionLocation => 'Standort';
@override
String get permissionBluetoothAdvertise => 'Bluetooth (sichtbar machen)';
@override
String get permissionBluetoothConnect => 'Bluetooth (verbinden)';
@override
String get permissionBluetoothScan => 'Bluetooth (suchen)';
@override
String get permissionNearbyWifi => 'Wi-Fi in der Nähe';
}
@@ -840,4 +840,49 @@ class AppLocalizationsEn extends AppLocalizations {
String playerRejoined(String name) {
return '$name has rejoined the game';
}
@override
String get leaveGameTitle => 'Leave the game?';
@override
String get leaveGameSingleDevice =>
'The game in progress will be lost and cannot be recovered.';
@override
String get leaveGameHost =>
'You are the host: if you leave, the game ends for everyone.';
@override
String get leaveGameClient =>
'You will leave the game. You can rejoin while the host keeps it open.';
@override
String get stayInGame => 'Keep playing';
@override
String get permissionsNeededTitle => 'Permissions needed';
@override
String get permissionsNeededBody => 'For multiplayer mode we need:';
@override
String get openAppSettingsQuestion => 'Open the app settings?';
@override
String get openSettings => 'Open settings';
@override
String get permissionLocation => 'Location';
@override
String get permissionBluetoothAdvertise => 'Bluetooth (advertise)';
@override
String get permissionBluetoothConnect => 'Bluetooth (connect)';
@override
String get permissionBluetoothScan => 'Bluetooth (scan)';
@override
String get permissionNearbyWifi => 'Nearby Wi-Fi';
}
@@ -841,4 +841,49 @@ class AppLocalizationsEs extends AppLocalizations {
String playerRejoined(String name) {
return '$name ha vuelto a la partida';
}
@override
String get leaveGameTitle => '¿Salir de la partida?';
@override
String get leaveGameSingleDevice =>
'Se perderá la partida en curso y no podrás recuperarla.';
@override
String get leaveGameHost =>
'Eres el anfitrión: si sales, la partida termina para todos los jugadores.';
@override
String get leaveGameClient =>
'Saldrás de la partida. Podrás volver mientras el anfitrión la mantenga abierta.';
@override
String get stayInGame => 'Seguir jugando';
@override
String get permissionsNeededTitle => 'Permisos necesarios';
@override
String get permissionsNeededBody => 'Para el modo multijugador necesitamos:';
@override
String get openAppSettingsQuestion => '¿Abrir la configuración de la app?';
@override
String get openSettings => 'Abrir configuración';
@override
String get permissionLocation => 'Ubicación';
@override
String get permissionBluetoothAdvertise => 'Bluetooth (anunciar)';
@override
String get permissionBluetoothConnect => 'Bluetooth (conectar)';
@override
String get permissionBluetoothScan => 'Bluetooth (escanear)';
@override
String get permissionNearbyWifi => 'Wi-Fi cercano';
}
+68 -21
View File
@@ -657,83 +657,83 @@ class AppLocalizationsEu extends AppLocalizations {
@override
String get selectAtLeastThreeUsersToStart =>
'Select at least 3 users to start.';
'Hautatu gutxienez 3 erabiltzaile hasteko.';
@override
String get hostPhoneMustSelectUser =>
'The host phone must select at least one user.';
'Ostalariaren mugikorrak gutxienez erabiltzaile bat hautatu behar du.';
@override
String get roomNoLongerInLobby => 'The room is no longer in the lobby.';
String get roomNoLongerInLobby => 'Gela jada ez dago lobbyan.';
@override
String get completeUserSelectionToStart =>
'Complete user selection to start.';
'Osatu erabiltzaileen hautaketa hasteko.';
@override
String get preparingSecureRoom => 'Preparing the secure room';
String get preparingSecureRoom => 'Gela segurua prestatzen';
@override
String get searchingNearbyBluetoothGames =>
'Searching nearby games over Bluetooth';
'Inguruko partidak bilatzen Bluetooth bidez';
@override
String get tapToJoin => 'Tap to join';
String get tapToJoin => 'Sakatu batzeko';
@override
String get bluetoothLocationPermissionsRequired =>
'Bluetooth and location permissions are required to search for games.';
'Bluetooth eta kokapen baimenak behar dira partidak bilatzeko.';
@override
String get bluetoothLocationPermissionsShort =>
'Bluetooth and location permissions are required';
'Bluetooth eta kokapen baimenak behar dira';
@override
String get couldNotStartSearch =>
'Could not start the search. Check Bluetooth and location.';
'Ezin izan da bilaketa hasi. Egiaztatu Bluetooth eta kokapena.';
@override
String couldNotConnectToHost(String host) {
return 'Could not connect to $host';
return 'Ezin izan da $host(e)ra konektatu';
}
@override
String get room => 'Gela';
@override
String get singleDeviceSubtitle => 'Game on this device';
String get singleDeviceSubtitle => 'Partida gailu honetan';
@override
String get singleDeviceDescription =>
'Ideal for playing together by passing the phone around. Fast, direct setup.';
'Ezin hobea denok elkarrekin jokatzeko mugikorra pasatuz. Konfigurazio azkarra eta zuzena.';
@override
String get multiDeviceSubtitle => 'Each player on their phone';
String get multiDeviceSubtitle => 'Jokalari bakoitza bere mugikorrean';
@override
String get multiDeviceDescription =>
'Create a premium room, share the QR code and manage users from the lobby.';
'Sortu gela premium bat, partekatu QR kodea eta kudeatu erabiltzaileak lobbytik.';
@override
String get singleDeviceGameLabel => 'Game on this device';
String get singleDeviceGameLabel => 'Partida gailu honetan';
@override
String get multiDeviceGameLabel => 'Multi-device game';
String get multiDeviceGameLabel => 'Gailu anitzeko partida';
@override
String get mainDeviceUser => 'Main device user';
String get mainDeviceUser => 'Gailuaren erabiltzaile nagusia';
@override
String get couldNotCreateRoom =>
'Could not create the room. Check Bluetooth.';
'Ezin izan da gela sortu. Egiaztatu Bluetooth.';
@override
String cannotStartWithReason(String reason) {
return 'Cannot start: $reason';
return 'Ezin da hasi: $reason';
}
@override
String get invalidRoom => 'invalid room';
String get invalidRoom => 'gela baliogabea';
@override
String get defaultPlayerName => 'Jokalaria';
@@ -847,4 +847,51 @@ class AppLocalizationsEu extends AppLocalizations {
String playerRejoined(String name) {
return '$name partidara itzuli da';
}
@override
String get leaveGameTitle => 'Partidatik irten nahi duzu?';
@override
String get leaveGameSingleDevice =>
'Abian den partida galduko da eta ezin izango duzu berreskuratu.';
@override
String get leaveGameHost =>
'Zu zara ostalaria: irtenez gero, partida jokalari guztientzat amaituko da.';
@override
String get leaveGameClient =>
'Partidatik aterako zara. Itzuli ahal izango zara ostalariak zabalik mantentzen duen bitartean.';
@override
String get stayInGame => 'Jokatzen jarraitu';
@override
String get permissionsNeededTitle => 'Baimenak behar dira';
@override
String get permissionsNeededBody =>
'Jokalari anitzeko modurako hau behar dugu:';
@override
String get openAppSettingsQuestion =>
'Aplikazioaren ezarpenak ireki nahi dituzu?';
@override
String get openSettings => 'Ireki ezarpenak';
@override
String get permissionLocation => 'Kokapena';
@override
String get permissionBluetoothAdvertise => 'Bluetooth (iragarri)';
@override
String get permissionBluetoothConnect => 'Bluetooth (konektatu)';
@override
String get permissionBluetoothScan => 'Bluetooth (eskaneatu)';
@override
String get permissionNearbyWifi => 'Inguruko Wi-Fi';
}
@@ -844,4 +844,51 @@ class AppLocalizationsFr extends AppLocalizations {
String playerRejoined(String name) {
return '$name a rejoint la partie';
}
@override
String get leaveGameTitle => 'Quitter la partie ?';
@override
String get leaveGameSingleDevice =>
'La partie en cours sera perdue et ne pourra pas être récupérée.';
@override
String get leaveGameHost =>
'Vous êtes l\'hôte : si vous partez, la partie se termine pour tout le monde.';
@override
String get leaveGameClient =>
'Vous quitterez la partie. Vous pourrez revenir tant que l\'hôte la laisse ouverte.';
@override
String get stayInGame => 'Continuer à jouer';
@override
String get permissionsNeededTitle => 'Autorisations nécessaires';
@override
String get permissionsNeededBody =>
'Pour le mode multijoueur, nous avons besoin de :';
@override
String get openAppSettingsQuestion =>
'Ouvrir les paramètres de l\'application ?';
@override
String get openSettings => 'Ouvrir les paramètres';
@override
String get permissionLocation => 'Localisation';
@override
String get permissionBluetoothAdvertise => 'Bluetooth (diffusion)';
@override
String get permissionBluetoothConnect => 'Bluetooth (connexion)';
@override
String get permissionBluetoothScan => 'Bluetooth (recherche)';
@override
String get permissionNearbyWifi => 'Wi-Fi à proximité';
}
+66 -22
View File
@@ -651,83 +651,82 @@ class AppLocalizationsHi extends AppLocalizations {
@override
String get selectAtLeastThreeUsersToStart =>
'Select at least 3 users to start.';
'शुरू करने के लिए कम से कम 3 उपयोगकर्ता चुनें।';
@override
String get hostPhoneMustSelectUser =>
'The host phone must select at least one user.';
'होस्ट फ़ोन को कम से कम एक उपयोगकर्ता चुनना होगा।';
@override
String get roomNoLongerInLobby => 'The room is no longer in the lobby.';
String get roomNoLongerInLobby => 'कमरा अब लॉबी में नहीं है।';
@override
String get completeUserSelectionToStart =>
'Complete user selection to start.';
'शुरू करने के लिए उपयोगकर्ताओं का चयन पूरा करें।';
@override
String get preparingSecureRoom => 'Preparing the secure room';
String get preparingSecureRoom => 'सुरक्षित कमरा तैयार किया जा रहा है';
@override
String get searchingNearbyBluetoothGames =>
'Searching nearby games over Bluetooth';
'ब्लूटूथ से आस-पास के गेम खोजे जा रहे हैं';
@override
String get tapToJoin => 'Tap to join';
String get tapToJoin => 'शामिल होने के लिए टैप करें';
@override
String get bluetoothLocationPermissionsRequired =>
'Bluetooth and location permissions are required to search for games.';
'गेम खोजने के लिए ब्लूटूथ और लोकेशन की अनुमति चाहिए।';
@override
String get bluetoothLocationPermissionsShort =>
'Bluetooth and location permissions are required';
'ब्लूटूथ और लोकेशन की अनुमति चाहिए';
@override
String get couldNotStartSearch =>
'Could not start the search. Check Bluetooth and location.';
'खोज शुरू नहीं हो सकी। ब्लूटूथ और लोकेशन जाँचें।';
@override
String couldNotConnectToHost(String host) {
return 'Could not connect to $host';
return '$host से कनेक्ट नहीं हो सका';
}
@override
String get room => 'कक्ष';
@override
String get singleDeviceSubtitle => 'Game on this device';
String get singleDeviceSubtitle => 'इसी डिवाइस पर खेल';
@override
String get singleDeviceDescription =>
'Ideal for playing together by passing the phone around. Fast, direct setup.';
'फ़ोन एक-दूसरे को देकर साथ खेलने के लिए बढ़िया। सेटअप तेज़ और सीधा।';
@override
String get multiDeviceSubtitle => 'Each player on their phone';
String get multiDeviceSubtitle => 'हर खिलाड़ी अपने फ़ोन पर';
@override
String get multiDeviceDescription =>
'Create a premium room, share the QR code and manage users from the lobby.';
'एक प्रीमियम कमरा बनाएँ, QR साझा करें और लॉबी से उपयोगकर्ता संभालें।';
@override
String get singleDeviceGameLabel => 'Game on this device';
String get singleDeviceGameLabel => 'इसी डिवाइस पर खेल';
@override
String get multiDeviceGameLabel => 'Multi-device game';
String get multiDeviceGameLabel => 'मल्टी-डिवाइस खेल';
@override
String get mainDeviceUser => 'Main device user';
String get mainDeviceUser => 'डिवाइस का मुख्य उपयोगकर्ता';
@override
String get couldNotCreateRoom =>
'Could not create the room. Check Bluetooth.';
String get couldNotCreateRoom => 'कमरा नहीं बन सका। ब्लूटूथ जाँचें।';
@override
String cannotStartWithReason(String reason) {
return 'Cannot start: $reason';
return 'शुरू नहीं हो सकता: $reason';
}
@override
String get invalidRoom => 'invalid room';
String get invalidRoom => 'अमान्य कमरा';
@override
String get defaultPlayerName => 'खिलाड़ी';
@@ -840,4 +839,49 @@ class AppLocalizationsHi extends AppLocalizations {
String playerRejoined(String name) {
return '$name खेल में वापस आ गए';
}
@override
String get leaveGameTitle => 'खेल छोड़ना है?';
@override
String get leaveGameSingleDevice =>
'चल रहा खेल ख़त्म हो जाएगा और वापस नहीं मिलेगा।';
@override
String get leaveGameHost =>
'आप होस्ट हैं: आपके जाने पर सभी खिलाड़ियों का खेल ख़त्म हो जाएगा।';
@override
String get leaveGameClient =>
'आप खेल से बाहर निकल जाएँगे। जब तक होस्ट इसे खुला रखे, आप लौट सकते हैं।';
@override
String get stayInGame => 'खेलते रहें';
@override
String get permissionsNeededTitle => 'अनुमतियाँ चाहिए';
@override
String get permissionsNeededBody => 'मल्टीप्लेयर मोड के लिए हमें चाहिए:';
@override
String get openAppSettingsQuestion => 'क्या ऐप की सेटिंग खोलें?';
@override
String get openSettings => 'सेटिंग खोलें';
@override
String get permissionLocation => 'लोकेशन';
@override
String get permissionBluetoothAdvertise => 'ब्लूटूथ (प्रसारण)';
@override
String get permissionBluetoothConnect => 'ब्लूटूथ (कनेक्ट)';
@override
String get permissionBluetoothScan => 'ब्लूटूथ (स्कैन)';
@override
String get permissionNearbyWifi => 'आस-पास का वाई-फ़ाई';
}
@@ -844,4 +844,50 @@ class AppLocalizationsIt extends AppLocalizations {
String playerRejoined(String name) {
return '$name è tornato in partita';
}
@override
String get leaveGameTitle => 'Vuoi uscire dalla partita?';
@override
String get leaveGameSingleDevice =>
'La partita in corso andrà persa e non potrà essere recuperata.';
@override
String get leaveGameHost =>
'Sei l\'host: se esci, la partita finisce per tutti i giocatori.';
@override
String get leaveGameClient =>
'Uscirai dalla partita. Potrai rientrare finché l\'host la tiene aperta.';
@override
String get stayInGame => 'Continua a giocare';
@override
String get permissionsNeededTitle => 'Autorizzazioni necessarie';
@override
String get permissionsNeededBody => 'Per la modalità multigiocatore servono:';
@override
String get openAppSettingsQuestion =>
'Vuoi aprire le impostazioni dell\'app?';
@override
String get openSettings => 'Apri impostazioni';
@override
String get permissionLocation => 'Posizione';
@override
String get permissionBluetoothAdvertise => 'Bluetooth (annuncio)';
@override
String get permissionBluetoothConnect => 'Bluetooth (connessione)';
@override
String get permissionBluetoothScan => 'Bluetooth (scansione)';
@override
String get permissionNearbyWifi => 'Wi-Fi nelle vicinanze';
}
+63 -29
View File
@@ -645,84 +645,76 @@ class AppLocalizationsJa extends AppLocalizations {
String get delete => '削除';
@override
String get selectAtLeastThreeUsersToStart =>
'Select at least 3 users to start.';
String get selectAtLeastThreeUsersToStart => '開始するには3人以上のユーザーを選んでください。';
@override
String get hostPhoneMustSelectUser =>
'The host phone must select at least one user.';
String get hostPhoneMustSelectUser => 'ホストの端末は少なくとも1人のユーザーを選ぶ必要があります。';
@override
String get roomNoLongerInLobby => 'The room is no longer in the lobby.';
String get roomNoLongerInLobby => 'ルームはすでにロビーにありません。';
@override
String get completeUserSelectionToStart =>
'Complete user selection to start.';
String get completeUserSelectionToStart => '開始するにはユーザーの選択を完了してください。';
@override
String get preparingSecureRoom => 'Preparing the secure room';
String get preparingSecureRoom => '安全なルームを準備しています';
@override
String get searchingNearbyBluetoothGames =>
'Searching nearby games over Bluetooth';
String get searchingNearbyBluetoothGames => 'Bluetoothで近くのゲームを検索しています';
@override
String get tapToJoin => 'Tap to join';
String get tapToJoin => 'タップして参加';
@override
String get bluetoothLocationPermissionsRequired =>
'Bluetooth and location permissions are required to search for games.';
'ゲームを検索するにはBluetoothと位置情報の許可が必要です。';
@override
String get bluetoothLocationPermissionsShort =>
'Bluetooth and location permissions are required';
String get bluetoothLocationPermissionsShort => 'Bluetoothと位置情報の許可が必要です';
@override
String get couldNotStartSearch =>
'Could not start the search. Check Bluetooth and location.';
String get couldNotStartSearch => '検索を開始できませんでした。Bluetoothと位置情報を確認してください。';
@override
String couldNotConnectToHost(String host) {
return 'Could not connect to $host';
return '$host に接続できませんでした';
}
@override
String get room => 'ルーム';
@override
String get singleDeviceSubtitle => 'Game on this device';
String get singleDeviceSubtitle => 'この端末でプレイ';
@override
String get singleDeviceDescription =>
'Ideal for playing together by passing the phone around. Fast, direct setup.';
String get singleDeviceDescription => '端末を回しながらみんなで遊ぶのに最適。設定はすばやく簡単。';
@override
String get multiDeviceSubtitle => 'Each player on their phone';
String get multiDeviceSubtitle => 'プレイヤーごとに自分の端末で';
@override
String get multiDeviceDescription =>
'Create a premium room, share the QR code and manage users from the lobby.';
'プレミアムなルームを作り、QRコードを共有し、ロビーからユーザーを管理します。';
@override
String get singleDeviceGameLabel => 'Game on this device';
String get singleDeviceGameLabel => 'この端末でのゲーム';
@override
String get multiDeviceGameLabel => 'Multi-device game';
String get multiDeviceGameLabel => 'マルチデバイスのゲーム';
@override
String get mainDeviceUser => 'Main device user';
String get mainDeviceUser => 'この端末のメインユーザー';
@override
String get couldNotCreateRoom =>
'Could not create the room. Check Bluetooth.';
String get couldNotCreateRoom => 'ルームを作成できませんでした。Bluetoothを確認してください。';
@override
String cannotStartWithReason(String reason) {
return 'Cannot start: $reason';
return '開始できません: $reason';
}
@override
String get invalidRoom => 'invalid room';
String get invalidRoom => '無効なルーム';
@override
String get defaultPlayerName => 'プレイヤー';
@@ -831,4 +823,46 @@ class AppLocalizationsJa extends AppLocalizations {
String playerRejoined(String name) {
return '$name がゲームに復帰しました';
}
@override
String get leaveGameTitle => 'ゲームから退出しますか?';
@override
String get leaveGameSingleDevice => '進行中のゲームは失われ、元に戻せません。';
@override
String get leaveGameHost => 'あなたはホストです。退出すると全員のゲームが終了します。';
@override
String get leaveGameClient => 'ゲームから退出します。ホストが開いている間は戻れます。';
@override
String get stayInGame => 'ゲームを続ける';
@override
String get permissionsNeededTitle => '必要な権限';
@override
String get permissionsNeededBody => 'マルチプレイには次の権限が必要です:';
@override
String get openAppSettingsQuestion => 'アプリの設定を開きますか?';
@override
String get openSettings => '設定を開く';
@override
String get permissionLocation => '位置情報';
@override
String get permissionBluetoothAdvertise => 'Bluetooth(アドバタイズ)';
@override
String get permissionBluetoothConnect => 'Bluetooth(接続)';
@override
String get permissionBluetoothScan => 'Bluetooth(スキャン)';
@override
String get permissionNearbyWifi => '近くのWi-Fi';
}
+63 -28
View File
@@ -645,84 +645,77 @@ class AppLocalizationsKo extends AppLocalizations {
String get delete => '삭제';
@override
String get selectAtLeastThreeUsersToStart =>
'Select at least 3 users to start.';
String get selectAtLeastThreeUsersToStart => '시작하려면 사용자를 3명 이상 선택하세요.';
@override
String get hostPhoneMustSelectUser =>
'The host phone must select at least one user.';
String get hostPhoneMustSelectUser => '호스트 기기는 사용자를 최소 한 명 선택해야 합니다.';
@override
String get roomNoLongerInLobby => 'The room is no longer in the lobby.';
String get roomNoLongerInLobby => '방이 더 이상 대기실에 없습니다.';
@override
String get completeUserSelectionToStart =>
'Complete user selection to start.';
String get completeUserSelectionToStart => '시작하려면 사용자 선택을 마치세요.';
@override
String get preparingSecureRoom => 'Preparing the secure room';
String get preparingSecureRoom => '보안 방을 준비하는 중';
@override
String get searchingNearbyBluetoothGames =>
'Searching nearby games over Bluetooth';
String get searchingNearbyBluetoothGames => '블루투스로 근처 게임을 찾는 중';
@override
String get tapToJoin => 'Tap to join';
String get tapToJoin => '눌러서 참여하기';
@override
String get bluetoothLocationPermissionsRequired =>
'Bluetooth and location permissions are required to search for games.';
'게임을 찾으려면 블루투스와 위치 권한이 필요합니다.';
@override
String get bluetoothLocationPermissionsShort =>
'Bluetooth and location permissions are required';
String get bluetoothLocationPermissionsShort => '블루투스와 위치 권한이 필요합니다';
@override
String get couldNotStartSearch =>
'Could not start the search. Check Bluetooth and location.';
String get couldNotStartSearch => '검색을 시작할 수 없습니다. 블루투스와 위치를 확인하세요.';
@override
String couldNotConnectToHost(String host) {
return 'Could not connect to $host';
return '$host에 연결할 수 없습니다';
}
@override
String get room => '';
@override
String get singleDeviceSubtitle => 'Game on this device';
String get singleDeviceSubtitle => '이 기기에서 진행';
@override
String get singleDeviceDescription =>
'Ideal for playing together by passing the phone around. Fast, direct setup.';
'휴대전화를 돌려 가며 함께 놀기에 좋습니다. 설정이 빠르고 간단합니다.';
@override
String get multiDeviceSubtitle => 'Each player on their phone';
String get multiDeviceSubtitle => '각자 자기 휴대전화로';
@override
String get multiDeviceDescription =>
'Create a premium room, share the QR code and manage users from the lobby.';
'프리미엄 방을 만들고 QR 코드를 공유하며 대기실에서 사용자를 관리하세요.';
@override
String get singleDeviceGameLabel => 'Game on this device';
String get singleDeviceGameLabel => '이 기기에서 하는 게임';
@override
String get multiDeviceGameLabel => 'Multi-device game';
String get multiDeviceGameLabel => '여러 기기로 하는 게임';
@override
String get mainDeviceUser => 'Main device user';
String get mainDeviceUser => '이 기기의 주 사용자';
@override
String get couldNotCreateRoom =>
'Could not create the room. Check Bluetooth.';
String get couldNotCreateRoom => '방을 만들 수 없습니다. 블루투스를 확인하세요.';
@override
String cannotStartWithReason(String reason) {
return 'Cannot start: $reason';
return '시작할 수 없습니다: $reason';
}
@override
String get invalidRoom => 'invalid room';
String get invalidRoom => '잘못된 방';
@override
String get defaultPlayerName => '플레이어';
@@ -831,4 +824,46 @@ class AppLocalizationsKo extends AppLocalizations {
String playerRejoined(String name) {
return '$name 님이 게임에 복귀했습니다';
}
@override
String get leaveGameTitle => '게임에서 나갈까요?';
@override
String get leaveGameSingleDevice => '진행 중인 게임이 사라지며 되돌릴 수 없습니다.';
@override
String get leaveGameHost => '당신은 호스트입니다. 나가면 모두의 게임이 끝납니다.';
@override
String get leaveGameClient => '게임에서 나갑니다. 호스트가 열어 두는 동안에는 다시 들어올 수 있습니다.';
@override
String get stayInGame => '계속 하기';
@override
String get permissionsNeededTitle => '필요한 권한';
@override
String get permissionsNeededBody => '멀티플레이 모드에는 다음 권한이 필요합니다:';
@override
String get openAppSettingsQuestion => '앱 설정을 열까요?';
@override
String get openSettings => '설정 열기';
@override
String get permissionLocation => '위치';
@override
String get permissionBluetoothAdvertise => '블루투스(광고)';
@override
String get permissionBluetoothConnect => '블루투스(연결)';
@override
String get permissionBluetoothScan => '블루투스(검색)';
@override
String get permissionNearbyWifi => '근처 Wi-Fi';
}
+67 -21
View File
@@ -655,83 +655,83 @@ class AppLocalizationsNl extends AppLocalizations {
@override
String get selectAtLeastThreeUsersToStart =>
'Select at least 3 users to start.';
'Selecteer minstens 3 gebruikers om te starten.';
@override
String get hostPhoneMustSelectUser =>
'The host phone must select at least one user.';
'De host-telefoon moet minstens één gebruiker selecteren.';
@override
String get roomNoLongerInLobby => 'The room is no longer in the lobby.';
String get roomNoLongerInLobby => 'De ruimte is niet meer in de lobby.';
@override
String get completeUserSelectionToStart =>
'Complete user selection to start.';
'Voltooi de gebruikersselectie om te starten.';
@override
String get preparingSecureRoom => 'Preparing the secure room';
String get preparingSecureRoom => 'Beveiligde ruimte voorbereiden';
@override
String get searchingNearbyBluetoothGames =>
'Searching nearby games over Bluetooth';
'Zoeken naar spellen in de buurt via Bluetooth';
@override
String get tapToJoin => 'Tap to join';
String get tapToJoin => 'Tik om deel te nemen';
@override
String get bluetoothLocationPermissionsRequired =>
'Bluetooth and location permissions are required to search for games.';
'Bluetooth- en locatietoestemming zijn nodig om spellen te zoeken.';
@override
String get bluetoothLocationPermissionsShort =>
'Bluetooth and location permissions are required';
'Bluetooth- en locatietoestemming zijn nodig';
@override
String get couldNotStartSearch =>
'Could not start the search. Check Bluetooth and location.';
'Kon het zoeken niet starten. Controleer Bluetooth en locatie.';
@override
String couldNotConnectToHost(String host) {
return 'Could not connect to $host';
return 'Kon geen verbinding maken met $host';
}
@override
String get room => 'Kamer';
@override
String get singleDeviceSubtitle => 'Game on this device';
String get singleDeviceSubtitle => 'Spel op dit toestel';
@override
String get singleDeviceDescription =>
'Ideal for playing together by passing the phone around. Fast, direct setup.';
'Ideaal om samen te spelen door de telefoon door te geven. Snel en direct ingesteld.';
@override
String get multiDeviceSubtitle => 'Each player on their phone';
String get multiDeviceSubtitle => 'Elke speler op zijn eigen telefoon';
@override
String get multiDeviceDescription =>
'Create a premium room, share the QR code and manage users from the lobby.';
'Maak een premium ruimte, deel de QR-code en beheer gebruikers vanuit de lobby.';
@override
String get singleDeviceGameLabel => 'Game on this device';
String get singleDeviceGameLabel => 'Spel op dit toestel';
@override
String get multiDeviceGameLabel => 'Multi-device game';
String get multiDeviceGameLabel => 'Spel met meerdere toestellen';
@override
String get mainDeviceUser => 'Main device user';
String get mainDeviceUser => 'Hoofdgebruiker van dit toestel';
@override
String get couldNotCreateRoom =>
'Could not create the room. Check Bluetooth.';
'Kon de ruimte niet aanmaken. Controleer Bluetooth.';
@override
String cannotStartWithReason(String reason) {
return 'Cannot start: $reason';
return 'Kan niet starten: $reason';
}
@override
String get invalidRoom => 'invalid room';
String get invalidRoom => 'ongeldige ruimte';
@override
String get defaultPlayerName => 'Speler';
@@ -845,4 +845,50 @@ class AppLocalizationsNl extends AppLocalizations {
String playerRejoined(String name) {
return '$name is terug in het spel';
}
@override
String get leaveGameTitle => 'Het spel verlaten?';
@override
String get leaveGameSingleDevice =>
'Het lopende spel gaat verloren en kan niet worden hersteld.';
@override
String get leaveGameHost =>
'Jij bent de host: als je weggaat, eindigt het spel voor iedereen.';
@override
String get leaveGameClient =>
'Je verlaat het spel. Je kunt terugkomen zolang de host het openhoudt.';
@override
String get stayInGame => 'Verder spelen';
@override
String get permissionsNeededTitle => 'Toestemmingen nodig';
@override
String get permissionsNeededBody =>
'Voor de multiplayermodus hebben we nodig:';
@override
String get openAppSettingsQuestion => 'De app-instellingen openen?';
@override
String get openSettings => 'Instellingen openen';
@override
String get permissionLocation => 'Locatie';
@override
String get permissionBluetoothAdvertise => 'Bluetooth (zichtbaar maken)';
@override
String get permissionBluetoothConnect => 'Bluetooth (verbinden)';
@override
String get permissionBluetoothScan => 'Bluetooth (scannen)';
@override
String get permissionNearbyWifi => 'Wi-Fi in de buurt';
}
+66 -21
View File
@@ -653,83 +653,83 @@ class AppLocalizationsPl extends AppLocalizations {
@override
String get selectAtLeastThreeUsersToStart =>
'Select at least 3 users to start.';
'Wybierz co najmniej 3 użytkowników, aby rozpocząć.';
@override
String get hostPhoneMustSelectUser =>
'The host phone must select at least one user.';
'Telefon gospodarza musi wybrać przynajmniej jednego użytkownika.';
@override
String get roomNoLongerInLobby => 'The room is no longer in the lobby.';
String get roomNoLongerInLobby => 'Pokój nie jest już w poczekalni.';
@override
String get completeUserSelectionToStart =>
'Complete user selection to start.';
'Dokończ wybór użytkowników, aby rozpocząć.';
@override
String get preparingSecureRoom => 'Preparing the secure room';
String get preparingSecureRoom => 'Przygotowywanie bezpiecznego pokoju';
@override
String get searchingNearbyBluetoothGames =>
'Searching nearby games over Bluetooth';
'Szukanie gier w pobliżu przez Bluetooth';
@override
String get tapToJoin => 'Tap to join';
String get tapToJoin => 'Dotknij, aby dołączyć';
@override
String get bluetoothLocationPermissionsRequired =>
'Bluetooth and location permissions are required to search for games.';
'Do wyszukiwania gier potrzebne są uprawnienia Bluetooth i lokalizacji.';
@override
String get bluetoothLocationPermissionsShort =>
'Bluetooth and location permissions are required';
'Potrzebne są uprawnienia Bluetooth i lokalizacji';
@override
String get couldNotStartSearch =>
'Could not start the search. Check Bluetooth and location.';
'Nie udało się rozpocząć wyszukiwania. Sprawdź Bluetooth i lokalizację.';
@override
String couldNotConnectToHost(String host) {
return 'Could not connect to $host';
return 'Nie udało się połączyć z $host';
}
@override
String get room => 'Pokój';
@override
String get singleDeviceSubtitle => 'Game on this device';
String get singleDeviceSubtitle => 'Gra na tym urządzeniu';
@override
String get singleDeviceDescription =>
'Ideal for playing together by passing the phone around. Fast, direct setup.';
'Idealne do wspólnej gry, podając telefon dalej. Szybka i prosta konfiguracja.';
@override
String get multiDeviceSubtitle => 'Each player on their phone';
String get multiDeviceSubtitle => 'Każdy gracz na swoim telefonie';
@override
String get multiDeviceDescription =>
'Create a premium room, share the QR code and manage users from the lobby.';
'Utwórz pokój premium, udostępnij kod QR i zarządzaj graczami z poczekalni.';
@override
String get singleDeviceGameLabel => 'Game on this device';
String get singleDeviceGameLabel => 'Gra na tym urządzeniu';
@override
String get multiDeviceGameLabel => 'Multi-device game';
String get multiDeviceGameLabel => 'Gra na wielu urządzeniach';
@override
String get mainDeviceUser => 'Main device user';
String get mainDeviceUser => 'Główny użytkownik urządzenia';
@override
String get couldNotCreateRoom =>
'Could not create the room. Check Bluetooth.';
'Nie udało się utworzyć pokoju. Sprawdź Bluetooth.';
@override
String cannotStartWithReason(String reason) {
return 'Cannot start: $reason';
return 'Nie można rozpocząć: $reason';
}
@override
String get invalidRoom => 'invalid room';
String get invalidRoom => 'nieprawidłowy pokój';
@override
String get defaultPlayerName => 'Gracz';
@@ -842,4 +842,49 @@ class AppLocalizationsPl extends AppLocalizations {
String playerRejoined(String name) {
return '$name wrócił(a) do gry';
}
@override
String get leaveGameTitle => 'Opuścić grę?';
@override
String get leaveGameSingleDevice =>
'Trwająca gra zostanie utracona i nie da się jej odzyskać.';
@override
String get leaveGameHost =>
'Jesteś gospodarzem: jeśli wyjdziesz, gra kończy się dla wszystkich.';
@override
String get leaveGameClient =>
'Opuścisz grę. Możesz wrócić, dopóki gospodarz jej nie zamknie.';
@override
String get stayInGame => 'Graj dalej';
@override
String get permissionsNeededTitle => 'Wymagane uprawnienia';
@override
String get permissionsNeededBody => 'Do trybu wieloosobowego potrzebujemy:';
@override
String get openAppSettingsQuestion => 'Otworzyć ustawienia aplikacji?';
@override
String get openSettings => 'Otwórz ustawienia';
@override
String get permissionLocation => 'Lokalizacja';
@override
String get permissionBluetoothAdvertise => 'Bluetooth (rozgłaszanie)';
@override
String get permissionBluetoothConnect => 'Bluetooth (łączenie)';
@override
String get permissionBluetoothScan => 'Bluetooth (skanowanie)';
@override
String get permissionNearbyWifi => 'Wi-Fi w pobliżu';
}
+48 -3
View File
@@ -28,7 +28,7 @@ class AppLocalizationsPt extends AppLocalizations {
'Sem medalhas novas desta vez. Continua a acumular fogo.';
@override
String get calculatingRewards => 'Calculando recompensas...';
String get calculatingRewards => 'A calcular recompensas...';
@override
String get fireLabel => 'Fogo';
@@ -194,7 +194,7 @@ class AppLocalizationsPt extends AppLocalizations {
'Certifique-se de que ninguém mais está olhando';
@override
String get showingWord => '👁️ Mostrando...';
String get showingWord => '👁️ A mostrar...';
@override
String get holdToSee => '👆 Mantenha pressionado para ver';
@@ -263,7 +263,7 @@ class AppLocalizationsPt extends AppLocalizations {
String get result => 'Resultado';
@override
String get revealing => 'Revelando...';
String get revealing => 'A revelar...';
@override
String get wasImpostor => 'Era IMPOSTOR! 🎉';
@@ -845,4 +845,49 @@ class AppLocalizationsPt extends AppLocalizations {
String playerRejoined(String name) {
return '$name voltou ao jogo';
}
@override
String get leaveGameTitle => 'Sair do jogo?';
@override
String get leaveGameSingleDevice =>
'O jogo em curso perde-se e não poderá ser recuperado.';
@override
String get leaveGameHost =>
'És o anfitrião: se saíres, o jogo termina para todos os jogadores.';
@override
String get leaveGameClient =>
'Vais sair do jogo. Podes voltar enquanto o anfitrião o mantiver aberto.';
@override
String get stayInGame => 'Continuar a jogar';
@override
String get permissionsNeededTitle => 'Permissões necessárias';
@override
String get permissionsNeededBody => 'Para o modo multijogador precisamos de:';
@override
String get openAppSettingsQuestion => 'Abrir as definições da aplicação?';
@override
String get openSettings => 'Abrir definições';
@override
String get permissionLocation => 'Localização';
@override
String get permissionBluetoothAdvertise => 'Bluetooth (anunciar)';
@override
String get permissionBluetoothConnect => 'Bluetooth (ligar)';
@override
String get permissionBluetoothScan => 'Bluetooth (procurar)';
@override
String get permissionNearbyWifi => 'Wi-Fi por perto';
}
+67 -21
View File
@@ -652,83 +652,83 @@ class AppLocalizationsRu extends AppLocalizations {
@override
String get selectAtLeastThreeUsersToStart =>
'Select at least 3 users to start.';
'Выберите не менее 3 пользователей, чтобы начать.';
@override
String get hostPhoneMustSelectUser =>
'The host phone must select at least one user.';
'Телефон ведущего должен выбрать хотя бы одного пользователя.';
@override
String get roomNoLongerInLobby => 'The room is no longer in the lobby.';
String get roomNoLongerInLobby => 'Комната больше не в лобби.';
@override
String get completeUserSelectionToStart =>
'Complete user selection to start.';
'Завершите выбор пользователей, чтобы начать.';
@override
String get preparingSecureRoom => 'Preparing the secure room';
String get preparingSecureRoom => 'Подготовка защищённой комнаты';
@override
String get searchingNearbyBluetoothGames =>
'Searching nearby games over Bluetooth';
'Поиск игр поблизости через Bluetooth';
@override
String get tapToJoin => 'Tap to join';
String get tapToJoin => 'Нажмите, чтобы присоединиться';
@override
String get bluetoothLocationPermissionsRequired =>
'Bluetooth and location permissions are required to search for games.';
'Для поиска игр нужны разрешения Bluetooth и геолокации.';
@override
String get bluetoothLocationPermissionsShort =>
'Bluetooth and location permissions are required';
'Нужны разрешения Bluetooth и геолокации';
@override
String get couldNotStartSearch =>
'Could not start the search. Check Bluetooth and location.';
'Не удалось начать поиск. Проверьте Bluetooth и геолокацию.';
@override
String couldNotConnectToHost(String host) {
return 'Could not connect to $host';
return 'Не удалось подключиться к $host';
}
@override
String get room => 'Комната';
@override
String get singleDeviceSubtitle => 'Game on this device';
String get singleDeviceSubtitle => 'Игра на этом устройстве';
@override
String get singleDeviceDescription =>
'Ideal for playing together by passing the phone around. Fast, direct setup.';
'Идеально, чтобы играть вместе, передавая телефон. Быстрая и простая настройка.';
@override
String get multiDeviceSubtitle => 'Each player on their phone';
String get multiDeviceSubtitle => 'Каждый игрок на своём телефоне';
@override
String get multiDeviceDescription =>
'Create a premium room, share the QR code and manage users from the lobby.';
'Создайте премиум-комнату, поделитесь QR-кодом и управляйте игроками из лобби.';
@override
String get singleDeviceGameLabel => 'Game on this device';
String get singleDeviceGameLabel => 'Игра на этом устройстве';
@override
String get multiDeviceGameLabel => 'Multi-device game';
String get multiDeviceGameLabel => 'Игра на нескольких устройствах';
@override
String get mainDeviceUser => 'Main device user';
String get mainDeviceUser => 'Основной пользователь устройства';
@override
String get couldNotCreateRoom =>
'Could not create the room. Check Bluetooth.';
'Не удалось создать комнату. Проверьте Bluetooth.';
@override
String cannotStartWithReason(String reason) {
return 'Cannot start: $reason';
return 'Невозможно начать: $reason';
}
@override
String get invalidRoom => 'invalid room';
String get invalidRoom => 'недопустимая комната';
@override
String get defaultPlayerName => 'Игрок';
@@ -841,4 +841,50 @@ class AppLocalizationsRu extends AppLocalizations {
String playerRejoined(String name) {
return '$name вернулся в игру';
}
@override
String get leaveGameTitle => 'Выйти из игры?';
@override
String get leaveGameSingleDevice =>
'Текущая партия будет потеряна без возможности восстановления.';
@override
String get leaveGameHost =>
'Вы ведущий: если вы выйдете, игра закончится для всех.';
@override
String get leaveGameClient =>
'Вы выйдете из игры. Вы сможете вернуться, пока ведущий её не закрыл.';
@override
String get stayInGame => 'Продолжить игру';
@override
String get permissionsNeededTitle => 'Нужны разрешения';
@override
String get permissionsNeededBody =>
'Для многопользовательского режима нужны:';
@override
String get openAppSettingsQuestion => 'Открыть настройки приложения?';
@override
String get openSettings => 'Открыть настройки';
@override
String get permissionLocation => 'Геолокация';
@override
String get permissionBluetoothAdvertise => 'Bluetooth (объявление)';
@override
String get permissionBluetoothConnect => 'Bluetooth (подключение)';
@override
String get permissionBluetoothScan => 'Bluetooth (сканирование)';
@override
String get permissionNearbyWifi => 'Wi-Fi поблизости';
}
+65 -21
View File
@@ -652,83 +652,83 @@ class AppLocalizationsTr extends AppLocalizations {
@override
String get selectAtLeastThreeUsersToStart =>
'Select at least 3 users to start.';
'Başlamak için en az 3 kullanıcı seç.';
@override
String get hostPhoneMustSelectUser =>
'The host phone must select at least one user.';
'Sunucu telefonu en az bir kullanıcı seçmeli.';
@override
String get roomNoLongerInLobby => 'The room is no longer in the lobby.';
String get roomNoLongerInLobby => 'Oda artık lobide değil.';
@override
String get completeUserSelectionToStart =>
'Complete user selection to start.';
'Başlamak için kullanıcı seçimini tamamla.';
@override
String get preparingSecureRoom => 'Preparing the secure room';
String get preparingSecureRoom => 'Güvenli oda hazırlanıyor';
@override
String get searchingNearbyBluetoothGames =>
'Searching nearby games over Bluetooth';
'Bluetooth ile yakındaki oyunlar aranıyor';
@override
String get tapToJoin => 'Tap to join';
String get tapToJoin => 'Katılmak için dokun';
@override
String get bluetoothLocationPermissionsRequired =>
'Bluetooth and location permissions are required to search for games.';
'Oyun aramak için Bluetooth ve konum izinleri gerekli.';
@override
String get bluetoothLocationPermissionsShort =>
'Bluetooth and location permissions are required';
'Bluetooth ve konum izinleri gerekli';
@override
String get couldNotStartSearch =>
'Could not start the search. Check Bluetooth and location.';
'Arama başlatılamadı. Bluetooth ve konumu kontrol et.';
@override
String couldNotConnectToHost(String host) {
return 'Could not connect to $host';
return '$host bağlantısı kurulamadı';
}
@override
String get room => 'Oda';
@override
String get singleDeviceSubtitle => 'Game on this device';
String get singleDeviceSubtitle => 'Bu cihazda oyun';
@override
String get singleDeviceDescription =>
'Ideal for playing together by passing the phone around. Fast, direct setup.';
'Telefonu elden ele dolaştırarak birlikte oynamak için ideal. Hızlı ve doğrudan kurulum.';
@override
String get multiDeviceSubtitle => 'Each player on their phone';
String get multiDeviceSubtitle => 'Her oyuncu kendi telefonunda';
@override
String get multiDeviceDescription =>
'Create a premium room, share the QR code and manage users from the lobby.';
'Premium bir oda oluştur, QR kodu paylaş ve kullanıcıları lobiden yönet.';
@override
String get singleDeviceGameLabel => 'Game on this device';
String get singleDeviceGameLabel => 'Bu cihazda oyun';
@override
String get multiDeviceGameLabel => 'Multi-device game';
String get multiDeviceGameLabel => 'Çok cihazlı oyun';
@override
String get mainDeviceUser => 'Main device user';
String get mainDeviceUser => 'Cihazın ana kullanıcısı';
@override
String get couldNotCreateRoom =>
'Could not create the room. Check Bluetooth.';
'Oda oluşturulamadı. Bluetooth\'u kontrol et.';
@override
String cannotStartWithReason(String reason) {
return 'Cannot start: $reason';
return 'Başlatılamıyor: $reason';
}
@override
String get invalidRoom => 'invalid room';
String get invalidRoom => 'geçersiz oda';
@override
String get defaultPlayerName => 'Oyuncu';
@@ -841,4 +841,48 @@ class AppLocalizationsTr extends AppLocalizations {
String playerRejoined(String name) {
return '$name oyuna geri döndü';
}
@override
String get leaveGameTitle => 'Oyundan çıkılsın mı?';
@override
String get leaveGameSingleDevice =>
'Devam eden oyun kaybolur ve geri getirilemez.';
@override
String get leaveGameHost => 'Sunucu sensin: çıkarsan oyun herkes için biter.';
@override
String get leaveGameClient =>
'Oyundan çıkacaksın. Sunucu odayı açık tuttuğu sürece geri dönebilirsin.';
@override
String get stayInGame => 'Oynamaya devam et';
@override
String get permissionsNeededTitle => 'Gerekli izinler';
@override
String get permissionsNeededBody => 'Çok oyunculu mod için şunlar gerekli:';
@override
String get openAppSettingsQuestion => 'Uygulama ayarları açılsın mı?';
@override
String get openSettings => 'Ayarları';
@override
String get permissionLocation => 'Konum';
@override
String get permissionBluetoothAdvertise => 'Bluetooth (yayın)';
@override
String get permissionBluetoothConnect => 'Bluetooth (bağlanma)';
@override
String get permissionBluetoothScan => 'Bluetooth (tarama)';
@override
String get permissionNearbyWifi => 'Yakındaki Wi-Fi';
}
+126 -62
View File
@@ -643,84 +643,74 @@ class AppLocalizationsZh extends AppLocalizations {
String get delete => '删除';
@override
String get selectAtLeastThreeUsersToStart =>
'Select at least 3 users to start.';
String get selectAtLeastThreeUsersToStart => '至少选择 3 名用户才能开始。';
@override
String get hostPhoneMustSelectUser =>
'The host phone must select at least one user.';
String get hostPhoneMustSelectUser => '房主的手机必须至少选择一名用户。';
@override
String get roomNoLongerInLobby => 'The room is no longer in the lobby.';
String get roomNoLongerInLobby => '房间已不在等候大厅。';
@override
String get completeUserSelectionToStart =>
'Complete user selection to start.';
String get completeUserSelectionToStart => '完成用户选择后才能开始。';
@override
String get preparingSecureRoom => 'Preparing the secure room';
String get preparingSecureRoom => '正在准备安全房间';
@override
String get searchingNearbyBluetoothGames =>
'Searching nearby games over Bluetooth';
String get searchingNearbyBluetoothGames => '正在通过蓝牙搜索附近的游戏';
@override
String get tapToJoin => 'Tap to join';
String get tapToJoin => '点击加入';
@override
String get bluetoothLocationPermissionsRequired =>
'Bluetooth and location permissions are required to search for games.';
String get bluetoothLocationPermissionsRequired => '搜索游戏需要蓝牙和定位权限。';
@override
String get bluetoothLocationPermissionsShort =>
'Bluetooth and location permissions are required';
String get bluetoothLocationPermissionsShort => '需要蓝牙和定位权限';
@override
String get couldNotStartSearch =>
'Could not start the search. Check Bluetooth and location.';
String get couldNotStartSearch => '无法开始搜索。请检查蓝牙和定位。';
@override
String couldNotConnectToHost(String host) {
return 'Could not connect to $host';
return '无法连接到 $host';
}
@override
String get room => '房间';
@override
String get singleDeviceSubtitle => 'Game on this device';
String get singleDeviceSubtitle => '在这台设备上游戏';
@override
String get singleDeviceDescription =>
'Ideal for playing together by passing the phone around. Fast, direct setup.';
String get singleDeviceDescription => '适合大家传着手机一起玩。设置快速直接。';
@override
String get multiDeviceSubtitle => 'Each player on their phone';
String get multiDeviceSubtitle => '每位玩家用自己的手机';
@override
String get multiDeviceDescription =>
'Create a premium room, share the QR code and manage users from the lobby.';
String get multiDeviceDescription => '创建高级房间,分享二维码,并在大厅管理用户。';
@override
String get singleDeviceGameLabel => 'Game on this device';
String get singleDeviceGameLabel => '本机游戏';
@override
String get multiDeviceGameLabel => 'Multi-device game';
String get multiDeviceGameLabel => '多设备游戏';
@override
String get mainDeviceUser => 'Main device user';
String get mainDeviceUser => '本机主用户';
@override
String get couldNotCreateRoom =>
'Could not create the room. Check Bluetooth.';
String get couldNotCreateRoom => '无法创建房间。请检查蓝牙。';
@override
String cannotStartWithReason(String reason) {
return 'Cannot start: $reason';
return '无法开始:$reason';
}
@override
String get invalidRoom => 'invalid room';
String get invalidRoom => '无效的房间';
@override
String get defaultPlayerName => '玩家';
@@ -829,6 +819,48 @@ class AppLocalizationsZh extends AppLocalizations {
String playerRejoined(String name) {
return '$name 已重新加入游戏';
}
@override
String get leaveGameTitle => '要退出游戏吗?';
@override
String get leaveGameSingleDevice => '正在进行的游戏将会丢失,且无法恢复。';
@override
String get leaveGameHost => '你是房主:一旦退出,所有玩家的游戏都会结束。';
@override
String get leaveGameClient => '你将退出这局游戏。只要房主还开着,你随时可以回来。';
@override
String get stayInGame => '继续游戏';
@override
String get permissionsNeededTitle => '需要权限';
@override
String get permissionsNeededBody => '多人游戏模式需要以下权限:';
@override
String get openAppSettingsQuestion => '要打开应用设置吗?';
@override
String get openSettings => '打开设置';
@override
String get permissionLocation => '定位';
@override
String get permissionBluetoothAdvertise => '蓝牙(广播)';
@override
String get permissionBluetoothConnect => '蓝牙(连接)';
@override
String get permissionBluetoothScan => '蓝牙(扫描)';
@override
String get permissionNearbyWifi => '附近的 Wi-Fi';
}
/// The translations for Chinese, as used in Taiwan (`zh_TW`).
@@ -1470,84 +1502,74 @@ class AppLocalizationsZhTw extends AppLocalizationsZh {
String get delete => '删除';
@override
String get selectAtLeastThreeUsersToStart =>
'Select at least 3 users to start.';
String get selectAtLeastThreeUsersToStart => '至少選擇 3 名使用者才能開始。';
@override
String get hostPhoneMustSelectUser =>
'The host phone must select at least one user.';
String get hostPhoneMustSelectUser => '房主的手機必須至少選擇一名使用者。';
@override
String get roomNoLongerInLobby => 'The room is no longer in the lobby.';
String get roomNoLongerInLobby => '房間已不在等候大廳。';
@override
String get completeUserSelectionToStart =>
'Complete user selection to start.';
String get completeUserSelectionToStart => '完成使用者選擇後才能開始。';
@override
String get preparingSecureRoom => 'Preparing the secure room';
String get preparingSecureRoom => '正在準備安全房間';
@override
String get searchingNearbyBluetoothGames =>
'Searching nearby games over Bluetooth';
String get searchingNearbyBluetoothGames => '正在透過藍牙搜尋附近的遊戲';
@override
String get tapToJoin => 'Tap to join';
String get tapToJoin => '點擊加入';
@override
String get bluetoothLocationPermissionsRequired =>
'Bluetooth and location permissions are required to search for games.';
String get bluetoothLocationPermissionsRequired => '搜尋遊戲需要藍牙和定位權限。';
@override
String get bluetoothLocationPermissionsShort =>
'Bluetooth and location permissions are required';
String get bluetoothLocationPermissionsShort => '需要藍牙和定位權限';
@override
String get couldNotStartSearch =>
'Could not start the search. Check Bluetooth and location.';
String get couldNotStartSearch => '無法開始搜尋。請檢查藍牙和定位。';
@override
String couldNotConnectToHost(String host) {
return 'Could not connect to $host';
return '無法連線到 $host';
}
@override
String get room => '房间';
@override
String get singleDeviceSubtitle => 'Game on this device';
String get singleDeviceSubtitle => '在這台裝置上遊戲';
@override
String get singleDeviceDescription =>
'Ideal for playing together by passing the phone around. Fast, direct setup.';
String get singleDeviceDescription => '適合大家傳著手機一起玩。設定快速直接。';
@override
String get multiDeviceSubtitle => 'Each player on their phone';
String get multiDeviceSubtitle => '每位玩家用自己的手機';
@override
String get multiDeviceDescription =>
'Create a premium room, share the QR code and manage users from the lobby.';
String get multiDeviceDescription => '建立高級房間,分享 QR Code,並在大廳管理使用者。';
@override
String get singleDeviceGameLabel => 'Game on this device';
String get singleDeviceGameLabel => '本機遊戲';
@override
String get multiDeviceGameLabel => 'Multi-device game';
String get multiDeviceGameLabel => '多裝置遊戲';
@override
String get mainDeviceUser => 'Main device user';
String get mainDeviceUser => '本機主要使用者';
@override
String get couldNotCreateRoom =>
'Could not create the room. Check Bluetooth.';
String get couldNotCreateRoom => '無法建立房間。請檢查藍牙。';
@override
String cannotStartWithReason(String reason) {
return 'Cannot start: $reason';
return '無法開始:$reason';
}
@override
String get invalidRoom => 'invalid room';
String get invalidRoom => '無效的房間';
@override
String get defaultPlayerName => '玩家';
@@ -1656,4 +1678,46 @@ class AppLocalizationsZhTw extends AppLocalizationsZh {
String playerRejoined(String name) {
return '$name 已重新加入遊戲';
}
@override
String get leaveGameTitle => '要退出遊戲嗎?';
@override
String get leaveGameSingleDevice => '正在進行的遊戲將會遺失,且無法復原。';
@override
String get leaveGameHost => '你是房主:一旦退出,所有玩家的遊戲都會結束。';
@override
String get leaveGameClient => '你將退出這局遊戲。只要房主還開著,你隨時可以回來。';
@override
String get stayInGame => '繼續遊戲';
@override
String get permissionsNeededTitle => '需要權限';
@override
String get permissionsNeededBody => '多人遊戲模式需要以下權限:';
@override
String get openAppSettingsQuestion => '要開啟應用程式設定嗎?';
@override
String get openSettings => '開啟設定';
@override
String get permissionLocation => '定位';
@override
String get permissionBluetoothAdvertise => '藍牙(廣播)';
@override
String get permissionBluetoothConnect => '藍牙(連線)';
@override
String get permissionBluetoothScan => '藍牙(掃描)';
@override
String get permissionNearbyWifi => '附近的 Wi-Fi';
}
+10
View File
@@ -15,11 +15,21 @@ import 'pantallas/pantalla_principal.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
// Desde targetSdk 35 el dibujado de borde a borde es obligatorio. Se pide
// explícitamente en vez de confiar en el valor por defecto de Flutter; son
// las pantallas, vía SafeArea, las que apartan su contenido de las barras.
// Con navegación de 3 botones el sistema pinta igualmente un velo tras ellos
// y eso no lo controla la app.
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: Brightness.light,
systemNavigationBarColor: TemaApp.colorFondo,
// Con el dibujado de borde a borde de Android 15 el color de la barra de
// navegación se ignora y queda transparente sobre un fondo oscuro, así
// que sus iconos tienen que ser claros para verse.
systemNavigationBarIconBrightness: Brightness.light,
),
);
runApp(const FaroleroApp());
+29 -25
View File
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import '../tema/dialogo_confirmacion.dart';
import 'package:farolero/l10n/generated/app_localizations.dart';
import 'package:provider/provider.dart';
import '../estado/estado_juego.dart';
@@ -53,31 +54,34 @@ class _PantallaAdivinanzaState extends State<PantallaAdivinanza> {
final partida = estado.partida;
if (partida == null) return const SizedBox.shrink();
return Scaffold(
appBar: AppBar(
title: Text(l10n.impostorGuessTitle),
automaticallyImplyLeading: false,
),
body: FondoFarolero(
intenso: true,
child: SafeArea(
child: Center(
child: SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const ArteGameplayFarolero.fase(height: 132),
const SizedBox(height: 12),
TarjetaFaseFarolero(
icono: Icons.theater_comedy,
assetIconPath: 'assets/ui/generated/actions/action_impostor_mask.webp',
titulo: l10n.impostorCanGuess,
subtitulo: l10n.ifCorrectImpostorsWin,
color: TemaApp.colorAcento,
child: _buildContenido(context, l10n, estado, partida.palabraSecreta),
),
],
return GuardiaSalidaPartida(
contexto: ContextoSalida.unDispositivo,
child: Scaffold(
appBar: AppBar(
title: Text(l10n.impostorGuessTitle),
automaticallyImplyLeading: false,
),
body: FondoFarolero(
intenso: true,
child: SafeArea(
child: Center(
child: SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const ArteGameplayFarolero.fase(height: 132),
const SizedBox(height: 12),
TarjetaFaseFarolero(
icono: Icons.theater_comedy,
assetIconPath: 'assets/ui/generated/actions/action_impostor_mask.webp',
titulo: l10n.impostorCanGuess,
subtitulo: l10n.ifCorrectImpostorsWin,
color: TemaApp.colorAcento,
child: _buildContenido(context, l10n, estado, partida.palabraSecreta),
),
],
),
),
),
),
+6 -1
View File
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import '../tema/banderas_idioma.dart';
import 'package:farolero/l10n/generated/app_localizations.dart';
import 'package:provider/provider.dart';
import '../servicios/servicio_idioma.dart';
@@ -28,6 +29,7 @@ class _PantallaAjustesState extends State<PantallaAjustes> {
appBar: AppBar(title: Text(l10n.settingsTitle)),
body: FondoFarolero(
intenso: true,
respetarBarras: true,
child: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
@@ -94,6 +96,7 @@ class _PantallaAjustesState extends State<PantallaAjustes> {
const SizedBox(height: 12),
_opcionIdioma(
context,
codigoBandera: 'sistema',
bandera: '\u{1F310}',
nombre: '${l10n.automaticLanguage} (${_nombreIdiomaDelSistema()})',
codigo: 'sistema',
@@ -104,6 +107,7 @@ class _PantallaAjustesState extends State<PantallaAjustes> {
...ServicioIdioma.idiomasSoportados.entries.map((entrada) {
return _opcionIdioma(
context,
codigoBandera: entrada.key,
bandera: entrada.value.bandera,
nombre: entrada.value.nombre,
codigo: entrada.key,
@@ -125,6 +129,7 @@ class _PantallaAjustesState extends State<PantallaAjustes> {
Widget _opcionIdioma(
BuildContext context, {
required String codigoBandera,
required String bandera,
required String nombre,
required String codigo,
@@ -132,7 +137,7 @@ class _PantallaAjustesState extends State<PantallaAjustes> {
required VoidCallback onTap,
}) {
return ListTile(
leading: Text(bandera, style: const TextStyle(fontSize: 24)),
leading: BanderaIdioma(codigo: codigoBandera, emoji: bandera),
title: Text(nombre),
trailing: seleccionado
? IconoFarolero(Icons.check_circle, color: TemaApp.colorAcento)
@@ -345,6 +345,7 @@ class _PantallaCrearPartidaState extends State<PantallaCrearPartida> {
appBar: AppBar(title: Text(l10n.createGame)),
body: FondoFarolero(
intenso: true,
respetarBarras: true,
child: SingleChildScrollView(
padding: const EdgeInsets.fromLTRB(18, 18, 18, 28),
child: Column(
+76 -72
View File
@@ -1,4 +1,5 @@
import 'dart:async';
import '../tema/dialogo_confirmacion.dart';
import 'package:flutter/material.dart';
import 'package:farolero/l10n/generated/app_localizations.dart';
import 'package:provider/provider.dart';
@@ -67,85 +68,88 @@ class _PantallaDebateState extends State<PantallaDebate> {
final tieneTemporizador = partida.config.tiempoDebateSegundos != null;
return Scaffold(
appBar: AppBar(
title: Text(l10n.debateRound(partida.rondaActual)),
automaticallyImplyLeading: false,
),
body: FondoFarolero(
intenso: true,
child: SafeArea(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
const ArteGameplayFarolero.fase(height: 110),
const SizedBox(height: 10),
if (tieneTemporizador) ...[
TemporizadorFarolero(
etiqueta: _tiempoAgotado ? l10n.timeUp : l10n.timeRemaining,
tiempo: _formatearTiempo(_segundosRestantes),
agotado: _tiempoAgotado,
),
const SizedBox(height: 16),
],
Expanded(
child: TarjetaFaseFarolero(
icono: Icons.forum,
assetIconPath: 'assets/ui/generated/actions/action_rules_book.webp',
titulo: l10n.playersInDebate,
subtitulo: l10n.activePlayersInfo(
partida.jugadoresActivos.length,
partida.impostoresActivos.length,
return GuardiaSalidaPartida(
contexto: ContextoSalida.unDispositivo,
child: Scaffold(
appBar: AppBar(
title: Text(l10n.debateRound(partida.rondaActual)),
automaticallyImplyLeading: false,
),
body: FondoFarolero(
intenso: true,
child: SafeArea(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
const ArteGameplayFarolero.fase(height: 110),
const SizedBox(height: 10),
if (tieneTemporizador) ...[
TemporizadorFarolero(
etiqueta: _tiempoAgotado ? l10n.timeUp : l10n.timeRemaining,
tiempo: _formatearTiempo(_segundosRestantes),
agotado: _tiempoAgotado,
),
child: Expanded(
child: ListView.separated(
itemCount: partida.jugadores.length,
separatorBuilder: (context, index) => const SizedBox(height: 8),
itemBuilder: (context, index) {
final jugador = partida.jugadores[index];
return EstadoJugadorFarolero(
nombre: '${index + 1}. ${jugador.nombre}',
subtitulo: jugador.eliminado ? l10n.eliminated : null,
icono: jugador.eliminado ? Icons.person_off : Icons.record_voice_over,
assetIconPath: jugador.eliminado ? null : 'assets/ui/generated/actions/action_players_group.webp',
destacado: !jugador.eliminado,
completado: !jugador.eliminado,
);
},
const SizedBox(height: 16),
],
Expanded(
child: TarjetaFaseFarolero(
icono: Icons.forum,
assetIconPath: 'assets/ui/generated/actions/action_rules_book.webp',
titulo: l10n.playersInDebate,
subtitulo: l10n.activePlayersInfo(
partida.jugadoresActivos.length,
partida.impostoresActivos.length,
),
),
),
),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: BotonFarolero.oscuro(
texto: l10n.notes,
icono: Icons.edit_note,
assetIconPath: 'assets/ui/generated/actions/action_notes_quill.webp',
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (_) => const PantallaNotas()),
child: Expanded(
child: ListView.separated(
itemCount: partida.jugadores.length,
separatorBuilder: (context, index) => const SizedBox(height: 8),
itemBuilder: (context, index) {
final jugador = partida.jugadores[index];
return EstadoJugadorFarolero(
nombre: '${index + 1}. ${jugador.nombre}',
subtitulo: jugador.eliminado ? l10n.eliminated : null,
icono: jugador.eliminado ? Icons.person_off : Icons.record_voice_over,
assetIconPath: jugador.eliminado ? null : 'assets/ui/generated/actions/action_players_group.webp',
destacado: !jugador.eliminado,
completado: !jugador.eliminado,
);
},
),
),
),
const SizedBox(width: 12),
Expanded(
flex: 2,
child: BotonFarolero(
texto: l10n.goToVoting,
icono: Icons.how_to_vote,
assetIconPath: 'assets/ui/generated/actions/action_vote_mask.webp',
onPressed: _irAVotacion,
),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: BotonFarolero.oscuro(
texto: l10n.notes,
icono: Icons.edit_note,
assetIconPath: 'assets/ui/generated/actions/action_notes_quill.webp',
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (_) => const PantallaNotas()),
);
},
),
),
),
],
),
],
const SizedBox(width: 12),
Expanded(
flex: 2,
child: BotonFarolero(
texto: l10n.goToVoting,
icono: Icons.how_to_vote,
assetIconPath: 'assets/ui/generated/actions/action_vote_mask.webp',
onPressed: _irAVotacion,
),
),
],
),
],
),
),
),
),
+103 -99
View File
@@ -1,4 +1,5 @@
import 'dart:async';
import '../tema/dialogo_confirmacion.dart';
import 'package:flutter/material.dart';
import 'package:farolero/l10n/generated/app_localizations.dart';
import 'package:farolero/modelos/inicio_partida_multijugador.dart';
@@ -117,110 +118,113 @@ class _PantallaDebateClienteState extends State<PantallaDebateCliente> {
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
return Scaffold(
backgroundColor: TemaApp.colorFondo,
appBar: AppBar(
title: Text(l10n.debate),
automaticallyImplyLeading: false,
backgroundColor: Colors.transparent,
elevation: 0,
actions: [
IconButton(
tooltip: l10n.seeYourWord,
icon: IconoFarolero(Icons.visibility),
onPressed: widget.jugadoresControlados.isEmpty
? null
: () => mostrarRevisionPalabraOnline(
context: context,
jugadoresControlados: widget.jugadoresControlados,
pistaImpostor: widget.pistaImpostor,
),
),
IconButton(
tooltip: l10n.notesTitle,
icon: IconoFarolero(Icons.edit_note),
onPressed: _puedeAbrirNotas
? () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => PantallaNotasOnline(
partidaId: widget.partidaId!,
jugadores: widget.jugadores,
autoresControlados: widget.jugadoresControlados,
),
return GuardiaSalidaPartida(
contexto: ContextoSalida.cliente,
child: Scaffold(
backgroundColor: TemaApp.colorFondo,
appBar: AppBar(
title: Text(l10n.debate),
automaticallyImplyLeading: false,
backgroundColor: Colors.transparent,
elevation: 0,
actions: [
IconButton(
tooltip: l10n.seeYourWord,
icon: IconoFarolero(Icons.visibility),
onPressed: widget.jugadoresControlados.isEmpty
? null
: () => mostrarRevisionPalabraOnline(
context: context,
jugadoresControlados: widget.jugadoresControlados,
pistaImpostor: widget.pistaImpostor,
),
)
: null,
),
],
),
body: FondoFarolero(
intenso: true,
child: SafeArea(
top: false,
child: SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Column(
children: [
const ArteGameplayFarolero.fase(height: 124),
const SizedBox(height: 12),
TarjetaFaseFarolero(
icono: Icons.forum,
assetIconPath: 'assets/ui/generated/actions/action_rules_book.webp',
titulo: l10n.debate,
subtitulo: l10n.debateInstructions,
child: Column(
children: [
if (widget.tiempoDebateSegundos != null) ...[
TemporizadorFarolero(
etiqueta: _segundosRestantes == 0
? l10n.timeUp
: l10n.timeRemaining,
tiempo: _formatearTiempo(_segundosRestantes),
agotado: _segundosRestantes == 0,
),
const SizedBox(height: 16),
] else ...[
Text(
l10n.debatePhaseActive,
style: Theme.of(context).textTheme.titleLarge,
textAlign: TextAlign.center,
),
const SizedBox(height: 16),
],
if (widget.primerTurnoNombre != null) ...[
EstadoJugadorFarolero(
nombre: l10n.firstTurnInstruction(
widget.primerTurnoNombre!,
),
IconButton(
tooltip: l10n.notesTitle,
icon: IconoFarolero(Icons.edit_note),
onPressed: _puedeAbrirNotas
? () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => PantallaNotasOnline(
partidaId: widget.partidaId!,
jugadores: widget.jugadores,
autoresControlados: widget.jugadoresControlados,
),
destacado: true,
completado: true,
icono: Icons.record_voice_over,
assetIconPath: 'assets/ui/generated/actions/action_players_group.webp',
),
const SizedBox(height: 12),
)
: null,
),
],
),
body: FondoFarolero(
intenso: true,
child: SafeArea(
top: false,
child: SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Column(
children: [
const ArteGameplayFarolero.fase(height: 124),
const SizedBox(height: 12),
TarjetaFaseFarolero(
icono: Icons.forum,
assetIconPath: 'assets/ui/generated/actions/action_rules_book.webp',
titulo: l10n.debate,
subtitulo: l10n.debateInstructions,
child: Column(
children: [
if (widget.tiempoDebateSegundos != null) ...[
TemporizadorFarolero(
etiqueta: _segundosRestantes == 0
? l10n.timeUp
: l10n.timeRemaining,
tiempo: _formatearTiempo(_segundosRestantes),
agotado: _segundosRestantes == 0,
),
const SizedBox(height: 16),
] else ...[
Text(
l10n.debatePhaseActive,
style: Theme.of(context).textTheme.titleLarge,
textAlign: TextAlign.center,
),
const SizedBox(height: 16),
],
if (widget.primerTurnoNombre != null) ...[
EstadoJugadorFarolero(
nombre: l10n.firstTurnInstruction(
widget.primerTurnoNombre!,
),
destacado: true,
completado: true,
icono: Icons.record_voice_over,
assetIconPath: 'assets/ui/generated/actions/action_players_group.webp',
),
const SizedBox(height: 12),
],
BotonFarolero.secundario(
texto: _votacionSolicitada
? l10n.votacionSolicitada
: l10n.solicitarVotacion,
icono: _votacionSolicitada
? Icons.hourglass_empty
: Icons.how_to_vote,
assetIconPath: _votacionSolicitada
? null
: 'assets/ui/generated/actions/action_vote_mask.webp',
onPressed: _votacionSolicitada
? null
: () {
setState(() => _votacionSolicitada = true);
widget.onSolicitarVotacion();
},
),
],
BotonFarolero.secundario(
texto: _votacionSolicitada
? l10n.votacionSolicitada
: l10n.solicitarVotacion,
icono: _votacionSolicitada
? Icons.hourglass_empty
: Icons.how_to_vote,
assetIconPath: _votacionSolicitada
? null
: 'assets/ui/generated/actions/action_vote_mask.webp',
onPressed: _votacionSolicitada
? null
: () {
setState(() => _votacionSolicitada = true);
widget.onSolicitarVotacion();
},
),
],
),
),
),
],
],
),
),
),
),
+15 -1
View File
@@ -1,4 +1,5 @@
import 'dart:async';
import '../tema/dialogo_confirmacion.dart';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:farolero/l10n/generated/app_localizations.dart';
@@ -257,7 +258,9 @@ class _PantallaGestorHostState extends State<PantallaGestorHost> {
clientesPendientes.every((id) => _clientesListos[id] == true);
final todosVotaron = estado.todosHanVotado();
return Scaffold(
return GuardiaSalidaPartida(
contexto: ContextoSalida.host,
child: Scaffold(
appBar: AppBar(
title: Text(l10n.hostGame),
automaticallyImplyLeading: false,
@@ -299,8 +302,15 @@ class _PantallaGestorHostState extends State<PantallaGestorHost> {
),
),
IconButton(
tooltip: l10n.leaveGame,
icon: IconoFarolero(Icons.close),
onPressed: () async {
if (!await confirmarSalirDePartida(
context,
ContextoSalida.host,
)) {
return;
}
await nearby.desconectar();
widget.onPartidaFin();
},
@@ -309,6 +319,7 @@ class _PantallaGestorHostState extends State<PantallaGestorHost> {
),
body: FondoFarolero(
intenso: true,
respetarBarras: true,
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
@@ -339,6 +350,7 @@ class _PantallaGestorHostState extends State<PantallaGestorHost> {
),
),
),
),
);
}
@@ -579,6 +591,7 @@ class _PantallaGestorHostState extends State<PantallaGestorHost> {
context,
MaterialPageRoute(
builder: (_) => PantallaPalabrasCliente(
protegerSalida: false,
jugadores: jugadoresHost,
pistaImpostor: partida.config.pistaImpostor
? partida.pistaImpostor
@@ -862,6 +875,7 @@ class _PantallaGestorHostState extends State<PantallaGestorHost> {
context,
MaterialPageRoute(
builder: (_) => PantallaVotacionCliente(
protegerSalida: false,
jugadores: partida.jugadoresActivos,
jugadoresControlados: jugadoresHost,
partidaId: context.read<ServicioNearby>().roomId,
+7
View File
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import '../tema/dialogo_confirmacion.dart';
import 'package:provider/provider.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'package:farolero/l10n/generated/app_localizations.dart';
@@ -42,6 +43,12 @@ class _PantallaLobbyHostState extends State<PantallaLobbyHost> {
leading: IconButton(
icon: IconoFarolero(Icons.close),
onPressed: () async {
if (!await confirmarSalirDePartida(
context,
ContextoSalida.host,
)) {
return;
}
await nearby.desconectar();
if (context.mounted) Navigator.pop(context);
},
+1
View File
@@ -89,6 +89,7 @@ class _PantallaNotasState extends State<PantallaNotas> {
),
body: FondoFarolero(
intenso: true,
respetarBarras: true,
child: _jugadorSeleccionadoId == null
? _construirSelectorJugador(partida)
: _construirNotas(partida),
+1
View File
@@ -118,6 +118,7 @@ class _PantallaNotasOnlineState extends State<PantallaNotasOnline> {
),
body: FondoFarolero(
intenso: true,
respetarBarras: true,
child: _autor == null ? _buildSelector(context) : _buildNotas(context),
),
),
+11 -1
View File
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:farolero/tema/dialogo_confirmacion.dart';
import 'package:farolero/l10n/generated/app_localizations.dart';
import 'package:farolero/modelos/inicio_partida_multijugador.dart';
import 'package:farolero/tema/componentes_farolero.dart';
@@ -10,11 +11,16 @@ class PantallaPalabrasCliente extends StatefulWidget {
final String? pistaImpostor;
final VoidCallback onTodosVistos;
/// El host abre esta pantalla desde el gestor: allí el atrás solo
/// debe cerrarla, no ofrecer abandonar la partida.
final bool protegerSalida;
const PantallaPalabrasCliente({
super.key,
required this.jugadores,
this.pistaImpostor,
required this.onTodosVistos,
this.protegerSalida = true,
});
@override
@@ -47,7 +53,10 @@ class _PantallaPalabrasClienteState extends State<PantallaPalabrasCliente> {
final l10n = AppLocalizations.of(context)!;
final actual = _actual;
return Scaffold(
return GuardiaSalidaPartida(
contexto: ContextoSalida.cliente,
activo: widget.protegerSalida,
child: Scaffold(
body: FondoFarolero(
intenso: true,
child: SafeArea(
@@ -147,6 +156,7 @@ class _PantallaPalabrasClienteState extends State<PantallaPalabrasCliente> {
),
),
),
),
);
}
}
+39 -34
View File
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import '../tema/dialogo_confirmacion.dart';
import 'package:farolero/l10n/generated/app_localizations.dart';
import 'package:provider/provider.dart';
import '../estado/estado_juego.dart';
@@ -59,42 +60,46 @@ class _PantallaResultadoState extends State<PantallaResultado>
final estado = context.read<EstadoJuego>();
final partida = estado.partida;
return Scaffold(
appBar: AppBar(
title: Text(l10n.result),
automaticallyImplyLeading: false,
),
body: FondoFarolero(
intenso: true,
child: Center(
child: SingleChildScrollView(
padding: const EdgeInsets.all(32),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Animación de suspense
if (!_revelado) ...[
const ArteGameplayFarolero.resultado(height: 152),
const SizedBox(height: 16),
Text(
l10n.revealing,
style: Theme.of(context).textTheme.headlineMedium,
),
const SizedBox(height: 24),
const CircularProgressIndicator(color: TemaApp.colorAcento),
],
if (_revelado) ...[
FadeTransition(
opacity: _animOpacidad,
child: ResultadoRondaFarolero(
resultado: widget.resultado,
jugadores: partida?.jugadores ?? const [],
acciones: _construirBotones(context, estado),
return GuardiaSalidaPartida(
contexto: ContextoSalida.unDispositivo,
child: Scaffold(
appBar: AppBar(
title: Text(l10n.result),
automaticallyImplyLeading: false,
),
body: FondoFarolero(
intenso: true,
respetarBarras: true,
child: Center(
child: SingleChildScrollView(
padding: const EdgeInsets.all(32),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Animación de suspense
if (!_revelado) ...[
const ArteGameplayFarolero.resultado(height: 152),
const SizedBox(height: 16),
Text(
l10n.revealing,
style: Theme.of(context).textTheme.headlineMedium,
),
),
const SizedBox(height: 24),
const CircularProgressIndicator(color: TemaApp.colorAcento),
],
if (_revelado) ...[
FadeTransition(
opacity: _animOpacidad,
child: ResultadoRondaFarolero(
resultado: widget.resultado,
jugadores: partida?.jugadores ?? const [],
acciones: _construirBotones(context, estado),
),
),
],
],
],
),
),
),
),
+28 -24
View File
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import '../tema/dialogo_confirmacion.dart';
import 'package:farolero/l10n/generated/app_localizations.dart';
import '../modelos/inicio_partida_multijugador.dart';
import '../modelos/snapshot_partida_online.dart';
@@ -158,30 +159,33 @@ class _PantallaResultadoOnlineState extends State<PantallaResultadoOnline> {
final l10n = AppLocalizations.of(context)!;
final resultado = _snapshot.resultadoActual;
return Scaffold(
backgroundColor: TemaApp.colorFondo,
appBar: AppBar(
title: Text(_snapshot.fase == 'adivinanza'
? l10n.impostorGuessTitle
: l10n.result),
automaticallyImplyLeading: false,
backgroundColor: Colors.transparent,
elevation: 0,
actions: _acciones(context, l10n),
),
body: FondoFarolero(
intenso: true,
child: SafeArea(
top: false,
child: SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: resultado == null
? _buildEsperaAdivinanza(context, l10n)
: ResultadoRondaFarolero(
resultado: resultado,
jugadores: _snapshot.jugadores,
mensaje: _snapshot.mensaje,
),
return GuardiaSalidaPartida(
contexto: ContextoSalida.cliente,
child: Scaffold(
backgroundColor: TemaApp.colorFondo,
appBar: AppBar(
title: Text(_snapshot.fase == 'adivinanza'
? l10n.impostorGuessTitle
: l10n.result),
automaticallyImplyLeading: false,
backgroundColor: Colors.transparent,
elevation: 0,
actions: _acciones(context, l10n),
),
body: FondoFarolero(
intenso: true,
child: SafeArea(
top: false,
child: SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: resultado == null
? _buildEsperaAdivinanza(context, l10n)
: ResultadoRondaFarolero(
resultado: resultado,
jugadores: _snapshot.jugadores,
mensaje: _snapshot.mensaje,
),
),
),
),
),
+61 -57
View File
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import '../tema/dialogo_confirmacion.dart';
import 'package:farolero/l10n/generated/app_localizations.dart';
import 'package:provider/provider.dart';
import '../estado/estado_juego.dart';
@@ -25,64 +26,67 @@ class _PantallaVerPalabraState extends State<PantallaVerPalabra> {
final todosHanVisto = partida.jugadores.every((j) => _hanVisto.contains(j.id));
return Scaffold(
appBar: AppBar(
title: Text(l10n.seeYourWord),
automaticallyImplyLeading: false,
),
body: FondoFarolero(
intenso: true,
child: SafeArea(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
const ArteGameplayFarolero.fase(height: 110),
const SizedBox(height: 10),
TarjetaFaseFarolero(
icono: Icons.visibility,
assetIconPath: 'assets/ui/generated/actions/action_reveal_word.webp',
titulo: l10n.roundNumber(partida.rondaActual),
subtitulo: l10n.eachPlayerMustSee,
),
const SizedBox(height: 16),
Expanded(
child: ListView.separated(
itemCount: partida.jugadores.length,
separatorBuilder: (context, index) => const SizedBox(height: 10),
itemBuilder: (context, index) {
final jugador = partida.jugadores[index];
final haVisto = _hanVisto.contains(jugador.id);
return EstadoJugadorFarolero(
nombre: '${index + 1}. ${jugador.nombre}',
subtitulo: haVisto ? l10n.alreadySeen : l10n.tapToSee,
icono: haVisto ? Icons.check_circle : Icons.visibility,
assetIconPath: haVisto ? null : 'assets/ui/generated/actions/action_reveal_word.webp',
destacado: haVisto,
completado: haVisto,
onTap: haVisto ? null : () => _mostrarPalabra(context, jugador.id),
);
},
return GuardiaSalidaPartida(
contexto: ContextoSalida.unDispositivo,
child: Scaffold(
appBar: AppBar(
title: Text(l10n.seeYourWord),
automaticallyImplyLeading: false,
),
body: FondoFarolero(
intenso: true,
child: SafeArea(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
const ArteGameplayFarolero.fase(height: 110),
const SizedBox(height: 10),
TarjetaFaseFarolero(
icono: Icons.visibility,
assetIconPath: 'assets/ui/generated/actions/action_reveal_word.webp',
titulo: l10n.roundNumber(partida.rondaActual),
subtitulo: l10n.eachPlayerMustSee,
),
),
const SizedBox(height: 16),
BotonFarolero(
texto: todosHanVisto
? l10n.allSeenStartDebate
: l10n.playersRemaining(partida.jugadores.length - _hanVisto.length),
icono: Icons.forum,
assetIconPath: 'assets/ui/generated/actions/action_rules_book.webp',
onPressed: todosHanVisto
? () {
estado.iniciarDebate();
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (_) => const PantallaDebate()),
);
}
: null,
),
],
const SizedBox(height: 16),
Expanded(
child: ListView.separated(
itemCount: partida.jugadores.length,
separatorBuilder: (context, index) => const SizedBox(height: 10),
itemBuilder: (context, index) {
final jugador = partida.jugadores[index];
final haVisto = _hanVisto.contains(jugador.id);
return EstadoJugadorFarolero(
nombre: '${index + 1}. ${jugador.nombre}',
subtitulo: haVisto ? l10n.alreadySeen : l10n.tapToSee,
icono: haVisto ? Icons.check_circle : Icons.visibility,
assetIconPath: haVisto ? null : 'assets/ui/generated/actions/action_reveal_word.webp',
destacado: haVisto,
completado: haVisto,
onTap: haVisto ? null : () => _mostrarPalabra(context, jugador.id),
);
},
),
),
const SizedBox(height: 16),
BotonFarolero(
texto: todosHanVisto
? l10n.allSeenStartDebate
: l10n.playersRemaining(partida.jugadores.length - _hanVisto.length),
icono: Icons.forum,
assetIconPath: 'assets/ui/generated/actions/action_rules_book.webp',
onPressed: todosHanVisto
? () {
estado.iniciarDebate();
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (_) => const PantallaDebate()),
);
}
: null,
),
],
),
),
),
),
+7 -1
View File
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import '../tema/dialogo_confirmacion.dart';
import 'package:farolero/l10n/generated/app_localizations.dart';
import 'package:provider/provider.dart';
import '../estado/estado_juego.dart';
@@ -25,7 +26,12 @@ class _PantallaVotacionState extends State<PantallaVotacion> {
final activos = partida.jugadoresActivos;
final todosVotaron = estado.todosHanVotado();
return _construirVotacionUnMovil(context, estado, partida, activos, todosVotaron);
return GuardiaSalidaPartida(
contexto: ContextoSalida.unDispositivo,
child: _construirVotacionUnMovil(
context, estado, partida, activos, todosVotaron,
),
);
}
Widget _construirVotacionUnMovil(
+12 -1
View File
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:farolero/tema/dialogo_confirmacion.dart';
import 'package:farolero/l10n/generated/app_localizations.dart';
import 'package:farolero/modelos/inicio_partida_multijugador.dart';
import 'package:farolero/modelos/jugador.dart';
@@ -17,6 +18,10 @@ class PantallaVotacionCliente extends StatefulWidget {
final String? pistaImpostor;
final Function(Map<String, String> votos) onVotos;
/// El host abre esta pantalla desde el gestor: allí el atrás solo
/// debe cerrarla, no ofrecer abandonar la partida.
final bool protegerSalida;
const PantallaVotacionCliente({
super.key,
required this.jugadores,
@@ -24,6 +29,7 @@ class PantallaVotacionCliente extends StatefulWidget {
this.partidaId,
this.pistaImpostor,
required this.onVotos,
this.protegerSalida = true,
});
@override
@@ -63,7 +69,10 @@ class _PantallaVotacionClienteState extends State<PantallaVotacionCliente> {
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
return Scaffold(
return GuardiaSalidaPartida(
contexto: ContextoSalida.cliente,
activo: widget.protegerSalida,
child: Scaffold(
backgroundColor: TemaApp.colorFondo,
appBar: AppBar(
title: Text(l10n.voting),
@@ -102,6 +111,7 @@ class _PantallaVotacionClienteState extends State<PantallaVotacionCliente> {
),
body: FondoFarolero(
intenso: true,
respetarBarras: true,
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
@@ -154,6 +164,7 @@ class _PantallaVotacionClienteState extends State<PantallaVotacionCliente> {
),
),
),
),
);
}
+20 -12
View File
@@ -1,4 +1,5 @@
import 'dart:io';
import 'package:farolero/l10n/generated/app_localizations.dart';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
@@ -24,11 +25,14 @@ class ServicioPermisos {
// Solicitar todos
final resultados = await permisos.request();
if (!context.mounted) return false;
final l10n = AppLocalizations.of(context)!;
// Verificar cuáles fueron denegados
final denegados = <String>[];
for (final entry in resultados.entries) {
if (!entry.value.isGranted) {
denegados.add(_nombrePermiso(entry.key));
denegados.add(_nombrePermiso(entry.key, l10n));
}
}
@@ -39,20 +43,20 @@ class ServicioPermisos {
final abrirConfig = await showDialog<bool>(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('Permisos necesarios'),
title: Text(l10n.permissionsNeededTitle),
content: Text(
'Para el modo multijugador necesitamos:\n\n'
'${l10n.permissionsNeededBody}\n\n'
'${denegados.map((d) => '$d').join('\n')}\n\n'
'¿Abrir configuración de la app?',
'${l10n.openAppSettingsQuestion}',
),
actions: [
TextButton(
onPressed: () => Navigator.pop(ctx, false),
child: const Text('Cancelar'),
child: Text(l10n.cancel),
),
TextButton(
onPressed: () => Navigator.pop(ctx, true),
child: const Text('Abrir configuración'),
child: Text(l10n.openSettings),
),
],
),
@@ -66,12 +70,16 @@ class ServicioPermisos {
return false;
}
static String _nombrePermiso(Permission p) {
if (p == Permission.locationWhenInUse) return 'Ubicación';
if (p == Permission.bluetoothAdvertise) return 'Bluetooth (anunciar)';
if (p == Permission.bluetoothConnect) return 'Bluetooth (conectar)';
if (p == Permission.bluetoothScan) return 'Bluetooth (escanear)';
if (p == Permission.nearbyWifiDevices) return 'Wi-Fi cercano';
static String _nombrePermiso(Permission p, AppLocalizations l10n) {
if (p == Permission.locationWhenInUse) return l10n.permissionLocation;
if (p == Permission.bluetoothAdvertise) {
return l10n.permissionBluetoothAdvertise;
}
if (p == Permission.bluetoothConnect) {
return l10n.permissionBluetoothConnect;
}
if (p == Permission.bluetoothScan) return l10n.permissionBluetoothScan;
if (p == Permission.nearbyWifiDevices) return l10n.permissionNearbyWifi;
return p.toString();
}
}
+128
View File
@@ -0,0 +1,128 @@
import 'package:flutter/material.dart';
/// Bandera del selector de idioma.
///
/// La mayoría son emoji de indicador regional y el sistema los dibuja solo.
/// Catalán y euskera no: Unicode define sus secuencias de subdivisión, pero
/// fuera de Inglaterra, Escocia y Gales no están en el conjunto recomendado,
/// así que casi ningún sistema las representa y salía una bandera negra. Esas
/// dos se pintan aquí; son geometría simple y así quedan nítidas a cualquier
/// tamaño sin añadir imágenes.
class BanderaIdioma extends StatelessWidget {
final String codigo;
final String emoji;
final double alto;
const BanderaIdioma({
super.key,
required this.codigo,
required this.emoji,
this.alto = 22,
});
static const _pintadas = {'ca', 'eu'};
/// True si la bandera de ese idioma se dibuja en vez de usar emoji.
static bool sePinta(String codigo) => _pintadas.contains(codigo);
@override
Widget build(BuildContext context) {
if (!sePinta(codigo)) {
// El emoji ocupa lo que ocupe; se le da la misma caja que a las pintadas
// para que la lista quede alineada.
return SizedBox(
width: alto * 1.5,
height: alto,
child: Center(
child: Text(emoji, style: TextStyle(fontSize: alto * 1.1)),
),
);
}
return SizedBox(
width: alto * 1.5,
height: alto,
child: ClipRRect(
borderRadius: BorderRadius.circular(3),
child: CustomPaint(
painter: codigo == 'ca'
? const _SenyeraPainter()
: const _IkurrinaPainter(),
size: Size(alto * 1.5, alto),
),
),
);
}
}
/// Senyera: cuatro palos rojos sobre fondo amarillo, nueve franjas iguales.
class _SenyeraPainter extends CustomPainter {
const _SenyeraPainter();
static const _amarillo = Color(0xFFFCDD09);
static const _rojo = Color(0xFFDA121A);
@override
void paint(Canvas canvas, Size size) {
canvas.drawRect(
Rect.fromLTWH(0, 0, size.width, size.height),
Paint()..color = _amarillo,
);
final franja = size.height / 9;
final pincel = Paint()..color = _rojo;
// Las franjas impares (1, 3, 5, 7) son los cuatro palos.
for (var i = 1; i < 9; i += 2) {
canvas.drawRect(
Rect.fromLTWH(0, franja * i, size.width, franja),
pincel,
);
}
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
/// Ikurriña: fondo rojo, aspa verde y cruz blanca encima.
class _IkurrinaPainter extends CustomPainter {
const _IkurrinaPainter();
static const _rojo = Color(0xFFD52B1E);
static const _verde = Color(0xFF009B48);
static const _blanco = Color(0xFFFFFFFF);
@override
void paint(Canvas canvas, Size size) {
final w = size.width;
final h = size.height;
canvas.drawRect(Rect.fromLTWH(0, 0, w, h), Paint()..color = _rojo);
// El aspa va de esquina a esquina, por debajo de la cruz.
final grosor = h * 0.19;
final aspa = Paint()
..color = _verde
..strokeWidth = grosor
..style = PaintingStyle.stroke;
canvas.save();
canvas.clipRect(Rect.fromLTWH(0, 0, w, h));
canvas.drawLine(Offset.zero, Offset(w, h), aspa);
canvas.drawLine(Offset(w, 0), Offset(0, h), aspa);
canvas.restore();
// Cruz blanca centrada, encima del aspa.
final blanco = Paint()..color = _blanco;
canvas.drawRect(
Rect.fromLTWH((w - grosor) / 2, 0, grosor, h),
blanco,
);
canvas.drawRect(
Rect.fromLTWH(0, (h - grosor) / 2, w, grosor),
blanco,
);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
+13 -1
View File
@@ -139,10 +139,20 @@ class FondoFarolero extends StatelessWidget {
final Widget child;
final bool intenso;
/// Aparta el contenido de las barras del sistema.
///
/// A partir de targetSdk 35 la app dibuja de borde a borde, así que sin esto
/// lo que quede abajo —normalmente el botón de acción— acaba debajo de la
/// barra de gestos. El fondo se sigue pintando entero; solo se aparta el
/// contenido. Las pantallas que ya envuelven su contenido en SafeArea no
/// necesitan activarlo.
final bool respetarBarras;
const FondoFarolero({
super.key,
required this.child,
this.intenso = false,
this.respetarBarras = false,
});
@override
@@ -163,7 +173,9 @@ class FondoFarolero extends StatelessWidget {
),
),
),
Positioned.fill(child: child),
Positioned.fill(
child: respetarBarras ? SafeArea(child: child) : child,
),
],
),
);
+170
View File
@@ -0,0 +1,170 @@
import 'package:flutter/material.dart';
import '../l10n/generated/app_localizations.dart';
import 'componentes_farolero.dart';
import 'tema_app.dart';
/// Quién está saliendo, que determina qué se pierde y por tanto qué se avisa.
enum ContextoSalida {
/// Un solo móvil: la partida vive en este dispositivo y se pierde entera.
unDispositivo,
/// El host de una partida multidispositivo: al salir la corta para todos.
host,
/// Un cliente: solo se va él y puede volver mientras la sala siga abierta.
cliente,
}
/// Diálogo de confirmación con el estilo de la app.
///
/// Devuelve `true` solo si el jugador confirma. Cerrarlo tocando fuera o con
/// el gesto de atrás cuenta como cancelar, que es lo que interesa cuando lo
/// que se está evitando es precisamente una salida accidental.
Future<bool> confirmarFarolero({
required BuildContext context,
required String titulo,
required String mensaje,
required String textoConfirmar,
required String textoCancelar,
IconData icono = Icons.warning_amber_rounded,
IconData iconoConfirmar = Icons.logout,
IconData iconoCancelar = Icons.play_arrow,
}) async {
final confirmado = await showDialog<bool>(
context: context,
barrierDismissible: true,
builder: (dialogContext) => Dialog(
backgroundColor: TemaApp.colorSuperficie,
insetPadding: const EdgeInsets.symmetric(horizontal: 28, vertical: 24),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24),
side: BorderSide(
color: TemaApp.colorNaranja.withValues(alpha: 0.45),
),
),
child: Padding(
padding: const EdgeInsets.fromLTRB(24, 28, 24, 24),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 72,
height: 72,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: TemaApp.colorAcento.withValues(alpha: 0.16),
border: Border.all(
color: TemaApp.colorAcento.withValues(alpha: 0.65),
width: 2,
),
),
child: IconoFarolero(
icono,
color: TemaApp.colorNaranja,
size: 38,
),
),
const SizedBox(height: 18),
Text(
titulo,
textAlign: TextAlign.center,
style: Theme.of(dialogContext).textTheme.titleLarge?.copyWith(
color: TemaApp.colorDorado,
),
),
const SizedBox(height: 10),
Text(
mensaje,
textAlign: TextAlign.center,
style: Theme.of(dialogContext).textTheme.bodyMedium?.copyWith(
color: TemaApp.colorTextoSecundario,
height: 1.35,
),
),
const SizedBox(height: 26),
// La acción segura va primero y destacada: si alguien llega aquí
// sin querer, lo cómodo tiene que ser quedarse.
BotonFarolero(
texto: textoCancelar,
icono: iconoCancelar,
onPressed: () => Navigator.of(dialogContext).pop(false),
),
const SizedBox(height: 12),
BotonFarolero.oscuro(
texto: textoConfirmar,
icono: iconoConfirmar,
onPressed: () => Navigator.of(dialogContext).pop(true),
),
],
),
),
),
);
return confirmado ?? false;
}
/// Pregunta antes de abandonar una partida en curso.
Future<bool> confirmarSalirDePartida(
BuildContext context,
ContextoSalida contexto,
) {
final l10n = AppLocalizations.of(context)!;
return confirmarFarolero(
context: context,
titulo: l10n.leaveGameTitle,
mensaje: switch (contexto) {
ContextoSalida.unDispositivo => l10n.leaveGameSingleDevice,
ContextoSalida.host => l10n.leaveGameHost,
ContextoSalida.cliente => l10n.leaveGameClient,
},
textoConfirmar: l10n.leaveGame,
textoCancelar: l10n.stayInGame,
);
}
/// Envuelve una pantalla de partida para que el gesto o botón de atrás no la
/// abandone sin preguntar.
///
/// Se encarga solo del atrás del sistema; los botones de cerrar de cada
/// pantalla llaman a [confirmarSalirDePartida] por su cuenta, porque además de
/// confirmar tienen que desconectar y navegar.
class GuardiaSalidaPartida extends StatelessWidget {
final Widget child;
final ContextoSalida contexto;
/// Qué hacer cuando el jugador confirma que quiere salir. Si es null se deja
/// que la ruta se cierre con normalidad.
final VoidCallback? onSalirConfirmado;
/// Permite desactivar la guarda sin sacar el widget del árbol, por ejemplo
/// cuando la partida ya ha terminado.
final bool activo;
const GuardiaSalidaPartida({
super.key,
required this.child,
required this.contexto,
this.onSalirConfirmado,
this.activo = true,
});
@override
Widget build(BuildContext context) {
return PopScope(
canPop: !activo,
onPopInvokedWithResult: (didPop, result) async {
if (didPop) return;
final salir = await confirmarSalirDePartida(context, contexto);
if (!salir || !context.mounted) return;
final alSalir = onSalirConfirmado;
if (alSalir != null) {
alSalir();
} else if (Navigator.of(context).canPop()) {
Navigator.of(context).pop();
}
},
child: child,
);
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
name: farolero
description: "Farolero — Juego de deducción social. ¿Quién finge saber?"
publish_to: 'none'
version: 1.1.41+46
version: 1.1.53+58
environment:
sdk: ^3.11.1
+110
View File
@@ -0,0 +1,110 @@
import 'dart:convert';
import 'dart:io';
import 'package:flutter_test/flutter_test.dart';
/// Guardas sobre los ficheros de traducción.
///
/// El fallo que motivó estos tests: 21 claves se quedaron con el texto inglés
/// dentro de árabe, japonés, coreano, chino, ruso, turco, hindi, neerlandés,
/// polaco y euskera. Nada fallaba: la app mostraba inglés y ya está.
void main() {
const idiomaPlantilla = 'es';
/// Coincidencias reales entre idiomas: palabras que se escriben igual y por
/// tanto no son un descuido. Cada entrada es "idioma:clave".
const coincidenciasLegitimas = {
// Nombre de la app y rangos numéricos, iguales en todas partes.
'de:appTitle', 'en:appTitle', 'fr:appTitle', 'it:appTitle',
// "Animals", "Professions", "Impostors", "Notes" son catalán correcto.
'ca:categoryAnimals', 'ca:categoryProfessions', 'ca:impostors',
'ca:notes', 'ca:notesTitle',
// "Vibration", "Version", "Name" son alemán correcto.
'de:vibration', 'de:version', 'de:profileName',
// "Sports", "Configuration", "Notes", "Vibration", "Version" son francés.
'fr:categorySports', 'fr:configuration', 'fr:notes', 'fr:notesTitle',
'fr:vibration', 'fr:version',
// "Round" se usa tal cual en italiano.
'it:roundNumber', 'it:roundElimination',
};
Map<String, String> cargar(String idioma) {
final fichero = File('lib/l10n/app_$idioma.arb');
final datos = json.decode(fichero.readAsStringSync()) as Map<String, dynamic>;
return {
for (final e in datos.entries)
if (!e.key.startsWith('@') && e.value is String)
e.key: e.value as String,
};
}
final idiomas = Directory('lib/l10n')
.listSync()
.whereType<File>()
.where((f) => f.path.endsWith('.arb'))
.map((f) => f.uri.pathSegments.last.replaceAll(RegExp(r'^app_|\.arb$'), ''))
.toList()
..sort();
final plantilla = cargar(idiomaPlantilla);
final ingles = cargar('en');
test('están los 18 idiomas soportados', () {
expect(idiomas.length, 18);
});
for (final idioma in idiomas) {
group('app_$idioma.arb', () {
final valores = cargar(idioma);
test('no le falta ninguna clave de la plantilla', () {
final faltan = plantilla.keys.where((k) => !valores.containsKey(k));
expect(faltan, isEmpty, reason: 'sin traducir: ${faltan.join(", ")}');
});
test('no tiene claves que la plantilla no conozca', () {
final sobran = valores.keys.where((k) => !plantilla.containsKey(k));
expect(sobran, isEmpty, reason: 'huérfanas: ${sobran.join(", ")}');
});
test('ningún valor está vacío', () {
final vacios = valores.entries
.where((e) => e.value.trim().isEmpty)
.map((e) => e.key);
expect(vacios, isEmpty);
});
if (idioma != 'en' && idioma != idiomaPlantilla) {
test('no se ha quedado el texto en inglés', () {
final enIngles = valores.entries
.where((e) =>
ingles[e.key] == e.value &&
plantilla[e.key] != e.value &&
!coincidenciasLegitimas.contains('$idioma:${e.key}'))
.map((e) => '${e.key} = "${e.value}"')
.toList();
expect(enIngles, isEmpty, reason: enIngles.join('\n'));
});
}
test('conserva los marcadores de posición de la plantilla', () {
final patron = RegExp(r'\{(\w+)\}');
final fallos = <String>[];
for (final entrada in valores.entries) {
final esperados = patron
.allMatches(plantilla[entrada.key] ?? '')
.map((m) => m.group(1)!)
.toSet();
final presentes =
patron.allMatches(entrada.value).map((m) => m.group(1)!).toSet();
// Los plurales ICU declaran el contador fuera de las llaves simples.
if (entrada.value.contains(', plural,')) continue;
if (!presentes.containsAll(esperados)) {
fallos.add('${entrada.key}: faltan ${esperados.difference(presentes)}');
}
}
expect(fallos, isEmpty, reason: fallos.join('\n'));
});
});
}
}