feat(app): redesigned interface, polls, drafts, forwarding and mentions

A new look across the app and a set of everyday messaging features.

Interface
- Home screen with Chats, Contacts and Settings tabs, a large title,
  search across chats and message text (diacritics-insensitive), filters
  and pinned chats.
- Conversation view with a translucent header and composer, grouped
  bubbles, author avatars and colours in groups, swipe to reply, an
  "N new messages" marker, a jump-to-latest button and in-chat search.
- Contact and group profiles: verification, shared photos, groups in
  common, disappearing messages, mute, block; members, admin badges,
  adding people, rename and leave for groups.
- Full-screen photo viewer that pages through the whole conversation.
- A stable avatar colour per person and a clearly visible read state.

Messaging
- Polls in chats and groups, single or multiple choice, with votes that
  can be changed or withdrawn; older clients see them as text.
- Drafts survive leaving a chat and show in the chat list.
- Forwarding of messages, photos, files and voice messages.
- Notes to self: a local-only, encrypted chat that never reaches the
  relay.
- @mentions in groups that notify even when the group is muted.
- Typing indicators sent as ephemeral messages, opt-in and mutual like
  read receipts.
- Delivery and read times per message and per group member.
- Profile photos, cropped, resized and stripped of metadata, delivered
  encrypted to contacts.
- Voice message playback at 1.5x and 2x.
- Call buttons in 1:1 chats and call log entries.

Fixes
- Muted groups no longer notify: muting was checked against the
  author's chat instead of the group.
- A blocked contact could unblock itself by changing its delivery
  address.
- Read receipts no longer regress to delivered when a late delivery
  receipt arrives.
- A message marked as failed corrects itself once it is delivered.
- Double ticks in groups now mean delivered to every member.
This commit is contained in:
Julius Joska
2026-10-03 22:44:53 +02:00
parent 933a74c900
commit 5246a97db2
56 changed files with 12028 additions and 1668 deletions
+748 -22
View File
@@ -212,12 +212,6 @@ abstract class AppLocalizations {
/// **'Už nejsi ve skupině. Historie zůstává, nové zprávy nedorazí.'**
String get groupsLeftBanner;
/// Nadpis bottom sheetu se seznamem členů skupiny
///
/// In cs, this message translates to:
/// **'Členové ({count})'**
String groupsMembersWithCount(int count);
/// Fallback jména vlastního avataru v seznamu členů skupiny | Titulek ListTile vlastní osoby v seznamu členů skupiny — stejný klíč jako ř. 486
///
/// In cs, this message translates to:
@@ -230,6 +224,96 @@ abstract class AppLocalizations {
/// **'Zakladatel'**
String get groupsFounder;
/// Odznak správce skupiny u člena v seznamu členů
///
/// In cs, this message translates to:
/// **'Správce'**
String get groupsAdmin;
/// Akce v nabídce člena: udělit roli správce
///
/// In cs, this message translates to:
/// **'Udělat správcem'**
String get groupsMakeAdmin;
/// Akce v nabídce člena: odebrat roli správce
///
/// In cs, this message translates to:
/// **'Odebrat roli správce'**
String get groupsDismissAdmin;
/// Akce v nabídce člena: odebrat ze skupiny
///
/// In cs, this message translates to:
/// **'Odebrat ze skupiny'**
String get groupsRemoveMember;
/// Titulek potvrzení odebrání člena
///
/// In cs, this message translates to:
/// **'Odebrat {name} ze skupiny?'**
String groupsRemoveMemberConfirmTitle(String name);
/// Text potvrzení odebrání člena
///
/// In cs, this message translates to:
/// **'Přestanou mu chodit nové zprávy skupiny. Dosavadní historie mu zůstane.'**
String get groupsRemoveMemberConfirmBody;
/// Potvrzovací tlačítko odebrání člena
///
/// In cs, this message translates to:
/// **'Odebrat'**
String get groupsRemoveAction;
/// Akce v nabídce člena: otevřít profil kontaktu
///
/// In cs, this message translates to:
/// **'Zobrazit kontakt'**
String get groupsViewContact;
/// Vysvětlení pod seznamem členů pro ne-správce ve vynucené skupině
///
/// In cs, this message translates to:
/// **'Jméno, členy a správce skupiny mění jen správci.'**
String get groupsAdminOnlyHint;
/// Vysvětlení pro ne-správce, dokud je ve skupině člen se starší verzí aplikace
///
/// In cs, this message translates to:
/// **'Jméno a správce mění jen správci. Přidávat lidi zatím může každý, protože někdo ve skupině má starší verzi Šepotu.'**
String get groupsAdminOnlyCompatHint;
/// SnackBar při selhání správcovské akce
///
/// In cs, this message translates to:
/// **'Změna se nepovedla: {error}'**
String groupsAdminActionFailed(String error);
/// Upozornění v profilu skupiny, když chybí mezistav od správce
///
/// In cs, this message translates to:
/// **'Stav skupiny se srovnává se správcem. Změny členů se můžou chvíli opozdit.'**
String get groupsResyncNotice;
/// Upozornění v profilu skupiny po odmítnuté neoprávněné změně
///
/// In cs, this message translates to:
/// **'Někdo bez oprávnění zkusil skupinu změnit. Změna se neprovedla.'**
String get groupsRejectedChangeNotice;
/// Chyba: akci smí udělat jen správce skupiny
///
/// In cs, this message translates to:
/// **'Tohle může udělat jen správce skupiny.'**
String get errorGroupNotAdmin;
/// Chyba: poslední správce se nemůže vzdát role
///
/// In cs, this message translates to:
/// **'Jsi jediný správce. Nejdřív udělej správcem někoho dalšího.'**
String get errorGroupLastAdmin;
/// hintText TextFieldu v dialogu přejmenování skupiny | labelText textového pole pro jméno skupiny (max 64 znaků)
///
/// In cs, this message translates to:
@@ -410,6 +494,42 @@ abstract class AppLocalizations {
/// **'Odpovědět'**
String get chatActionReply;
/// Akce v nabídce po podržení zprávy
///
/// In cs, this message translates to:
/// **'Přeposlat'**
String get chatActionForward;
/// Nadpis panelu výběru chatu pro přeposlání
///
/// In cs, this message translates to:
/// **'Přeposlat do…'**
String get forwardTitle;
/// Nápověda v poli hledání panelu přeposlání
///
/// In cs, this message translates to:
/// **'Hledat kontakt nebo skupinu'**
String get forwardSearchHint;
/// Prázdný výsledek hledání v panelu přeposlání
///
/// In cs, this message translates to:
/// **'Nic tu není'**
String get forwardEmpty;
/// SnackBar po přeposlání zprávy
///
/// In cs, this message translates to:
/// **'Přeposláno: {name}'**
String forwardDone(String name);
/// SnackBar při chybě přeposlání
///
/// In cs, this message translates to:
/// **'Přeposlání se nepovedlo: {error}'**
String forwardFailed(String error);
/// Položka akčního bottom sheetu zprávy — kopírování textu do schránky | Popisek OutlinedButton.icon pro zkopírování Šepot ID do schránky
///
/// In cs, this message translates to:
@@ -512,6 +632,24 @@ abstract class AppLocalizations {
/// **'Soubor je příliš velký (max {maxMb} MB)'**
String attachmentTooLarge(int maxMb);
/// Titulek dialogu před odesláním obrázku jako dokumentu, když z něj nejde odstranit EXIF (HEIC, RAW)
///
/// In cs, this message translates to:
/// **'Fotka odejde i s polohou'**
String get attachmentKeepsMetadataTitle;
/// Text téhož dialogu
///
/// In cs, this message translates to:
/// **'Tenhle formát fotky (třeba HEIC) neumím zbavit metadat. Odešla by v originále včetně polohy, kde vznikla, a údajů o telefonu. Bezpečnější je poslat ji přes Galerii, kde se metadata odstraní.'**
String get attachmentKeepsMetadataBody;
/// Potvrzovací tlačítko téhož dialogu
///
/// In cs, this message translates to:
/// **'Poslat originál'**
String get attachmentSendOriginal;
/// SnackBar (_showError) při selhání výběru přílohy
///
/// In cs, this message translates to:
@@ -578,6 +716,12 @@ abstract class AppLocalizations {
/// **'Skupina potřebuje aspoň 1 člena'**
String get errorGroupNeedsMember;
/// Chyba při přeposlání přílohy, která už byla smazána nebo nestažena
///
/// In cs, this message translates to:
/// **'Příloha už v telefonu není'**
String get errorAttachmentUnavailable;
/// StateError z createGroup při překročení max. počtu členů; zobrazuje UI zakládání skupiny. Počet v textu + české skloňování (člen/členové/členů) → ICU plural. | StateError z addGroupMembers — identický text jako v createGroup (ř. 583), stejný klíč. ICU plural.
///
/// In cs, this message translates to:
@@ -1082,24 +1226,186 @@ abstract class AppLocalizations {
/// **'Nová konverzace'**
String get chatListNewConversation;
/// Náhled poslední zprávy v dlaždici — fotka s popiskem; emoji je součást textu
///
/// In cs, this message translates to:
/// **'📷 {caption}'**
String chatListPhotoWithCaptionPreview(String caption);
/// Náhled poslední zprávy v dlaždici — soubor; emoji je součást textu. Skládaný literál: obsahuje vnořený fallback "Soubor" (viz samostatný záznam) — při lokalizaci předat placeholderu už vyřešenou hodnotu msg.fileName ?? commonFile.
///
/// In cs, this message translates to:
/// **'📎 {fileName}'**
String chatListFilePreview(String fileName);
/// Náhled poslední zprávy v dlaždici pro zprávu typu readReceipt (potvrzení o přečtení)
///
/// In cs, this message translates to:
/// **'Přečteno'**
String get chatListReadReceiptPreview;
/// Předpona náhledu v seznamu chatů, když je v chatu rozepsaná zpráva
///
/// In cs, this message translates to:
/// **'Koncept'**
String get chatListDraft;
/// Název chatu se sebou samým (seznam chatů, hlavička, kontakty, přeposlání)
///
/// In cs, this message translates to:
/// **'Poznámky pro sebe'**
String get notesTitle;
/// Podtitulek poznámek pro sebe — nic se neodesílá na server
///
/// In cs, this message translates to:
/// **'Jen v tomto telefonu, šifrovaně'**
String get notesSubtitle;
/// Tlačítko hlasového hovoru v hlavičce chatu
///
/// In cs, this message translates to:
/// **'Zavolat'**
String get callVoice;
/// Tlačítko videohovoru v hlavičce chatu
///
/// In cs, this message translates to:
/// **'Videohovor'**
String get callVideo;
/// Stav odchozího hovoru, dokud protistrana nezvedne
///
/// In cs, this message translates to:
/// **'Vyzvání…'**
String get callStatusRinging;
/// Stav příchozího hlasového hovoru
///
/// In cs, this message translates to:
/// **'Příchozí hovor'**
String get callIncomingVoice;
/// Stav příchozího videohovoru
///
/// In cs, this message translates to:
/// **'Příchozí videohovor'**
String get callIncomingVideo;
/// Stav po přijetí, než naběhne spojení
///
/// In cs, this message translates to:
/// **'Spojuji…'**
String get callStatusConnecting;
/// Krátce po konci hovoru
///
/// In cs, this message translates to:
/// **'Hovor skončil'**
String get callEnded;
/// Protistrana má jiný hovor
///
/// In cs, this message translates to:
/// **'Obsazeno'**
String get callEndedBusy;
/// Hovor byl odmítnut
///
/// In cs, this message translates to:
/// **'Hovor odmítnut'**
String get callEndedRejected;
/// Odchozí hovor vypršel bez odpovědi
///
/// In cs, this message translates to:
/// **'Nikdo to nevzal'**
String get callEndedUnanswered;
/// Hovor se nepodařilo spojit
///
/// In cs, this message translates to:
/// **'Spojení se nepodařilo'**
String get callEndedFailed;
/// Podtitulek na obrazovce hovoru
///
/// In cs, this message translates to:
/// **'Šifrováno end-to-end'**
String get callEncrypted;
/// Přijetí příchozího hovoru
///
/// In cs, this message translates to:
/// **'Přijmout'**
String get callAccept;
/// Odmítnutí příchozího hovoru
///
/// In cs, this message translates to:
/// **'Odmítnout'**
String get callReject;
/// Přepínač mikrofonu (popisek pro čtečku)
///
/// In cs, this message translates to:
/// **'Ztlumit mikrofon'**
String get callMute;
/// Přepínač hlasitého odposlechu
///
/// In cs, this message translates to:
/// **'Reproduktor'**
String get callSpeaker;
/// Přepínač kamery ve videohovoru
///
/// In cs, this message translates to:
/// **'Vypnout kameru'**
String get callCamera;
/// Přední/zadní kamera
///
/// In cs, this message translates to:
/// **'Přepnout kameru'**
String get callSwitchCamera;
/// Ukončení hovoru
///
/// In cs, this message translates to:
/// **'Zavěsit'**
String get callHangUp;
/// Záznam v chatu
///
/// In cs, this message translates to:
/// **'Zmeškaný hovor'**
String get callLogMissed;
/// Odchozí hovor, který protistrana nevzala
///
/// In cs, this message translates to:
/// **'Nepřijatý hovor'**
String get callLogUnanswered;
/// Záznam v chatu
///
/// In cs, this message translates to:
/// **'Odmítnutý hovor'**
String get callLogRejected;
/// Záznam v chatu — protistrana měla jiný hovor
///
/// In cs, this message translates to:
/// **'Obsazeno'**
String get callLogBusy;
/// Záznam v chatu
///
/// In cs, this message translates to:
/// **'Hovor se nespojil'**
String get callLogFailed;
/// Záznam proběhlého hlasového hovoru s délkou
///
/// In cs, this message translates to:
/// **'Hovor · {duration}'**
String callLogVoice(String duration);
/// Záznam proběhlého videohovoru s délkou
///
/// In cs, this message translates to:
/// **'Videohovor · {duration}'**
String callLogVideo(String duration);
/// Relativní čas poslední zprávy v dlaždici, méně než 1 minuta
///
/// In cs, this message translates to:
@@ -1700,10 +2006,10 @@ abstract class AppLocalizations {
/// **'Zprávy se stáhnou až po otevření appky.'**
String get pushModeOffDesc;
/// Label volby 'up' v dialogu výběru režimu pushů ('UnifiedPush' je název technologie — nepřekládat, přeložit jen '(doporučeno)')
/// Label volby 'up' v dialogu výběru režimu pushů ('UnifiedPush' je název technologie — nepřekládat, přeložit jen '(bez Googlu)')
///
/// In cs, this message translates to:
/// **'UnifiedPush (doporučeno)'**
/// **'UnifiedPush (bez Googlu)'**
String get pushModeUp;
/// Popisek volby UnifiedPush v dialogu výběru režimu pushů ('ntfy', 'F-Droid', 'Play' jsou názvy — nepřekládat)
@@ -1715,7 +2021,7 @@ abstract class AppLocalizations {
/// Label volby 'fcm' v dialogu výběru režimu pushů (vlastní název — pravděpodobně shodný ve všech jazycích, ale klíč mít)
///
/// In cs, this message translates to:
/// **'Google (FCM)'**
/// **'Google (FCM, výchozí)'**
String get pushModeFcm;
/// Popisek volby Google (FCM) v dialogu výběru režimu pushů. POZOR: v kódu DVA adjacentní literály (ř. 51–52: '…jde ' + 'Googlu; obsah…') — sloučit do jednoho klíče.
@@ -1787,7 +2093,7 @@ abstract class AppLocalizations {
/// Subtitle ListTile v nastavení, když je aktivní režim FCM
///
/// In cs, this message translates to:
/// **'Google (FCM) — rychlé, opt-in'**
/// **'Google (FCM)'**
String get pushSubtitleFcm;
/// Validační chyba pod formulářem obnovy účtu, když je jméno prázdné
@@ -2293,6 +2599,426 @@ abstract class AppLocalizations {
/// In cs, this message translates to:
/// **'Fotku se nepodařilo načíst'**
String get photoPreviewDecodeFailed;
/// Položka v nabídce zprávy — detail doručení a přečtení.
///
/// In cs, this message translates to:
/// **'Info o zprávě'**
String get chatActionInfo;
/// Info o zprávě: řádek času odeslání.
///
/// In cs, this message translates to:
/// **'Odesláno'**
String get messageInfoSent;
/// Info o zprávě: řádek času doručení.
///
/// In cs, this message translates to:
/// **'Doručeno'**
String get messageInfoDelivered;
/// Info o zprávě: řádek času přečtení.
///
/// In cs, this message translates to:
/// **'Přečteno'**
String get messageInfoRead;
/// Info o zprávě: událost ještě nenastala.
///
/// In cs, this message translates to:
/// **'zatím ne'**
String get messageInfoPending;
/// Info o zprávě: vysvětlení, proč chybí čas přečtení.
///
/// In cs, this message translates to:
/// **'Kdy si zprávu přečetli, uvidíš, jen když sám sdílíš potvrzení přečtení (Nastavení).'**
String get messageInfoReadReceiptsOff;
/// Řádek pod poslední odeslanou zprávou — čas přečtení.
///
/// In cs, this message translates to:
/// **'Přečteno {time}'**
String chatStatusReadAt(String time);
/// Řádek pod poslední odeslanou zprávou — čas doručení.
///
/// In cs, this message translates to:
/// **'Doručeno {time}'**
String chatStatusDeliveredAt(String time);
/// Nabídka skupiny a titulek obrazovky pro přidání lidí.
///
/// In cs, this message translates to:
/// **'Přidat členy'**
String get groupsAddMembers;
/// Potvrzovací tlačítko v AppBaru při přidávání členů.
///
/// In cs, this message translates to:
/// **'Přidat'**
String get groupsAddMembersAction;
/// Chyba při přidávání členů.
///
/// In cs, this message translates to:
/// **'Přidání se nepovedlo: {error}'**
String groupsAddMembersFailed(String error);
/// Prázdný výběr — všechny kontakty už ve skupině jsou.
///
/// In cs, this message translates to:
/// **'Všechny tvoje kontakty už ve skupině jsou. Nového člověka nejdřív přidej do kontaktů přes QR kód.'**
String get groupsNoContactsToAdd;
/// Karta spodní navigace a nadpis seznamu chatů.
///
/// In cs, this message translates to:
/// **'Chaty'**
String get navChats;
/// Tlačítko pro zahájení nového chatu.
///
/// In cs, this message translates to:
/// **'Nový chat'**
String get chatListNewChat;
/// Placeholder hledání v seznamu chatů.
///
/// In cs, this message translates to:
/// **'Hledat v chatech a zprávách'**
String get chatListSearchHint;
/// Filtr seznamu chatů — vše.
///
/// In cs, this message translates to:
/// **'Vše'**
String get chatFilterAll;
/// Filtr seznamu chatů — nepřečtené.
///
/// In cs, this message translates to:
/// **'Nepřečtené'**
String get chatFilterUnread;
/// Filtr seznamu chatů — skupiny.
///
/// In cs, this message translates to:
/// **'Skupiny'**
String get chatFilterGroups;
/// Odkaz na archiv v řádku filtrů.
///
/// In cs, this message translates to:
/// **'Archiv'**
String get chatFilterArchive;
/// Hledání v chatech nic nenašlo.
///
/// In cs, this message translates to:
/// **'Nic nenalezeno.'**
String get chatListNoResults;
/// Vybraný filtr je prázdný.
///
/// In cs, this message translates to:
/// **'Tady zatím nic není.'**
String get chatListFilterEmpty;
/// Akce: připnout chat nahoru.
///
/// In cs, this message translates to:
/// **'Připnout'**
String get chatListPin;
/// Akce: odepnout chat.
///
/// In cs, this message translates to:
/// **'Odepnout'**
String get chatListUnpin;
/// Hlavička chatu / menu: otevřít profil kontaktu.
///
/// In cs, this message translates to:
/// **'Zobrazit profil'**
String get chatOpenProfile;
/// Menu skupinového chatu: profil skupiny.
///
/// In cs, this message translates to:
/// **'Profil skupiny'**
String get groupsProfile;
/// Hledání v jedné konverzaci — placeholder a popisek tlačítka.
///
/// In cs, this message translates to:
/// **'Hledat v konverzaci'**
String get chatSearchHint;
/// Hledání v konverzaci bez výsledku (krátce, vedle pole).
///
/// In cs, this message translates to:
/// **'Nic'**
String get chatSearchNoMatches;
/// Pořadí aktuální shody hledání, např. „2 z 5“.
///
/// In cs, this message translates to:
/// **'{current} z {total}'**
String chatSearchCounter(int current, int total);
/// Tlačítko: předchozí (starší) shoda.
///
/// In cs, this message translates to:
/// **'Starší shoda'**
String get chatSearchOlder;
/// Tlačítko: další (novější) shoda.
///
/// In cs, this message translates to:
/// **'Novější shoda'**
String get chatSearchNewer;
/// Oddělovač nad první nepřečtenou zprávou.
///
/// In cs, this message translates to:
/// **'{count, plural, one{1 nová zpráva} few{{count} nové zprávy} other{{count} nových zpráv}}'**
String chatUnreadDivider(int count);
/// Tlačítko: skok na nejnovější zprávy.
///
/// In cs, this message translates to:
/// **'Na nejnovější zprávy'**
String get chatJumpToLatest;
/// Tlačítko přílohy v poli pro psaní.
///
/// In cs, this message translates to:
/// **'Přiložit'**
String get chatAttach;
/// Tlačítko odeslat.
///
/// In cs, this message translates to:
/// **'Odeslat'**
String get chatSend;
/// Tlačítko nahrát hlasovou zprávu.
///
/// In cs, this message translates to:
/// **'Nahrát hlasovou zprávu'**
String get chatRecordVoice;
/// Karta sdílených fotek v profilu.
///
/// In cs, this message translates to:
/// **'Sdílená média'**
String get profileSharedMedia;
/// Akce profilu: napsat zprávu.
///
/// In cs, this message translates to:
/// **'Zpráva'**
String get profileMessage;
/// Akce profilu: hledat v konverzaci.
///
/// In cs, this message translates to:
/// **'Hledat'**
String get profileSearch;
/// Akce profilu: zrušit ztlumení (krátce).
///
/// In cs, this message translates to:
/// **'Zvuk'**
String get profileUnmute;
/// Akce profilu: mizící zprávy (krátce).
///
/// In cs, this message translates to:
/// **'Mizení'**
String get profileDisappearing;
/// Karta společných skupin v profilu kontaktu.
///
/// In cs, this message translates to:
/// **'Společné skupiny'**
String get profileCommonGroups;
/// Řádek profilu: bezpečnostní číslo.
///
/// In cs, this message translates to:
/// **'Bezpečnostní číslo'**
String get profileSafetyNumber;
/// Podtitulek bezpečnostního čísla u neověřeného kontaktu.
///
/// In cs, this message translates to:
/// **'Porovnejte osobně nebo QR kódem'**
String get profileSafetyNumberHint;
/// Stav ověřeného kontaktu v hlavičce profilu.
///
/// In cs, this message translates to:
/// **'Ověřeno osobně'**
String get profileVerifiedInPerson;
/// Tlačítko v profilu neověřeného kontaktu.
///
/// In cs, this message translates to:
/// **'Ověřit kontakt'**
String get profileVerifyNow;
/// Akce profilu skupiny: přidat členy (krátce).
///
/// In cs, this message translates to:
/// **'Přidat'**
String get profileAdd;
/// Podtitulek profilu skupiny: počet členů · datum založení.
///
/// In cs, this message translates to:
/// **'Skupina · {members} · založena {date}'**
String profileGroupSubtitle(String members, String date);
/// Počet členů ze stropu skupiny, např. „4 ze 128“.
///
/// In cs, this message translates to:
/// **'{count} ze {max}'**
String profileMembersOfMax(int count, int max);
/// Podtitulek chatu / náhled v seznamu: protistrana píše.
///
/// In cs, this message translates to:
/// **'píše…'**
String get chatTyping;
/// Skupina: kdo píše (křestní jméno).
///
/// In cs, this message translates to:
/// **'{name} píše…'**
String chatTypingNamed(String name);
/// Skupina: píše víc lidí najednou.
///
/// In cs, this message translates to:
/// **'Několik lidí píše…'**
String get chatTypingSeveral;
/// Nastavení: přepínač „píše…“.
///
/// In cs, this message translates to:
/// **'Ukazovat, že píšu'**
String get settingsTypingTitle;
/// Popis přepínače „píše…“.
///
/// In cs, this message translates to:
/// **'Oboustranné — kdo nesdílí, nevidí (výchozí vypnuto)'**
String get settingsTypingSubtitle;
/// Položka nabídky příloh: vytvořit anketu.
///
/// In cs, this message translates to:
/// **'Anketa'**
String get pollAttach;
/// Nadpis formuláře nové ankety.
///
/// In cs, this message translates to:
/// **'Nová anketa'**
String get pollCreateTitle;
/// Pole otázky ankety.
///
/// In cs, this message translates to:
/// **'Otázka'**
String get pollQuestion;
/// Placeholder možnosti ankety s pořadím.
///
/// In cs, this message translates to:
/// **'Možnost {number}'**
String pollOptionHint(int number);
/// Tlačítko: přidat možnost do ankety.
///
/// In cs, this message translates to:
/// **'Přidat možnost'**
String get pollAddOption;
/// Tlačítko: odebrat možnost.
///
/// In cs, this message translates to:
/// **'Odebrat možnost'**
String get pollRemoveOption;
/// Přepínač: víc odpovědí na osobu.
///
/// In cs, this message translates to:
/// **'Povolit víc odpovědí'**
String get pollAllowMultiple;
/// Hlavička ankety s jednou volbou.
///
/// In cs, this message translates to:
/// **'Anketa'**
String get pollSingle;
/// Hlavička ankety s více volbami.
///
/// In cs, this message translates to:
/// **'Anketa, více voleb'**
String get pollMulti;
/// Počet hlasujících v anketě.
///
/// In cs, this message translates to:
/// **'{count, plural, =0{zatím bez hlasů} one{1 hlas} few{{count} hlasy} other{{count} hlasů}}'**
String pollVoters(int count);
/// Záložní text ankety pro starší verze appky — první řádek.
///
/// In cs, this message translates to:
/// **'Anketa: {question}'**
String pollFallback(String question);
/// Záložní text ankety — výzva k aktualizaci.
///
/// In cs, this message translates to:
/// **'Hlasovat jde v aktuální verzi Šepotu.'**
String get pollFallbackUpdate;
/// Popisek avataru v Nastavení (čtečka obrazovky).
///
/// In cs, this message translates to:
/// **'Změnit profilovou fotku'**
String get profilePhotoEdit;
/// Akce: vybrat profilovou fotku z galerie.
///
/// In cs, this message translates to:
/// **'Vybrat fotku'**
String get profilePhotoPick;
/// Akce: odebrat profilovou fotku.
///
/// In cs, this message translates to:
/// **'Odebrat fotku'**
String get profilePhotoRemove;
/// Vysvětlení, kdo profilovou fotku uvidí.
///
/// In cs, this message translates to:
/// **'Fotku uvidí jen lidé, se kterými si píšeš — šifrovaně, stejně jako zprávy. Poloha ani údaje o fotce se neposílají.'**
String get profilePhotoHint;
/// Chyba nastavení profilové fotky.
///
/// In cs, this message translates to:
/// **'Fotku se nepodařilo nastavit: {error}'**
String profilePhotoFailed(String error);
}
class _AppLocalizationsDelegate
+437 -18
View File
@@ -75,17 +75,67 @@ class AppLocalizationsCs extends AppLocalizations {
String get groupsLeftBanner =>
'Už nejsi ve skupině. Historie zůstává, nové zprávy nedorazí.';
@override
String groupsMembersWithCount(int count) {
return 'Členové ($count)';
}
@override
String get groupsYou => 'Ty';
@override
String get groupsFounder => 'Zakladatel';
@override
String get groupsAdmin => 'Správce';
@override
String get groupsMakeAdmin => 'Udělat správcem';
@override
String get groupsDismissAdmin => 'Odebrat roli správce';
@override
String get groupsRemoveMember => 'Odebrat ze skupiny';
@override
String groupsRemoveMemberConfirmTitle(String name) {
return 'Odebrat $name ze skupiny?';
}
@override
String get groupsRemoveMemberConfirmBody =>
'Přestanou mu chodit nové zprávy skupiny. Dosavadní historie mu zůstane.';
@override
String get groupsRemoveAction => 'Odebrat';
@override
String get groupsViewContact => 'Zobrazit kontakt';
@override
String get groupsAdminOnlyHint =>
'Jméno, členy a správce skupiny mění jen správci.';
@override
String get groupsAdminOnlyCompatHint =>
'Jméno a správce mění jen správci. Přidávat lidi zatím může každý, protože někdo ve skupině má starší verzi Šepotu.';
@override
String groupsAdminActionFailed(String error) {
return 'Změna se nepovedla: $error';
}
@override
String get groupsResyncNotice =>
'Stav skupiny se srovnává se správcem. Změny členů se můžou chvíli opozdit.';
@override
String get groupsRejectedChangeNotice =>
'Někdo bez oprávnění zkusil skupinu změnit. Změna se neprovedla.';
@override
String get errorGroupNotAdmin => 'Tohle může udělat jen správce skupiny.';
@override
String get errorGroupLastAdmin =>
'Jsi jediný správce. Nejdřív udělej správcem někoho dalšího.';
@override
String get groupsNameHint => 'Název skupiny';
@@ -192,6 +242,28 @@ class AppLocalizationsCs extends AppLocalizations {
@override
String get chatActionReply => 'Odpovědět';
@override
String get chatActionForward => 'Přeposlat';
@override
String get forwardTitle => 'Přeposlat do…';
@override
String get forwardSearchHint => 'Hledat kontakt nebo skupinu';
@override
String get forwardEmpty => 'Nic tu není';
@override
String forwardDone(String name) {
return 'Přeposláno: $name';
}
@override
String forwardFailed(String error) {
return 'Přeposlání se nepovedlo: $error';
}
@override
String get commonCopy => 'Kopírovat';
@@ -248,6 +320,16 @@ class AppLocalizationsCs extends AppLocalizations {
return 'Soubor je příliš velký (max $maxMb MB)';
}
@override
String get attachmentKeepsMetadataTitle => 'Fotka odejde i s polohou';
@override
String get attachmentKeepsMetadataBody =>
'Tenhle formát fotky (třeba HEIC) neumím zbavit metadat. Odešla by v originále včetně polohy, kde vznikla, a údajů o telefonu. Bezpečnější je poslat ji přes Galerii, kde se metadata odstraní.';
@override
String get attachmentSendOriginal => 'Poslat originál';
@override
String attachmentPickFailed(String error) {
return 'Výběr přílohy selhal: $error';
@@ -292,6 +374,9 @@ class AppLocalizationsCs extends AppLocalizations {
@override
String get errorGroupNeedsMember => 'Skupina potřebuje aspoň 1 člena';
@override
String get errorAttachmentUnavailable => 'Příloha už v telefonu není';
@override
String errorGroupMaxMembers(int maxMembers) {
return 'Skupina může mít nejvýš $maxMembers členů';
@@ -601,19 +686,100 @@ class AppLocalizationsCs extends AppLocalizations {
@override
String get chatListNewConversation => 'Nová konverzace';
@override
String chatListPhotoWithCaptionPreview(String caption) {
return '📷 $caption';
}
@override
String chatListFilePreview(String fileName) {
return '📎 $fileName';
}
@override
String get chatListReadReceiptPreview => 'Přečteno';
@override
String get chatListDraft => 'Koncept';
@override
String get notesTitle => 'Poznámky pro sebe';
@override
String get notesSubtitle => 'Jen v tomto telefonu, šifrovaně';
@override
String get callVoice => 'Zavolat';
@override
String get callVideo => 'Videohovor';
@override
String get callStatusRinging => 'Vyzvání…';
@override
String get callIncomingVoice => 'Příchozí hovor';
@override
String get callIncomingVideo => 'Příchozí videohovor';
@override
String get callStatusConnecting => 'Spojuji…';
@override
String get callEnded => 'Hovor skončil';
@override
String get callEndedBusy => 'Obsazeno';
@override
String get callEndedRejected => 'Hovor odmítnut';
@override
String get callEndedUnanswered => 'Nikdo to nevzal';
@override
String get callEndedFailed => 'Spojení se nepodařilo';
@override
String get callEncrypted => 'Šifrováno end-to-end';
@override
String get callAccept => 'Přijmout';
@override
String get callReject => 'Odmítnout';
@override
String get callMute => 'Ztlumit mikrofon';
@override
String get callSpeaker => 'Reproduktor';
@override
String get callCamera => 'Vypnout kameru';
@override
String get callSwitchCamera => 'Přepnout kameru';
@override
String get callHangUp => 'Zavěsit';
@override
String get callLogMissed => 'Zmeškaný hovor';
@override
String get callLogUnanswered => 'Nepřijatý hovor';
@override
String get callLogRejected => 'Odmítnutý hovor';
@override
String get callLogBusy => 'Obsazeno';
@override
String get callLogFailed => 'Hovor se nespojil';
@override
String callLogVoice(String duration) {
return 'Hovor · $duration';
}
@override
String callLogVideo(String duration) {
return 'Videohovor · $duration';
}
@override
String get chatListTimeNow => 'teď';
@@ -943,14 +1109,14 @@ class AppLocalizationsCs extends AppLocalizations {
String get pushModeOffDesc => 'Zprávy se stáhnou až po otevření appky.';
@override
String get pushModeUp => 'UnifiedPush (doporučeno)';
String get pushModeUp => 'UnifiedPush (bez Googlu)';
@override
String get pushModeUpDesc =>
'Degooglované — potřebuje aplikaci ntfy (F-Droid/Play).';
@override
String get pushModeFcm => 'Google (FCM)';
String get pushModeFcm => 'Google (FCM, výchozí)';
@override
String get pushModeFcmDesc =>
@@ -995,7 +1161,7 @@ class AppLocalizationsCs extends AppLocalizations {
String get pushNoDistributorFallback => 'bez distributora';
@override
String get pushSubtitleFcm => 'Google (FCM) — rychlé, opt-in';
String get pushSubtitleFcm => 'Google (FCM)';
@override
String get restoreErrorNameRequired => 'Zadej zobrazované jméno.';
@@ -1302,4 +1468,257 @@ class AppLocalizationsCs extends AppLocalizations {
@override
String get photoPreviewDecodeFailed => 'Fotku se nepodařilo načíst';
@override
String get chatActionInfo => 'Info o zprávě';
@override
String get messageInfoSent => 'Odesláno';
@override
String get messageInfoDelivered => 'Doručeno';
@override
String get messageInfoRead => 'Přečteno';
@override
String get messageInfoPending => 'zatím ne';
@override
String get messageInfoReadReceiptsOff =>
'Kdy si zprávu přečetli, uvidíš, jen když sám sdílíš potvrzení přečtení (Nastavení).';
@override
String chatStatusReadAt(String time) {
return 'Přečteno $time';
}
@override
String chatStatusDeliveredAt(String time) {
return 'Doručeno $time';
}
@override
String get groupsAddMembers => 'Přidat členy';
@override
String get groupsAddMembersAction => 'Přidat';
@override
String groupsAddMembersFailed(String error) {
return 'Přidání se nepovedlo: $error';
}
@override
String get groupsNoContactsToAdd =>
'Všechny tvoje kontakty už ve skupině jsou. Nového člověka nejdřív přidej do kontaktů přes QR kód.';
@override
String get navChats => 'Chaty';
@override
String get chatListNewChat => 'Nový chat';
@override
String get chatListSearchHint => 'Hledat v chatech a zprávách';
@override
String get chatFilterAll => 'Vše';
@override
String get chatFilterUnread => 'Nepřečtené';
@override
String get chatFilterGroups => 'Skupiny';
@override
String get chatFilterArchive => 'Archiv';
@override
String get chatListNoResults => 'Nic nenalezeno.';
@override
String get chatListFilterEmpty => 'Tady zatím nic není.';
@override
String get chatListPin => 'Připnout';
@override
String get chatListUnpin => 'Odepnout';
@override
String get chatOpenProfile => 'Zobrazit profil';
@override
String get groupsProfile => 'Profil skupiny';
@override
String get chatSearchHint => 'Hledat v konverzaci';
@override
String get chatSearchNoMatches => 'Nic';
@override
String chatSearchCounter(int current, int total) {
return '$current z $total';
}
@override
String get chatSearchOlder => 'Starší shoda';
@override
String get chatSearchNewer => 'Novější shoda';
@override
String chatUnreadDivider(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count nových zpráv',
few: '$count nové zprávy',
one: '1 nová zpráva',
);
return '$_temp0';
}
@override
String get chatJumpToLatest => 'Na nejnovější zprávy';
@override
String get chatAttach => 'Přiložit';
@override
String get chatSend => 'Odeslat';
@override
String get chatRecordVoice => 'Nahrát hlasovou zprávu';
@override
String get profileSharedMedia => 'Sdílená média';
@override
String get profileMessage => 'Zpráva';
@override
String get profileSearch => 'Hledat';
@override
String get profileUnmute => 'Zvuk';
@override
String get profileDisappearing => 'Mizení';
@override
String get profileCommonGroups => 'Společné skupiny';
@override
String get profileSafetyNumber => 'Bezpečnostní číslo';
@override
String get profileSafetyNumberHint => 'Porovnejte osobně nebo QR kódem';
@override
String get profileVerifiedInPerson => 'Ověřeno osobně';
@override
String get profileVerifyNow => 'Ověřit kontakt';
@override
String get profileAdd => 'Přidat';
@override
String profileGroupSubtitle(String members, String date) {
return 'Skupina · $members · založena $date';
}
@override
String profileMembersOfMax(int count, int max) {
return '$count ze $max';
}
@override
String get chatTyping => 'píše…';
@override
String chatTypingNamed(String name) {
return '$name píše…';
}
@override
String get chatTypingSeveral => 'Několik lidí píše…';
@override
String get settingsTypingTitle => 'Ukazovat, že píšu';
@override
String get settingsTypingSubtitle =>
'Oboustranné — kdo nesdílí, nevidí (výchozí vypnuto)';
@override
String get pollAttach => 'Anketa';
@override
String get pollCreateTitle => 'Nová anketa';
@override
String get pollQuestion => 'Otázka';
@override
String pollOptionHint(int number) {
return 'Možnost $number';
}
@override
String get pollAddOption => 'Přidat možnost';
@override
String get pollRemoveOption => 'Odebrat možnost';
@override
String get pollAllowMultiple => 'Povolit víc odpovědí';
@override
String get pollSingle => 'Anketa';
@override
String get pollMulti => 'Anketa, více voleb';
@override
String pollVoters(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count hlasů',
few: '$count hlasy',
one: '1 hlas',
zero: 'zatím bez hlasů',
);
return '$_temp0';
}
@override
String pollFallback(String question) {
return 'Anketa: $question';
}
@override
String get pollFallbackUpdate => 'Hlasovat jde v aktuální verzi Šepotu.';
@override
String get profilePhotoEdit => 'Změnit profilovou fotku';
@override
String get profilePhotoPick => 'Vybrat fotku';
@override
String get profilePhotoRemove => 'Odebrat fotku';
@override
String get profilePhotoHint =>
'Fotku uvidí jen lidé, se kterými si píšeš — šifrovaně, stejně jako zprávy. Poloha ani údaje o fotce se neposílají.';
@override
String profilePhotoFailed(String error) {
return 'Fotku se nepodařilo nastavit: $error';
}
}
+437 -18
View File
@@ -73,17 +73,67 @@ class AppLocalizationsDe extends AppLocalizations {
String get groupsLeftBanner =>
'Du bist nicht mehr in der Gruppe. Der Verlauf bleibt, neue Nachrichten kommen nicht mehr an.';
@override
String groupsMembersWithCount(int count) {
return 'Mitglieder ($count)';
}
@override
String get groupsYou => 'Du';
@override
String get groupsFounder => 'Hat die Gruppe gegründet';
@override
String get groupsAdmin => 'Admin';
@override
String get groupsMakeAdmin => 'Zum Admin machen';
@override
String get groupsDismissAdmin => 'Adminrolle entziehen';
@override
String get groupsRemoveMember => 'Aus der Gruppe entfernen';
@override
String groupsRemoveMemberConfirmTitle(String name) {
return '$name aus der Gruppe entfernen?';
}
@override
String get groupsRemoveMemberConfirmBody =>
'Neue Nachrichten der Gruppe kommen dann nicht mehr an. Der bisherige Verlauf bleibt erhalten.';
@override
String get groupsRemoveAction => 'Entfernen';
@override
String get groupsViewContact => 'Kontakt anzeigen';
@override
String get groupsAdminOnlyHint =>
'Nur Admins können Namen, Mitglieder und Admins der Gruppe ändern.';
@override
String get groupsAdminOnlyCompatHint =>
'Nur Admins können die Gruppe umbenennen oder Admins ändern. Personen hinzufügen kann vorerst jeder, weil jemand in der Gruppe eine ältere Šepot-Version hat.';
@override
String groupsAdminActionFailed(String error) {
return 'Änderung fehlgeschlagen: $error';
}
@override
String get groupsResyncNotice =>
'Die Gruppe gleicht sich mit dem Admin ab. Änderungen an Mitgliedern können sich kurz verzögern.';
@override
String get groupsRejectedChangeNotice =>
'Jemand ohne Berechtigung hat versucht, die Gruppe zu ändern. Die Änderung wurde nicht übernommen.';
@override
String get errorGroupNotAdmin => 'Das kann nur ein Admin der Gruppe.';
@override
String get errorGroupLastAdmin =>
'Du bist der einzige Admin. Mach zuerst jemand anderen zum Admin.';
@override
String get groupsNameHint => 'Gruppenname';
@@ -191,6 +241,28 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get chatActionReply => 'Antworten';
@override
String get chatActionForward => 'Weiterleiten';
@override
String get forwardTitle => 'Weiterleiten an…';
@override
String get forwardSearchHint => 'Kontakt oder Gruppe suchen';
@override
String get forwardEmpty => 'Nichts gefunden';
@override
String forwardDone(String name) {
return 'Weitergeleitet an $name';
}
@override
String forwardFailed(String error) {
return 'Weiterleiten fehlgeschlagen: $error';
}
@override
String get commonCopy => 'Kopieren';
@@ -248,6 +320,16 @@ class AppLocalizationsDe extends AppLocalizations {
return 'Datei ist zu groß (max. $maxMb MB)';
}
@override
String get attachmentKeepsMetadataTitle => 'Foto enthält den Standort';
@override
String get attachmentKeepsMetadataBody =>
'Aus diesem Fotoformat (z. B. HEIC) kann ich die Metadaten nicht entfernen. Es würde im Original gesendet, einschließlich Aufnahmeort und Angaben zum Telefon. Sicherer ist das Senden über die Galerie, dort werden die Metadaten entfernt.';
@override
String get attachmentSendOriginal => 'Original senden';
@override
String attachmentPickFailed(String error) {
return 'Auswahl des Anhangs fehlgeschlagen: $error';
@@ -294,6 +376,10 @@ class AppLocalizationsDe extends AppLocalizations {
String get errorGroupNeedsMember =>
'Die Gruppe braucht mindestens 1 Mitglied';
@override
String get errorAttachmentUnavailable =>
'Der Anhang ist nicht mehr auf diesem Telefon';
@override
String errorGroupMaxMembers(int maxMembers) {
return 'Die Gruppe kann höchstens $maxMembers Mitglieder haben';
@@ -604,19 +690,100 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get chatListNewConversation => 'Neue Unterhaltung';
@override
String chatListPhotoWithCaptionPreview(String caption) {
return '📷 $caption';
}
@override
String chatListFilePreview(String fileName) {
return '📎 $fileName';
}
@override
String get chatListReadReceiptPreview => 'Gelesen';
@override
String get chatListDraft => 'Entwurf';
@override
String get notesTitle => 'Notizen für mich';
@override
String get notesSubtitle => 'Nur auf diesem Telefon, verschlüsselt';
@override
String get callVoice => 'Anrufen';
@override
String get callVideo => 'Videoanruf';
@override
String get callStatusRinging => 'Klingelt…';
@override
String get callIncomingVoice => 'Eingehender Anruf';
@override
String get callIncomingVideo => 'Eingehender Videoanruf';
@override
String get callStatusConnecting => 'Verbinde…';
@override
String get callEnded => 'Anruf beendet';
@override
String get callEndedBusy => 'Besetzt';
@override
String get callEndedRejected => 'Anruf abgelehnt';
@override
String get callEndedUnanswered => 'Keine Antwort';
@override
String get callEndedFailed => 'Verbindung fehlgeschlagen';
@override
String get callEncrypted => 'Ende-zu-Ende-verschlüsselt';
@override
String get callAccept => 'Annehmen';
@override
String get callReject => 'Ablehnen';
@override
String get callMute => 'Stummschalten';
@override
String get callSpeaker => 'Lautsprecher';
@override
String get callCamera => 'Kamera aus';
@override
String get callSwitchCamera => 'Kamera wechseln';
@override
String get callHangUp => 'Auflegen';
@override
String get callLogMissed => 'Verpasster Anruf';
@override
String get callLogUnanswered => 'Unbeantworteter Anruf';
@override
String get callLogRejected => 'Abgelehnter Anruf';
@override
String get callLogBusy => 'Besetzt';
@override
String get callLogFailed => 'Anruf fehlgeschlagen';
@override
String callLogVoice(String duration) {
return 'Anruf · $duration';
}
@override
String callLogVideo(String duration) {
return 'Videoanruf · $duration';
}
@override
String get chatListTimeNow => 'jetzt';
@@ -962,14 +1129,14 @@ class AppLocalizationsDe extends AppLocalizations {
'Nachrichten werden erst beim Öffnen der App abgerufen.';
@override
String get pushModeUp => 'UnifiedPush (empfohlen)';
String get pushModeUp => 'UnifiedPush (ohne Google)';
@override
String get pushModeUpDesc =>
'Google-frei — braucht die App ntfy (F-Droid/Play).';
@override
String get pushModeFcm => 'Google (FCM)';
String get pushModeFcm => 'Google (FCM, Standard)';
@override
String get pushModeFcmDesc =>
@@ -1014,7 +1181,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get pushNoDistributorFallback => 'kein Distributor';
@override
String get pushSubtitleFcm => 'Google (FCM) — schnell, opt-in';
String get pushSubtitleFcm => 'Google (FCM)';
@override
String get restoreErrorNameRequired => 'Gib einen Anzeigenamen ein.';
@@ -1324,4 +1491,256 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get photoPreviewDecodeFailed => 'Foto konnte nicht geladen werden';
@override
String get chatActionInfo => 'Nachrichteninfo';
@override
String get messageInfoSent => 'Gesendet';
@override
String get messageInfoDelivered => 'Zugestellt';
@override
String get messageInfoRead => 'Gelesen';
@override
String get messageInfoPending => 'noch nicht';
@override
String get messageInfoReadReceiptsOff =>
'Wann deine Nachrichten gelesen wurden, siehst du nur, wenn du selbst Lesebestätigungen teilst (Einstellungen).';
@override
String chatStatusReadAt(String time) {
return 'Gelesen $time';
}
@override
String chatStatusDeliveredAt(String time) {
return 'Zugestellt $time';
}
@override
String get groupsAddMembers => 'Mitglieder hinzufügen';
@override
String get groupsAddMembersAction => 'Hinzufügen';
@override
String groupsAddMembersFailed(String error) {
return 'Hinzufügen fehlgeschlagen: $error';
}
@override
String get groupsNoContactsToAdd =>
'Alle deine Kontakte sind schon in der Gruppe. Füge neue Personen zuerst per QR-Code zu deinen Kontakten hinzu.';
@override
String get navChats => 'Chats';
@override
String get chatListNewChat => 'Neuer Chat';
@override
String get chatListSearchHint => 'Chats und Nachrichten durchsuchen';
@override
String get chatFilterAll => 'Alle';
@override
String get chatFilterUnread => 'Ungelesen';
@override
String get chatFilterGroups => 'Gruppen';
@override
String get chatFilterArchive => 'Archiv';
@override
String get chatListNoResults => 'Nichts gefunden.';
@override
String get chatListFilterEmpty => 'Hier ist noch nichts.';
@override
String get chatListPin => 'Anheften';
@override
String get chatListUnpin => 'Lösen';
@override
String get chatOpenProfile => 'Profil anzeigen';
@override
String get groupsProfile => 'Gruppeninfo';
@override
String get chatSearchHint => 'Im Chat suchen';
@override
String get chatSearchNoMatches => 'Keine';
@override
String chatSearchCounter(int current, int total) {
return '$current von $total';
}
@override
String get chatSearchOlder => 'Ältere Treffer';
@override
String get chatSearchNewer => 'Neuerer Treffer';
@override
String chatUnreadDivider(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count neue Nachrichten',
one: '1 neue Nachricht',
);
return '$_temp0';
}
@override
String get chatJumpToLatest => 'Zu den neuesten';
@override
String get chatAttach => 'Anhängen';
@override
String get chatSend => 'Senden';
@override
String get chatRecordVoice => 'Sprachnachricht aufnehmen';
@override
String get profileSharedMedia => 'Geteilte Medien';
@override
String get profileMessage => 'Nachricht';
@override
String get profileSearch => 'Suchen';
@override
String get profileUnmute => 'Ton an';
@override
String get profileDisappearing => 'Verschwinden';
@override
String get profileCommonGroups => 'Gemeinsame Gruppen';
@override
String get profileSafetyNumber => 'Sicherheitsnummer';
@override
String get profileSafetyNumberHint =>
'Persönlich oder per QR-Code vergleichen';
@override
String get profileVerifiedInPerson => 'Persönlich verifiziert';
@override
String get profileVerifyNow => 'Kontakt verifizieren';
@override
String get profileAdd => 'Hinzufügen';
@override
String profileGroupSubtitle(String members, String date) {
return 'Gruppe · $members · erstellt am $date';
}
@override
String profileMembersOfMax(int count, int max) {
return '$count von $max';
}
@override
String get chatTyping => 'schreibt…';
@override
String chatTypingNamed(String name) {
return '$name schreibt…';
}
@override
String get chatTypingSeveral => 'Mehrere schreiben…';
@override
String get settingsTypingTitle => 'Tippindikator';
@override
String get settingsTypingSubtitle =>
'Gegenseitig — wer nicht teilt, sieht nichts (standardmäßig aus)';
@override
String get pollAttach => 'Umfrage';
@override
String get pollCreateTitle => 'Neue Umfrage';
@override
String get pollQuestion => 'Frage';
@override
String pollOptionHint(int number) {
return 'Option $number';
}
@override
String get pollAddOption => 'Option hinzufügen';
@override
String get pollRemoveOption => 'Option entfernen';
@override
String get pollAllowMultiple => 'Mehrere Antworten erlauben';
@override
String get pollSingle => 'Umfrage';
@override
String get pollMulti => 'Umfrage, Mehrfachauswahl';
@override
String pollVoters(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count Stimmen',
one: '1 Stimme',
zero: 'noch keine Stimmen',
);
return '$_temp0';
}
@override
String pollFallback(String question) {
return 'Umfrage: $question';
}
@override
String get pollFallbackUpdate => 'Zum Abstimmen Šepot aktualisieren.';
@override
String get profilePhotoEdit => 'Profilbild ändern';
@override
String get profilePhotoPick => 'Foto auswählen';
@override
String get profilePhotoRemove => 'Foto entfernen';
@override
String get profilePhotoHint =>
'Nur deine Chatpartner sehen es — Ende-zu-Ende-verschlüsselt wie Nachrichten. Standort und Fotodaten werden nicht gesendet.';
@override
String profilePhotoFailed(String error) {
return 'Foto konnte nicht gesetzt werden: $error';
}
}
+436 -18
View File
@@ -73,17 +73,67 @@ class AppLocalizationsEn extends AppLocalizations {
String get groupsLeftBanner =>
'You\'re no longer in this group. Your history stays, but new messages won\'t arrive.';
@override
String groupsMembersWithCount(int count) {
return 'Members ($count)';
}
@override
String get groupsYou => 'You';
@override
String get groupsFounder => 'Founder';
@override
String get groupsAdmin => 'Admin';
@override
String get groupsMakeAdmin => 'Make admin';
@override
String get groupsDismissAdmin => 'Remove admin role';
@override
String get groupsRemoveMember => 'Remove from group';
@override
String groupsRemoveMemberConfirmTitle(String name) {
return 'Remove $name from the group?';
}
@override
String get groupsRemoveMemberConfirmBody =>
'They will stop getting new messages from this group. Their existing history stays.';
@override
String get groupsRemoveAction => 'Remove';
@override
String get groupsViewContact => 'View contact';
@override
String get groupsAdminOnlyHint =>
'Only admins can change the group name, members and admins.';
@override
String get groupsAdminOnlyCompatHint =>
'Only admins can rename the group or change admins. Anyone can still add people, because someone in the group has an older version of Šepot.';
@override
String groupsAdminActionFailed(String error) {
return 'The change failed: $error';
}
@override
String get groupsResyncNotice =>
'The group is catching up with its admin. Member changes may show up with a delay.';
@override
String get groupsRejectedChangeNotice =>
'Someone without permission tried to change the group. The change was not applied.';
@override
String get errorGroupNotAdmin => 'Only a group admin can do this.';
@override
String get errorGroupLastAdmin =>
'You\'re the only admin. Make someone else an admin first.';
@override
String get groupsNameHint => 'Group name';
@@ -190,6 +240,28 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get chatActionReply => 'Reply';
@override
String get chatActionForward => 'Forward';
@override
String get forwardTitle => 'Forward to…';
@override
String get forwardSearchHint => 'Search contact or group';
@override
String get forwardEmpty => 'Nothing here';
@override
String forwardDone(String name) {
return 'Forwarded to $name';
}
@override
String forwardFailed(String error) {
return 'Forwarding failed: $error';
}
@override
String get commonCopy => 'Copy';
@@ -246,6 +318,16 @@ class AppLocalizationsEn extends AppLocalizations {
return 'File is too large (max $maxMb MB)';
}
@override
String get attachmentKeepsMetadataTitle => 'Photo will include location';
@override
String get attachmentKeepsMetadataBody =>
'I can\'t remove metadata from this photo format (e.g. HEIC). It would be sent as the original, including where it was taken and details about the phone. Sending it via Gallery is safer, as metadata is removed there.';
@override
String get attachmentSendOriginal => 'Send original';
@override
String attachmentPickFailed(String error) {
return 'Picking attachment failed: $error';
@@ -290,6 +372,10 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get errorGroupNeedsMember => 'A group needs at least 1 member';
@override
String get errorAttachmentUnavailable =>
'The attachment is no longer on this phone';
@override
String errorGroupMaxMembers(int maxMembers) {
return 'A group can have at most $maxMembers members';
@@ -596,19 +682,100 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get chatListNewConversation => 'New conversation';
@override
String chatListPhotoWithCaptionPreview(String caption) {
return '📷 $caption';
}
@override
String chatListFilePreview(String fileName) {
return '📎 $fileName';
}
@override
String get chatListReadReceiptPreview => 'Read';
@override
String get chatListDraft => 'Draft';
@override
String get notesTitle => 'Note to self';
@override
String get notesSubtitle => 'Only on this phone, encrypted';
@override
String get callVoice => 'Call';
@override
String get callVideo => 'Video call';
@override
String get callStatusRinging => 'Ringing…';
@override
String get callIncomingVoice => 'Incoming call';
@override
String get callIncomingVideo => 'Incoming video call';
@override
String get callStatusConnecting => 'Connecting…';
@override
String get callEnded => 'Call ended';
@override
String get callEndedBusy => 'Busy';
@override
String get callEndedRejected => 'Call declined';
@override
String get callEndedUnanswered => 'No answer';
@override
String get callEndedFailed => 'Couldn\'t connect';
@override
String get callEncrypted => 'End-to-end encrypted';
@override
String get callAccept => 'Accept';
@override
String get callReject => 'Decline';
@override
String get callMute => 'Mute';
@override
String get callSpeaker => 'Speaker';
@override
String get callCamera => 'Turn off camera';
@override
String get callSwitchCamera => 'Switch camera';
@override
String get callHangUp => 'Hang up';
@override
String get callLogMissed => 'Missed call';
@override
String get callLogUnanswered => 'Unanswered call';
@override
String get callLogRejected => 'Declined call';
@override
String get callLogBusy => 'Busy';
@override
String get callLogFailed => 'Call failed';
@override
String callLogVoice(String duration) {
return 'Call · $duration';
}
@override
String callLogVideo(String duration) {
return 'Video call · $duration';
}
@override
String get chatListTimeNow => 'now';
@@ -941,14 +1108,14 @@ class AppLocalizationsEn extends AppLocalizations {
String get pushModeOffDesc => 'Messages arrive only after you open the app.';
@override
String get pushModeUp => 'UnifiedPush (recommended)';
String get pushModeUp => 'UnifiedPush (no Google)';
@override
String get pushModeUpDesc =>
'De-Googled — needs the ntfy app (F-Droid/Play).';
@override
String get pushModeFcm => 'Google (FCM)';
String get pushModeFcm => 'Google (FCM, default)';
@override
String get pushModeFcmDesc =>
@@ -993,7 +1160,7 @@ class AppLocalizationsEn extends AppLocalizations {
String get pushNoDistributorFallback => 'no distributor';
@override
String get pushSubtitleFcm => 'Google (FCM) — fast, opt-in';
String get pushSubtitleFcm => 'Google (FCM)';
@override
String get restoreErrorNameRequired => 'Enter a display name.';
@@ -1297,4 +1464,255 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get photoPreviewDecodeFailed => 'Couldn\'t load the photo';
@override
String get chatActionInfo => 'Message info';
@override
String get messageInfoSent => 'Sent';
@override
String get messageInfoDelivered => 'Delivered';
@override
String get messageInfoRead => 'Read';
@override
String get messageInfoPending => 'not yet';
@override
String get messageInfoReadReceiptsOff =>
'You only see when people read your messages if you share read receipts yourself (Settings).';
@override
String chatStatusReadAt(String time) {
return 'Read $time';
}
@override
String chatStatusDeliveredAt(String time) {
return 'Delivered $time';
}
@override
String get groupsAddMembers => 'Add members';
@override
String get groupsAddMembersAction => 'Add';
@override
String groupsAddMembersFailed(String error) {
return 'Could not add members: $error';
}
@override
String get groupsNoContactsToAdd =>
'All your contacts are already in this group. Add someone new to your contacts via QR code first.';
@override
String get navChats => 'Chats';
@override
String get chatListNewChat => 'New chat';
@override
String get chatListSearchHint => 'Search chats and messages';
@override
String get chatFilterAll => 'All';
@override
String get chatFilterUnread => 'Unread';
@override
String get chatFilterGroups => 'Groups';
@override
String get chatFilterArchive => 'Archive';
@override
String get chatListNoResults => 'Nothing found.';
@override
String get chatListFilterEmpty => 'Nothing here yet.';
@override
String get chatListPin => 'Pin';
@override
String get chatListUnpin => 'Unpin';
@override
String get chatOpenProfile => 'View profile';
@override
String get groupsProfile => 'Group info';
@override
String get chatSearchHint => 'Search in chat';
@override
String get chatSearchNoMatches => 'None';
@override
String chatSearchCounter(int current, int total) {
return '$current of $total';
}
@override
String get chatSearchOlder => 'Older match';
@override
String get chatSearchNewer => 'Newer match';
@override
String chatUnreadDivider(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count new messages',
one: '1 new message',
);
return '$_temp0';
}
@override
String get chatJumpToLatest => 'Jump to latest';
@override
String get chatAttach => 'Attach';
@override
String get chatSend => 'Send';
@override
String get chatRecordVoice => 'Record voice message';
@override
String get profileSharedMedia => 'Shared media';
@override
String get profileMessage => 'Message';
@override
String get profileSearch => 'Search';
@override
String get profileUnmute => 'Unmute';
@override
String get profileDisappearing => 'Disappear';
@override
String get profileCommonGroups => 'Groups in common';
@override
String get profileSafetyNumber => 'Safety number';
@override
String get profileSafetyNumberHint => 'Compare in person or by QR code';
@override
String get profileVerifiedInPerson => 'Verified in person';
@override
String get profileVerifyNow => 'Verify contact';
@override
String get profileAdd => 'Add';
@override
String profileGroupSubtitle(String members, String date) {
return 'Group · $members · created $date';
}
@override
String profileMembersOfMax(int count, int max) {
return '$count of $max';
}
@override
String get chatTyping => 'typing…';
@override
String chatTypingNamed(String name) {
return '$name is typing…';
}
@override
String get chatTypingSeveral => 'Several people are typing…';
@override
String get settingsTypingTitle => 'Typing indicators';
@override
String get settingsTypingSubtitle =>
'Mutual — if you don\'t share it, you don\'t see it (off by default)';
@override
String get pollAttach => 'Poll';
@override
String get pollCreateTitle => 'New poll';
@override
String get pollQuestion => 'Question';
@override
String pollOptionHint(int number) {
return 'Option $number';
}
@override
String get pollAddOption => 'Add option';
@override
String get pollRemoveOption => 'Remove option';
@override
String get pollAllowMultiple => 'Allow multiple answers';
@override
String get pollSingle => 'Poll';
@override
String get pollMulti => 'Poll, multiple choice';
@override
String pollVoters(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count votes',
one: '1 vote',
zero: 'no votes yet',
);
return '$_temp0';
}
@override
String pollFallback(String question) {
return 'Poll: $question';
}
@override
String get pollFallbackUpdate => 'Update Šepot to vote.';
@override
String get profilePhotoEdit => 'Change profile photo';
@override
String get profilePhotoPick => 'Choose photo';
@override
String get profilePhotoRemove => 'Remove photo';
@override
String get profilePhotoHint =>
'Only people you chat with will see it — end-to-end encrypted like your messages. No location or photo metadata is sent.';
@override
String profilePhotoFailed(String error) {
return 'Could not set photo: $error';
}
}
+437 -18
View File
@@ -73,17 +73,68 @@ class AppLocalizationsIt extends AppLocalizations {
String get groupsLeftBanner =>
'Non sei più nel gruppo. La cronologia resta, i nuovi messaggi non arriveranno.';
@override
String groupsMembersWithCount(int count) {
return 'Membri ($count)';
}
@override
String get groupsYou => 'Tu';
@override
String get groupsFounder => 'Fondatore';
@override
String get groupsAdmin => 'Amministratore';
@override
String get groupsMakeAdmin => 'Rendi amministratore';
@override
String get groupsDismissAdmin => 'Rimuovi ruolo di amministratore';
@override
String get groupsRemoveMember => 'Rimuovi dal gruppo';
@override
String groupsRemoveMemberConfirmTitle(String name) {
return 'Rimuovere $name dal gruppo?';
}
@override
String get groupsRemoveMemberConfirmBody =>
'Non riceverà più i nuovi messaggi del gruppo. La cronologia esistente resta.';
@override
String get groupsRemoveAction => 'Rimuovi';
@override
String get groupsViewContact => 'Vedi contatto';
@override
String get groupsAdminOnlyHint =>
'Solo gli amministratori possono cambiare nome, membri e amministratori del gruppo.';
@override
String get groupsAdminOnlyCompatHint =>
'Solo gli amministratori possono rinominare il gruppo o cambiare gli amministratori. Per ora chiunque può aggiungere persone, perché qualcuno nel gruppo ha una versione precedente di Šepot.';
@override
String groupsAdminActionFailed(String error) {
return 'Modifica non riuscita: $error';
}
@override
String get groupsResyncNotice =>
'Il gruppo si sta allineando con l\'amministratore. Le modifiche ai membri potrebbero arrivare in ritardo.';
@override
String get groupsRejectedChangeNotice =>
'Qualcuno senza permesso ha provato a modificare il gruppo. La modifica non è stata applicata.';
@override
String get errorGroupNotAdmin =>
'Solo un amministratore del gruppo può farlo.';
@override
String get errorGroupLastAdmin =>
'Sei l\'unico amministratore. Prima rendi amministratore qualcun altro.';
@override
String get groupsNameHint => 'Nome del gruppo';
@@ -191,6 +242,28 @@ class AppLocalizationsIt extends AppLocalizations {
@override
String get chatActionReply => 'Rispondi';
@override
String get chatActionForward => 'Inoltra';
@override
String get forwardTitle => 'Inoltra a…';
@override
String get forwardSearchHint => 'Cerca contatto o gruppo';
@override
String get forwardEmpty => 'Nessun risultato';
@override
String forwardDone(String name) {
return 'Inoltrato a $name';
}
@override
String forwardFailed(String error) {
return 'Inoltro non riuscito: $error';
}
@override
String get commonCopy => 'Copia';
@@ -247,6 +320,16 @@ class AppLocalizationsIt extends AppLocalizations {
return 'Il file è troppo grande (max $maxMb MB)';
}
@override
String get attachmentKeepsMetadataTitle => 'La foto includerà la posizione';
@override
String get attachmentKeepsMetadataBody =>
'Non riesco a rimuovere i metadati da questo formato (ad es. HEIC). Verrebbe inviata in originale, compresi il luogo dello scatto e i dati del telefono. È più sicuro inviarla dalla Galleria, dove i metadati vengono rimossi.';
@override
String get attachmentSendOriginal => 'Invia originale';
@override
String attachmentPickFailed(String error) {
return 'Selezione dell\'allegato non riuscita: $error';
@@ -292,6 +375,10 @@ class AppLocalizationsIt extends AppLocalizations {
@override
String get errorGroupNeedsMember => 'Il gruppo ha bisogno di almeno 1 membro';
@override
String get errorAttachmentUnavailable =>
'L\'allegato non è più su questo telefono';
@override
String errorGroupMaxMembers(int maxMembers) {
return 'Il gruppo può avere al massimo $maxMembers membri';
@@ -600,19 +687,100 @@ class AppLocalizationsIt extends AppLocalizations {
@override
String get chatListNewConversation => 'Nuova conversazione';
@override
String chatListPhotoWithCaptionPreview(String caption) {
return '📷 $caption';
}
@override
String chatListFilePreview(String fileName) {
return '📎 $fileName';
}
@override
String get chatListReadReceiptPreview => 'Letto';
@override
String get chatListDraft => 'Bozza';
@override
String get notesTitle => 'Note per me';
@override
String get notesSubtitle => 'Solo su questo telefono, cifrato';
@override
String get callVoice => 'Chiama';
@override
String get callVideo => 'Videochiamata';
@override
String get callStatusRinging => 'Squilla…';
@override
String get callIncomingVoice => 'Chiamata in arrivo';
@override
String get callIncomingVideo => 'Videochiamata in arrivo';
@override
String get callStatusConnecting => 'Connessione…';
@override
String get callEnded => 'Chiamata terminata';
@override
String get callEndedBusy => 'Occupato';
@override
String get callEndedRejected => 'Chiamata rifiutata';
@override
String get callEndedUnanswered => 'Nessuna risposta';
@override
String get callEndedFailed => 'Connessione non riuscita';
@override
String get callEncrypted => 'Crittografia end-to-end';
@override
String get callAccept => 'Accetta';
@override
String get callReject => 'Rifiuta';
@override
String get callMute => 'Disattiva microfono';
@override
String get callSpeaker => 'Altoparlante';
@override
String get callCamera => 'Disattiva fotocamera';
@override
String get callSwitchCamera => 'Cambia fotocamera';
@override
String get callHangUp => 'Riaggancia';
@override
String get callLogMissed => 'Chiamata persa';
@override
String get callLogUnanswered => 'Chiamata senza risposta';
@override
String get callLogRejected => 'Chiamata rifiutata';
@override
String get callLogBusy => 'Occupato';
@override
String get callLogFailed => 'Chiamata non riuscita';
@override
String callLogVoice(String duration) {
return 'Chiamata · $duration';
}
@override
String callLogVideo(String duration) {
return 'Videochiamata · $duration';
}
@override
String get chatListTimeNow => 'adesso';
@@ -951,14 +1119,14 @@ class AppLocalizationsIt extends AppLocalizations {
'I messaggi verranno scaricati solo all\'apertura dell\'app.';
@override
String get pushModeUp => 'UnifiedPush (consigliato)';
String get pushModeUp => 'UnifiedPush (senza Google)';
@override
String get pushModeUpDesc =>
'Senza Google — richiede l\'app ntfy (F-Droid/Play).';
@override
String get pushModeFcm => 'Google (FCM)';
String get pushModeFcm => 'Google (FCM, predefinito)';
@override
String get pushModeFcmDesc =>
@@ -1003,7 +1171,7 @@ class AppLocalizationsIt extends AppLocalizations {
String get pushNoDistributorFallback => 'nessun distributore';
@override
String get pushSubtitleFcm => 'Google (FCM) — veloce, opt-in';
String get pushSubtitleFcm => 'Google (FCM)';
@override
String get restoreErrorNameRequired => 'Inserisci il nome visualizzato.';
@@ -1311,4 +1479,255 @@ class AppLocalizationsIt extends AppLocalizations {
@override
String get photoPreviewDecodeFailed => 'Impossibile caricare la foto';
@override
String get chatActionInfo => 'Info messaggio';
@override
String get messageInfoSent => 'Inviato';
@override
String get messageInfoDelivered => 'Consegnato';
@override
String get messageInfoRead => 'Letto';
@override
String get messageInfoPending => 'non ancora';
@override
String get messageInfoReadReceiptsOff =>
'Vedi quando i tuoi messaggi vengono letti solo se condividi anche tu le conferme di lettura (Impostazioni).';
@override
String chatStatusReadAt(String time) {
return 'Letto $time';
}
@override
String chatStatusDeliveredAt(String time) {
return 'Consegnato $time';
}
@override
String get groupsAddMembers => 'Aggiungi membri';
@override
String get groupsAddMembersAction => 'Aggiungi';
@override
String groupsAddMembersFailed(String error) {
return 'Impossibile aggiungere: $error';
}
@override
String get groupsNoContactsToAdd =>
'Tutti i tuoi contatti sono già nel gruppo. Aggiungi prima una nuova persona ai contatti tramite codice QR.';
@override
String get navChats => 'Chat';
@override
String get chatListNewChat => 'Nuova chat';
@override
String get chatListSearchHint => 'Cerca in chat e messaggi';
@override
String get chatFilterAll => 'Tutte';
@override
String get chatFilterUnread => 'Non lette';
@override
String get chatFilterGroups => 'Gruppi';
@override
String get chatFilterArchive => 'Archivio';
@override
String get chatListNoResults => 'Nessun risultato.';
@override
String get chatListFilterEmpty => 'Ancora niente qui.';
@override
String get chatListPin => 'Fissa';
@override
String get chatListUnpin => 'Sblocca';
@override
String get chatOpenProfile => 'Vedi profilo';
@override
String get groupsProfile => 'Info gruppo';
@override
String get chatSearchHint => 'Cerca nella chat';
@override
String get chatSearchNoMatches => 'Nessuno';
@override
String chatSearchCounter(int current, int total) {
return '$current di $total';
}
@override
String get chatSearchOlder => 'Risultato precedente';
@override
String get chatSearchNewer => 'Risultato successivo';
@override
String chatUnreadDivider(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count nuovi messaggi',
one: '1 nuovo messaggio',
);
return '$_temp0';
}
@override
String get chatJumpToLatest => 'Vai ai più recenti';
@override
String get chatAttach => 'Allega';
@override
String get chatSend => 'Invia';
@override
String get chatRecordVoice => 'Registra messaggio vocale';
@override
String get profileSharedMedia => 'Media condivisi';
@override
String get profileMessage => 'Messaggio';
@override
String get profileSearch => 'Cerca';
@override
String get profileUnmute => 'Riattiva';
@override
String get profileDisappearing => 'Effimeri';
@override
String get profileCommonGroups => 'Gruppi in comune';
@override
String get profileSafetyNumber => 'Numero di sicurezza';
@override
String get profileSafetyNumberHint => 'Confronta di persona o con codice QR';
@override
String get profileVerifiedInPerson => 'Verificato di persona';
@override
String get profileVerifyNow => 'Verifica contatto';
@override
String get profileAdd => 'Aggiungi';
@override
String profileGroupSubtitle(String members, String date) {
return 'Gruppo · $members · creato il $date';
}
@override
String profileMembersOfMax(int count, int max) {
return '$count su $max';
}
@override
String get chatTyping => 'sta scrivendo…';
@override
String chatTypingNamed(String name) {
return '$name sta scrivendo…';
}
@override
String get chatTypingSeveral => 'Più persone stanno scrivendo…';
@override
String get settingsTypingTitle => 'Indicatore di scrittura';
@override
String get settingsTypingSubtitle =>
'Reciproco — se non lo condividi, non lo vedi (disattivato di default)';
@override
String get pollAttach => 'Sondaggio';
@override
String get pollCreateTitle => 'Nuovo sondaggio';
@override
String get pollQuestion => 'Domanda';
@override
String pollOptionHint(int number) {
return 'Opzione $number';
}
@override
String get pollAddOption => 'Aggiungi opzione';
@override
String get pollRemoveOption => 'Rimuovi opzione';
@override
String get pollAllowMultiple => 'Consenti più risposte';
@override
String get pollSingle => 'Sondaggio';
@override
String get pollMulti => 'Sondaggio, scelta multipla';
@override
String pollVoters(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count voti',
one: '1 voto',
zero: 'ancora nessun voto',
);
return '$_temp0';
}
@override
String pollFallback(String question) {
return 'Sondaggio: $question';
}
@override
String get pollFallbackUpdate => 'Aggiorna Šepot per votare.';
@override
String get profilePhotoEdit => 'Cambia foto profilo';
@override
String get profilePhotoPick => 'Scegli foto';
@override
String get profilePhotoRemove => 'Rimuovi foto';
@override
String get profilePhotoHint =>
'La vedranno solo le persone con cui chatti — cifrata come i messaggi. Posizione e metadati non vengono inviati.';
@override
String profilePhotoFailed(String error) {
return 'Impossibile impostare la foto: $error';
}
}
+439 -19
View File
@@ -75,17 +75,68 @@ class AppLocalizationsRu extends AppLocalizations {
String get groupsLeftBanner =>
'Вы больше не в группе. История сохранится, но новые сообщения приходить не будут.';
@override
String groupsMembersWithCount(int count) {
return 'Участники ($count)';
}
@override
String get groupsYou => 'Вы';
@override
String get groupsFounder => 'Создатель';
@override
String get groupsAdmin => 'Администратор';
@override
String get groupsMakeAdmin => 'Сделать администратором';
@override
String get groupsDismissAdmin => 'Снять роль администратора';
@override
String get groupsRemoveMember => 'Удалить из группы';
@override
String groupsRemoveMemberConfirmTitle(String name) {
return 'Удалить $name из группы?';
}
@override
String get groupsRemoveMemberConfirmBody =>
'Новые сообщения группы перестанут приходить. Прежняя история сохранится.';
@override
String get groupsRemoveAction => 'Удалить';
@override
String get groupsViewContact => 'Открыть контакт';
@override
String get groupsAdminOnlyHint =>
'Название, участников и администраторов группы меняют только администраторы.';
@override
String get groupsAdminOnlyCompatHint =>
'Переименовать группу и менять администраторов могут только администраторы. Добавлять людей пока может любой, потому что у кого-то в группе старая версия Šepot.';
@override
String groupsAdminActionFailed(String error) {
return 'Не удалось внести изменение: $error';
}
@override
String get groupsResyncNotice =>
'Группа сверяется с администратором. Изменения состава могут появиться с задержкой.';
@override
String get groupsRejectedChangeNotice =>
'Кто-то без прав попытался изменить группу. Изменение не применено.';
@override
String get errorGroupNotAdmin =>
'Это может сделать только администратор группы.';
@override
String get errorGroupLastAdmin =>
'Вы единственный администратор. Сначала назначьте администратором кого-то ещё.';
@override
String get groupsNameHint => 'Название группы';
@@ -192,6 +243,28 @@ class AppLocalizationsRu extends AppLocalizations {
@override
String get chatActionReply => 'Ответить';
@override
String get chatActionForward => 'Переслать';
@override
String get forwardTitle => 'Переслать в…';
@override
String get forwardSearchHint => 'Найти контакт или группу';
@override
String get forwardEmpty => 'Ничего не найдено';
@override
String forwardDone(String name) {
return 'Переслано: $name';
}
@override
String forwardFailed(String error) {
return 'Не удалось переслать: $error';
}
@override
String get commonCopy => 'Копировать';
@@ -248,6 +321,16 @@ class AppLocalizationsRu extends AppLocalizations {
return 'Файл слишком большой (макс. $maxMb МБ)';
}
@override
String get attachmentKeepsMetadataTitle => 'Фото будет с геолокацией';
@override
String get attachmentKeepsMetadataBody =>
'Из этого формата фото (например, HEIC) я не могу удалить метаданные. Оно будет отправлено в оригинале, включая место съёмки и данные о телефоне. Безопаснее отправить его через Галерею — там метаданные удаляются.';
@override
String get attachmentSendOriginal => 'Отправить оригинал';
@override
String attachmentPickFailed(String error) {
return 'Не удалось выбрать вложение: $error';
@@ -292,6 +375,10 @@ class AppLocalizationsRu extends AppLocalizations {
@override
String get errorGroupNeedsMember => 'В группе должен быть хотя бы 1 участник';
@override
String get errorAttachmentUnavailable =>
'Вложения больше нет на этом телефоне';
@override
String errorGroupMaxMembers(int maxMembers) {
return 'Максимальное число участников группы — $maxMembers';
@@ -603,19 +690,100 @@ class AppLocalizationsRu extends AppLocalizations {
@override
String get chatListNewConversation => 'Новый чат';
@override
String chatListPhotoWithCaptionPreview(String caption) {
return '📷 $caption';
}
@override
String chatListFilePreview(String fileName) {
return '📎 $fileName';
}
@override
String get chatListReadReceiptPreview => 'Прочитано';
@override
String get chatListDraft => 'Черновик';
@override
String get notesTitle => 'Заметки для себя';
@override
String get notesSubtitle => 'Только на этом телефоне, в зашифрованном виде';
@override
String get callVoice => 'Позвонить';
@override
String get callVideo => 'Видеозвонок';
@override
String get callStatusRinging => 'Вызов…';
@override
String get callIncomingVoice => 'Входящий звонок';
@override
String get callIncomingVideo => 'Входящий видеозвонок';
@override
String get callStatusConnecting => 'Соединение…';
@override
String get callEnded => 'Звонок завершён';
@override
String get callEndedBusy => 'Занято';
@override
String get callEndedRejected => 'Звонок отклонён';
@override
String get callEndedUnanswered => 'Нет ответа';
@override
String get callEndedFailed => 'Не удалось соединиться';
@override
String get callEncrypted => 'Сквозное шифрование';
@override
String get callAccept => 'Принять';
@override
String get callReject => 'Отклонить';
@override
String get callMute => 'Выключить микрофон';
@override
String get callSpeaker => 'Динамик';
@override
String get callCamera => 'Выключить камеру';
@override
String get callSwitchCamera => 'Сменить камеру';
@override
String get callHangUp => 'Завершить';
@override
String get callLogMissed => 'Пропущенный звонок';
@override
String get callLogUnanswered => 'Звонок без ответа';
@override
String get callLogRejected => 'Отклонённый звонок';
@override
String get callLogBusy => 'Занято';
@override
String get callLogFailed => 'Звонок не удался';
@override
String callLogVoice(String duration) {
return 'Звонок · $duration';
}
@override
String callLogVideo(String duration) {
return 'Видеозвонок · $duration';
}
@override
String get chatListTimeNow => 'сейчас';
@@ -958,14 +1126,14 @@ class AppLocalizationsRu extends AppLocalizations {
'Сообщения загрузятся только после открытия приложения.';
@override
String get pushModeUp => 'UnifiedPush (рекомендуется)';
String get pushModeUp => 'UnifiedPush (без Google)';
@override
String get pushModeUpDesc =>
'Без сервисов Google — требуется приложение ntfy (F-Droid/Play).';
@override
String get pushModeFcm => 'Google (FCM)';
String get pushModeFcm => 'Google (FCM, по умолчанию)';
@override
String get pushModeFcmDesc =>
@@ -1010,8 +1178,7 @@ class AppLocalizationsRu extends AppLocalizations {
String get pushNoDistributorFallback => 'без дистрибьютора';
@override
String get pushSubtitleFcm =>
'Google (FCM) — быстро, только по вашему выбору';
String get pushSubtitleFcm => 'Google (FCM)';
@override
String get restoreErrorNameRequired => 'Введите отображаемое имя.';
@@ -1336,4 +1503,257 @@ class AppLocalizationsRu extends AppLocalizations {
@override
String get photoPreviewDecodeFailed => 'Не удалось загрузить фото';
@override
String get chatActionInfo => 'Сведения о сообщении';
@override
String get messageInfoSent => 'Отправлено';
@override
String get messageInfoDelivered => 'Доставлено';
@override
String get messageInfoRead => 'Прочитано';
@override
String get messageInfoPending => 'ещё нет';
@override
String get messageInfoReadReceiptsOff =>
'Время прочтения видно, только если вы сами делитесь отчётами о прочтении (Настройки).';
@override
String chatStatusReadAt(String time) {
return 'Прочитано $time';
}
@override
String chatStatusDeliveredAt(String time) {
return 'Доставлено $time';
}
@override
String get groupsAddMembers => 'Добавить участников';
@override
String get groupsAddMembersAction => 'Добавить';
@override
String groupsAddMembersFailed(String error) {
return 'Не удалось добавить: $error';
}
@override
String get groupsNoContactsToAdd =>
'Все ваши контакты уже в группе. Сначала добавьте нового человека в контакты по QR-коду.';
@override
String get navChats => 'Чаты';
@override
String get chatListNewChat => 'Новый чат';
@override
String get chatListSearchHint => 'Поиск по чатам и сообщениям';
@override
String get chatFilterAll => 'Все';
@override
String get chatFilterUnread => 'Непрочитанные';
@override
String get chatFilterGroups => 'Группы';
@override
String get chatFilterArchive => 'Архив';
@override
String get chatListNoResults => 'Ничего не найдено.';
@override
String get chatListFilterEmpty => 'Здесь пока ничего нет.';
@override
String get chatListPin => 'Закрепить';
@override
String get chatListUnpin => 'Открепить';
@override
String get chatOpenProfile => 'Открыть профиль';
@override
String get groupsProfile => 'Информация о группе';
@override
String get chatSearchHint => 'Поиск в чате';
@override
String get chatSearchNoMatches => 'Нет';
@override
String chatSearchCounter(int current, int total) {
return '$current из $total';
}
@override
String get chatSearchOlder => 'Предыдущее совпадение';
@override
String get chatSearchNewer => 'Следующее совпадение';
@override
String chatUnreadDivider(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count новых сообщений',
few: '$count новых сообщения',
one: '$count новое сообщение',
);
return '$_temp0';
}
@override
String get chatJumpToLatest => 'К последним сообщениям';
@override
String get chatAttach => 'Прикрепить';
@override
String get chatSend => 'Отправить';
@override
String get chatRecordVoice => 'Записать голосовое';
@override
String get profileSharedMedia => 'Общие медиа';
@override
String get profileMessage => 'Написать';
@override
String get profileSearch => 'Поиск';
@override
String get profileUnmute => 'Включить звук';
@override
String get profileDisappearing => 'Исчезание';
@override
String get profileCommonGroups => 'Общие группы';
@override
String get profileSafetyNumber => 'Код безопасности';
@override
String get profileSafetyNumberHint => 'Сравните лично или по QR-коду';
@override
String get profileVerifiedInPerson => 'Проверено лично';
@override
String get profileVerifyNow => 'Проверить контакт';
@override
String get profileAdd => 'Добавить';
@override
String profileGroupSubtitle(String members, String date) {
return 'Группа · $members · создана $date';
}
@override
String profileMembersOfMax(int count, int max) {
return '$count из $max';
}
@override
String get chatTyping => 'печатает…';
@override
String chatTypingNamed(String name) {
return '$name печатает…';
}
@override
String get chatTypingSeveral => 'Несколько человек печатают…';
@override
String get settingsTypingTitle => 'Индикатор набора';
@override
String get settingsTypingSubtitle =>
'Взаимно — не делитесь, не видите (по умолчанию выкл.)';
@override
String get pollAttach => 'Опрос';
@override
String get pollCreateTitle => 'Новый опрос';
@override
String get pollQuestion => 'Вопрос';
@override
String pollOptionHint(int number) {
return 'Вариант $number';
}
@override
String get pollAddOption => 'Добавить вариант';
@override
String get pollRemoveOption => 'Удалить вариант';
@override
String get pollAllowMultiple => 'Разрешить несколько ответов';
@override
String get pollSingle => 'Опрос';
@override
String get pollMulti => 'Опрос, несколько ответов';
@override
String pollVoters(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count голосов',
few: '$count голоса',
one: '$count голос',
zero: 'пока нет голосов',
);
return '$_temp0';
}
@override
String pollFallback(String question) {
return 'Опрос: $question';
}
@override
String get pollFallbackUpdate => 'Обновите Šepot, чтобы голосовать.';
@override
String get profilePhotoEdit => 'Изменить фото профиля';
@override
String get profilePhotoPick => 'Выбрать фото';
@override
String get profilePhotoRemove => 'Удалить фото';
@override
String get profilePhotoHint =>
'Фото увидят только ваши собеседники — зашифровано, как и сообщения. Геоданные и метаданные не отправляются.';
@override
String profilePhotoFailed(String error) {
return 'Не удалось установить фото: $error';
}
}