Spanish (es) draft for the bridge screens
DRAFT, needs native review.
Rebased onto bridge/f2f-apps (ebdd2ac). NetworkSection.kt was taken from
the bridge branch whole and its text moved to resources again, so every
bridge behaviour stays as that branch wrote it: several lines with failover,
offers, sharing with a confirmation, scanning a line, and nothing said to go
around a saved bridge.
- 19 new resources: the bridge list, failover and sharing text, the sign-in
"Connect through a bridge" toggle, the four "off while you use a bridge"
notices (calls, wallet, link previews, and the no-bridge failure).
- statusLineText() mirrors the new statusLine() branches, including "none
reached" and "N bridges saved"; the English function stays for its tests.
- describeFailure takes the no-bridge sentence from the view model;
ChainRpc.Failure.OffWhileBridged maps to the wallet notice.
- ScanAddressDialog's default hint and refusal are resources.
- Obfs4Settings.AddResult and AroundTheBridge keep their English for the
tests; the screens show resources.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
5dbf626f46
commit
0d62e81d1a
@@ -3930,7 +3930,7 @@ private fun ColumnScope.MediaQualitySection() {
|
||||
}
|
||||
if (io.flamenet.client.AroundTheBridge.active) {
|
||||
Text(
|
||||
io.flamenet.client.AroundTheBridge.LINK_PREVIEWS_OFF,
|
||||
stringResource(R.string.core_bridge_link_previews_off),
|
||||
fontSize = 13.sp,
|
||||
color = Palette.SecondaryText,
|
||||
modifier = Modifier.testTag("link-previews-bridged"),
|
||||
|
||||
@@ -601,7 +601,15 @@ internal fun ColumnScope.SignInScreen(
|
||||
TextButton(
|
||||
onClick = { bridges = !bridges },
|
||||
modifier = Modifier.fillMaxWidth().testTag("signin-bridges"),
|
||||
) { Text(if (bridges) "Hide bridge settings" else "Connect through a bridge") }
|
||||
) {
|
||||
Text(
|
||||
if (bridges) {
|
||||
stringResource(R.string.set_bridge_signin_hide)
|
||||
} else {
|
||||
stringResource(R.string.set_bridge_signin_show)
|
||||
},
|
||||
)
|
||||
}
|
||||
if (bridges) NetworkSection()
|
||||
}
|
||||
|
||||
|
||||
@@ -2987,8 +2987,10 @@ class MessengerViewModel(
|
||||
update { it.copy(error = str(R.string.core_calls_turned_off)) }
|
||||
return@launch
|
||||
}
|
||||
CallPolicy.bridgeRefusal()?.let { refusal ->
|
||||
update { it.copy(error = refusal) }
|
||||
CallPolicy.bridgeRefusal()?.let {
|
||||
// The English is AroundTheBridge.CALLS_OFF; the screen gets it in
|
||||
// the phone's language.
|
||||
update { it.copy(error = str(R.string.core_bridge_calls_off)) }
|
||||
return@launch
|
||||
}
|
||||
callWasConnected = false
|
||||
|
||||
@@ -24,7 +24,10 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.res.pluralStringResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.sp
|
||||
import io.flamenet.messenger.R
|
||||
import io.flamenet.client.Obfs4Routing
|
||||
import io.flamenet.obfs4.BridgeLine
|
||||
import io.flamenet.obfs4.BridgeLineResult
|
||||
@@ -66,11 +69,11 @@ fun ColumnScope.NetworkSection(
|
||||
val lines = remember(tick) { settings.lines }
|
||||
val parsed = if (draft.isBlank()) null else BridgeLine.parse(draft)
|
||||
|
||||
Text("Network", style = MaterialTheme.typography.titleMedium)
|
||||
Text(stringResource(R.string.set_network_title), style = MaterialTheme.typography.titleMedium)
|
||||
|
||||
// Reads what the transport did, never the stored list.
|
||||
Text(
|
||||
statusLine(),
|
||||
statusLineText(),
|
||||
fontSize = 13.sp,
|
||||
color = Palette.SecondaryText,
|
||||
modifier = Modifier.testTag("obfs4-status"),
|
||||
@@ -80,11 +83,11 @@ fun ColumnScope.NetworkSection(
|
||||
val offers = remember(tick) { model?.bridgeOffers().orEmpty() }
|
||||
if (offers.isNotEmpty()) {
|
||||
Spacer(Modifier.height(Space.md))
|
||||
Text("Offered to you", fontWeight = FontWeight.Medium, fontSize = 15.sp)
|
||||
Text(stringResource(R.string.set_network_offered), fontWeight = FontWeight.Medium, fontSize = 15.sp)
|
||||
for (offer in offers) {
|
||||
Spacer(Modifier.height(Space.sm))
|
||||
Text(
|
||||
"${offer.fromName} shared a bridge",
|
||||
stringResource(R.string.set_network_shared_a_bridge, offer.fromName),
|
||||
fontSize = 14.sp,
|
||||
modifier = Modifier.testTag("obfs4-offer-${offer.fromUser}"),
|
||||
)
|
||||
@@ -99,7 +102,7 @@ fun ColumnScope.NetworkSection(
|
||||
Spacer(Modifier.height(Space.xs))
|
||||
Row(modifier = Modifier.fillMaxWidth()) {
|
||||
KitPrimaryButton(
|
||||
text = "Use this bridge",
|
||||
text = stringResource(R.string.set_network_use_bridge),
|
||||
onClick = {
|
||||
when (val result = settings.accept(offer.line, from = offer.fromName)) {
|
||||
is Obfs4Settings.AddResult.Added, Obfs4Settings.AddResult.AlreadySaved -> {
|
||||
@@ -108,7 +111,7 @@ fun ColumnScope.NetworkSection(
|
||||
}
|
||||
|
||||
else -> {
|
||||
refusal = result.message
|
||||
refusal = addResultWords(context, result)
|
||||
}
|
||||
}
|
||||
tick++
|
||||
@@ -119,7 +122,7 @@ fun ColumnScope.NetworkSection(
|
||||
)
|
||||
Spacer(Modifier.width(Space.sm))
|
||||
KitSecondaryButton(
|
||||
text = "Dismiss",
|
||||
text = stringResource(R.string.set_network_dismiss),
|
||||
onClick = {
|
||||
model?.dismissBridgeOffer(offer.fromUser)
|
||||
tick++
|
||||
@@ -134,7 +137,7 @@ fun ColumnScope.NetworkSection(
|
||||
// The stored lines (§24.6).
|
||||
if (lines.isNotEmpty()) {
|
||||
Spacer(Modifier.height(Space.md))
|
||||
Text("Your bridges", fontWeight = FontWeight.Medium, fontSize = 15.sp)
|
||||
Text(stringResource(R.string.set_network_your_bridges), fontWeight = FontWeight.Medium, fontSize = 15.sp)
|
||||
lines.forEachIndexed { index, stored ->
|
||||
Spacer(Modifier.height(Space.sm))
|
||||
Text(
|
||||
@@ -145,12 +148,15 @@ fun ColumnScope.NetworkSection(
|
||||
)
|
||||
Reading(stored.line)
|
||||
stored.offeredBy?.let {
|
||||
Text("From $it", fontSize = 12.sp, color = Palette.SecondaryText)
|
||||
Text(stringResource(R.string.set_network_from, it), fontSize = 12.sp, color = Palette.SecondaryText)
|
||||
}
|
||||
Text(
|
||||
stored.lastWorked?.let {
|
||||
"Last worked " + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT).format(Date(it * 1000))
|
||||
} ?: "Hasn't connected yet",
|
||||
stringResource(
|
||||
R.string.set_network_last_worked,
|
||||
DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT).format(Date(it * 1000)),
|
||||
)
|
||||
} ?: stringResource(R.string.set_network_not_connected_yet),
|
||||
fontSize = 12.sp,
|
||||
color = Palette.SecondaryText,
|
||||
)
|
||||
@@ -160,11 +166,10 @@ fun ColumnScope.NetworkSection(
|
||||
tick++
|
||||
},
|
||||
modifier = Modifier.testTag("obfs4-remove-$index"),
|
||||
) { Text("Remove", color = Palette.Danger) }
|
||||
) { Text(stringResource(R.string.common_remove), color = Palette.Danger) }
|
||||
}
|
||||
Text(
|
||||
"The app tries one bridge at a time, starting with the one that last worked. " +
|
||||
"A bridge that stops working stays here until you remove it.",
|
||||
stringResource(R.string.set_network_tries_in_turn),
|
||||
fontSize = 12.sp,
|
||||
color = Palette.SecondaryText,
|
||||
)
|
||||
@@ -199,7 +204,7 @@ fun ColumnScope.NetworkSection(
|
||||
|
||||
is BridgeLineResult.Ok -> {
|
||||
Text(
|
||||
"Reads as ${parsed.bridge.host} port ${parsed.bridge.port}",
|
||||
stringResource(R.string.set_network_reads_as, parsed.bridge.host, parsed.bridge.port),
|
||||
fontSize = 12.sp,
|
||||
color = Palette.SecondaryText,
|
||||
modifier = Modifier.testTag("obfs4-parsed"),
|
||||
@@ -225,7 +230,7 @@ fun ColumnScope.NetworkSection(
|
||||
Spacer(Modifier.height(Space.sm))
|
||||
|
||||
KitPrimaryButton(
|
||||
text = "Save this bridge",
|
||||
text = stringResource(R.string.set_network_save),
|
||||
onClick = {
|
||||
// Goes through `add`, which parses again and stores only what it
|
||||
// could use.
|
||||
@@ -236,7 +241,7 @@ fun ColumnScope.NetworkSection(
|
||||
}
|
||||
|
||||
else -> {
|
||||
refusal = result.message
|
||||
refusal = addResultWords(context, result)
|
||||
}
|
||||
}
|
||||
tick++
|
||||
@@ -247,7 +252,7 @@ fun ColumnScope.NetworkSection(
|
||||
)
|
||||
Spacer(Modifier.height(Space.sm))
|
||||
KitSecondaryButton(
|
||||
text = "Scan a code",
|
||||
text = stringResource(R.string.set_network_scan_code),
|
||||
onClick = {
|
||||
val has =
|
||||
androidx.core.content.ContextCompat.checkSelfPermission(
|
||||
@@ -264,10 +269,10 @@ fun ColumnScope.NetworkSection(
|
||||
val share = remember(tick) { settings.bridgeLine }
|
||||
if (share != null && model != null && buddies.isNotEmpty()) {
|
||||
Spacer(Modifier.height(Space.md))
|
||||
Text("Share it with", fontWeight = FontWeight.Medium, fontSize = 15.sp)
|
||||
Text(stringResource(R.string.set_network_share_with), fontWeight = FontWeight.Medium, fontSize = 15.sp)
|
||||
Text(
|
||||
// Says who learns what.
|
||||
WHAT_THEY_LEARN,
|
||||
stringResource(R.string.set_network_share_note),
|
||||
fontSize = 12.sp,
|
||||
color = Palette.SecondaryText,
|
||||
)
|
||||
@@ -282,7 +287,12 @@ fun ColumnScope.NetworkSection(
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
KitSecondaryButton(
|
||||
text = if (sharedWith.contains(buddy.userId)) "Sent" else "Send",
|
||||
text =
|
||||
if (sharedWith.contains(buddy.userId)) {
|
||||
stringResource(R.string.set_network_sent)
|
||||
} else {
|
||||
stringResource(R.string.common_send)
|
||||
},
|
||||
onClick = { confirmShare = buddy },
|
||||
// Not disabled after sending.
|
||||
tag = "obfs4-share-${buddy.userId}",
|
||||
@@ -294,21 +304,20 @@ fun ColumnScope.NetworkSection(
|
||||
Spacer(Modifier.height(Space.sm))
|
||||
|
||||
Text(
|
||||
"Paste the line a bridge provider gave you. It's one long line that starts with " +
|
||||
"obfs4, copy all of it, including the part after cert=.",
|
||||
stringResource(R.string.set_network_paste_hint),
|
||||
fontSize = 12.sp,
|
||||
color = Palette.SecondaryText,
|
||||
)
|
||||
|
||||
Spacer(Modifier.height(Space.sm))
|
||||
|
||||
Text(EXPLANATION, fontSize = 12.sp, color = Palette.SecondaryText)
|
||||
Text(stringResource(R.string.set_network_explanation), fontSize = 12.sp, color = Palette.SecondaryText)
|
||||
|
||||
confirmShare?.let { buddy ->
|
||||
AlertDialog(
|
||||
onDismissRequest = { confirmShare = null },
|
||||
title = { Text("Share your bridge?") },
|
||||
text = { Text(WHAT_THEY_LEARN) },
|
||||
title = { Text(stringResource(R.string.set_network_share_title)) },
|
||||
text = { Text(stringResource(R.string.set_network_share_note)) },
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
@@ -317,9 +326,11 @@ fun ColumnScope.NetworkSection(
|
||||
confirmShare = null
|
||||
},
|
||||
modifier = Modifier.testTag("obfs4-share-confirm"),
|
||||
) { Text("Send") }
|
||||
) { Text(stringResource(R.string.common_send)) }
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = { confirmShare = null }) { Text(stringResource(R.string.common_cancel)) }
|
||||
},
|
||||
dismissButton = { TextButton(onClick = { confirmShare = null }) { Text("Cancel") } },
|
||||
)
|
||||
}
|
||||
|
||||
@@ -331,8 +342,8 @@ fun ColumnScope.NetworkSection(
|
||||
refusal = null
|
||||
},
|
||||
onDismiss = { scanning = false },
|
||||
hint = "Point at the code holding the bridge line.",
|
||||
denied = "Flamenet cannot use the camera. Allow it in Android settings, or paste the line instead.",
|
||||
hint = stringResource(R.string.set_network_scan_hint),
|
||||
denied = stringResource(R.string.set_network_scan_denied),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -349,7 +360,7 @@ private fun Reading(line: String) {
|
||||
|
||||
is BridgeLineResult.Ok -> {
|
||||
Text(
|
||||
"Reads as ${parsed.bridge.host} port ${parsed.bridge.port}",
|
||||
stringResource(R.string.set_network_reads_as, parsed.bridge.host, parsed.bridge.port),
|
||||
fontSize = 12.sp,
|
||||
color = Palette.SecondaryText,
|
||||
)
|
||||
@@ -403,21 +414,36 @@ internal fun statusLine(
|
||||
}
|
||||
}
|
||||
|
||||
/** §24.3: before the first send, say what the contact learns. */
|
||||
private const val WHAT_THEY_LEARN =
|
||||
"They get the line and decide for themselves. Whoever runs the bridge will " +
|
||||
"see one more person connecting, and your contact will know you use it."
|
||||
/**
|
||||
* The refusal for a line that could not be added, in the phone's language.
|
||||
* [Obfs4Settings.AddResult.message] keeps the English, which tests read.
|
||||
*/
|
||||
private fun addResultWords(
|
||||
context: android.content.Context,
|
||||
result: Obfs4Settings.AddResult,
|
||||
): String =
|
||||
when (result) {
|
||||
Obfs4Settings.AddResult.TooMany -> context.getString(R.string.set_network_too_many)
|
||||
Obfs4Settings.AddResult.AlreadySaved -> context.getString(R.string.set_network_already_saved)
|
||||
else -> result.message
|
||||
}
|
||||
|
||||
/**
|
||||
* Says what it does not protect, in the same breath as what it does.
|
||||
* [statusLine] in the phone's language, for the screen. The English function
|
||||
* stays because tests pin it without a Context; the branches here must stay
|
||||
* in step with it, including that nothing is said to go around a saved bridge.
|
||||
*/
|
||||
private const val EXPLANATION =
|
||||
"Some networks block Flamenet outright, or recognise it and slow it down. A bridge is a " +
|
||||
"machine somewhere else that your app talks to instead, in a way that doesn't look " +
|
||||
"like anything in particular, not like Flamenet, and not like a video call or a web " +
|
||||
"page either. The bridge passes your traffic on to your server.\n\n" +
|
||||
"Two things worth being clear about. Your server sees exactly what it saw before, so " +
|
||||
"this doesn't hide anything from whoever runs it. And whoever runs the bridge can see " +
|
||||
"that you're connecting to them, though not what you're saying, your messages stay " +
|
||||
"end-to-end encrypted the whole way, as they always are.\n\n" +
|
||||
"If Flamenet already works where you are, you don't need this."
|
||||
@Composable
|
||||
internal fun statusLineText(
|
||||
bridge: Obfs4Bridge? = Obfs4Routing.lastCarried ?: Obfs4Routing.bridge,
|
||||
handshakes: Int = if (Obfs4Routing.lastCarried != null) 1 else 0,
|
||||
count: Int = Obfs4Routing.bridges.size,
|
||||
everyLineFailed: Boolean = Obfs4Routing.everyLineFailed,
|
||||
): String =
|
||||
when {
|
||||
bridge == null -> stringResource(R.string.set_network_status_direct)
|
||||
handshakes > 0 -> stringResource(R.string.set_network_status_through, bridge.host, bridge.port)
|
||||
everyLineFailed -> stringResource(R.string.set_network_status_none_reached)
|
||||
count > 1 -> pluralStringResource(R.plurals.set_network_status_saved_many, count, count)
|
||||
else -> stringResource(R.string.set_network_status_saved, bridge.host, bridge.port)
|
||||
}
|
||||
|
||||
@@ -144,6 +144,11 @@ fun userFacingMessage(
|
||||
context.getString(R.string.core_err_accounts_service_returned, e.status)
|
||||
}
|
||||
|
||||
// §24.6: the chain node cannot be reached through a bridge.
|
||||
is ChainRpc.Failure.OffWhileBridged -> {
|
||||
context.getString(R.string.core_bridge_wallet_off)
|
||||
}
|
||||
|
||||
// The wallet's chain node. Node(detail) is the node's own words.
|
||||
is ChainRpc.Failure.Http -> {
|
||||
context.getString(R.string.core_err_node_answered_with, e.code)
|
||||
|
||||
@@ -64,7 +64,7 @@ fun ColumnScope.WalletScreen(
|
||||
// §24.6: the chain node is a host a bridge cannot reach.
|
||||
if (io.flamenet.client.AroundTheBridge.active) {
|
||||
Text(
|
||||
io.flamenet.client.AroundTheBridge.WALLET_OFF,
|
||||
stringResource(R.string.core_bridge_wallet_off),
|
||||
fontSize = 13.sp,
|
||||
color = Palette.SecondaryText,
|
||||
modifier = Modifier.testTag("wallet-bridged"),
|
||||
|
||||
@@ -144,4 +144,8 @@
|
||||
<string name="core_notif_no_reply_from">Todavía sin respuesta de %1$s</string>
|
||||
<string name="core_notif_no_reply">Todavía sin respuesta</string>
|
||||
<string name="core_notif_no_reply_in_chats">Todavía sin respuesta en %1$d chats</string>
|
||||
<string name="core_no_bridge_reached">No se pudo llegar a ningún puente. La aplicación sigue intentándolo y no se conectará sin uno mientras haya un puente guardado.</string>
|
||||
<string name="core_bridge_calls_off">Las llamadas están desactivadas mientras usas un puente. Una llamada se conecta sin pasar por el puente, así que la red en la que estás podría verla.</string>
|
||||
<string name="core_bridge_wallet_off">La cartera está desactivada mientras usas un puente. Se comunica directamente con un nodo público de la cadena, y un puente solo llega a tu servidor de Flamenet.</string>
|
||||
<string name="core_bridge_link_previews_off">Las vistas previas de enlaces están desactivadas mientras usas un puente. Generar una conectaría directamente con el sitio web enlazado, sin pasar por el puente.</string>
|
||||
</resources>
|
||||
|
||||
@@ -95,7 +95,6 @@
|
||||
<string name="set_network_use_bridge">Usar este puente</string>
|
||||
<string name="set_network_dismiss">Descartar</string>
|
||||
<string name="set_network_save">Guardar este puente</string>
|
||||
<string name="set_network_stop">Dejar de usar el puente</string>
|
||||
<string name="set_network_share_with">Compartirlo con</string>
|
||||
<string name="set_network_share_note">Reciben la línea y deciden por su cuenta. Quien administra el puente verá a una persona más conectándose, y tu contacto sabrá que tú lo usas.</string>
|
||||
<string name="set_network_sent">Enviado</string>
|
||||
@@ -160,4 +159,23 @@
|
||||
<string name="set_network_status_direct">Conectando directamente a tu servidor de Flamenet. Es lo correcto casi en cualquier lugar.</string>
|
||||
<string name="set_network_status_through">Pasando por %1$s:%2$d. El tráfico hacia tu servidor va envuelto para que quien lo transporta no pueda saber qué es; tu servidor sigue viendo lo mismo de siempre.</string>
|
||||
<string name="set_network_status_saved">Puente guardado: %1$s:%2$d. Todavía no ha pasado nada por él; la aplicación lo intentará la próxima vez que se conecte.</string>
|
||||
<string name="set_network_your_bridges">Tus puentes</string>
|
||||
<string name="set_network_from">De %1$s</string>
|
||||
<string name="set_network_last_worked">Funcionó por última vez: %1$s</string>
|
||||
<string name="set_network_not_connected_yet">Todavía no se ha conectado</string>
|
||||
<string name="set_network_tries_in_turn">La aplicación prueba un puente a la vez, empezando por el último que funcionó. Un puente que deja de funcionar se queda aquí hasta que lo quites.</string>
|
||||
<string name="set_network_scan_code">Escanear un código</string>
|
||||
<string name="set_network_share_title">¿Compartir tu puente?</string>
|
||||
<string name="set_network_scan_hint">Apunta al código que contiene la línea del puente.</string>
|
||||
<string name="set_network_scan_denied">Flamenet no puede usar la cámara. Permítelo en los ajustes de Android, o pega la línea en su lugar.</string>
|
||||
<string name="set_network_too_many">Puedes guardar hasta 8 puentes. Quita uno antes de agregar otro.</string>
|
||||
<string name="set_network_already_saved">Este puente ya está en tu lista.</string>
|
||||
<string name="set_network_status_none_reached">No se pudo llegar a ningún puente. La aplicación probó cada uno y sigue intentándolo, y no se conectará sin un puente mientras haya uno guardado. Quítalos todos para conectarte directamente.</string>
|
||||
<plurals name="set_network_status_saved_many">
|
||||
<item quantity="one">%1$d puente guardado. Todavía no ha pasado nada por él; la aplicación lo intentará la próxima vez que se conecte.</item>
|
||||
<item quantity="many">%1$d puentes guardados. Todavía no ha pasado nada por ellos; la aplicación los intentará la próxima vez que se conecte.</item>
|
||||
<item quantity="other">%1$d puentes guardados. Todavía no ha pasado nada por ellos; la aplicación los intentará la próxima vez que se conecte.</item>
|
||||
</plurals>
|
||||
<string name="set_bridge_signin_show">Conectar a través de un puente</string>
|
||||
<string name="set_bridge_signin_hide">Ocultar ajustes del puente</string>
|
||||
</resources>
|
||||
|
||||
@@ -143,4 +143,8 @@
|
||||
<string name="core_notif_no_reply_from">Still no reply from %1$s</string>
|
||||
<string name="core_notif_no_reply">Still no reply</string>
|
||||
<string name="core_notif_no_reply_in_chats">Still no reply in %1$d chats</string>
|
||||
<string name="core_no_bridge_reached">No bridge could be reached. The app keeps trying them, and won\'t connect without one while a bridge is saved.</string>
|
||||
<string name="core_bridge_calls_off">Calls are off while you use a bridge. A call connects around the bridge, so the network you\'re on could see it.</string>
|
||||
<string name="core_bridge_wallet_off">The wallet is off while you use a bridge. It talks to a public chain node directly, and a bridge only reaches your Flamenet server.</string>
|
||||
<string name="core_bridge_link_previews_off">Link previews are off while you use a bridge. Making one would connect to the linked website directly, around the bridge.</string>
|
||||
</resources>
|
||||
|
||||
@@ -104,7 +104,6 @@
|
||||
<string name="set_network_use_bridge">Use this bridge</string>
|
||||
<string name="set_network_dismiss">Dismiss</string>
|
||||
<string name="set_network_save">Save this bridge</string>
|
||||
<string name="set_network_stop">Stop using a bridge</string>
|
||||
<string name="set_network_share_with">Share it with</string>
|
||||
<string name="set_network_share_note">They get the line and decide for themselves. Whoever runs the bridge will see one more person connecting, and your contact will know you use it.</string>
|
||||
<string name="set_network_sent">Sent</string>
|
||||
@@ -177,4 +176,22 @@
|
||||
<string name="set_network_status_direct">Connecting directly to your Flamenet server. That\'s the right setting almost everywhere.</string>
|
||||
<string name="set_network_status_through">Going through %1$s:%2$d. Traffic to your server is wrapped so that whoever carries it can\'t tell what it is, your server still sees what it always did.</string>
|
||||
<string name="set_network_status_saved">Bridge saved: %1$s:%2$d. Nothing has gone through it yet, the app will try the next time it goes online.</string>
|
||||
<string name="set_network_your_bridges">Your bridges</string>
|
||||
<string name="set_network_from">From %1$s</string>
|
||||
<string name="set_network_last_worked">Last worked %1$s</string>
|
||||
<string name="set_network_not_connected_yet">Hasn\'t connected yet</string>
|
||||
<string name="set_network_tries_in_turn">The app tries one bridge at a time, starting with the one that last worked. A bridge that stops working stays here until you remove it.</string>
|
||||
<string name="set_network_scan_code">Scan a code</string>
|
||||
<string name="set_network_share_title">Share your bridge?</string>
|
||||
<string name="set_network_scan_hint">Point at the code holding the bridge line.</string>
|
||||
<string name="set_network_scan_denied">Flamenet cannot use the camera. Allow it in Android settings, or paste the line instead.</string>
|
||||
<string name="set_network_too_many">You can keep up to 8 bridges. Remove one before adding another.</string>
|
||||
<string name="set_network_already_saved">This bridge is already in your list.</string>
|
||||
<string name="set_network_status_none_reached">No bridge could be reached. The app tried each one in turn and keeps trying, and it won\'t connect without a bridge while one is saved. Remove them all to connect directly.</string>
|
||||
<plurals name="set_network_status_saved_many">
|
||||
<item quantity="one">%1$d bridges saved. Nothing has gone through them yet, the app will try them the next time it goes online.</item>
|
||||
<item quantity="other">%1$d bridges saved. Nothing has gone through them yet, the app will try them the next time it goes online.</item>
|
||||
</plurals>
|
||||
<string name="set_bridge_signin_show">Connect through a bridge</string>
|
||||
<string name="set_bridge_signin_hide">Hide bridge settings</string>
|
||||
</resources>
|
||||
|
||||
@@ -31,6 +31,9 @@ where it was taken from.
|
||||
| bridge | puente | yes, "la línea del puente" | |
|
||||
| bridge line | línea del puente | yes | |
|
||||
| bridge provider | quien te dio el puente | no | Plain description in place of a noun. |
|
||||
| around the bridge (a connection that skips it) | sin pasar por el puente | no | "Conectaría directamente con el sitio web enlazado, sin pasar por el puente." |
|
||||
| bridge offer, offered to you | puente ofrecido, te ofrecieron | no | |
|
||||
| live stream | transmisión en vivo | no | |
|
||||
| safety number | número de seguridad | yes | Plural: números de seguridad. |
|
||||
| compare safety numbers | comparar los números de seguridad | yes | |
|
||||
| contact link | enlace de contacto | no | |
|
||||
|
||||
Reference in New Issue
Block a user