mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-11-03 16:10:00 +00:00
Merge remote-tracking branch 'origin/develop' into feature/account-provider-selection
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="error_no_compatible_app_found">"لم يُعثر على تطبيق ليتعامل مع هذا الحدث."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="common_date_date_at_time">"%1$s في %2$s"</string>
|
||||
<string name="common_date_this_month">"هذا الشهر"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="emoji_picker_category_activity">"أنشطة"</string>
|
||||
<string name="emoji_picker_category_flags">"أعلام"</string>
|
||||
<string name="emoji_picker_category_foods">"أكل وشرب"</string>
|
||||
<string name="emoji_picker_category_nature">"حيوانات وطبيعة"</string>
|
||||
<string name="emoji_picker_category_objects">"أشياء"</string>
|
||||
<string name="emoji_picker_category_people">"الابتسامات والأشخاص"</string>
|
||||
<string name="emoji_picker_category_places">"سفر وأماكن"</string>
|
||||
<string name="emoji_picker_category_recent">"الرموز التعبيرية الأخيرة"</string>
|
||||
<string name="emoji_picker_category_symbols">"رموز"</string>
|
||||
<string name="emoji_picker_search_placeholder">"البحث عن رموز تعبيرية"</string>
|
||||
</resources>
|
||||
@@ -7,5 +7,7 @@
|
||||
<string name="emoji_picker_category_objects">"Objetos"</string>
|
||||
<string name="emoji_picker_category_people">"Emojis y personas"</string>
|
||||
<string name="emoji_picker_category_places">"Viajes y lugares"</string>
|
||||
<string name="emoji_picker_category_recent">"Emojis recientes"</string>
|
||||
<string name="emoji_picker_category_symbols">"Símbolos"</string>
|
||||
<string name="emoji_picker_search_placeholder">"Buscar emojis"</string>
|
||||
</resources>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<string name="emoji_picker_category_flags">"Flagi"</string>
|
||||
<string name="emoji_picker_category_foods">"Jedzenie i napoje"</string>
|
||||
<string name="emoji_picker_category_nature">"Zwierzęta i natura"</string>
|
||||
<string name="emoji_picker_category_objects">"Obiekty"</string>
|
||||
<string name="emoji_picker_category_objects">"Przedmioty"</string>
|
||||
<string name="emoji_picker_category_people">"Buźki i osoby"</string>
|
||||
<string name="emoji_picker_category_places">"Podróż i miejsca"</string>
|
||||
<string name="emoji_picker_category_recent">"Ostatnie emoji"</string>
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="state_event_avatar_changed_too">"(الصورة غُيِّرت أيضاً)"</string>
|
||||
<string name="state_event_avatar_url_changed">"غيّرَ %1$s صورته الشخصية"</string>
|
||||
<string name="state_event_avatar_url_changed_by_you">"قمتَ بتغيير صورتك الشخصية"</string>
|
||||
<string name="state_event_demoted_to_member">"تم خفض رتبة %1$s إلى عضو"</string>
|
||||
<string name="state_event_demoted_to_moderator">"تم خفض رتبة %1$s إلى مشرف"</string>
|
||||
<string name="state_event_display_name_changed_from">"غيّر %1$s اسمه من %2$s إلى %3$s"</string>
|
||||
<string name="state_event_display_name_changed_from_by_you">"غيّرتَ اسمك من %1$s إلى %2$s"</string>
|
||||
<string name="state_event_display_name_removed">"أزال %1$s اسمه (كان %2$s سابقاً)"</string>
|
||||
<string name="state_event_display_name_removed_by_you">"قمتَ بحذف اسمك (كان %1$s سابقاً)"</string>
|
||||
<string name="state_event_display_name_set">"عيّن %1$s اسمه ليكون %2$s"</string>
|
||||
<string name="state_event_display_name_set_by_you">"عيّنتَ اسمك ليكون %1$s"</string>
|
||||
<string name="state_event_promoted_to_administrator">"تمت ترقية %1$s إلى مسؤول"</string>
|
||||
<string name="state_event_promoted_to_moderator">"تمت ترقية %1$s إلى مشرف"</string>
|
||||
<string name="state_event_room_avatar_changed">"غيّر %1$s صورة الغرفة"</string>
|
||||
<string name="state_event_room_avatar_changed_by_you">"قمتَ بتغيير صورة الغرفة"</string>
|
||||
<string name="state_event_room_avatar_removed">"أزال %1$s صورة الغرفة"</string>
|
||||
<string name="state_event_room_avatar_removed_by_you">"قمتَ بإزالة صورة الغرفة"</string>
|
||||
<string name="state_event_room_ban">"%1$s حظر %2$s"</string>
|
||||
<string name="state_event_room_ban_by_you">"قمتَ بحظر %1$s"</string>
|
||||
<string name="state_event_room_ban_by_you_with_reason">"حظرت %1$s: %2$s"</string>
|
||||
<string name="state_event_room_ban_with_reason">"قام %1$s بحظر %2$s: %3$s"</string>
|
||||
<string name="state_event_room_created">"%1$s أنشأ الغرفة"</string>
|
||||
<string name="state_event_room_created_by_you">"قمتَ بإنشاء الغرفة"</string>
|
||||
<string name="state_event_room_invite">"%1$s دعا %2$s"</string>
|
||||
<string name="state_event_room_invite_accepted">"قَبِل %1$s الدعوة"</string>
|
||||
<string name="state_event_room_invite_accepted_by_you">"قمتَ بقبول الدعوة"</string>
|
||||
<string name="state_event_room_invite_by_you">"قمتَ بدعوة %1$s"</string>
|
||||
<string name="state_event_room_invite_you">"قام %1$s بدعوتك"</string>
|
||||
<string name="state_event_room_join">"انضمَّ %1$s إلى الغرفة"</string>
|
||||
<string name="state_event_room_join_by_you">"اِنضممت إلى الغرفة"</string>
|
||||
<string name="state_event_room_knock">"طلب %1$s الانضمام"</string>
|
||||
<string name="state_event_room_knock_accepted">"سمح %1$s لـ %2$s بالانضمام"</string>
|
||||
<string name="state_event_room_knock_accepted_by_you">"قمتَ بالسماح لـ %1$s بالانضمام"</string>
|
||||
<string name="state_event_room_knock_by_you">"قمتَ بطلب الانضمام"</string>
|
||||
<string name="state_event_room_knock_denied">"رفض %1$s طلب %2$s بالانضمام"</string>
|
||||
<string name="state_event_room_knock_denied_by_you">"قمتَ برفض طلب %1$s للانضمام"</string>
|
||||
<string name="state_event_room_knock_denied_you">"رفض %1$s طلب انضمامك"</string>
|
||||
<string name="state_event_room_knock_retracted">"لم يعد %1$s مهتماً بالانضمام"</string>
|
||||
<string name="state_event_room_knock_retracted_by_you">"قمتَ بإلغاء طلب انضمامك"</string>
|
||||
<string name="state_event_room_leave">"غادر %1$s المجموعة"</string>
|
||||
<string name="state_event_room_leave_by_you">"قمتَ بمغادرة المجموعة"</string>
|
||||
<string name="state_event_room_name_changed">"غيّر %1$s اسم الغرفة إلى: %2$s"</string>
|
||||
<string name="state_event_room_name_changed_by_you">"قمتَ بتغيير اسم الغرفة إلى: %1$s"</string>
|
||||
<string name="state_event_room_name_removed">"حذف %1$s اسم الغرفة"</string>
|
||||
<string name="state_event_room_name_removed_by_you">"قمتَ بحذف اسم الغرفة"</string>
|
||||
<string name="state_event_room_none">"%1$s لم يُجرِ أي تغييرات"</string>
|
||||
<string name="state_event_room_none_by_you">"لم تُجرِ أي تغييرات"</string>
|
||||
<string name="state_event_room_pinned_events_changed">"غيّر %1$s الرسائل المثبّتة"</string>
|
||||
<string name="state_event_room_pinned_events_changed_by_you">"غيّرت الرسائل المثبّتة"</string>
|
||||
<string name="state_event_room_pinned_events_pinned">"ثبّت %1$s رسالة"</string>
|
||||
<string name="state_event_room_pinned_events_pinned_by_you">"قمت بتثبيت رسالة"</string>
|
||||
<string name="state_event_room_pinned_events_unpinned">"ألغى %1$s تثبيت رسالة"</string>
|
||||
<string name="state_event_room_pinned_events_unpinned_by_you">"قمت بإلغاء تثبيت رسالة"</string>
|
||||
<string name="state_event_room_reject">"رفض %1$s الدعوة"</string>
|
||||
<string name="state_event_room_reject_by_you">"قمتَ برفض الدعوة"</string>
|
||||
<string name="state_event_room_remove">"%1$s طرد %2$s"</string>
|
||||
<string name="state_event_room_remove_by_you">"قمتَ بطرد %1$s"</string>
|
||||
<string name="state_event_room_remove_by_you_with_reason">"أزلت %1$s: %2$s"</string>
|
||||
<string name="state_event_room_remove_with_reason">"قام %1$s بإزالة %2$s: %3$s"</string>
|
||||
<string name="state_event_room_third_party_invite">"أرسل %1$s دعوة إلى %2$s لينضم إلى الغرفة"</string>
|
||||
<string name="state_event_room_third_party_invite_by_you">"قمتَ بإرسال دعوة إلى %1$s لينضم إلى الغرفة"</string>
|
||||
<string name="state_event_room_third_party_revoked_invite">"تراجع %1$s عن دعوة %2$s للانضمام إلى الغرفة"</string>
|
||||
<string name="state_event_room_third_party_revoked_invite_by_you">"قمتَ بالتراجع عن دعوة %1$s للانضمام إلى الغرفة"</string>
|
||||
<string name="state_event_room_topic_changed">"غيّر %1$s الموضوع إلى: %2$s"</string>
|
||||
<string name="state_event_room_topic_changed_by_you">"قمتَ بتغيير الموضوع إلى: %1$s"</string>
|
||||
<string name="state_event_room_topic_removed">"أزال %1$s موضوع الغرفة"</string>
|
||||
<string name="state_event_room_topic_removed_by_you">"قمتَ بإزالة موضوع الغرفة"</string>
|
||||
<string name="state_event_room_unban">"%1$s فكّ الحظر عن %2$s"</string>
|
||||
<string name="state_event_room_unban_by_you">"قمتَ بفك الحظر عن %1$s"</string>
|
||||
<string name="state_event_room_unknown_membership_change">"أحدث %1$s تغييراً غير معلوم في عضويته"</string>
|
||||
</resources>
|
||||
@@ -19,6 +19,8 @@
|
||||
<string name="state_event_room_avatar_removed_by_you">"چهرک اتاق را برداشتید"</string>
|
||||
<string name="state_event_room_ban">"%2$s به دست %1$s مسدود کرد"</string>
|
||||
<string name="state_event_room_ban_by_you">"%1$s را مسدود کردید"</string>
|
||||
<string name="state_event_room_ban_by_you_with_reason">"شما %1$s: %2$s را محروم کردید"</string>
|
||||
<string name="state_event_room_ban_with_reason">"%1$s محروم شد %2$s: %3$s"</string>
|
||||
<string name="state_event_room_created">"%1$s اتاق را ایجاد کرد"</string>
|
||||
<string name="state_event_room_created_by_you">"اتاق را ساختید"</string>
|
||||
<string name="state_event_room_invite">"%1$s از %2$s دعوت کرد"</string>
|
||||
@@ -55,6 +57,8 @@
|
||||
<string name="state_event_room_reject_by_you">"دعوت را رد کردید"</string>
|
||||
<string name="state_event_room_remove">"%2$s به دست %1$s برداشته شد"</string>
|
||||
<string name="state_event_room_remove_by_you">"%1$s را برداشتید"</string>
|
||||
<string name="state_event_room_remove_by_you_with_reason">"شما %1$s: %2$s را حذف کردید"</string>
|
||||
<string name="state_event_room_remove_with_reason">"%1$s حذف شد %2$s: %3$s"</string>
|
||||
<string name="state_event_room_third_party_invite">"%1$s دعوتی برای پیوستن %2$s به اتاق فرستاد"</string>
|
||||
<string name="state_event_room_third_party_invite_by_you">"برای %1$s دعوت پیوستن به اتاق فرستادید"</string>
|
||||
<string name="state_event_room_third_party_revoked_invite">"%1$s دعوت پیوستن به اتاق %2$s را باطل کرد"</string>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_bottom_sheet_create_dm_confirmation_button_title">"إرسال دعوة"</string>
|
||||
<string name="screen_bottom_sheet_create_dm_message">"هل تريد بدء دردشة مع %1$s؟"</string>
|
||||
<string name="screen_bottom_sheet_create_dm_title">"إرسال دعوة؟"</string>
|
||||
<string name="screen_bottom_sheet_create_dm_unknown_user_content">"ليست لديك حاليًا أي دردشات مع هذا الشخص. أكّد دعوته قبل المتابعة."</string>
|
||||
<string name="screen_bottom_sheet_create_dm_unknown_user_title">"هل تريد بدء دردشة مع جهة الاتصال الجديدة هذه؟"</string>
|
||||
<string name="screen_invites_invited_you">"دعاك %1$s (%2$s)"</string>
|
||||
</resources>
|
||||
@@ -3,5 +3,7 @@
|
||||
<string name="screen_bottom_sheet_create_dm_confirmation_button_title">"Enviar invitación"</string>
|
||||
<string name="screen_bottom_sheet_create_dm_message">"¿Quieres iniciar un chat con %1$s?"</string>
|
||||
<string name="screen_bottom_sheet_create_dm_title">"¿Enviar invitación?"</string>
|
||||
<string name="screen_bottom_sheet_create_dm_unknown_user_content">"De momento no tienes ningún chat con esta persona. Confirma que quieres invitarla antes de continuar."</string>
|
||||
<string name="screen_bottom_sheet_create_dm_unknown_user_title">"¿Iniciar un chat con este nuevo contacto?"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) te invitó"</string>
|
||||
</resources>
|
||||
|
||||
@@ -3,5 +3,7 @@
|
||||
<string name="screen_bottom_sheet_create_dm_confirmation_button_title">"فرستادن دعوت"</string>
|
||||
<string name="screen_bottom_sheet_create_dm_message">"میخواهید گپی را با %1$s بیاغازید؟"</string>
|
||||
<string name="screen_bottom_sheet_create_dm_title">"فرستادن دعوت؟"</string>
|
||||
<string name="screen_bottom_sheet_create_dm_unknown_user_content">"شما در حال حاضر هیچ گفتوگویی با این شخص ندارید. قبل از ادامه، دعوت از او را تأیید کنید."</string>
|
||||
<string name="screen_bottom_sheet_create_dm_unknown_user_title">"با این مخاطب جدید گفتوگو را شروع کنید؟"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) دعوتتان کرد"</string>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_media_browser_delete_confirmation_subtitle">"ستتم إزالة هذا الملف من الغرفة ولن يتمكن الأعضاء من الوصول إليه."</string>
|
||||
<string name="screen_media_browser_delete_confirmation_title">"إزالة الملف؟"</string>
|
||||
<string name="screen_media_browser_download_error_message">"تحقّق من اتصالك بالإنترنت وحاول مرة أخرى."</string>
|
||||
<string name="screen_media_browser_files_empty_state_subtitle">"ستظهر هنا المستندات والملفات الصوتية والرسائل الصوتية التي يتم رفعها إلى هذه الغرفة."</string>
|
||||
<string name="screen_media_browser_files_empty_state_title">"لم يتم رفع أي ملفات بعد"</string>
|
||||
<string name="screen_media_browser_list_loading_files">"جارٍ تحميل الملفات…"</string>
|
||||
<string name="screen_media_browser_list_loading_media">"جارٍ تحميل الوسائط…"</string>
|
||||
<string name="screen_media_browser_list_mode_files">"الملفات"</string>
|
||||
<string name="screen_media_browser_list_mode_media">"الوسائط"</string>
|
||||
<string name="screen_media_browser_media_empty_state_subtitle">"ستظهر هنا الصور ومقاطع الفيديو التي يتم رفعها إلى هذه الغرفة."</string>
|
||||
<string name="screen_media_browser_media_empty_state_title">"لم يتم رفع أي وسائط بعد"</string>
|
||||
<string name="screen_media_browser_title">"الوسائط والملفات"</string>
|
||||
<string name="screen_media_details_file_format">"التنسيق"</string>
|
||||
<string name="screen_media_details_filename">"الاسم"</string>
|
||||
<string name="screen_media_details_no_more_files_to_show">"لا توجد ملفات أخرى لعرضها"</string>
|
||||
<string name="screen_media_details_no_more_media_to_show">"لا توجد وسائط أخرى لعرضها"</string>
|
||||
<string name="screen_media_details_title">"معلومات الملف"</string>
|
||||
<string name="screen_media_details_uploaded_by">"تم الرفع بواسطة"</string>
|
||||
<string name="screen_media_details_uploaded_on">"تم الرفع في"</string>
|
||||
</resources>
|
||||
@@ -6,16 +6,17 @@
|
||||
<string name="screen_media_browser_files_empty_state_subtitle">"Los documentos, archivos de audio y mensajes de voz subidos a esta sala se mostrarán aquí."</string>
|
||||
<string name="screen_media_browser_files_empty_state_title">"Aún no se ha subido ningún archivo"</string>
|
||||
<string name="screen_media_browser_list_loading_files">"Cargando archivos…"</string>
|
||||
<string name="screen_media_browser_list_loading_media">"Cargando medios…"</string>
|
||||
<string name="screen_media_browser_list_loading_media">"Cargando multimedia…"</string>
|
||||
<string name="screen_media_browser_list_mode_files">"Archivos"</string>
|
||||
<string name="screen_media_browser_list_mode_media">"Medios"</string>
|
||||
<string name="screen_media_browser_list_mode_media">"Multimedia"</string>
|
||||
<string name="screen_media_browser_media_empty_state_subtitle">"Las imágenes y vídeos subidos a esta sala se mostrarán aquí."</string>
|
||||
<string name="screen_media_browser_media_empty_state_title">"Aún no se ha subido ningún medio"</string>
|
||||
<string name="screen_media_browser_title">"Medios y archivos"</string>
|
||||
<string name="screen_media_browser_title">"Multimedia y archivos"</string>
|
||||
<string name="screen_media_details_file_format">"Formato de archivo"</string>
|
||||
<string name="screen_media_details_filename">"Nombre del archivo"</string>
|
||||
<string name="screen_media_details_no_more_files_to_show">"No hay más archivos que mostrar"</string>
|
||||
<string name="screen_media_details_no_more_media_to_show">"No hay más medios que mostrar"</string>
|
||||
<string name="screen_media_details_title">"Información del archivo"</string>
|
||||
<string name="screen_media_details_uploaded_by">"Subido por"</string>
|
||||
<string name="screen_media_details_uploaded_on">"Subido el"</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_media_browser_delete_confirmation_subtitle">"این فایل از اتاق حذف خواهد شد و اعضا به آن دسترسی نخواهند داشت."</string>
|
||||
<string name="screen_media_browser_delete_confirmation_title">"حذف پرونده؟"</string>
|
||||
<string name="screen_media_browser_download_error_message">"بررسی اتّصال اینترنتیتان و تلاش دوباره."</string>
|
||||
<string name="screen_media_browser_files_empty_state_subtitle">"سندها، پروندهها و پیامهای صوتی بار گذاشته در این اتاق اینجا نشان داده خواهند شد."</string>
|
||||
@@ -13,6 +14,9 @@
|
||||
<string name="screen_media_browser_title">"رسانهها و پروندهها"</string>
|
||||
<string name="screen_media_details_file_format">"قالب پرونده"</string>
|
||||
<string name="screen_media_details_filename">"نام پرونده"</string>
|
||||
<string name="screen_media_details_no_more_files_to_show">"فایل بیشتری برای نمایش وجود ندارد"</string>
|
||||
<string name="screen_media_details_no_more_media_to_show">"رسانه دیگری برای نمایش وجود ندارد"</string>
|
||||
<string name="screen_media_details_title">"اطلاعات فایل"</string>
|
||||
<string name="screen_media_details_uploaded_by">"بارگذاشته به دست"</string>
|
||||
<string name="screen_media_details_uploaded_on">"بارگذاشته در"</string>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"من أجل جعل التطبيق يستخدم الكاميرا عليك بمنح الإذن لذلك في إعدادات النظام."</string>
|
||||
<string name="dialog_permission_generic">"يرجى منح الإذن في إعدادات النظام."</string>
|
||||
<string name="dialog_permission_microphone">"من أجل جعل التطبيق يستخدم المايكروفون عليك بمنح الإذن لذلك في إعدادت النظام."</string>
|
||||
<string name="dialog_permission_notification">"من أجل جعل التطبيق يظهر الإشعارات عليك أن تمنح الإذن في إعدادات النظام."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"يتحقق من قدرة التطبيق على عرض الإشعارات."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"التحقق من الأذونات"</string>
|
||||
</resources>
|
||||
+5
@@ -10,4 +10,9 @@ package io.element.android.libraries.push.api.gateway
|
||||
|
||||
sealed class PushGatewayFailure : Exception() {
|
||||
class PusherRejected : PushGatewayFailure()
|
||||
|
||||
/**
|
||||
* The gateway refused the notification because too many were sent to it.
|
||||
*/
|
||||
class RateLimited : PushGatewayFailure()
|
||||
}
|
||||
|
||||
+28
-15
@@ -12,6 +12,7 @@ import dev.zacsweers.metro.ContributesBinding
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.push.api.gateway.PushGatewayFailure
|
||||
import retrofit2.HttpException
|
||||
|
||||
interface PushGatewayNotifyRequest {
|
||||
data class Params(
|
||||
@@ -33,26 +34,38 @@ class DefaultPushGatewayNotifyRequest(
|
||||
val pushGatewayApi = pushGatewayApiFactory.create(
|
||||
params.url.substringBefore(PushGatewayConfig.URI_PUSH_GATEWAY_PREFIX_PATH)
|
||||
)
|
||||
val response = pushGatewayApi.notify(
|
||||
PushGatewayNotifyBody(
|
||||
PushGatewayNotification(
|
||||
eventId = params.eventId.value,
|
||||
roomId = params.roomId.value,
|
||||
devices = listOf(
|
||||
PushGatewayDevice(
|
||||
params.appId,
|
||||
params.pushKey,
|
||||
PusherData(mapOf(
|
||||
"cs" to "A_FAKE_SECRET",
|
||||
))
|
||||
)
|
||||
),
|
||||
val response = try {
|
||||
pushGatewayApi.notify(
|
||||
PushGatewayNotifyBody(
|
||||
PushGatewayNotification(
|
||||
eventId = params.eventId.value,
|
||||
roomId = params.roomId.value,
|
||||
devices = listOf(
|
||||
PushGatewayDevice(
|
||||
params.appId,
|
||||
params.pushKey,
|
||||
PusherData(mapOf(
|
||||
"cs" to "A_FAKE_SECRET",
|
||||
))
|
||||
)
|
||||
),
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
} catch (httpException: HttpException) {
|
||||
if (httpException.code() in RATE_LIMITED_STATUS_CODES) {
|
||||
throw PushGatewayFailure.RateLimited()
|
||||
}
|
||||
throw httpException
|
||||
}
|
||||
|
||||
if (response.rejectedPushKeys.contains(params.pushKey)) {
|
||||
throw PushGatewayFailure.PusherRejected()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 429 is the standard answer, ntfy answers 507 when a device is over its message quota.
|
||||
*/
|
||||
private val RATE_LIMITED_STATUS_CODES = setOf(429, 507)
|
||||
|
||||
+7
@@ -62,6 +62,13 @@ class PushLoopbackTest(
|
||||
)
|
||||
job.cancel()
|
||||
return
|
||||
} catch (_: PushGatewayFailure.RateLimited) {
|
||||
delegate.updateState(
|
||||
description = stringProvider.getString(R.string.troubleshoot_notifications_test_push_loop_back_failure_rate_limit),
|
||||
status = NotificationTroubleshootTestState.Status.Failure()
|
||||
)
|
||||
job.cancel()
|
||||
return
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Failed to test push")
|
||||
delegate.updateState(
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="notification_channel_call">"إتصال"</string>
|
||||
<string name="notification_channel_listening_for_events">"الاستماع إلى الأحداث"</string>
|
||||
<string name="notification_channel_noisy">"إشعارات الصاخبة"</string>
|
||||
<string name="notification_channel_ringing_calls">"رنين المكالمات"</string>
|
||||
<string name="notification_channel_silent">"إشعارات صامتة"</string>
|
||||
<plurals name="notification_compat_summary_line_for_room">
|
||||
<item quantity="zero">"%1$s: %2$d رسائل"</item>
|
||||
<item quantity="one">"%1$s: %2$d رسالة"</item>
|
||||
<item quantity="two">"%1$s: %2$d رسالتان"</item>
|
||||
<item quantity="few">"%1$s: %2$d رسائل"</item>
|
||||
<item quantity="many">"%1$s: %2$d رسالة"</item>
|
||||
<item quantity="other">"%1$s: %2$d رسالة"</item>
|
||||
</plurals>
|
||||
<plurals name="notification_compat_summary_title">
|
||||
<item quantity="zero">"%d إشعارات"</item>
|
||||
<item quantity="one">"%d إشعار"</item>
|
||||
<item quantity="two">"%d إشعاران"</item>
|
||||
<item quantity="few">"%d إشعارات"</item>
|
||||
<item quantity="many">"%d إشعار"</item>
|
||||
<item quantity="other">"%d إشعار"</item>
|
||||
</plurals>
|
||||
<string name="notification_error_unified_push_unregistered_android">"تعذّر تسجيل موزّع إشعارات UnifiedPush، لذلك لن تتلقى إشعارات بعد الآن. يرجى التحقق من إعدادات إشعارات التطبيق وحالة موزّع الإشعارات الفورية."</string>
|
||||
<string name="notification_fallback_content">"أتتك رسائل جديدة."</string>
|
||||
<plurals name="notification_fallback_n_content">
|
||||
<item quantity="zero">"لديك %d رسائل جديدة."</item>
|
||||
<item quantity="one">"لديك %d رسالة جديدة."</item>
|
||||
<item quantity="two">"لديك %d رسالتان جديدتان."</item>
|
||||
<item quantity="few">"لديك %d رسائل جديدة."</item>
|
||||
<item quantity="many">"لديك %d رسالة جديدة."</item>
|
||||
<item quantity="other">"لديك %d رسالة جديدة."</item>
|
||||
</plurals>
|
||||
<string name="notification_incoming_audio_call">"📞 مكالمة واردة"</string>
|
||||
<string name="notification_incoming_call">"📹 مكالمة واردة"</string>
|
||||
<string name="notification_inline_reply_failed">"** فشل الإرسال - يرجى فتح الغرفة"</string>
|
||||
<string name="notification_invitation_action_join">"إنضمام"</string>
|
||||
<string name="notification_invitation_action_reject">"رفض"</string>
|
||||
<plurals name="notification_invitations">
|
||||
<item quantity="zero">"%d دعوة"</item>
|
||||
<item quantity="one">"%d دعوة"</item>
|
||||
<item quantity="two">"%d دعوات"</item>
|
||||
<item quantity="few">"%d دعوات"</item>
|
||||
<item quantity="many">"%d دعوات"</item>
|
||||
<item quantity="other">"%d دعوات"</item>
|
||||
</plurals>
|
||||
<string name="notification_invite_body">"دعاك للتحدث"</string>
|
||||
<string name="notification_invite_body_with_sender">"دعاك %1$s إلى الدردشة"</string>
|
||||
<string name="notification_knock_request_body">"طلبت الإنضمام"</string>
|
||||
<string name="notification_mentioned_you_body">"ذكرك: %1$s"</string>
|
||||
<string name="notification_new_messages">"رسائل جديدة"</string>
|
||||
<plurals name="notification_new_messages_for_room">
|
||||
<item quantity="zero">"%d رسالة جديدة"</item>
|
||||
<item quantity="one">"%d رسالة جديدة"</item>
|
||||
<item quantity="two">"%d من الرسائل الجديدة"</item>
|
||||
<item quantity="few">"%d من الرسائل الجديدة"</item>
|
||||
<item quantity="many">"%d من الرسائل الجديدة"</item>
|
||||
<item quantity="other">"%d من الرسائل الجديدة"</item>
|
||||
</plurals>
|
||||
<string name="notification_reaction_body">"تفاعلت بـ %1$s"</string>
|
||||
<string name="notification_room_action_mark_as_read">"وضع علامة كمقروء"</string>
|
||||
<string name="notification_room_action_quick_reply">"رد سريع "</string>
|
||||
<string name="notification_room_invite_body">"دعاك للانضمام للغرفة"</string>
|
||||
<string name="notification_room_invite_body_with_sender">"دعاك %1$s للانضمام إلى الغرفة"</string>
|
||||
<string name="notification_sender_me">"أنا"</string>
|
||||
<string name="notification_sender_mention_reply">"إشارة أو رد من %1$s"</string>
|
||||
<string name="notification_space_invite_body">"دعاك للانضمام إلى المساحة"</string>
|
||||
<string name="notification_space_invite_body_with_sender">"دعاك %1$s للانضمام إلى المساحة"</string>
|
||||
<string name="notification_test_push_notification_content">"إنك ترى الإشعارات! اضغط عليّ!"</string>
|
||||
<string name="notification_thread_in_room">"سلسلة في %1$s"</string>
|
||||
<string name="notification_ticker_text_dm">"%1$s:%2$s"</string>
|
||||
<string name="notification_ticker_text_group">"%1$s:%2$s:%3$s"</string>
|
||||
<plurals name="notification_unread_notified_messages">
|
||||
<item quantity="zero">"%d رسالة مُعلَمة لم تُقرأ"</item>
|
||||
<item quantity="one">"%d رسالة مُعلَمة لم تُقرأ"</item>
|
||||
<item quantity="two">"%d من الرسائل المُعلَمة لم تُقرأ"</item>
|
||||
<item quantity="few">"%d من الرسائل المُعلَمة لم تُقرأ"</item>
|
||||
<item quantity="many">"%d من الرسائل المُعلَمة لم تُقرأ"</item>
|
||||
<item quantity="other">"%d من الرسائل المُعلَمة لم تُقرأ"</item>
|
||||
</plurals>
|
||||
<string name="notification_unread_notified_messages_and_invitation">"%1$s و %2$s"</string>
|
||||
<string name="notification_unread_notified_messages_in_room">"%1$s في %2$s"</string>
|
||||
<string name="notification_unread_notified_messages_in_room_and_invitation">"%1$s في %2$s و %3$s"</string>
|
||||
<plurals name="notification_unread_notified_messages_in_room_rooms">
|
||||
<item quantity="zero">"%d غرفة"</item>
|
||||
<item quantity="one">"%d غرفة"</item>
|
||||
<item quantity="two">"%d من الغرف"</item>
|
||||
<item quantity="few">"%d من الغرف"</item>
|
||||
<item quantity="many">"%d من الغرف"</item>
|
||||
<item quantity="other">"%d من الغرف"</item>
|
||||
</plurals>
|
||||
<string name="push_distributor_background_sync_android">"المزامنة في الخلفية"</string>
|
||||
<string name="push_distributor_firebase_android">"خدمات Google"</string>
|
||||
<string name="push_no_valid_google_play_services_apk_android">"لم يتم العثور على خدمات Google صالحة. الإشعارات قد لا تعمل كما يجب."</string>
|
||||
<string name="troubleshoot_notifications_test_blocked_users_description">"التحقق من المستخدمين المحظورين"</string>
|
||||
<string name="troubleshoot_notifications_test_blocked_users_quick_fix">"عرض المستخدمين المحظورين"</string>
|
||||
<string name="troubleshoot_notifications_test_blocked_users_result_none">"لا يوجد مستخدمون محظورون."</string>
|
||||
<plurals name="troubleshoot_notifications_test_blocked_users_result_some">
|
||||
<item quantity="zero">"لقد حظرت %1$d مستخدمين. لن تتلقى إشعارات لهؤلاء المستخدمين."</item>
|
||||
<item quantity="one">"لقد حظرت %1$d مستخدم. لن تتلقى إشعارات لهذا المستخدم."</item>
|
||||
<item quantity="two">"لقد حظرت %1$d مستخدمين. لن تتلقى إشعارات لهذين المستخدمين."</item>
|
||||
<item quantity="few">"لقد حظرت %1$d مستخدمين. لن تتلقى إشعارات لهؤلاء المستخدمين."</item>
|
||||
<item quantity="many">"لقد حظرت %1$d مستخدمًا. لن تتلقى إشعارات لهؤلاء المستخدمين."</item>
|
||||
<item quantity="other">"لقد حظرت %1$d مستخدم. لن تتلقى إشعارات لهؤلاء المستخدمين."</item>
|
||||
</plurals>
|
||||
<string name="troubleshoot_notifications_test_blocked_users_title">"المستخدمون المحظورون"</string>
|
||||
<string name="troubleshoot_notifications_test_current_push_provider_description">"يحصل على اسم الموفّر الحالي."</string>
|
||||
<string name="troubleshoot_notifications_test_current_push_provider_failure">"لم يتم تحديد أي موفّر إشعارات فورية."</string>
|
||||
<string name="troubleshoot_notifications_test_current_push_provider_failure_distributor_not_found">"موفّر الإشعارات الفورية الحالي: %1$s والموزّع الحالي: %2$s. لكن لم يتم العثور على الموزّع %3$s. ربما تم إلغاء تثبيت التطبيق؟"</string>
|
||||
<string name="troubleshoot_notifications_test_current_push_provider_failure_no_distributor">"موفّر الإشعارات الفورية الحالي: %1$s، لكن لم يتم إعداد أي موزّعين."</string>
|
||||
<string name="troubleshoot_notifications_test_current_push_provider_success">"موفّر الإشعارات الفورية الحالي: %1$s."</string>
|
||||
<string name="troubleshoot_notifications_test_current_push_provider_success_with_distributor">"موفّر الإشعارات الفورية الحالي: %1$s (%2$s)"</string>
|
||||
<string name="troubleshoot_notifications_test_current_push_provider_title">"موفّر الإشعارات الفورية الحالي"</string>
|
||||
<string name="troubleshoot_notifications_test_detect_push_provider_description">"يتحقق من أن التطبيق يدعم موفّر إشعارات فورية واحدًا على الأقل."</string>
|
||||
<string name="troubleshoot_notifications_test_detect_push_provider_failure">"لم يتم العثور على دعم لأي موفّر إشعارات فورية."</string>
|
||||
<plurals name="troubleshoot_notifications_test_detect_push_provider_success">
|
||||
<item quantity="zero">"تم العثور على %1$d من موفّري الإشعارات الفورية: %2$s"</item>
|
||||
<item quantity="one">"تم العثور على %1$d موفّر إشعارات فورية: %2$s"</item>
|
||||
<item quantity="two">"تم العثور على %1$d من موفّري الإشعارات الفورية: %2$s"</item>
|
||||
<item quantity="few">"تم العثور على %1$d من موفّري الإشعارات الفورية: %2$s"</item>
|
||||
<item quantity="many">"تم العثور على %1$d من موفّري الإشعارات الفورية: %2$s"</item>
|
||||
<item quantity="other">"تم العثور على %1$d من موفّري الإشعارات الفورية: %2$s"</item>
|
||||
</plurals>
|
||||
<string name="troubleshoot_notifications_test_detect_push_provider_success_2">"تم إنشاء التطبيق بدعم لـ: %1$s"</string>
|
||||
<string name="troubleshoot_notifications_test_detect_push_provider_title">"دعم موفّر الإشعارات الفورية"</string>
|
||||
<string name="troubleshoot_notifications_test_display_notification_description">"يتحقق من قدرة التطبيق على عرض إشعار."</string>
|
||||
<string name="troubleshoot_notifications_test_display_notification_failure">"لم يتم النقر على الإشعار."</string>
|
||||
<string name="troubleshoot_notifications_test_display_notification_permission_failure">"تعذّر عرض الإشعار."</string>
|
||||
<string name="troubleshoot_notifications_test_display_notification_success">"تم النقر على الإشعار!"</string>
|
||||
<string name="troubleshoot_notifications_test_display_notification_title">"عرض إشعار"</string>
|
||||
<string name="troubleshoot_notifications_test_display_notification_waiting">"يرجى النقر على الإشعار لمتابعة الاختبار."</string>
|
||||
<string name="troubleshoot_notifications_test_push_loop_back_description">"يتحقق من أن التطبيق يستقبل الإشعارات الفورية."</string>
|
||||
<string name="troubleshoot_notifications_test_push_loop_back_failure_1">"خطأ: رفض موفّر الإشعارات الفورية الطلب."</string>
|
||||
<string name="troubleshoot_notifications_test_push_loop_back_failure_2">"خطأ: %1$s."</string>
|
||||
<string name="troubleshoot_notifications_test_push_loop_back_failure_3">"خطأ، تعذّر اختبار الإشعارات الفورية."</string>
|
||||
<string name="troubleshoot_notifications_test_push_loop_back_failure_4">"خطأ، انتهت مهلة انتظار الإشعار الفوري."</string>
|
||||
<string name="troubleshoot_notifications_test_push_loop_back_failure_rate_limit">"خطأ: بوابة الإشعارات الفورية تفرض قيودًا على معدّل استخدام هذا الجهاز، لذا لن تكون الإشعارات موثوقة. يُرجى إعداد بوابة إشعارات فورية أخرى."</string>
|
||||
<string name="troubleshoot_notifications_test_push_loop_back_success">"استغرق اختبار إرسال واستقبال الإشعارات الفورية %1$d مللي ثانية."</string>
|
||||
<string name="troubleshoot_notifications_test_push_loop_back_title">"اختبار إرسال واستقبال الإشعارات الفورية"</string>
|
||||
</resources>
|
||||
@@ -13,7 +13,17 @@
|
||||
<item quantity="one">"%d notificación"</item>
|
||||
<item quantity="other">"%d notificaciones"</item>
|
||||
</plurals>
|
||||
<string name="notification_error_unified_push_unregistered_android">"No se pudo registrar el distribuidor de notificaciones de UnifiedPush, así que no recibirás más notificaciones. Comprueba los ajustes de notificaciones de la aplicación y el estado del distribuidor de push."</string>
|
||||
<string name="notification_fallback_content">"Tienes nuevos mensajes."</string>
|
||||
<plurals name="notification_fallback_n_content">
|
||||
<item quantity="one">"Tienes %d mensaje nuevo."</item>
|
||||
<item quantity="other">"Tienes %d mensajes nuevos."</item>
|
||||
</plurals>
|
||||
<plurals name="notification_gallery_body">
|
||||
<item quantity="one">"Se ha compartido %1$d archivo adjunto"</item>
|
||||
<item quantity="other">"Se han compartido %1$d archivos adjuntos"</item>
|
||||
</plurals>
|
||||
<string name="notification_incoming_audio_call">"📞 Llamada entrante"</string>
|
||||
<string name="notification_incoming_call">"📹 Llamada entrante"</string>
|
||||
<string name="notification_inline_reply_failed">"** No se ha podido enviar - por favor, abre la sala"</string>
|
||||
<string name="notification_invitation_action_join">"Unirse"</string>
|
||||
@@ -24,6 +34,7 @@
|
||||
</plurals>
|
||||
<string name="notification_invite_body">"Te invitó a chatear"</string>
|
||||
<string name="notification_invite_body_with_sender">"%1$s te invitó a chatear"</string>
|
||||
<string name="notification_live_location_started_body">"Comenzó a compartir su ubicación en tiempo real"</string>
|
||||
<string name="notification_mentioned_you_body">"Te mencionó: %1$s"</string>
|
||||
<string name="notification_new_messages">"Mensajes nuevos"</string>
|
||||
<plurals name="notification_new_messages_for_room">
|
||||
@@ -37,7 +48,10 @@
|
||||
<string name="notification_room_invite_body_with_sender">"%1$s te invitó a unirte a la sala"</string>
|
||||
<string name="notification_sender_me">"Yo"</string>
|
||||
<string name="notification_sender_mention_reply">"%1$s mencionó o respondió"</string>
|
||||
<string name="notification_space_invite_body">"Te invitó a unirte al espacio"</string>
|
||||
<string name="notification_space_invite_body_with_sender">"%1$s te invitó a unirte al espacio"</string>
|
||||
<string name="notification_test_push_notification_content">"¡Estás viendo la notificación! ¡Haz clic en mí!"</string>
|
||||
<string name="notification_thread_in_room">"Hilo en %1$s"</string>
|
||||
<string name="notification_ticker_text_dm">"%1$s: %2$s"</string>
|
||||
<string name="notification_ticker_text_group">"%1$s: %2$s %3$s"</string>
|
||||
<plurals name="notification_unread_notified_messages">
|
||||
@@ -54,10 +68,20 @@
|
||||
<string name="push_distributor_background_sync_android">"Sincronización en segundo plano"</string>
|
||||
<string name="push_distributor_firebase_android">"Servicios de Google"</string>
|
||||
<string name="push_no_valid_google_play_services_apk_android">"No se han encontrado Servicios de Google Play válidos. Es posible que las notificaciones no funcionen correctamente."</string>
|
||||
<string name="troubleshoot_notifications_test_blocked_users_description">"Comprobando usuarios bloqueados"</string>
|
||||
<string name="troubleshoot_notifications_test_blocked_users_quick_fix">"Ver usuarios bloqueados"</string>
|
||||
<string name="troubleshoot_notifications_test_blocked_users_result_none">"No hay usuarios bloqueados."</string>
|
||||
<plurals name="troubleshoot_notifications_test_blocked_users_result_some">
|
||||
<item quantity="one">"Has bloqueado %1$d usuario. No recibirás notificaciones de este usuario."</item>
|
||||
<item quantity="other">"Has bloqueado %1$d usuarios. No recibirás notificaciones de estos usuarios."</item>
|
||||
</plurals>
|
||||
<string name="troubleshoot_notifications_test_blocked_users_title">"Usuarios bloqueados"</string>
|
||||
<string name="troubleshoot_notifications_test_current_push_provider_description">"Obtener el nombre del proveedor actual."</string>
|
||||
<string name="troubleshoot_notifications_test_current_push_provider_failure">"No se ha seleccionado ningún proveedor de push."</string>
|
||||
<string name="troubleshoot_notifications_test_current_push_provider_failure_distributor_not_found">"Proveedor de push actual: %1$s y distribuidor actual: %2$s. Pero no se encuentra el distribuidor %3$s. ¿Quizás se ha desinstalado la aplicación?"</string>
|
||||
<string name="troubleshoot_notifications_test_current_push_provider_failure_no_distributor">"Proveedor de push actual: %1$s, pero no se ha configurado ningún distribuidor."</string>
|
||||
<string name="troubleshoot_notifications_test_current_push_provider_success">"Proveedor de push actual: %1$s."</string>
|
||||
<string name="troubleshoot_notifications_test_current_push_provider_success_with_distributor">"Proveedor de push actual: %1$s (%2$s)"</string>
|
||||
<string name="troubleshoot_notifications_test_current_push_provider_title">"Proveedor de push actual"</string>
|
||||
<string name="troubleshoot_notifications_test_detect_push_provider_description">"Asegurarse de que la aplicación tiene al menos un proveedor de push."</string>
|
||||
<string name="troubleshoot_notifications_test_detect_push_provider_failure">"No se encontró ningún proveedor de push."</string>
|
||||
|
||||
@@ -13,7 +13,17 @@
|
||||
<item quantity="one">"%dاعلان"</item>
|
||||
<item quantity="other">"%dاعلان"</item>
|
||||
</plurals>
|
||||
<string name="notification_error_unified_push_unregistered_android">"توزیعکننده اعلان UnifiedPush قابل ثبت نیست، بنابراین دیگر اعلانی دریافت نخواهید کرد. لطفاً تنظیمات اعلانهای برنامه و وضعیت توزیعکننده اعلان را بررسی کنید."</string>
|
||||
<string name="notification_fallback_content">"پیامهای جدیدی دارید."</string>
|
||||
<plurals name="notification_fallback_n_content">
|
||||
<item quantity="one">"شما یک پیام جدید %d دارید."</item>
|
||||
<item quantity="other">"شما پیامهای جدید %d دارید."</item>
|
||||
</plurals>
|
||||
<plurals name="notification_gallery_body">
|
||||
<item quantity="one">"پیوست %1$d مشترک"</item>
|
||||
<item quantity="other">"پیوستهای %1$d مشترک"</item>
|
||||
</plurals>
|
||||
<string name="notification_incoming_audio_call">"📞 تماس ورودی"</string>
|
||||
<string name="notification_incoming_call">"📹 تماس ورودی"</string>
|
||||
<string name="notification_inline_reply_failed">"**شکست در فرستادن - لطفاً اتاق را بگشایید"</string>
|
||||
<string name="notification_invitation_action_join">"پیوستن"</string>
|
||||
@@ -24,6 +34,7 @@
|
||||
</plurals>
|
||||
<string name="notification_invite_body">"به گپ دعوتتان کرد"</string>
|
||||
<string name="notification_invite_body_with_sender">"%1$s به گپ دعوتتان کرد"</string>
|
||||
<string name="notification_live_location_started_body">"شروع به اشتراک گذاری موقعیت مکانی زنده خود کردند"</string>
|
||||
<string name="notification_mentioned_you_body">"به شما اشاره کرد: %1$s"</string>
|
||||
<string name="notification_new_messages">"پیام جدید"</string>
|
||||
<plurals name="notification_new_messages_for_room">
|
||||
@@ -37,7 +48,10 @@
|
||||
<string name="notification_room_invite_body_with_sender">"%1$s دعوت کرد به اتاق بپیوندید"</string>
|
||||
<string name="notification_sender_me">"خودم"</string>
|
||||
<string name="notification_sender_mention_reply">"%1$s اشاره کرد یا پاسخ داد"</string>
|
||||
<string name="notification_space_invite_body">"از شما دعوت شد تا به این فضا بپیوندید"</string>
|
||||
<string name="notification_space_invite_body_with_sender">"%1$s از شما دعوت کرد تا به این فضا بپیوندید"</string>
|
||||
<string name="notification_test_push_notification_content">"دارید آگاهی را مشاهده میکنید! کلیک کنید!"</string>
|
||||
<string name="notification_thread_in_room">"رزوه در %1$s"</string>
|
||||
<string name="notification_ticker_text_dm">"%1$s: %2$s"</string>
|
||||
<string name="notification_ticker_text_group">"%1$s: %2$s %3$s"</string>
|
||||
<plurals name="notification_unread_notified_messages">
|
||||
@@ -54,13 +68,28 @@
|
||||
<string name="push_distributor_background_sync_android">"همگام سازی پسزمینه"</string>
|
||||
<string name="push_distributor_firebase_android">"خدمات گوگل"</string>
|
||||
<string name="push_no_valid_google_play_services_apk_android">"خدمت پلی گوگل معتبری پیدا نشد. ممکن است آگاهیها به درستی کار نکنند."</string>
|
||||
<string name="troubleshoot_notifications_test_blocked_users_description">"بررسی کاربران مسدود شده"</string>
|
||||
<string name="troubleshoot_notifications_test_blocked_users_quick_fix">"مشاهده کاربران مسدود شده"</string>
|
||||
<string name="troubleshoot_notifications_test_blocked_users_result_none">"هیچ کاربری مسدود نشده است."</string>
|
||||
<plurals name="troubleshoot_notifications_test_blocked_users_result_some">
|
||||
<item quantity="one">"شما کاربر %1$d را مسدود کردهاید. شما اعلانهایی برای این کاربر دریافت نخواهید کرد."</item>
|
||||
<item quantity="other">"شما کاربران %1$d را مسدود کردهاید. برای این کاربران اعلان دریافت نخواهید کرد."</item>
|
||||
</plurals>
|
||||
<string name="troubleshoot_notifications_test_blocked_users_title">"کاربران مسدود"</string>
|
||||
<string name="troubleshoot_notifications_test_current_push_provider_description">"گرفتن نام فراهم کنندهٔ کنونی."</string>
|
||||
<string name="troubleshoot_notifications_test_current_push_provider_failure">"هیچ فراهم کنندهٔ ارسالی گزیده نشده."</string>
|
||||
<string name="troubleshoot_notifications_test_current_push_provider_failure_distributor_not_found">"ارائه دهنده فعلی پوش: %1$s و توزیع کننده فعلی: %2$s. اما توزیع کننده %3$s پیدا نشد. شاید برنامه حذف نصب شده باشد؟"</string>
|
||||
<string name="troubleshoot_notifications_test_current_push_provider_failure_no_distributor">"ارائه دهنده فشار فعلی: %1$s، اما هیچ توزیع کننده ای پیکربندی نشده است."</string>
|
||||
<string name="troubleshoot_notifications_test_current_push_provider_success">"فراهم کنندهٔ ارسال کنونی: %1$s."</string>
|
||||
<string name="troubleshoot_notifications_test_current_push_provider_success_with_distributor">"ارائه دهنده خدمات فشار فعلی: %1$s (%2$s)"</string>
|
||||
<string name="troubleshoot_notifications_test_current_push_provider_title">"فراهم کنندهٔ ارسال کنونی"</string>
|
||||
<string name="troubleshoot_notifications_test_detect_push_provider_description">"ازمینان از پشتیبانی برنامه از لااقل یک فراهم کنندهٔ ارسال."</string>
|
||||
<string name="troubleshoot_notifications_test_detect_push_provider_failure">"پشتیبانی از هیچ فراهم کنندهٔ ارسالی پیدا نشد."</string>
|
||||
<plurals name="troubleshoot_notifications_test_detect_push_provider_success">
|
||||
<item quantity="one">"ارائه دهنده فشار %1$d یافت شد: %2$s"</item>
|
||||
<item quantity="other">"ارائه دهندگان فشار %1$d یافت شد: %2$s"</item>
|
||||
</plurals>
|
||||
<string name="troubleshoot_notifications_test_detect_push_provider_success_2">"این برنامه با پشتیبانی از موارد زیر ساخته شده است: %1$s"</string>
|
||||
<string name="troubleshoot_notifications_test_detect_push_provider_title">"پشتیبانی از فراهمکنندهٔ ارسال"</string>
|
||||
<string name="troubleshoot_notifications_test_display_notification_description">"بررسی توانایی برنامه در نمایش آگاهی."</string>
|
||||
<string name="troubleshoot_notifications_test_display_notification_failure">"روی آگاهی زده نشد."</string>
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
<item quantity="one">"Sinulla on %d uusi viesti."</item>
|
||||
<item quantity="other">"Sinulla on %d uutta viestiä."</item>
|
||||
</plurals>
|
||||
<plurals name="notification_gallery_body">
|
||||
<item quantity="one">"Jakoi %1$d liitteen"</item>
|
||||
<item quantity="other">"Jakoi %1$d liitettä"</item>
|
||||
</plurals>
|
||||
<string name="notification_incoming_audio_call">"📞 Saapuva puhelu"</string>
|
||||
<string name="notification_incoming_call">"📹 Saapuva puhelu"</string>
|
||||
<string name="notification_inline_reply_failed">"** Lähetys epäonnistui - avaa huone"</string>
|
||||
@@ -30,6 +34,7 @@
|
||||
</plurals>
|
||||
<string name="notification_invite_body">"Kutsui sinut keskustelemaan"</string>
|
||||
<string name="notification_invite_body_with_sender">"%1$s kutsui sinut keskustelemaan"</string>
|
||||
<string name="notification_live_location_started_body">"Aloitti reaaliaikaisen sijainnin jakamisen"</string>
|
||||
<string name="notification_mentioned_you_body">"Mainitsi sinut: %1$s"</string>
|
||||
<string name="notification_new_messages">"Uusia viestejä"</string>
|
||||
<plurals name="notification_new_messages_for_room">
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
<item quantity="one">"Vous avez %d nouveau message."</item>
|
||||
<item quantity="other">"Vous avez %d nouveaux messages."</item>
|
||||
</plurals>
|
||||
<plurals name="notification_gallery_body">
|
||||
<item quantity="one">"%1$d attachement partagé"</item>
|
||||
<item quantity="other">"%1$d attachements partagés"</item>
|
||||
</plurals>
|
||||
<string name="notification_incoming_audio_call">"📞 Appel entrant"</string>
|
||||
<string name="notification_incoming_call">"📹 Appel entrant"</string>
|
||||
<string name="notification_inline_reply_failed">"** Échec de l’envoi - veuillez ouvrir le salon"</string>
|
||||
@@ -30,6 +34,7 @@
|
||||
</plurals>
|
||||
<string name="notification_invite_body">"Vous a invité(e) à discuter"</string>
|
||||
<string name="notification_invite_body_with_sender">"%1$s vous a invité à discuter"</string>
|
||||
<string name="notification_live_location_started_body">"A commencé à partager sa position en direct"</string>
|
||||
<string name="notification_mentioned_you_body">"Mentionné(e) : %1$s"</string>
|
||||
<string name="notification_new_messages">"Nouveaux messages"</string>
|
||||
<plurals name="notification_new_messages_for_room">
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
</plurals>
|
||||
<string name="notification_invite_body">"已邀请你聊天"</string>
|
||||
<string name="notification_invite_body_with_sender">"%1$s 已邀请你聊天"</string>
|
||||
<string name="notification_knock_request_body">"已申请加入"</string>
|
||||
<string name="notification_live_location_started_body">"已开始共享其实时位置"</string>
|
||||
<string name="notification_mentioned_you_body">"提到了你:%1$s"</string>
|
||||
<string name="notification_new_messages">"新消息"</string>
|
||||
@@ -92,6 +93,7 @@
|
||||
<string name="troubleshoot_notifications_test_push_loop_back_failure_2">"错误:%1$s。"</string>
|
||||
<string name="troubleshoot_notifications_test_push_loop_back_failure_3">"错误,无法测试推送。"</string>
|
||||
<string name="troubleshoot_notifications_test_push_loop_back_failure_4">"错误,等待推送超时。"</string>
|
||||
<string name="troubleshoot_notifications_test_push_loop_back_failure_rate_limit">"错误:推送网关已对此设备限流,因此通知可能不稳定。请更换其它推送网关。"</string>
|
||||
<string name="troubleshoot_notifications_test_push_loop_back_success">"推送回路耗时 %1$d 毫秒。"</string>
|
||||
<string name="troubleshoot_notifications_test_push_loop_back_title">"测试推送回路"</string>
|
||||
</resources>
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
</plurals>
|
||||
<string name="notification_invite_body">"Invited you to chat"</string>
|
||||
<string name="notification_invite_body_with_sender">"%1$s invited you to chat"</string>
|
||||
<string name="notification_knock_request_body">"Requested to join"</string>
|
||||
<string name="notification_live_location_started_body">"Started sharing their live location"</string>
|
||||
<string name="notification_mentioned_you_body">"Mentioned you: %1$s"</string>
|
||||
<string name="notification_new_messages">"New Messages"</string>
|
||||
@@ -102,6 +103,7 @@
|
||||
<string name="troubleshoot_notifications_test_push_loop_back_failure_2">"Error: %1$s."</string>
|
||||
<string name="troubleshoot_notifications_test_push_loop_back_failure_3">"Error, cannot test push."</string>
|
||||
<string name="troubleshoot_notifications_test_push_loop_back_failure_4">"Error, timeout waiting for push."</string>
|
||||
<string name="troubleshoot_notifications_test_push_loop_back_failure_rate_limit">"Error: the push gateway is rate limiting this device, so notifications won\'t be reliable. Please set up a different push gateway."</string>
|
||||
<string name="troubleshoot_notifications_test_push_loop_back_success">"Push loop back took %1$d ms."</string>
|
||||
<string name="troubleshoot_notifications_test_push_loop_back_title">"Test Push loop back"</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (c) 2026 Element Creations Ltd.
|
||||
~
|
||||
~ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
~ Please see LICENSE files in the repository root for full details.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<!-- Body of the notification shown to users who can act on a knock (MSC4506 knock push rule). -->
|
||||
<string name="notification_knock_request_body">"Requested to join"</string>
|
||||
</resources>
|
||||
+55
@@ -12,8 +12,11 @@ import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.push.api.gateway.PushGatewayFailure
|
||||
import io.element.android.libraries.push.impl.test.DefaultTestPush
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import okhttp3.ResponseBody.Companion.toResponseBody
|
||||
import org.junit.Assert.assertThrows
|
||||
import org.junit.Test
|
||||
import retrofit2.HttpException
|
||||
import retrofit2.Response
|
||||
|
||||
class DefaultPushGatewayNotifyRequestTest {
|
||||
@Test
|
||||
@@ -64,6 +67,58 @@ class DefaultPushGatewayNotifyRequestTest {
|
||||
assertThat(factory.baseUrlParameter).isEqualTo("aUrl")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `notify with a rate limiting status should throw expected Exception`() {
|
||||
listOf(429, 507).forEach { statusCode ->
|
||||
val factory = FakePushGatewayApiFactory(
|
||||
notifyResponse = {
|
||||
throw HttpException(Response.error<Unit>(statusCode, "".toResponseBody()))
|
||||
}
|
||||
)
|
||||
val pushGatewayNotifyRequest = DefaultPushGatewayNotifyRequest(
|
||||
pushGatewayApiFactory = factory,
|
||||
)
|
||||
assertThrows(PushGatewayFailure.RateLimited::class.java) {
|
||||
runTest {
|
||||
pushGatewayNotifyRequest.execute(
|
||||
PushGatewayNotifyRequest.Params(
|
||||
url = "aUrl",
|
||||
appId = "anAppId",
|
||||
pushKey = "aPushKey",
|
||||
eventId = DefaultTestPush.TEST_EVENT_ID,
|
||||
roomId = DefaultTestPush.TEST_ROOM_ID,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `notify with another http error should not be mapped to a rate limit`() {
|
||||
val factory = FakePushGatewayApiFactory(
|
||||
notifyResponse = {
|
||||
throw HttpException(Response.error<Unit>(500, "".toResponseBody()))
|
||||
}
|
||||
)
|
||||
val pushGatewayNotifyRequest = DefaultPushGatewayNotifyRequest(
|
||||
pushGatewayApiFactory = factory,
|
||||
)
|
||||
assertThrows(HttpException::class.java) {
|
||||
runTest {
|
||||
pushGatewayNotifyRequest.execute(
|
||||
PushGatewayNotifyRequest.Params(
|
||||
url = "aUrl",
|
||||
appId = "anAppId",
|
||||
pushKey = "aPushKey",
|
||||
eventId = DefaultTestPush.TEST_EVENT_ID,
|
||||
roomId = DefaultTestPush.TEST_ROOM_ID,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `notify with rejected push key should throw expected Exception`() {
|
||||
val factory = FakePushGatewayApiFactory(
|
||||
|
||||
+19
@@ -59,6 +59,25 @@ class PushLoopbackTestTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test PushLoopbackTest RateLimited error`() = runTest {
|
||||
val sut = createPushLoopbackTest(
|
||||
pushService = FakePushService(
|
||||
testPushBlock = {
|
||||
throw PushGatewayFailure.RateLimited()
|
||||
}
|
||||
),
|
||||
stringProvider = FakeStringProvider(A_FAILURE_REASON),
|
||||
)
|
||||
sut.runAndTestState {
|
||||
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(true))
|
||||
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress)
|
||||
val lastItem = awaitItem()
|
||||
assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure())
|
||||
assertThat(lastItem.description).isEqualTo(A_FAILURE_REASON)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test PushLoopbackTest PusherRejected error with quick fix`() = runTest {
|
||||
val rotateTokenLambda = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_firebase_availability_description">"يتحقق من توفر Firebase."</string>
|
||||
<string name="troubleshoot_notifications_test_firebase_availability_failure">"Firebase غير متاح."</string>
|
||||
<string name="troubleshoot_notifications_test_firebase_availability_success">"Firebase متاح."</string>
|
||||
<string name="troubleshoot_notifications_test_firebase_availability_title">"التحقق من Firebase"</string>
|
||||
<string name="troubleshoot_notifications_test_firebase_token_description">"يتحقق من توفر رمز Firebase المميز."</string>
|
||||
<string name="troubleshoot_notifications_test_firebase_token_failure">"رمز Firebase المميز غير معروف."</string>
|
||||
<string name="troubleshoot_notifications_test_firebase_token_success">"رمز Firebase المميز: %1$s."</string>
|
||||
<string name="troubleshoot_notifications_test_firebase_token_title">"التحقق من رمز Firebase المميز"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_unified_push_description">"يتحقق من توفر موزّعي UnifiedPush."</string>
|
||||
<string name="troubleshoot_notifications_test_unified_push_failure">"لم يتم العثور على أي موزّع UnifiedPush."</string>
|
||||
<plurals name="troubleshoot_notifications_test_unified_push_success">
|
||||
<item quantity="zero">"تم العثور على %1$d من موزّعي UnifiedPush: %2$s."</item>
|
||||
<item quantity="one">"تم العثور على %1$d موزّع UnifiedPush: %2$s."</item>
|
||||
<item quantity="two">"تم العثور على %1$d من موزّعي UnifiedPush: %2$s."</item>
|
||||
<item quantity="few">"تم العثور على %1$d من موزّعي UnifiedPush: %2$s."</item>
|
||||
<item quantity="many">"تم العثور على %1$d من موزّعي UnifiedPush: %2$s."</item>
|
||||
<item quantity="other">"تم العثور على %1$d من موزّعي UnifiedPush: %2$s."</item>
|
||||
</plurals>
|
||||
<string name="troubleshoot_notifications_test_unified_push_title">"التحقق من UnifiedPush"</string>
|
||||
</resources>
|
||||
@@ -2,5 +2,9 @@
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_unified_push_description">"اطمینان از در دسترس بودن توزیعگرهای ارسال یکپارچه."</string>
|
||||
<string name="troubleshoot_notifications_test_unified_push_failure">"هیچ توزیعگر ارسال یکپارچهای پیدا نشد."</string>
|
||||
<plurals name="troubleshoot_notifications_test_unified_push_success">
|
||||
<item quantity="one">"توزیعکنندهی %1$d پیدا شد: %2$s."</item>
|
||||
<item quantity="other">"توزیعکنندگان %1$d موارد زیر را یافتند: %2$s."</item>
|
||||
</plurals>
|
||||
<string name="troubleshoot_notifications_test_unified_push_title">"بررسی ارسال یکپارچه"</string>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="rich_text_editor_a11y_add_attachment">"إضافة مرفق"</string>
|
||||
<string name="rich_text_editor_bullet_list">"تبديل قائمة النقاط"</string>
|
||||
<string name="rich_text_editor_close_formatting_options">"إلغاء وإغلاق خيارات تنسيق النص"</string>
|
||||
<string name="rich_text_editor_code_block">"تبديل كتلة التعليمات البرمجية"</string>
|
||||
<string name="rich_text_editor_composer_caption_placeholder">"أضف تعليقًا توضيحيًا"</string>
|
||||
<string name="rich_text_editor_composer_encrypted_placeholder">"رسالة مشفّرة…"</string>
|
||||
<string name="rich_text_editor_composer_placeholder">"راسل…"</string>
|
||||
<string name="rich_text_editor_composer_unencrypted_placeholder">"رسالة غير مشفّرة…"</string>
|
||||
<string name="rich_text_editor_create_link">"إنشاء رابط"</string>
|
||||
<string name="rich_text_editor_edit_link">"تعديل الرابط"</string>
|
||||
<string name="rich_text_editor_format_action">"%1$s، الحالة: %2$s"</string>
|
||||
<string name="rich_text_editor_format_bold">"تطبيق التنسيق الغامق"</string>
|
||||
<string name="rich_text_editor_format_italic">"تطبيق التنسيق المائل"</string>
|
||||
<string name="rich_text_editor_format_state_disabled">"معطّل"</string>
|
||||
<string name="rich_text_editor_format_state_off">"غير مفعّل"</string>
|
||||
<string name="rich_text_editor_format_state_on">"مفعّل"</string>
|
||||
<string name="rich_text_editor_format_strikethrough">"تطبيق التنسيق الذي يتوسّطه خط"</string>
|
||||
<string name="rich_text_editor_format_underline">"تطبيق التنسيق الذي تحته خط"</string>
|
||||
<string name="rich_text_editor_full_screen_toggle">"تبديل وضع ملء الشاشة"</string>
|
||||
<string name="rich_text_editor_indent">"ترك مسافة بادئة"</string>
|
||||
<string name="rich_text_editor_inline_code">"تطبيق تنسيق الكود المضمن"</string>
|
||||
<string name="rich_text_editor_link">"تعيين الرابط"</string>
|
||||
<string name="rich_text_editor_numbered_list">"تبديل القائمة المرقمة"</string>
|
||||
<string name="rich_text_editor_open_compose_options">"فتح خيارات كتابة الرسالة"</string>
|
||||
<string name="rich_text_editor_quote">"تبديل الاقتباس"</string>
|
||||
<string name="rich_text_editor_remove_link">"حذف الرابط"</string>
|
||||
<string name="rich_text_editor_unindent">"إزالة المسافة البادئة"</string>
|
||||
<string name="rich_text_editor_url_placeholder">"الرابط"</string>
|
||||
<string name="screen_media_upload_preview_caption_warning">"قد لا تكون التعليقات التوضيحية مرئية للأشخاص الذين يستخدمون تطبيقات أقدم."</string>
|
||||
<string name="screen_room_voice_message_tooltip">"اضغط مطولًا للتسجيل"</string>
|
||||
</resources>
|
||||
@@ -10,9 +10,12 @@
|
||||
<string name="rich_text_editor_composer_unencrypted_placeholder">"Mensaje no cifrado…"</string>
|
||||
<string name="rich_text_editor_create_link">"Crear un enlace"</string>
|
||||
<string name="rich_text_editor_edit_link">"Editar enlace"</string>
|
||||
<string name="rich_text_editor_format_action">"%1$s, estado: %2$s"</string>
|
||||
<string name="rich_text_editor_format_bold">"Aplicar formato negrita"</string>
|
||||
<string name="rich_text_editor_format_italic">"Aplicar formato cursiva"</string>
|
||||
<string name="rich_text_editor_format_state_disabled">"deshabilitado"</string>
|
||||
<string name="rich_text_editor_format_state_off">"desactivado"</string>
|
||||
<string name="rich_text_editor_format_state_on">"activado"</string>
|
||||
<string name="rich_text_editor_format_strikethrough">"Aplicar formato tachado"</string>
|
||||
<string name="rich_text_editor_format_underline">"Aplicar formato de subrayado"</string>
|
||||
<string name="rich_text_editor_full_screen_toggle">"Pantalla completa"</string>
|
||||
|
||||
@@ -28,5 +28,6 @@
|
||||
<string name="rich_text_editor_remove_link">"برداشتن پیوند"</string>
|
||||
<string name="rich_text_editor_unindent">"تونرفتگی"</string>
|
||||
<string name="rich_text_editor_url_placeholder">"پیوند"</string>
|
||||
<string name="screen_media_upload_preview_caption_warning">"ممکن است زیرنویسها برای افرادی که از برنامههای قدیمیتر استفاده میکنند قابل مشاهده نباشند."</string>
|
||||
<string name="screen_room_voice_message_tooltip">"نگه داشتن برای ضبط"</string>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_push_history_title">"سجل الإشعارات الفورية"</string>
|
||||
<string name="troubleshoot_notifications_screen_action">"تشغيل الاختبارات"</string>
|
||||
<string name="troubleshoot_notifications_screen_action_again">"تشغيل الاختبارات مرة أخرى"</string>
|
||||
<string name="troubleshoot_notifications_screen_failure">"فشلت بعض الاختبارات. يرجى التحقق من التفاصيل."</string>
|
||||
<string name="troubleshoot_notifications_screen_notice">"شغّل الاختبارات لاكتشاف أي مشكلة في إعداداتك قد تجعل الإشعارات لا تعمل كما هو متوقع."</string>
|
||||
<string name="troubleshoot_notifications_screen_quick_fix_action">"محاولة الإصلاح"</string>
|
||||
<string name="troubleshoot_notifications_screen_success">"اجتازت جميع الاختبارات بنجاح."</string>
|
||||
<string name="troubleshoot_notifications_screen_title">"استكشاف أخطاء الإشعارات وإصلاحها"</string>
|
||||
<string name="troubleshoot_notifications_screen_waiting">"تتطلب بعض الاختبارات انتباهك. يرجى التحقق من التفاصيل."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,611 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="a11y_add_avatar">"أضف صورة رمزية"</string>
|
||||
<string name="a11y_add_reaction">"أضف تفاعل: %1$s"</string>
|
||||
<string name="a11y_address">"العنوان"</string>
|
||||
<string name="a11y_avatar">"الصورة الرمزية"</string>
|
||||
<string name="a11y_clear_search_field">"مسح حقل البحث"</string>
|
||||
<string name="a11y_collapse_message_text_field">"تصغير حقل نص الرسالة"</string>
|
||||
<string name="a11y_create_poll_votes_allowed_decrease">"تقليل عدد الأصوات المسموح بها لكل شخص"</string>
|
||||
<string name="a11y_create_poll_votes_allowed_increase">"زيادة عدد الأصوات المسموح بها لكل شخص"</string>
|
||||
<string name="a11y_delete">"احذف"</string>
|
||||
<plurals name="a11y_digits_entered">
|
||||
<item quantity="zero">"تم إدخال %1$d أرقام"</item>
|
||||
<item quantity="one">"تم إدخال %1$d رقم"</item>
|
||||
<item quantity="two">"تم إدخال %1$d رقمين"</item>
|
||||
<item quantity="few">"تم إدخال %1$d أرقام"</item>
|
||||
<item quantity="many">"تم إدخال %1$d رقمًا"</item>
|
||||
<item quantity="other">"تم إدخال %1$d رقم"</item>
|
||||
</plurals>
|
||||
<string name="a11y_duration">"المدة: %1$s"</string>
|
||||
<string name="a11y_edit_avatar">"تعديل الصورة الرمزية"</string>
|
||||
<string name="a11y_edit_room_address_hint">"العنوان الكامل سيكون %1$s"</string>
|
||||
<string name="a11y_encryption_details">"تفاصيل التشفير"</string>
|
||||
<string name="a11y_expand_message_text_field">"تكبير حقل نص الرسالة"</string>
|
||||
<string name="a11y_hide_password">"أخفِ كلمة السر"</string>
|
||||
<string name="a11y_info">"معلومات"</string>
|
||||
<string name="a11y_join_call">"انضم للمكالمة"</string>
|
||||
<string name="a11y_jump_to_bottom">"الانتقال للأسفل"</string>
|
||||
<string name="a11y_jump_to_unread">"الانتقال إلى الرسائل غير المقروءة"</string>
|
||||
<string name="a11y_move_the_map_to_my_location">"انقل الخريطة إلى موقعي"</string>
|
||||
<string name="a11y_notifications_mentions_only">"الإشارات فقط"</string>
|
||||
<string name="a11y_notifications_muted">"مكتوم"</string>
|
||||
<string name="a11y_notifications_new_mentions">"إشارات جديدة"</string>
|
||||
<string name="a11y_notifications_new_messages">"رسائل جديدة"</string>
|
||||
<string name="a11y_notifications_ongoing_call">"مكالمة جارية"</string>
|
||||
<string name="a11y_other_user_avatar">"صورة رمزية لمستخدم آخر"</string>
|
||||
<string name="a11y_page_n">"الصفحة %1$d"</string>
|
||||
<string name="a11y_pause">"إيقاف مؤقت"</string>
|
||||
<string name="a11y_paused_voice_message">"الرسالة الصوتية، المدة: %1$s ، الموضع الحالي: %2$s"</string>
|
||||
<string name="a11y_photo_preview">"معاينة الصورة"</string>
|
||||
<string name="a11y_pin_field">"حقل الرمز السري (PIN) "</string>
|
||||
<string name="a11y_pinned_location">"موقع محدد"</string>
|
||||
<string name="a11y_play">"تشغيل"</string>
|
||||
<string name="a11y_playback_speed">"سرعة التشغيل"</string>
|
||||
<string name="a11y_poll">"استفتاء"</string>
|
||||
<string name="a11y_poll_end">"استفتاء منتهٍ"</string>
|
||||
<string name="a11y_position">"الموضع: %1$s"</string>
|
||||
<string name="a11y_qr_code">"رمز QR"</string>
|
||||
<string name="a11y_react_with">"تفاعل مع %1$s"</string>
|
||||
<string name="a11y_react_with_other_emojis">"تفاعل مع الرموز التعبيرية الأخرى"</string>
|
||||
<string name="a11y_read_receipts_multiple">"قرأ %1$s و%2$s الرسالة السابقة"</string>
|
||||
<plurals name="a11y_read_receipts_multiple_with_others">
|
||||
<item quantity="zero">"قرأ %1$s و%2$d آخرون الرسالة السابقة"</item>
|
||||
<item quantity="one">"قرأ %1$s و%2$d آخر الرسالة السابقة"</item>
|
||||
<item quantity="two">"قرأ %1$s و%2$d آخران الرسالة السابقة"</item>
|
||||
<item quantity="few">"قرأ %1$s و%2$d آخرون الرسالة السابقة"</item>
|
||||
<item quantity="many">"قرأ %1$s و%2$d آخر الرسالة السابقة"</item>
|
||||
<item quantity="other">"قرأ %1$s و%2$d آخر الرسالة السابقة"</item>
|
||||
</plurals>
|
||||
<string name="a11y_read_receipts_single">"قرأ %1$s الرسالة السابقة"</string>
|
||||
<string name="a11y_read_receipts_tap_to_show_all_android">"إظهار كل إيصالات القراءة"</string>
|
||||
<string name="a11y_remove_reaction">"أزِل التفاعل: %1$s"</string>
|
||||
<string name="a11y_remove_reaction_with">"أزِل التفاعل بـ %1$s"</string>
|
||||
<string name="a11y_room_avatar">"الصورة الرمزية للغرفة"</string>
|
||||
<string name="a11y_send_files">"إرسال ملفات"</string>
|
||||
<string name="a11y_sender_location">"موقع المرسل"</string>
|
||||
<string name="a11y_sent_by_sender_at_date">"أرسلها %1$s في %2$s"</string>
|
||||
<string name="a11y_session_verification_time_limited_action_required">"إجراء مقيد زمنياً، لديك دقيقة واحدة للتحقق "</string>
|
||||
<string name="a11y_settings_with_required_action">"الإعدادات، إجراء مطلوب"</string>
|
||||
<string name="a11y_show_password">"إظهار كلمة السر"</string>
|
||||
<string name="a11y_start_call">"بدء مكالمة"</string>
|
||||
<string name="a11y_start_video_call">"بدء مكالمة فيديو"</string>
|
||||
<string name="a11y_start_voice_call">"بدء مكالمة صوتية"</string>
|
||||
<string name="a11y_thread_in_room">"سلسلة في %1$s"</string>
|
||||
<string name="a11y_threads_in_room">"سلاسل في %1$s"</string>
|
||||
<string name="a11y_tombstoned_room">"غرفة مستبدلة"</string>
|
||||
<string name="a11y_user_avatar">"الصورة الرمزية للمستخدم"</string>
|
||||
<string name="a11y_user_menu">"قائمة المستخدم"</string>
|
||||
<string name="a11y_video_preview">"معاينة الفيديو"</string>
|
||||
<string name="a11y_view_avatar">"عرض الصورة الرمزية"</string>
|
||||
<string name="a11y_view_details">"عرض التفاصيل"</string>
|
||||
<string name="a11y_voice_message">"رسالة صوتية، المدة: %1$s"</string>
|
||||
<string name="a11y_voice_message_record">"تسجيل رسالة صوتية."</string>
|
||||
<string name="a11y_voice_message_stop_recording">"إيقاف التسجيل"</string>
|
||||
<string name="a11y_your_avatar">"الصورة الرمزية الخاصة بك"</string>
|
||||
<string name="action_accept">"قبول"</string>
|
||||
<string name="action_add_caption">"أضف وصف"</string>
|
||||
<string name="action_add_existing_rooms">"إضافة غرف موجودة"</string>
|
||||
<string name="action_add_to_timeline">"أضف إلى الجدول الزمني"</string>
|
||||
<string name="action_back">"رجوع"</string>
|
||||
<string name="action_call">"مكالمة"</string>
|
||||
<string name="action_cancel">"الغاء"</string>
|
||||
<string name="action_cancel_for_now">"ليس الآن"</string>
|
||||
<string name="action_choose_file">"اختيار ملف"</string>
|
||||
<string name="action_choose_photo">"اختيار صورة"</string>
|
||||
<string name="action_clear">"مسح"</string>
|
||||
<string name="action_close">"إغلاق"</string>
|
||||
<string name="action_complete_verification">"أتمم التحقق"</string>
|
||||
<string name="action_confirm">"تأكيد"</string>
|
||||
<string name="action_confirm_password">"تأكيد كلمة المرور"</string>
|
||||
<string name="action_continue">"المتابعة"</string>
|
||||
<string name="action_copy">"نسخ"</string>
|
||||
<string name="action_copy_caption">"نسخ التعليق التوضيحي"</string>
|
||||
<string name="action_copy_link">"نسخ الرابط"</string>
|
||||
<string name="action_copy_link_to_message">"نسخ رابط الرسالة"</string>
|
||||
<string name="action_copy_text">"انسخ النص"</string>
|
||||
<string name="action_create">"إنشاء"</string>
|
||||
<string name="action_create_room">"إنشاء غرفة"</string>
|
||||
<string name="action_create_space">"إنشاء مساحة"</string>
|
||||
<string name="action_deactivate">"تعطيل"</string>
|
||||
<string name="action_deactivate_account">"تعطيل الحساب"</string>
|
||||
<string name="action_decline">"رفض"</string>
|
||||
<string name="action_decline_and_block">"رفض وحظر"</string>
|
||||
<string name="action_delete">"حذف"</string>
|
||||
<string name="action_delete_account">"حذف الحساب"</string>
|
||||
<string name="action_delete_file">"حذف الملف"</string>
|
||||
<string name="action_delete_poll">"حذف الاستطلاع"</string>
|
||||
<string name="action_deselect_all">"إلغاء تحديد الكل"</string>
|
||||
<string name="action_disable">"تعطيل"</string>
|
||||
<string name="action_discard">"تجاهل"</string>
|
||||
<string name="action_dismiss">"إغلاق"</string>
|
||||
<string name="action_done">"تم"</string>
|
||||
<string name="action_download">"تنزيل"</string>
|
||||
<string name="action_edit">"تعديل"</string>
|
||||
<string name="action_edit_caption">"تعديل التعليق التوضيحي"</string>
|
||||
<string name="action_edit_poll">"تعديل الاستفتاء"</string>
|
||||
<string name="action_enable">"تمكين"</string>
|
||||
<string name="action_end_poll">"إنهاء الاستفتاء"</string>
|
||||
<string name="action_enter_pin">"إدخال رمز PIN"</string>
|
||||
<string name="action_explore_public_spaces">"استكشاف المساحات العامة"</string>
|
||||
<string name="action_finish">"إنهاء"</string>
|
||||
<string name="action_forgot_password">"أنسيت كلمة السر؟"</string>
|
||||
<string name="action_forward">"إعادة توجيه"</string>
|
||||
<string name="action_go_back">"ارجع"</string>
|
||||
<string name="action_go_to_roles_and_permissions">"الانتقال إلى الأدوار والصلاحيات"</string>
|
||||
<string name="action_go_to_settings">"اذهب إلى الإعدادات"</string>
|
||||
<string name="action_ignore">"تجاهل"</string>
|
||||
<string name="action_invite">"دعوة "</string>
|
||||
<string name="action_invite_friends">"دعوة أشخاص"</string>
|
||||
<string name="action_invite_friends_to_app">"قم بدعوة الأصدقاء إلى %1$s"</string>
|
||||
<string name="action_invite_people_to_app">"دعوة أشخاص إلى %1$s"</string>
|
||||
<string name="action_invites_list">"الدعوات"</string>
|
||||
<string name="action_join">"إنضمام"</string>
|
||||
<string name="action_learn_more">"تعلم المزيد"</string>
|
||||
<string name="action_leave">"مغادرة"</string>
|
||||
<string name="action_leave_conversation">"مغادرة المحادثة"</string>
|
||||
<string name="action_leave_room">"مغادرة الغرفة"</string>
|
||||
<string name="action_leave_space">"مغادرة المساحة"</string>
|
||||
<string name="action_load_more">"تحميل المزيد"</string>
|
||||
<string name="action_manage_account">"إدارة الحساب"</string>
|
||||
<string name="action_manage_account_and_devices">"إدارة الحساب والأجهزة"</string>
|
||||
<string name="action_manage_devices">"إدارة الأجهزة"</string>
|
||||
<string name="action_manage_rooms">"إدارة الغرف"</string>
|
||||
<string name="action_message">"إرسال رسالة"</string>
|
||||
<string name="action_minimize">"تصغير"</string>
|
||||
<string name="action_next">"التالي"</string>
|
||||
<string name="action_no">"لا"</string>
|
||||
<string name="action_not_now">"ليس الآن"</string>
|
||||
<string name="action_ok">"حسناً"</string>
|
||||
<string name="action_open_context_menu">"فتح قائمة السياق"</string>
|
||||
<string name="action_open_settings">"الإعدادات"</string>
|
||||
<string name="action_open_with">"فتح باستخدام"</string>
|
||||
<string name="action_pin">"تثبيت"</string>
|
||||
<string name="action_quick_reply">"رد سريع "</string>
|
||||
<string name="action_quote">"عبارة"</string>
|
||||
<string name="action_react">"تفاعَل"</string>
|
||||
<string name="action_reject">"رفض"</string>
|
||||
<string name="action_remove">"ازالة"</string>
|
||||
<string name="action_remove_caption">"إزالة التعليق التوضيحي"</string>
|
||||
<string name="action_remove_message">"إزالة الرسالة"</string>
|
||||
<string name="action_reply">"رد"</string>
|
||||
<string name="action_reply_in_thread">"ردّ في ثريد"</string>
|
||||
<string name="action_report">"إبلاغ"</string>
|
||||
<string name="action_report_bug">"الإبلاغ عن مشكلة"</string>
|
||||
<string name="action_report_content">"الابلاغ عن المحتوى"</string>
|
||||
<string name="action_report_dm">"الإبلاغ عن المحادثة"</string>
|
||||
<string name="action_report_room">"الإبلاغ عن الغرفة"</string>
|
||||
<string name="action_reset">"إعادة تعيين"</string>
|
||||
<string name="action_reset_identity">"إعادة تعيين الهوية"</string>
|
||||
<string name="action_retry">"اعادة المحاولة"</string>
|
||||
<string name="action_retry_decryption">"أعد محاولة فك التشفير"</string>
|
||||
<string name="action_save">"حفظ"</string>
|
||||
<string name="action_search">"بحث"</string>
|
||||
<string name="action_select_all">"تحديد الكل"</string>
|
||||
<string name="action_send">"ارسال"</string>
|
||||
<string name="action_send_edited_message">"إرسال الرسالة المعدّلة"</string>
|
||||
<string name="action_send_message">"أرسل رسالة"</string>
|
||||
<string name="action_send_voice_message">"إرسال رسالة صوتية"</string>
|
||||
<string name="action_share">"مشاركة"</string>
|
||||
<string name="action_share_link">"مشاركة رابط"</string>
|
||||
<string name="action_share_live_location">"مشاركة الموقع المباشر"</string>
|
||||
<string name="action_show">"إظهار"</string>
|
||||
<string name="action_sign_in_again">"تسجيل الدخول مرة أخرى"</string>
|
||||
<string name="action_signout">"إزالة هذا الجهاز"</string>
|
||||
<string name="action_signout_anyway">"إزالة هذا الجهاز على أي حال"</string>
|
||||
<string name="action_skip">"تخطي"</string>
|
||||
<string name="action_start">"ابدأ"</string>
|
||||
<string name="action_start_chat">"ابدأ المحادثة"</string>
|
||||
<string name="action_start_over">"البدء من جديد"</string>
|
||||
<string name="action_start_verification">"ابدأ التحقق"</string>
|
||||
<string name="action_static_map_load">"انقر لتحميل الخريطة"</string>
|
||||
<string name="action_stop">"إيقاف"</string>
|
||||
<string name="action_take_photo">"التقاط صورة"</string>
|
||||
<string name="action_tap_for_options">"اضغط لعرض الخيارات"</string>
|
||||
<string name="action_translate">"ترجمة"</string>
|
||||
<string name="action_try_again">"حاول مرة أخرى"</string>
|
||||
<string name="action_unpin">"إلغاء التثبيت"</string>
|
||||
<string name="action_video_call">"مكالمة فيديو"</string>
|
||||
<string name="action_view">"عرض"</string>
|
||||
<string name="action_view_in_timeline">"عرض في المخطط الزمني"</string>
|
||||
<string name="action_view_source">"عرض المصدر"</string>
|
||||
<string name="action_voice_call">"مكالمة صوتية"</string>
|
||||
<string name="action_yes">"نعم"</string>
|
||||
<string name="action_yes_try_again">"نعم، حاول مرة أخرى"</string>
|
||||
<string name="banner_migrate_to_native_sliding_sync_description">"يدعم خادمك الآن بروتوكولًا جديدًا أسرع. سجّل الخروج ثم سجّل الدخول مرة أخرى للترقية الآن. سيساعدك القيام بذلك الآن على تجنب تسجيل خروج قسري عند إزالة البروتوكول القديم لاحقًا."</string>
|
||||
<string name="banner_migrate_to_native_sliding_sync_title">"ترقية متاحة"</string>
|
||||
<string name="common_about">"حول التطبيق"</string>
|
||||
<string name="common_acceptable_use_policy">"سياسة الاستخدام المقبول"</string>
|
||||
<string name="common_add_account">"إضافة حساب"</string>
|
||||
<string name="common_add_another_account">"إضافة حساب آخر"</string>
|
||||
<string name="common_adding_caption">"جارٍ إضافة تعليق توضيحي"</string>
|
||||
<string name="common_advanced_settings">"إعدادات متقدمة"</string>
|
||||
<string name="common_an_image">"صورة"</string>
|
||||
<string name="common_analytics">"التحليلات"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_left_room">"قمتَ بمغادرة المجموعة"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_session_logged_out">"تم تسجيل خروجك من الجلسة"</string>
|
||||
<string name="common_appearance">"المظهر"</string>
|
||||
<string name="common_audio">"الصوت"</string>
|
||||
<string name="common_beta">"تجريبي"</string>
|
||||
<string name="common_blocked_users">"المستخدمون المحظورون"</string>
|
||||
<string name="common_bubbles">"فقاعات"</string>
|
||||
<string name="common_call_declined">"تم رفض المكالمة"</string>
|
||||
<string name="common_call_in_progress">"مكالمة جارية"</string>
|
||||
<string name="common_call_started">"بدأت المكالمة"</string>
|
||||
<string name="common_call_you_declined">"رفضت مكالمة"</string>
|
||||
<string name="common_chat_backup">"النسخ الاحتياطي للدردشة"</string>
|
||||
<string name="common_copied_to_clipboard">"تم النسخ إلى الحافظة"</string>
|
||||
<string name="common_copyright">"حقوق الملكية"</string>
|
||||
<string name="common_creating_room">"يتم إنشاء الغرفة…"</string>
|
||||
<string name="common_creating_space">"جارٍ إنشاء المساحة…"</string>
|
||||
<string name="common_current_user_canceled_knock">"تم إلغاء الطلب"</string>
|
||||
<string name="common_current_user_left_room">"غادرت الغرفة"</string>
|
||||
<string name="common_current_user_left_space">"غادرت المساحة"</string>
|
||||
<string name="common_current_user_rejected_invite">"تم رفض الدعوة"</string>
|
||||
<string name="common_decryption_error">"خطأ في فك التشفير"</string>
|
||||
<string name="common_description">"الوصف"</string>
|
||||
<string name="common_developer_options">"خيارات المطوِّرين"</string>
|
||||
<string name="common_device_id">"معرّف الجهاز"</string>
|
||||
<string name="common_direct_chat">"الدردشة المباشرة"</string>
|
||||
<string name="common_do_not_show_this_again">"عدم إظهار هذا مرة أخرى"</string>
|
||||
<string name="common_download_failed">"فشل التنزيل"</string>
|
||||
<string name="common_downloading">"جارٍ التنزيل"</string>
|
||||
<string name="common_edited_suffix">"(مُعدّلة)"</string>
|
||||
<string name="common_editing">"تعديل"</string>
|
||||
<string name="common_editing_caption">"جارٍ تعديل التعليق التوضيحي"</string>
|
||||
<string name="common_emote">"* %1$s %2$s"</string>
|
||||
<string name="common_empty_file">"ملف فارغ"</string>
|
||||
<string name="common_encryption">"التشفير"</string>
|
||||
<string name="common_encryption_enabled">"التشفير مفعّل"</string>
|
||||
<string name="common_ends_at">"ينتهي عند %1$s"</string>
|
||||
<string name="common_enter_your_pin">"أدخل رمز PIN الخاص بك"</string>
|
||||
<string name="common_error">"خطأ"</string>
|
||||
<string name="common_error_registering_pusher_android">"حدث خطأ، قد لا تتلقى إشعارات للرسائل الجديدة. يرجى استكشاف أخطاء الإشعارات وإصلاحها من الإعدادات.
|
||||
|
||||
السبب: %1$s."</string>
|
||||
<string name="common_everyone">"الجميع"</string>
|
||||
<string name="common_failed">"فشل"</string>
|
||||
<string name="common_favourite">"مفضلة"</string>
|
||||
<string name="common_favourited">"مضافة إلى المفضلة"</string>
|
||||
<string name="common_fetching_notifications_title_android">"جارٍ مزامنة الإشعارات…"</string>
|
||||
<string name="common_file">"ملف"</string>
|
||||
<string name="common_file_deleted">"تمت إزالة الملف"</string>
|
||||
<string name="common_file_saved">"تم حفظ الملف"</string>
|
||||
<string name="common_file_saved_on_disk_android">"تم حفظ الملف في التنزيلات"</string>
|
||||
<string name="common_forward_message">"إعادة توجيه الرسالة"</string>
|
||||
<string name="common_frequently_used">"المستخدمة بكثرة"</string>
|
||||
<string name="common_gallery">"المعرض"</string>
|
||||
<string name="common_gif">"GIF"</string>
|
||||
<string name="common_group_call_in_progress">"مكالمة جماعية جارية"</string>
|
||||
<string name="common_image">"صورة"</string>
|
||||
<string name="common_in_reply_to">"ردٌّ على %1$s"</string>
|
||||
<string name="common_install_apk_android">"تثبيت ملف الـAPK"</string>
|
||||
<string name="common_invite_unknown_profile">"لم يتم العثور على الـMatrix ID هذا، ولذا فالدعوة قد لا تكون وصلت."</string>
|
||||
<string name="common_leaving_room">"تتم مغادرة المجموعة"</string>
|
||||
<string name="common_leaving_space">"جارٍ مغادرة المساحة"</string>
|
||||
<string name="common_line_copied_to_clipboard">"تم نسخ السطر إلى الحافظة"</string>
|
||||
<string name="common_link_copied_to_clipboard">"تم نسخ الرابط إلى الحافظة"</string>
|
||||
<string name="common_link_new_device">"ربط جهاز جديد"</string>
|
||||
<string name="common_live_location">"الموقع المباشر"</string>
|
||||
<string name="common_live_location_ended">"انتهت مشاركة الموقع المباشر"</string>
|
||||
<string name="common_loading">"جارٍ التحميل…"</string>
|
||||
<string name="common_loading_more">"جارٍ تحميل المزيد…"</string>
|
||||
<plurals name="common_many_members">
|
||||
<item quantity="zero">"%d آخرون"</item>
|
||||
<item quantity="one">"%d آخر"</item>
|
||||
<item quantity="two">"%d آخران"</item>
|
||||
<item quantity="few">"%d آخرون"</item>
|
||||
<item quantity="many">"%d آخر"</item>
|
||||
<item quantity="other">"%d آخر"</item>
|
||||
</plurals>
|
||||
<plurals name="common_member_count">
|
||||
<item quantity="zero">"%1$d أعضاء"</item>
|
||||
<item quantity="one">"%1$d عضو"</item>
|
||||
<item quantity="two">"%1$d عضو"</item>
|
||||
<item quantity="few">"%1$d أعضاء"</item>
|
||||
<item quantity="many">"%1$d عضو"</item>
|
||||
<item quantity="other">"%1$d عضو"</item>
|
||||
</plurals>
|
||||
<string name="common_message">"رسالة"</string>
|
||||
<string name="common_message_actions">"إجراءات الرسالة"</string>
|
||||
<string name="common_message_failed_to_send">"فشل إرسال الرسالة"</string>
|
||||
<string name="common_message_layout">"مظهر الرسائل"</string>
|
||||
<string name="common_message_removed">"حُذِفت الرسالة"</string>
|
||||
<string name="common_modern">"حديث"</string>
|
||||
<string name="common_mute">"كتم"</string>
|
||||
<string name="common_name">"الاسم"</string>
|
||||
<string name="common_name_and_id">"%1$s (%2$s)"</string>
|
||||
<string name="common_no_results">"لا نتائج"</string>
|
||||
<string name="common_no_room_name">"لا يوجد اسم للغرفة"</string>
|
||||
<string name="common_no_space_name">"لا يوجد اسم للمساحة"</string>
|
||||
<string name="common_not_encrypted">"غير مشفّر"</string>
|
||||
<string name="common_offline">"غير متصل"</string>
|
||||
<string name="common_open_source_licenses">"تراخيص المصادر المفتوحة"</string>
|
||||
<string name="common_or">"أو"</string>
|
||||
<string name="common_other_options">"خيارات أخرى"</string>
|
||||
<string name="common_password">"كلمة السر"</string>
|
||||
<string name="common_people">"الأشخاص"</string>
|
||||
<string name="common_permalink">"الرابط الثابت"</string>
|
||||
<string name="common_permission">"الإذن"</string>
|
||||
<string name="common_pinned">"مثبّتة"</string>
|
||||
<string name="common_please_check_internet_connection">"يرجى التحقق من اتصالك بالإنترنت"</string>
|
||||
<string name="common_please_wait">"يرجى الانتظار…"</string>
|
||||
<string name="common_poll_end_confirmation">"أمتأكد من رغبتك بإنهاء الاستفتاء؟"</string>
|
||||
<string name="common_poll_summary">"استفتاء: %1$s"</string>
|
||||
<string name="common_poll_summary_prefix">"استطلاع"</string>
|
||||
<string name="common_poll_total_votes">"مجموع الأصوات: %1$s"</string>
|
||||
<string name="common_poll_undisclosed_text">"ستظهر النتائج في حين انتهاء الاستفتاء"</string>
|
||||
<plurals name="common_poll_votes_count">
|
||||
<item quantity="zero">"%d صوت"</item>
|
||||
<item quantity="one">"%d صوت"</item>
|
||||
<item quantity="two">"%d صوت"</item>
|
||||
<item quantity="few">"%d أصوات"</item>
|
||||
<item quantity="many">"%d صوت"</item>
|
||||
<item quantity="other">"%d صوت"</item>
|
||||
</plurals>
|
||||
<string name="common_preparing">"جارٍ التحضير…"</string>
|
||||
<string name="common_privacy_policy">"سياسة الخصوصية"</string>
|
||||
<string name="common_private">"خاصة"</string>
|
||||
<string name="common_private_room">"غرفة خاصة"</string>
|
||||
<string name="common_private_space">"مساحة خاصة"</string>
|
||||
<string name="common_public">"عامة"</string>
|
||||
<string name="common_public_room">"غرفة عامة"</string>
|
||||
<string name="common_public_space">"مساحة عامة"</string>
|
||||
<string name="common_reaction">"التفاعل"</string>
|
||||
<string name="common_reactions">"ردود الفعل"</string>
|
||||
<string name="common_reason">"السبب"</string>
|
||||
<string name="common_recovery_key">"مفتاح الاسترداد"</string>
|
||||
<string name="common_refreshing">"يتم التحديث…"</string>
|
||||
<string name="common_removing">"جارٍ الإزالة…"</string>
|
||||
<plurals name="common_replies">
|
||||
<item quantity="zero">"%1$d ردود"</item>
|
||||
<item quantity="one">"%1$d رد"</item>
|
||||
<item quantity="two">"%1$d ردّان"</item>
|
||||
<item quantity="few">"%1$d ردود"</item>
|
||||
<item quantity="many">"%1$d ردًا"</item>
|
||||
<item quantity="other">"%1$d رد"</item>
|
||||
</plurals>
|
||||
<string name="common_replying_to">"الرد على %1$s"</string>
|
||||
<string name="common_report_a_problem">"الإبلاغ عن مشكلة"</string>
|
||||
<string name="common_report_submitted">"أُرسِل الإبلاغ"</string>
|
||||
<string name="common_rich_text_editor">"محرر النص المنسق"</string>
|
||||
<string name="common_role">"الدور"</string>
|
||||
<string name="common_room">"غرفة"</string>
|
||||
<string name="common_room_name">"اسم الغرفة"</string>
|
||||
<string name="common_room_name_placeholder">"مثال: اسم مشروعك"</string>
|
||||
<plurals name="common_rooms">
|
||||
<item quantity="zero">"%1$d غرف"</item>
|
||||
<item quantity="one">"%1$d غرفة"</item>
|
||||
<item quantity="two">"%1$d غرفتان"</item>
|
||||
<item quantity="few">"%1$d غرف"</item>
|
||||
<item quantity="many">"%1$d غرفة"</item>
|
||||
<item quantity="other">"%1$d غرفة"</item>
|
||||
</plurals>
|
||||
<string name="common_saved_changes">"تم حفظ التغييرات"</string>
|
||||
<string name="common_saving">"جارٍ الحفظ"</string>
|
||||
<string name="common_screen_lock">"قفل الشاشة"</string>
|
||||
<string name="common_search_for_someone">"اِبحث عن شخص ما"</string>
|
||||
<string name="common_search_results">"نتائج البحث"</string>
|
||||
<string name="common_security">"الأمان"</string>
|
||||
<string name="common_seen_by">"شوهد بواسطة"</string>
|
||||
<string name="common_select_account">"اختر حسابًا"</string>
|
||||
<plurals name="common_selected_count">
|
||||
<item quantity="zero">"تم تحديد %1$d"</item>
|
||||
<item quantity="one">"تم تحديد %1$d"</item>
|
||||
<item quantity="two">"تم تحديد %1$d"</item>
|
||||
<item quantity="few">"تم تحديد %1$d"</item>
|
||||
<item quantity="many">"تم تحديد %1$d"</item>
|
||||
<item quantity="other">"تم تحديد %1$d"</item>
|
||||
</plurals>
|
||||
<string name="common_send_to">"إرسال إلى"</string>
|
||||
<string name="common_sending">"جارٍ الإرسال…"</string>
|
||||
<string name="common_sending_failed">"فشل الإرسال"</string>
|
||||
<string name="common_sent">"تم الإرسال"</string>
|
||||
<string name="common_sentence_delimiter">". "</string>
|
||||
<string name="common_server_not_supported">"السيرفر غير مدعوم"</string>
|
||||
<string name="common_server_unreachable">"الخادم غير متاح"</string>
|
||||
<string name="common_server_url">"عنوان URL للسيرفر"</string>
|
||||
<string name="common_settings">"الإعدادات"</string>
|
||||
<string name="common_share_space">"مشاركة المساحة"</string>
|
||||
<string name="common_shared_history">"يمكن للأعضاء الجدد رؤية السجل"</string>
|
||||
<string name="common_shared_live_location">"تمت مشاركة الموقع المباشر"</string>
|
||||
<string name="common_shared_location">"الموقع المشارَك"</string>
|
||||
<string name="common_shared_space">"مساحة مشتركة"</string>
|
||||
<string name="common_signing_out">"جارٍ إزالة الجهاز"</string>
|
||||
<string name="common_something_went_wrong">"حدث خطأ ما"</string>
|
||||
<string name="common_something_went_wrong_message">"واجهنا مشكلة. يرجى المحاولة مرة أخرى."</string>
|
||||
<string name="common_space">"مساحة"</string>
|
||||
<string name="common_space_members">"أعضاء المساحة"</string>
|
||||
<string name="common_space_topic_placeholder">"ما موضوع هذه المساحة؟"</string>
|
||||
<plurals name="common_spaces">
|
||||
<item quantity="zero">"%1$d مساحات"</item>
|
||||
<item quantity="one">"%1$d مساحة"</item>
|
||||
<item quantity="two">"%1$d مساحتان"</item>
|
||||
<item quantity="few">"%1$d مساحات"</item>
|
||||
<item quantity="many">"%1$d مساحة"</item>
|
||||
<item quantity="other">"%1$d مساحة"</item>
|
||||
</plurals>
|
||||
<string name="common_starting_chat">"يتم بدء المحادثة…"</string>
|
||||
<string name="common_sticker">"مُلصَق"</string>
|
||||
<string name="common_success">"تمت العملية بنجاح"</string>
|
||||
<string name="common_suggested">"مقترح"</string>
|
||||
<string name="common_suggestions">"اقتراحات"</string>
|
||||
<string name="common_syncing">"تتم المزامنة"</string>
|
||||
<string name="common_text">"نص"</string>
|
||||
<string name="common_third_party_notices">"إشعارات الجهات الخارجية"</string>
|
||||
<string name="common_thread">"ثريد"</string>
|
||||
<string name="common_threads">"السلاسل"</string>
|
||||
<string name="common_topic">"الموضوع"</string>
|
||||
<string name="common_topic_placeholder">"ما موضوع هذه الغرفة؟"</string>
|
||||
<string name="common_unable_to_decrypt">"غير قادر على فك التشفير"</string>
|
||||
<string name="common_unable_to_decrypt_insecure_device">"أُرسلت من جهاز غير آمن"</string>
|
||||
<string name="common_unable_to_decrypt_no_access">"ليس لديك صلاحية الوصول إلى هذه الرسالة"</string>
|
||||
<string name="common_unable_to_decrypt_verification_violation">"تمت إعادة تعيين الهوية الرقمية الموثّقة للمرسل"</string>
|
||||
<string name="common_unable_to_invite_message">"لم يتم التمكن من إرسال الدعوة إلى عضو أو أكثر."</string>
|
||||
<string name="common_unable_to_invite_title">"غير قادر على إرسال الدعوة (الدعوات)"</string>
|
||||
<string name="common_unlock">"إلغاء القفل"</string>
|
||||
<string name="common_unmute">"إلغاء الكتم"</string>
|
||||
<string name="common_unsupported_call">"مكالمة غير مدعومة"</string>
|
||||
<string name="common_unsupported_event">"حدث غير مدعوم"</string>
|
||||
<string name="common_user_started_a_call">"بدأ %1$s مكالمة"</string>
|
||||
<string name="common_username">"اسم المستخدم"</string>
|
||||
<string name="common_verification_cancelled">"أُلغيَ التحقق"</string>
|
||||
<string name="common_verification_complete">"اكتمل التحقق"</string>
|
||||
<string name="common_verification_failed">"فشل التحقق"</string>
|
||||
<string name="common_verified">"تم التحقق"</string>
|
||||
<string name="common_verify_device">"التحقّق من الجهاز"</string>
|
||||
<string name="common_verify_identity">"تحقّق من الهوية"</string>
|
||||
<string name="common_verify_user">"تحقّق من المستخدم"</string>
|
||||
<string name="common_video">"فيديو"</string>
|
||||
<string name="common_video_quality_high">"جودة عالية"</string>
|
||||
<string name="common_video_quality_high_description">"أفضل جودة، لكن بحجم ملف أكبر"</string>
|
||||
<string name="common_video_quality_low">"جودة منخفضة"</string>
|
||||
<string name="common_video_quality_low_description">"أسرع سرعة رفع وأصغر حجم ملف"</string>
|
||||
<string name="common_video_quality_standard">"جودة قياسية"</string>
|
||||
<string name="common_video_quality_standard_description">"توازن بين الجودة وسرعة الرفع"</string>
|
||||
<string name="common_voice_message">"رسالة صوتية"</string>
|
||||
<string name="common_waiting">"جارٍ الانتظار…"</string>
|
||||
<string name="common_waiting_for_decryption_key">"في انتظار هذه الرسالة"</string>
|
||||
<string name="common_waiting_live_location">"في انتظار الموقع المباشر…"</string>
|
||||
<string name="common_world_readable_history">"يمكن لأي شخص رؤية السجل"</string>
|
||||
<string name="common_you">"أنت"</string>
|
||||
<string name="content_scanner_not_found">"التنزيل غير متاح."</string>
|
||||
<string name="content_scanner_not_found_title">"لم يتم العثور على الملف"</string>
|
||||
<string name="content_scanner_scanning">"جاري المسح…"</string>
|
||||
<string name="content_scanner_unsafe_message">"تم تعطيل المعاينة والتنزيل."</string>
|
||||
<string name="content_scanner_unsafe_title">"الملف غير آمن"</string>
|
||||
<string name="crypto_event_key_forwarded_known_profile_dialog_content">"شارك %1$s (%2$s) هذه الرسالة لأنك لم تكن في الغرفة عند إرسالها."</string>
|
||||
<string name="crypto_event_key_forwarded_unknown_profile_dialog_content">"شارك %1$s هذه الرسالة لأنك لم تكن في الغرفة عند إرسالها."</string>
|
||||
<string name="crypto_history_visible">"تم إعداد هذه الغرفة بحيث يمكن للأعضاء الجدد قراءة السجل. %1$s"</string>
|
||||
<string name="crypto_identity_change_pin_violation">"تمت إعادة تعيين الهوية الرقمية لـ %1$s. %2$s"</string>
|
||||
<string name="crypto_identity_change_pin_violation_new">"تمت إعادة تعيين الهوية الرقمية الخاصة بـ %1$s %2$s. %3$s"</string>
|
||||
<string name="crypto_identity_change_pin_violation_new_user_id">"(%1$s)"</string>
|
||||
<string name="crypto_identity_change_profile_pin_violation">"تمت إعادة تعيين الهوية الرقمية الخاصة بـ %1$s."</string>
|
||||
<string name="crypto_identity_change_verification_violation_new">"تمت إعادة تعيين الهوية الرقمية الخاصة بـ %1$s %2$s. %3$s"</string>
|
||||
<string name="crypto_identity_change_withdraw_verification_action">"إلغاء التحقق"</string>
|
||||
<string name="dialog_allow_access">"السماح بالوصول"</string>
|
||||
<string name="dialog_confirm_link_message">"ينقلك الرابط %1$s إلى موقع آخر %2$s
|
||||
|
||||
هل أنت متأكد من رغبتك في المتابعة؟"</string>
|
||||
<string name="dialog_confirm_link_title">"تحقّق جيدًا من هذا الرابط"</string>
|
||||
<string name="dialog_default_video_quality_selector_subtitle">"اختر الجودة الافتراضية للفيديوهات التي ترفعها."</string>
|
||||
<string name="dialog_default_video_quality_selector_title">"جودة رفع الفيديو"</string>
|
||||
<string name="dialog_file_too_large_to_upload_subtitle">"الحد الأقصى المسموح به لحجم الملف هو: %1$s"</string>
|
||||
<string name="dialog_file_too_large_to_upload_title">"حجم الملف كبير جدًا ولا يمكن رفعه"</string>
|
||||
<string name="dialog_room_reported">"تم الإبلاغ عن الغرفة"</string>
|
||||
<string name="dialog_room_reported_and_left">"تم الإبلاغ عن الغرفة ومغادرتها"</string>
|
||||
<string name="dialog_title_confirmation">"التأكيد"</string>
|
||||
<string name="dialog_title_error">"خطأ"</string>
|
||||
<string name="dialog_title_success">"تمت العملية بنجاح"</string>
|
||||
<string name="dialog_title_warning">"تحذير"</string>
|
||||
<string name="dialog_unsaved_changes_description">"لديك تغييرات غير محفوظة."</string>
|
||||
<string name="dialog_unsaved_changes_description_android">"لم تُحفظ تغييراتك. هل أنت متأكد من أنك تريد الرجوع؟"</string>
|
||||
<string name="dialog_unsaved_changes_title">"حفظ التغييرات؟"</string>
|
||||
<string name="dialog_video_quality_selector_subtitle_file_size">"الحد الأقصى المسموح به لحجم الملف هو: %1$s"</string>
|
||||
<string name="dialog_video_quality_selector_subtitle_no_file_size">"اختر جودة الفيديو الذي تريد رفعه."</string>
|
||||
<string name="dialog_video_quality_selector_title">"اختر جودة رفع الفيديو"</string>
|
||||
<string name="error_account_already_logged_in">"لقد سجّلت الدخول بالفعل على هذا الجهاز باسم %1$s."</string>
|
||||
<string name="error_account_creation_not_possible">"يجب ترقية خادمك المنزلي لدعم Matrix Authentication Service وإنشاء الحسابات."</string>
|
||||
<string name="error_failed_creating_the_permalink">"فشِل إنشاء رابطٍ دائم (permalink)"</string>
|
||||
<string name="error_failed_loading_map">"%1$s لم يستطع تحميل الخريطة. يرجى المحاولة مجدداً لاحقاً."</string>
|
||||
<string name="error_failed_loading_messages">"فشِل تحميل الرسائل"</string>
|
||||
<string name="error_failed_locating_user">"%1$s لم يستطع الوصول إلى موقعك. يرجى المحاولة مجدداً لاحقاً."</string>
|
||||
<string name="error_failed_uploading_voice_message">"تعذّر رفع رسالتك الصوتية."</string>
|
||||
<string name="error_invalid_invite">"لم تعد الغرفة موجودة أو لم تعد الدعوة صالحة."</string>
|
||||
<string name="error_location_service_disabled_android">"يرجى تفعيل GPS للوصول إلى الميزات المستندة إلى الموقع."</string>
|
||||
<string name="error_message_not_found">"لم يتم العثور على الرسالة"</string>
|
||||
<string name="error_missing_location_auth_android">"لا يملك %1$s الإذن بالوصول إلى موقعك. يمكنك تفعيل وصوله في الإعدادات."</string>
|
||||
<string name="error_missing_location_rationale_android">"لا يملك %1$s الإذن بالوصول إلى موقعك. فعّل وصوله تحت."</string>
|
||||
<string name="error_missing_microphone_voice_rationale_android">"ليس لدى %1$s إذن للوصول إلى الميكروفون. اسمح بالوصول لتسجيل رسالة صوتية."</string>
|
||||
<string name="error_network_or_server_issue">"قد يكون ذلك بسبب مشكلات في الشبكة أو الخادم."</string>
|
||||
<string name="error_room_address_already_exists">"عنوان الغرفة هذا موجود بالفعل. يرجى محاولة تعديل حقل عنوان الغرفة أو تغيير اسم الغرفة"</string>
|
||||
<string name="error_room_address_invalid_symbols">"بعض الأحرف غير مسموح بها. يُسمح فقط بالحروف والأرقام والرموز التالية: ! $ & ‘ ( ) * + / ; = ? @ [ ] - . _"</string>
|
||||
<string name="error_some_messages_have_not_been_sent">"لم تُرسَل بعض الرسائل"</string>
|
||||
<string name="error_unknown">"عذراً، قد حدث خطأ"</string>
|
||||
<string name="invite_friends_rich_title">"🔐️ انضم إليّ في %1$s"</string>
|
||||
<string name="invite_friends_text">"مرحباً، راسلني في %1$s: %2$s"</string>
|
||||
<string name="live_location_sharing_foreground_service_channel_title_android">"مشاركة الموقع المباشر"</string>
|
||||
<string name="live_location_sharing_foreground_service_message_android">"جارٍ مشاركة الموقع"</string>
|
||||
<string name="live_location_sharing_foreground_service_title_android">"%1$s - الموقع المباشر"</string>
|
||||
<string name="login_initial_device_name_android">"%1$s Android"</string>
|
||||
<string name="preference_rageshake">"رجّ الهاتف للإبلاغ عن خطأ"</string>
|
||||
<string name="screen_bug_report_a11y_screenshot">"لقطة شاشة"</string>
|
||||
<string name="screen_create_poll_option_accessibility_label">"%1$s: %2$s"</string>
|
||||
<string name="screen_create_poll_options_section_title">"الخيارات"</string>
|
||||
<string name="screen_create_poll_remove_accessibility_label">"إزالة %1$s"</string>
|
||||
<string name="screen_create_poll_settings_section_title">"الإعدادات"</string>
|
||||
<string name="screen_create_poll_votes_allowed_per_person">"الأصوات المسموح بها لكل شخص"</string>
|
||||
<string name="screen_live_location_sheet_nobody_sharing">"لا يشارك أحد موقعه"</string>
|
||||
<string name="screen_live_location_sheet_sharing_live_location">"مشاركة الموقع المباشر"</string>
|
||||
<plurals name="screen_live_location_sheet_subtitle">
|
||||
<item quantity="zero">"%1$d أشخاص"</item>
|
||||
<item quantity="one">"%1$d شخص"</item>
|
||||
<item quantity="two">"%1$d شخصان"</item>
|
||||
<item quantity="few">"%1$d أشخاص"</item>
|
||||
<item quantity="many">"%1$d شخصًا"</item>
|
||||
<item quantity="other">"%1$d شخص"</item>
|
||||
</plurals>
|
||||
<string name="screen_live_location_sheet_title">"على الخريطة"</string>
|
||||
<string name="screen_media_picker_error_failed_selection">"تعذّر اختيار الوسائط، يرجى المحاولة مجدداً."</string>
|
||||
<string name="screen_pinned_timeline_empty_state_description">"اضغط على رسالة واختر “%1$s” لإضافتها هنا."</string>
|
||||
<string name="screen_pinned_timeline_empty_state_headline">"ثبّت الرسائل المهمة لتسهيل العثور عليها"</string>
|
||||
<plurals name="screen_pinned_timeline_screen_title">
|
||||
<item quantity="zero">"%1$d رسائل مثبّتة"</item>
|
||||
<item quantity="one">"%1$d رسالة مثبّتة"</item>
|
||||
<item quantity="two">"%1$d رسالتان مثبّتتان"</item>
|
||||
<item quantity="few">"%1$d رسائل مثبّتة"</item>
|
||||
<item quantity="many">"%1$d رسالة مثبّتة"</item>
|
||||
<item quantity="other">"%1$d رسالة مثبّتة"</item>
|
||||
</plurals>
|
||||
<string name="screen_pinned_timeline_screen_title_empty">"الرسائل المثبّتة"</string>
|
||||
<string name="screen_reset_identity_confirmation_subtitle">"أنت على وشك الانتقال إلى حسابك على %1$s لإعادة تعيين هويتك الرقمية. بعد ذلك ستعود إلى التطبيق."</string>
|
||||
<string name="screen_reset_identity_confirmation_title">"لا يمكنك التأكيد؟ انتقل إلى حسابك لإعادة تعيين هويتك الرقمية."</string>
|
||||
<string name="screen_resolve_send_failure_changed_identity_primary_button_title">"إلغاء التحقق والإرسال"</string>
|
||||
<string name="screen_resolve_send_failure_changed_identity_subtitle">"يمكنك إلغاء التحقق الذي أجريته وإرسال هذه الرسالة على أي حال، أو الإلغاء في الوقت الحالي والمحاولة مرة أخرى لاحقًا بعد إعادة التحقق من %1$s."</string>
|
||||
<string name="screen_resolve_send_failure_changed_identity_title">"لم تُرسل رسالتك لأن الهوية الرقمية الموثّقة لـ %1$s أُعيد تعيينها"</string>
|
||||
<string name="screen_resolve_send_failure_unsigned_device_primary_button_title">"إرسال الرسالة على أي حال"</string>
|
||||
<string name="screen_resolve_send_failure_unsigned_device_subtitle">"يستخدم %1$s جهازًا واحدًا أو أكثر لم يتم التحقق منه. يمكنك إرسال الرسالة على أي حال، أو الإلغاء في الوقت الحالي والمحاولة مرة أخرى لاحقًا بعد أن يتحقق %2$s من جميع أجهزته."</string>
|
||||
<string name="screen_resolve_send_failure_unsigned_device_title">"لم تُرسل رسالتك لأن %1$s لم يتحقق من جميع الأجهزة"</string>
|
||||
<string name="screen_resolve_send_failure_you_unsigned_device_subtitle">"لم يتم التحقق من جهاز واحد أو أكثر من أجهزتك. يمكنك إرسال الرسالة على أي حال، أو الإلغاء في الوقت الحالي والمحاولة مرة أخرى لاحقًا بعد أن تتحقق من جميع أجهزتك."</string>
|
||||
<string name="screen_resolve_send_failure_you_unsigned_device_title">"لم تُرسل رسالتك لأنك لم تتحقق من جهاز واحد أو أكثر من أجهزتك"</string>
|
||||
<string name="screen_room_change_role_administrators_or_owners_title">"تعديل المسؤولين أو المالكين"</string>
|
||||
<string name="screen_room_error_failed_processing_media">"تعذّرت معالجة الوسائط من أجل رفعها، يرجى المحاولة مجدداً."</string>
|
||||
<string name="screen_room_error_failed_retrieving_user_details">"تعذّر استرداد معلومات المستخدم"</string>
|
||||
<string name="screen_room_event_pill">"رسالة في %1$s"</string>
|
||||
<string name="screen_room_grouped_state_events_expand">"توسيع"</string>
|
||||
<string name="screen_room_grouped_state_events_reduce">"طي"</string>
|
||||
<string name="screen_room_live_location_banner">"مشاركة الموقع المباشر"</string>
|
||||
<string name="screen_room_permalink_same_room_android">"أنت في هذه الغرفة بالفعل!"</string>
|
||||
<string name="screen_room_pinned_banner_indicator">"%1$s من %2$s"</string>
|
||||
<string name="screen_room_pinned_banner_indicator_description">"%1$s رسائل مثبّتة"</string>
|
||||
<string name="screen_room_pinned_banner_loading_description">"جارٍ تحميل الرسالة…"</string>
|
||||
<string name="screen_room_pinned_banner_view_all_button_title">"عرض الكل"</string>
|
||||
<string name="screen_room_title">"الدردشة"</string>
|
||||
<string name="screen_share_location_title">"مشاركة موقع"</string>
|
||||
<string name="screen_share_my_location_action">"شارك موقعي"</string>
|
||||
<string name="screen_share_open_apple_maps">"فتح في Apple Maps"</string>
|
||||
<string name="screen_share_open_google_maps">"فتح في Google Maps"</string>
|
||||
<string name="screen_share_open_osm_maps">"فتح في OpenStreetMap"</string>
|
||||
<string name="screen_share_this_location_action">"مشاركة الموقع الجغرافي المُحدّد"</string>
|
||||
<string name="screen_sharing_location_option_sheet_title">"خيارات المشاركة"</string>
|
||||
<string name="screen_space_list_description">"المساحات التي أنشأتها أو انضممت إليها."</string>
|
||||
<string name="screen_space_list_details">"%1$s • %2$s"</string>
|
||||
<string name="screen_space_list_empty_state_title">"أنشئ مساحات لتنظيم الغرف"</string>
|
||||
<string name="screen_space_list_parent_space">"مساحة %1$s"</string>
|
||||
<string name="screen_space_list_title">"المساحات"</string>
|
||||
<string name="screen_static_location_sheet_timestamp_description">"تمت المشاركة %1$s"</string>
|
||||
<string name="screen_static_location_sheet_title">"على الخريطة"</string>
|
||||
<string name="screen_timeline_item_menu_send_failure_changed_identity">"لم تُرسل الرسالة لأن الهوية الرقمية الموثّقة لـ %1$s أُعيد تعيينها."</string>
|
||||
<string name="screen_timeline_item_menu_send_failure_unsigned_device">"لم تُرسل الرسالة لأن %1$s لم يتحقق من جميع الأجهزة."</string>
|
||||
<string name="screen_timeline_item_menu_send_failure_you_unsigned_device">"لم تُرسل الرسالة لأنك لم تتحقق من جهاز واحد أو أكثر من أجهزتك."</string>
|
||||
<string name="screen_view_location_title">"الموقع"</string>
|
||||
<string name="settings_version_number">"الإصدار: %1$s (%2$s)"</string>
|
||||
<string name="test_language_identifier">"ar"</string>
|
||||
<string name="timeline_decryption_failure_historical_event_no_key_backup">"الرسائل السابقة غير متاحة على هذا الجهاز"</string>
|
||||
<string name="timeline_decryption_failure_historical_event_unverified_device">"يجب التحقق من هذا الجهاز للوصول إلى الرسائل السابقة"</string>
|
||||
<string name="timeline_decryption_failure_historical_event_user_not_joined">"ليس لديك صلاحية الوصول إلى هذه الرسالة"</string>
|
||||
<string name="timeline_decryption_failure_unable_to_decrypt">"تعذّر فك تشفير الرسالة"</string>
|
||||
<string name="timeline_decryption_failure_withheld_unverified">"تم حظر هذه الرسالة إما لأنك لم تتحقق من جهازك أو لأن المرسل يحتاج إلى التحقق من هويتك الرقمية."</string>
|
||||
<string name="vulkan_not_supported_dialog_content_android">"جهازك قديم جدًا؛ يلزم جهاز يعمل بنظام Android 8 أو أحدث."</string>
|
||||
<string name="vulkan_not_supported_dialog_title_android">"عرض الخرائط غير مدعوم"</string>
|
||||
</resources>
|
||||
@@ -1,51 +1,101 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="a11y_add_avatar">"Añadir avatar"</string>
|
||||
<string name="a11y_add_reaction">"Añadir reacción: %1$s"</string>
|
||||
<string name="a11y_address">"Dirección"</string>
|
||||
<string name="a11y_avatar">"Avatar"</string>
|
||||
<string name="a11y_clear_search_field">"Borrar consulta"</string>
|
||||
<string name="a11y_collapse_message_text_field">"Minimizar el campo de texto del mensaje"</string>
|
||||
<string name="a11y_create_poll_votes_allowed_decrease">"Disminuir el número de votos permitidos por persona"</string>
|
||||
<string name="a11y_create_poll_votes_allowed_increase">"Aumentar el número de votos permitidos por persona"</string>
|
||||
<string name="a11y_custom_emoji">"Emoji personalizado"</string>
|
||||
<string name="a11y_delete">"Borrar"</string>
|
||||
<plurals name="a11y_digits_entered">
|
||||
<item quantity="one">"%1$d dígito introducido"</item>
|
||||
<item quantity="other">"%1$d dígitos introducidos"</item>
|
||||
</plurals>
|
||||
<string name="a11y_duration">"Duración: %1$s"</string>
|
||||
<string name="a11y_edit_avatar">"Editar avatar"</string>
|
||||
<string name="a11y_edit_room_address_hint">"La dirección completa será %1$s"</string>
|
||||
<string name="a11y_encryption_details">"Detalles de cifrado"</string>
|
||||
<string name="a11y_expand_message_text_field">"Expandir campo de texto del mensaje"</string>
|
||||
<string name="a11y_gallery_attachment">"Galería, archivo adjunto %1$d"</string>
|
||||
<string name="a11y_gallery_failed_scan">"Galería, escaneo fallido %1$d"</string>
|
||||
<string name="a11y_gallery_image">"Galería, imagen %1$d"</string>
|
||||
<plurals name="a11y_gallery_more_media">
|
||||
<item quantity="one">"Galería, %1$d elemento multimedia más"</item>
|
||||
<item quantity="other">"Galería, %1$d elementos multimedia más"</item>
|
||||
</plurals>
|
||||
<string name="a11y_gallery_scanning">"Galería, escaneando %1$d"</string>
|
||||
<string name="a11y_gallery_video">"Galería, vídeo %1$d"</string>
|
||||
<string name="a11y_hide_password">"Ocultar contraseña"</string>
|
||||
<string name="a11y_info">"Info"</string>
|
||||
<string name="a11y_join_call">"Unirse a la llamada"</string>
|
||||
<string name="a11y_jump_to_bottom">"Ir al final"</string>
|
||||
<string name="a11y_jump_to_unread">"Ir a los mensajes no leídos"</string>
|
||||
<string name="a11y_jump_to_unread_messages">"Ir al primer mensaje no leído"</string>
|
||||
<string name="a11y_move_the_map_to_my_location">"Desplazar el mapa a mi ubicación"</string>
|
||||
<string name="a11y_notifications_mentions_only">"Sólo menciones"</string>
|
||||
<string name="a11y_notifications_muted">"Silenciado"</string>
|
||||
<string name="a11y_notifications_new_mentions">"Menciones nuevas"</string>
|
||||
<string name="a11y_notifications_new_messages">"Mensajes nuevos"</string>
|
||||
<string name="a11y_notifications_ongoing_call">"Llamada en curso"</string>
|
||||
<string name="a11y_other_user_avatar">"Avatar del otro usuario"</string>
|
||||
<string name="a11y_page_n">"Página %1$d"</string>
|
||||
<string name="a11y_pause">"Pausar"</string>
|
||||
<string name="a11y_paused_voice_message">"Mensaje de voz, duración: %1$s, posición actual: %2$s"</string>
|
||||
<string name="a11y_photo_preview">"Vista previa de la foto"</string>
|
||||
<string name="a11y_pin_field">"Campo PIN"</string>
|
||||
<string name="a11y_pinned_location">"Ubicación fijada"</string>
|
||||
<string name="a11y_play">"Reproducir"</string>
|
||||
<string name="a11y_playback_speed">"Velocidad de reproducción"</string>
|
||||
<string name="a11y_poll">"Encuesta"</string>
|
||||
<string name="a11y_poll_end">"Encuesta finalizada"</string>
|
||||
<string name="a11y_position">"Posición: %1$s"</string>
|
||||
<string name="a11y_qr_code">"Código QR"</string>
|
||||
<string name="a11y_react_with">"Reacciona con %1$s"</string>
|
||||
<string name="a11y_react_with_other_emojis">"Reacciona con otros emojis"</string>
|
||||
<string name="a11y_read_receipts_multiple">"Leído por %1$s y %2$s"</string>
|
||||
<string name="a11y_read_receipts_multiple">"Mensaje anterior leído por %1$s y %2$s"</string>
|
||||
<plurals name="a11y_read_receipts_multiple_with_others">
|
||||
<item quantity="one">"Leído por %1$s y %2$d otro"</item>
|
||||
<item quantity="other">"Leído por %1$s y %2$d otros"</item>
|
||||
<item quantity="one">"Mensaje anterior leído por %1$s y %2$d más"</item>
|
||||
<item quantity="other">"Mensaje anterior leído por %1$s y %2$d más"</item>
|
||||
</plurals>
|
||||
<string name="a11y_read_receipts_single">"Leído por %1$s"</string>
|
||||
<string name="a11y_read_receipts_single">"Mensaje anterior leído por %1$s"</string>
|
||||
<string name="a11y_read_receipts_tap_to_show_all_android">"mostrar todas las confirmaciones de lectura"</string>
|
||||
<string name="a11y_remove_reaction">"Elimina la reacción con %1$s"</string>
|
||||
<string name="a11y_remove_reaction_with">"Retirar la reacción con %1$s"</string>
|
||||
<string name="a11y_room_avatar">"Avatar de la sala"</string>
|
||||
<string name="a11y_send_files">"Enviar archivos"</string>
|
||||
<string name="a11y_sender_location">"Ubicación del remitente"</string>
|
||||
<string name="a11y_sent_by_sender_at_date">"Enviado por %1$s a las %2$s"</string>
|
||||
<string name="a11y_session_verification_time_limited_action_required">"Acción de tiempo limitado requerida, tienes un minuto para hacer la verificación"</string>
|
||||
<string name="a11y_settings_with_required_action">"Ajustes, acción requerida"</string>
|
||||
<string name="a11y_show_password">"Mostrar contraseña"</string>
|
||||
<string name="a11y_start_call">"Iniciar llamada"</string>
|
||||
<string name="a11y_start_video_call">"Iniciar una videollamada"</string>
|
||||
<string name="a11y_start_voice_call">"Iniciar una llamada de voz"</string>
|
||||
<string name="a11y_status">"Estado"</string>
|
||||
<string name="a11y_thread_in_room">"Hilo en %1$s"</string>
|
||||
<string name="a11y_threads_in_room">"Hilos en %1$s"</string>
|
||||
<string name="a11y_tombstoned_room">"Sala clausurada"</string>
|
||||
<string name="a11y_user_avatar">"Avatar del usuario"</string>
|
||||
<string name="a11y_user_menu">"Menú de usuario"</string>
|
||||
<string name="a11y_video_preview">"Vista previa del vídeo"</string>
|
||||
<string name="a11y_view_avatar">"Ver avatar"</string>
|
||||
<string name="a11y_view_details">"Mostrar detalles"</string>
|
||||
<string name="a11y_voice_message">"Mensaje de voz, duración: %1$s"</string>
|
||||
<string name="a11y_voice_message_record">"Grabar mensaje de voz"</string>
|
||||
<string name="a11y_voice_message_stop_recording">"Detener grabación"</string>
|
||||
<string name="a11y_your_avatar">"Tu avatar"</string>
|
||||
<string name="action_accept">"Aceptar"</string>
|
||||
<string name="action_add_caption">"Agregar leyenda"</string>
|
||||
<string name="action_add_existing_rooms">"Añadir salas existentes"</string>
|
||||
<string name="action_add_to_timeline">"Añadir a la cronología"</string>
|
||||
<string name="action_back">"Atrás"</string>
|
||||
<string name="action_call">"Llamar"</string>
|
||||
<string name="action_cancel">"Cancelar"</string>
|
||||
<string name="action_cancel_for_now">"Cancelar por ahora"</string>
|
||||
<string name="action_choose_file">"Seleccionar archivo"</string>
|
||||
<string name="action_choose_photo">"Elegir foto"</string>
|
||||
<string name="action_clear">"Borrar"</string>
|
||||
<string name="action_close">"Cerrar"</string>
|
||||
@@ -60,24 +110,34 @@
|
||||
<string name="action_copy_text">"Copiar texto"</string>
|
||||
<string name="action_create">"Crear"</string>
|
||||
<string name="action_create_room">"Crear una sala"</string>
|
||||
<string name="action_create_space">"Crear espacio"</string>
|
||||
<string name="action_deactivate">"Desactivar"</string>
|
||||
<string name="action_deactivate_account">"Desactivar cuenta"</string>
|
||||
<string name="action_decline">"Rechazar"</string>
|
||||
<string name="action_decline_and_block">"Rechazar y bloquear"</string>
|
||||
<string name="action_delete">"Eliminar"</string>
|
||||
<string name="action_delete_account">"Eliminar cuenta"</string>
|
||||
<string name="action_delete_file">"Eliminar archivo"</string>
|
||||
<string name="action_delete_poll">"Eliminar encuesta"</string>
|
||||
<string name="action_deselect_all">"Deseleccionar todo"</string>
|
||||
<string name="action_disable">"Desactivar"</string>
|
||||
<string name="action_discard">"Descartar"</string>
|
||||
<string name="action_dismiss">"Descartar"</string>
|
||||
<string name="action_done">"Hecho"</string>
|
||||
<string name="action_download">"Descargar"</string>
|
||||
<string name="action_edit">"Editar"</string>
|
||||
<string name="action_edit_caption">"Editar leyenda"</string>
|
||||
<string name="action_edit_poll">"Editar encuesta"</string>
|
||||
<string name="action_enable">"Activar"</string>
|
||||
<string name="action_end_poll">"Finalizar encuesta"</string>
|
||||
<string name="action_enter_pin">"Introducir PIN"</string>
|
||||
<string name="action_explore_public_spaces">"Explorar espacios públicos"</string>
|
||||
<string name="action_finish">"Finalizar"</string>
|
||||
<string name="action_forgot_password">"¿Olvidaste tu contraseña?"</string>
|
||||
<string name="action_forward">"Reenviar"</string>
|
||||
<string name="action_go_back">"Volver atrás"</string>
|
||||
<string name="action_go_to_roles_and_permissions">"Ir a roles y permisos"</string>
|
||||
<string name="action_go_to_settings">"Ir a ajustes"</string>
|
||||
<string name="action_ignore">"Ignorar"</string>
|
||||
<string name="action_invite">"Invitar"</string>
|
||||
<string name="action_invite_friends">"Invitar personas"</string>
|
||||
@@ -89,14 +149,20 @@
|
||||
<string name="action_leave">"Salir"</string>
|
||||
<string name="action_leave_conversation">"Salir de la conversación"</string>
|
||||
<string name="action_leave_room">"Salir de la sala"</string>
|
||||
<string name="action_leave_space">"Salir del espacio"</string>
|
||||
<string name="action_load_more">"Cargar más"</string>
|
||||
<string name="action_manage_account">"Gestionar cuenta"</string>
|
||||
<string name="action_manage_account_and_devices">"Gestionar cuenta y dispositivos"</string>
|
||||
<string name="action_manage_devices">"Administrar dispositivos"</string>
|
||||
<string name="action_manage_rooms">"Gestionar salas"</string>
|
||||
<string name="action_mark_as_read">"Marcar como leído"</string>
|
||||
<string name="action_message">"Enviar mensaje"</string>
|
||||
<string name="action_minimize">"Minimizar"</string>
|
||||
<string name="action_next">"Siguiente"</string>
|
||||
<string name="action_no">"No"</string>
|
||||
<string name="action_not_now">"Ahora no"</string>
|
||||
<string name="action_ok">"OK"</string>
|
||||
<string name="action_open_context_menu">"Abrir menú contextual"</string>
|
||||
<string name="action_open_settings">"Ajustes"</string>
|
||||
<string name="action_open_with">"Abrir con"</string>
|
||||
<string name="action_pin">"Fijar"</string>
|
||||
@@ -108,7 +174,7 @@
|
||||
<string name="action_remove_caption">"Quitar leyenda"</string>
|
||||
<string name="action_remove_message">"Eliminar mensaje"</string>
|
||||
<string name="action_reply">"Responder"</string>
|
||||
<string name="action_reply_in_thread">"Responder en el hilo"</string>
|
||||
<string name="action_reply_in_thread">"Responder en hilo"</string>
|
||||
<string name="action_report">"Denunciar"</string>
|
||||
<string name="action_report_bug">"Informar de un error"</string>
|
||||
<string name="action_report_content">"Denunciar contenido"</string>
|
||||
@@ -120,51 +186,69 @@
|
||||
<string name="action_retry_decryption">"Reintentar descifrado"</string>
|
||||
<string name="action_save">"Guardar"</string>
|
||||
<string name="action_search">"Buscar"</string>
|
||||
<string name="action_select_all">"Seleccionar todo"</string>
|
||||
<string name="action_send">"Enviar"</string>
|
||||
<string name="action_send_edited_message">"Enviar mensaje editado"</string>
|
||||
<string name="action_send_message">"Enviar mensaje"</string>
|
||||
<string name="action_send_voice_message">"Enviar mensaje de voz"</string>
|
||||
<string name="action_share">"Compartir"</string>
|
||||
<string name="action_share_link">"Compartir enlace"</string>
|
||||
<string name="action_share_live_location">"Compartir ubicación en directo"</string>
|
||||
<string name="action_show">"Mostrar"</string>
|
||||
<string name="action_sign_in_again">"Inicia sesión de nuevo"</string>
|
||||
<string name="action_signout">"Cerrar sesión"</string>
|
||||
<string name="action_signout_anyway">"Cerrar sesión de todos modos"</string>
|
||||
<string name="action_signout">"Eliminar este dispositivo"</string>
|
||||
<string name="action_signout_anyway">"Eliminar este dispositivo de todos modos"</string>
|
||||
<string name="action_skip">"Saltar"</string>
|
||||
<string name="action_start">"Comenzar"</string>
|
||||
<string name="action_start_chat">"Iniciar chat"</string>
|
||||
<string name="action_start_over">"Empezar de nuevo"</string>
|
||||
<string name="action_start_verification">"Iniciar la verificación"</string>
|
||||
<string name="action_static_map_load">"Pulsa para cargar el mapa"</string>
|
||||
<string name="action_stop">"Parar"</string>
|
||||
<string name="action_take_photo">"Hacer foto"</string>
|
||||
<string name="action_tap_for_options">"Toca para ver opciones"</string>
|
||||
<string name="action_translate">"Traducir"</string>
|
||||
<string name="action_try_again">"Intentar de nuevo"</string>
|
||||
<string name="action_unpin">"Desprender"</string>
|
||||
<string name="action_video_call">"Videollamada"</string>
|
||||
<string name="action_view">"Ver"</string>
|
||||
<string name="action_view_in_timeline">"Ver en la cronología"</string>
|
||||
<string name="action_view_source">"Ver fuente"</string>
|
||||
<string name="action_voice_call">"Llamada de voz"</string>
|
||||
<string name="action_yes">"Sí"</string>
|
||||
<string name="action_yes_try_again">"Sí, intentar de nuevo"</string>
|
||||
<string name="banner_migrate_to_native_sliding_sync_description">"Tu servidor es ahora compatible con un protocolo nuevo y más rápido. Cierra la sesión y vuelve a iniciarla para actualizar ahora. Haciéndolo ahora, evitarás tener que cerrar la sesión cuando se elimine el protocolo antiguo."</string>
|
||||
<string name="banner_migrate_to_native_sliding_sync_title">"Actualización disponible"</string>
|
||||
<string name="common_about">"Acerca de"</string>
|
||||
<string name="common_acceptable_use_policy">"Política de uso aceptable"</string>
|
||||
<string name="common_add_account">"Añadir una cuenta"</string>
|
||||
<string name="common_add_another_account">"Añadir cuenta"</string>
|
||||
<string name="common_adding_caption">"Añadiendo leyenda"</string>
|
||||
<string name="common_advanced_settings">"Ajustes avanzados"</string>
|
||||
<string name="common_an_image">"una imagen"</string>
|
||||
<string name="common_analytics">"Estadísticas"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_left_room">"Saliste de la sala"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_session_logged_out">"Se te ha desconectado de la sesión"</string>
|
||||
<string name="common_appearance">"Apariencia"</string>
|
||||
<string name="common_audio">"Sonido"</string>
|
||||
<string name="common_beta">"Beta"</string>
|
||||
<string name="common_blocked_users">"Usuarios bloqueados"</string>
|
||||
<string name="common_bubbles">"Burbujas"</string>
|
||||
<string name="common_call_declined">"Llamada rechazada"</string>
|
||||
<string name="common_call_in_progress">"Llamada en curso"</string>
|
||||
<string name="common_call_started">"Llamada iniciada"</string>
|
||||
<string name="common_call_you_declined">"Rechazaste una llamada"</string>
|
||||
<string name="common_chat_backup">"Copia de seguridad del chat"</string>
|
||||
<string name="common_copied_to_clipboard">"Copiado al portapapeles"</string>
|
||||
<string name="common_copyright">"Derechos de autor"</string>
|
||||
<string name="common_creating_room">"Creando sala…"</string>
|
||||
<string name="common_creating_space">"Creando espacio…"</string>
|
||||
<string name="common_current_user_canceled_knock">"Solicitud cancelada"</string>
|
||||
<string name="common_current_user_left_room">"Saliste de la sala"</string>
|
||||
<string name="common_current_user_left_space">"Saliste del espacio"</string>
|
||||
<string name="common_current_user_rejected_invite">"Invitación rechazada"</string>
|
||||
<string name="common_decryption_error">"Error de descifrado"</string>
|
||||
<string name="common_description">"Descripción"</string>
|
||||
<string name="common_developer_options">"Opciones de desarrollador"</string>
|
||||
<string name="common_device_id">"ID de dispositivo"</string>
|
||||
<string name="common_direct_chat">"Chat directo"</string>
|
||||
@@ -178,6 +262,7 @@
|
||||
<string name="common_empty_file">"Archivo vacío"</string>
|
||||
<string name="common_encryption">"Cifrado"</string>
|
||||
<string name="common_encryption_enabled">"Cifrado activado"</string>
|
||||
<string name="common_ends_at">"Termina a las %1$s"</string>
|
||||
<string name="common_enter_your_pin">"Introduce tu PIN"</string>
|
||||
<string name="common_error">"Error"</string>
|
||||
<string name="common_error_registering_pusher_android">"Se ha producido un error, es posible que no recibas notificaciones de mensajes nuevos. Soluciona los problemas con las notificaciones desde los ajustes.
|
||||
@@ -187,20 +272,35 @@ Motivo: %1$s."</string>
|
||||
<string name="common_failed">"Falló"</string>
|
||||
<string name="common_favourite">"Favorito"</string>
|
||||
<string name="common_favourited">"Marcado como favorito"</string>
|
||||
<string name="common_fetching_notifications_title_android">"Sincronizando notificaciones…"</string>
|
||||
<string name="common_file">"Archivo"</string>
|
||||
<string name="common_file_deleted">"Archivo eliminado"</string>
|
||||
<string name="common_file_saved">"Archivo guardado"</string>
|
||||
<string name="common_file_saved_on_disk_android">"Archivo guardado en Descargas"</string>
|
||||
<string name="common_forward_message">"Reenviar mensaje"</string>
|
||||
<string name="common_frequently_used">"Usado frecuentemente"</string>
|
||||
<string name="common_gallery">"Galería"</string>
|
||||
<plurals name="common_gallery_reply_attachments">
|
||||
<item quantity="one">"%1$d archivo adjunto…"</item>
|
||||
<item quantity="other">"%1$d archivos adjuntos…"</item>
|
||||
</plurals>
|
||||
<plurals name="common_gallery_reply_media_items">
|
||||
<item quantity="one">"%1$d elemento multimedia…"</item>
|
||||
<item quantity="other">"%1$d elementos multimedia…"</item>
|
||||
</plurals>
|
||||
<string name="common_gif">"GIF"</string>
|
||||
<string name="common_group_call_in_progress">"Llamada grupal en curso"</string>
|
||||
<string name="common_image">"Imagen"</string>
|
||||
<string name="common_in_reply_to">"En respuesta a %1$s"</string>
|
||||
<string name="common_install_apk_android">"Instalar APK"</string>
|
||||
<string name="common_invite_unknown_profile">"No se encontró este ID de Matrix, por lo que es posible que no se reciba la invitación."</string>
|
||||
<string name="common_leaving_room">"Saliendo de la sala"</string>
|
||||
<string name="common_leaving_space">"Saliendo del espacio"</string>
|
||||
<string name="common_line_copied_to_clipboard">"Línea copiada al portapapeles"</string>
|
||||
<string name="common_link_copied_to_clipboard">"Enlace copiado al portapapeles"</string>
|
||||
<string name="common_link_new_device">"Vincular un dispositivo nuevo"</string>
|
||||
<string name="common_live_location">"Location en directo"</string>
|
||||
<string name="common_live_location_ended">"La ubicación en tiempo real ha terminado"</string>
|
||||
<string name="common_loading">"Cargando…"</string>
|
||||
<string name="common_loading_more">"Cargando más…"</string>
|
||||
<plurals name="common_many_members">
|
||||
@@ -213,17 +313,22 @@ Motivo: %1$s."</string>
|
||||
</plurals>
|
||||
<string name="common_message">"Mensaje"</string>
|
||||
<string name="common_message_actions">"Acciones del mensaje"</string>
|
||||
<string name="common_message_failed_to_send">"El mensaje no se pudo enviar"</string>
|
||||
<string name="common_message_layout">"Diseño de los mensajes"</string>
|
||||
<string name="common_message_removed">"Mensaje eliminado"</string>
|
||||
<string name="common_modern">"Moderno"</string>
|
||||
<string name="common_mute">"Silenciar"</string>
|
||||
<string name="common_name">"Nombre"</string>
|
||||
<string name="common_name_and_id">"%1$s (%2$s)"</string>
|
||||
<string name="common_no_results">"No hay resultados"</string>
|
||||
<string name="common_no_room_name">"Sala sin nombre"</string>
|
||||
<string name="common_no_space_name">"Espacio sin nombre"</string>
|
||||
<string name="common_not_encrypted">"No cifrado"</string>
|
||||
<string name="common_offline">"Sin conexión"</string>
|
||||
<string name="common_on_a_call">"En una llamada"</string>
|
||||
<string name="common_open_source_licenses">"Licencias de código abierto"</string>
|
||||
<string name="common_or">"o"</string>
|
||||
<string name="common_other_options">"Otras opciones"</string>
|
||||
<string name="common_password">"Contraseña"</string>
|
||||
<string name="common_people">"Personas"</string>
|
||||
<string name="common_permalink">"Enlace permanente"</string>
|
||||
@@ -233,27 +338,43 @@ Motivo: %1$s."</string>
|
||||
<string name="common_please_wait">"Espera, por favor…"</string>
|
||||
<string name="common_poll_end_confirmation">"¿Estás seguro de que quieres finalizar esta encuesta?"</string>
|
||||
<string name="common_poll_summary">"Encuesta: %1$s"</string>
|
||||
<string name="common_poll_summary_prefix">"Encuesta"</string>
|
||||
<string name="common_poll_total_votes">"Total de votos: %1$s"</string>
|
||||
<string name="common_poll_undisclosed_text">"Los resultados se mostrarán una vez finalizada la encuesta"</string>
|
||||
<plurals name="common_poll_votes_count">
|
||||
<item quantity="one">"%d voto"</item>
|
||||
<item quantity="other">"%d votos"</item>
|
||||
</plurals>
|
||||
<string name="common_preparing">"Preparando…"</string>
|
||||
<string name="common_privacy_policy">"Política de privacidad"</string>
|
||||
<string name="common_private">"Privado"</string>
|
||||
<string name="common_private_room">"Sala privada"</string>
|
||||
<string name="common_private_space">"Espacio privado"</string>
|
||||
<string name="common_public">"Público"</string>
|
||||
<string name="common_public_room">"Sala pública"</string>
|
||||
<string name="common_public_space">"Espacio público"</string>
|
||||
<string name="common_reaction">"Reacción"</string>
|
||||
<string name="common_reactions">"Reacciones"</string>
|
||||
<string name="common_reason">"Motivo"</string>
|
||||
<string name="common_recovery_key">"Clave de recuperación"</string>
|
||||
<string name="common_refreshing">"Recargando…"</string>
|
||||
<string name="common_removing">"Eliminando…"</string>
|
||||
<plurals name="common_replies">
|
||||
<item quantity="one">"%1$d respuesta"</item>
|
||||
<item quantity="other">"%1$d respuestas"</item>
|
||||
</plurals>
|
||||
<string name="common_replying_to">"Respondiendo a %1$s"</string>
|
||||
<string name="common_report_a_problem">"Informar de un problema"</string>
|
||||
<string name="common_report_submitted">"Informe enviado"</string>
|
||||
<string name="common_rich_text_editor">"Editor de texto enriquecido"</string>
|
||||
<string name="common_role">"Rol"</string>
|
||||
<string name="common_room">"Sala"</string>
|
||||
<string name="common_room_name">"Nombre de la sala"</string>
|
||||
<string name="common_room_name_placeholder">"p. ej., el nombre de tu proyecto"</string>
|
||||
<plurals name="common_rooms">
|
||||
<item quantity="one">"%1$d sala"</item>
|
||||
<item quantity="other">"%1$d salas"</item>
|
||||
</plurals>
|
||||
<string name="common_saved_changes">"Cambios guardados"</string>
|
||||
<string name="common_saving">"Guardando"</string>
|
||||
<string name="common_screen_lock">"Bloqueo de pantalla"</string>
|
||||
@@ -261,37 +382,58 @@ Motivo: %1$s."</string>
|
||||
<string name="common_search_results">"Buscar resultados"</string>
|
||||
<string name="common_security">"Seguridad"</string>
|
||||
<string name="common_seen_by">"Visto por"</string>
|
||||
<string name="common_select_account">"Elige una cuenta"</string>
|
||||
<plurals name="common_selected_count">
|
||||
<item quantity="one">"%1$d seleccionado"</item>
|
||||
<item quantity="other">"%1$d seleccionados"</item>
|
||||
</plurals>
|
||||
<string name="common_send_to">"Enviar a"</string>
|
||||
<string name="common_sending">"Enviando…"</string>
|
||||
<string name="common_sending_failed">"Fallo al enviar"</string>
|
||||
<string name="common_sent">"Enviado"</string>
|
||||
<string name="common_sentence_delimiter">". "</string>
|
||||
<string name="common_server_not_supported">"Servidor no compatible"</string>
|
||||
<string name="common_server_unreachable">"Servidor inaccesible"</string>
|
||||
<string name="common_server_url">"Dirección del servidor"</string>
|
||||
<string name="common_settings">"Ajustes"</string>
|
||||
<string name="common_share_space">"Compartir espacio"</string>
|
||||
<string name="common_shared_history">"Los miembros nuevos ven el historial"</string>
|
||||
<string name="common_shared_live_location">"Ubicación compartida en directo"</string>
|
||||
<string name="common_shared_location">"Ubicación compartida"</string>
|
||||
<string name="common_signing_out">"Cerrando sesión"</string>
|
||||
<string name="common_shared_space">"Espacio compartido"</string>
|
||||
<string name="common_signing_out">"Eliminando dispositivo"</string>
|
||||
<string name="common_something_went_wrong">"Algo salió mal"</string>
|
||||
<string name="common_something_went_wrong_message">"Hemos encontrado un problema. Inténtalo de nuevo."</string>
|
||||
<string name="common_space">"Espacio"</string>
|
||||
<string name="common_space_members">"Miembros del espacio"</string>
|
||||
<string name="common_space_topic_placeholder">"¿De qué trata este espacio?"</string>
|
||||
<plurals name="common_spaces">
|
||||
<item quantity="one">"%1$d espacio"</item>
|
||||
<item quantity="other">"%1$d espacios"</item>
|
||||
</plurals>
|
||||
<string name="common_starting_chat">"Iniciando chat…"</string>
|
||||
<string name="common_sticker">"Sticker"</string>
|
||||
<string name="common_success">"Terminado"</string>
|
||||
<string name="common_suggested">"Sugerido"</string>
|
||||
<string name="common_suggestions">"Sugerencias"</string>
|
||||
<string name="common_syncing">"Sincronizando"</string>
|
||||
<string name="common_text">"Texto"</string>
|
||||
<string name="common_third_party_notices">"Avisos de terceros"</string>
|
||||
<string name="common_thread">"Hilo"</string>
|
||||
<string name="common_threads">"Hilos"</string>
|
||||
<string name="common_topic">"Tema"</string>
|
||||
<string name="common_topic_placeholder">"¿De qué trata esta sala?"</string>
|
||||
<string name="common_unable_to_decrypt">"No se puede descifrar"</string>
|
||||
<string name="common_unable_to_decrypt_insecure_device">"Enviado desde un dispositivo no seguro"</string>
|
||||
<string name="common_unable_to_decrypt_no_access">"No tienes acceso a este mensaje"</string>
|
||||
<string name="common_unable_to_decrypt_verification_violation">"Se restableció la identidad verificada del remitente"</string>
|
||||
<string name="common_unable_to_decrypt_verification_violation">"Se restableció la identidad digital verificada del remitente"</string>
|
||||
<string name="common_unable_to_invite_message">"Las invitaciones no se pudieron enviar a uno o más usuarios."</string>
|
||||
<string name="common_unable_to_invite_title">"No se pudo enviar la(s) invitación(es)"</string>
|
||||
<string name="common_unlock">"Desbloquear"</string>
|
||||
<string name="common_unmute">"Dejar de silenciar"</string>
|
||||
<string name="common_unsupported_call">"Llamada no compatible"</string>
|
||||
<string name="common_unsupported_event">"Evento no compatible"</string>
|
||||
<string name="common_user_started_a_call">"%1$s inició una llamada"</string>
|
||||
<string name="common_username">"Usuario"</string>
|
||||
<string name="common_verification_cancelled">"Verificación cancelada"</string>
|
||||
<string name="common_verification_complete">"Verificación completada"</string>
|
||||
@@ -301,20 +443,41 @@ Motivo: %1$s."</string>
|
||||
<string name="common_verify_identity">"Verificar identidad"</string>
|
||||
<string name="common_verify_user">"Verificar usuario"</string>
|
||||
<string name="common_video">"Vídeo"</string>
|
||||
<string name="common_video_quality_high">"Calidad alta"</string>
|
||||
<string name="common_video_quality_high_description">"La mejor calidad, pero mayor tamaño de archivo"</string>
|
||||
<string name="common_video_quality_low">"Calidad baja"</string>
|
||||
<string name="common_video_quality_low_description">"Velocidad de subida más rápida y tamaño de archivo más pequeño"</string>
|
||||
<string name="common_video_quality_standard">"Calidad estándar"</string>
|
||||
<string name="common_video_quality_standard_description">"Equilibrio entre calidad y velocidad de subida"</string>
|
||||
<string name="common_voice_message">"Mensaje de voz"</string>
|
||||
<string name="common_waiting">"Esperando…"</string>
|
||||
<string name="common_waiting_for_decryption_key">"Esperando este mensaje"</string>
|
||||
<string name="common_waiting_live_location">"Esperando la ubicación en directo…"</string>
|
||||
<string name="common_world_readable_history">"Cualquiera puede ver el historial"</string>
|
||||
<string name="common_you">"Tú"</string>
|
||||
<string name="crypto_identity_change_pin_violation">"Se restableció la identidad de %1$s. %2$s"</string>
|
||||
<string name="crypto_identity_change_pin_violation_new">"Se restableció la identidad de %1$s %2$s. %3$s"</string>
|
||||
<string name="content_scanner_not_found">"Descarga no disponible."</string>
|
||||
<string name="content_scanner_not_found_title">"Algo salió mal"</string>
|
||||
<string name="content_scanner_scanning">"Escaneando…"</string>
|
||||
<string name="content_scanner_unsafe_message">"Se ha desactivado la vista previa y la descarga."</string>
|
||||
<string name="content_scanner_unsafe_title">"El archivo no es seguro"</string>
|
||||
<string name="crypto_event_key_forwarded_known_profile_dialog_content">"%1$s (%2$s) compartió este mensaje ya que no estabas en la sala cuando se envió."</string>
|
||||
<string name="crypto_event_key_forwarded_unknown_profile_dialog_content">"%1$s compartió este mensaje ya que no estabas en la sala cuando se envió."</string>
|
||||
<string name="crypto_history_visible">"Esta sala se ha configurado para que los miembros nuevos puedan leer el historial. %1$s"</string>
|
||||
<string name="crypto_identity_change_pin_violation">"Se restableció la identidad digital de %1$s. %2$s"</string>
|
||||
<string name="crypto_identity_change_pin_violation_new">"Se restableció la identidad digital de %1$s %2$s. %3$s"</string>
|
||||
<string name="crypto_identity_change_pin_violation_new_user_id">"(%1$s)"</string>
|
||||
<string name="crypto_identity_change_profile_pin_violation">"Se restableció la identidad de %1$s."</string>
|
||||
<string name="crypto_identity_change_verification_violation_new">"Se restableció la identidad de %1$s %2$s. %3$s"</string>
|
||||
<string name="crypto_identity_change_profile_pin_violation">"Se restableció la identidad digital de %1$s."</string>
|
||||
<string name="crypto_identity_change_verification_violation_new">"Se restableció la identidad digital de %1$s %2$s. %3$s"</string>
|
||||
<string name="crypto_identity_change_withdraw_verification_action">"Retirar la verificación"</string>
|
||||
<string name="dialog_allow_access">"Permitir acceso"</string>
|
||||
<string name="dialog_confirm_link_message">"El enlace %1$s te está llevando a otro sitio %2$s
|
||||
|
||||
¿Estás seguro de que quieres continuar?"</string>
|
||||
<string name="dialog_confirm_link_title">"Revisa este enlace"</string>
|
||||
<string name="dialog_default_video_quality_selector_subtitle">"Selecciona la calidad por defecto de los vídeos que subas."</string>
|
||||
<string name="dialog_default_video_quality_selector_title">"Calidad de subida de vídeos"</string>
|
||||
<string name="dialog_file_too_large_to_upload_subtitle">"El tamaño máximo de archivo permitido es: %1$s"</string>
|
||||
<string name="dialog_file_too_large_to_upload_title">"El archivo es demasiado grande para ser subido"</string>
|
||||
<string name="dialog_room_reported">"Sala denunciada"</string>
|
||||
<string name="dialog_room_reported_and_left">"Denunciaste y saliste de la sala"</string>
|
||||
<string name="dialog_title_confirmation">"Confirmar"</string>
|
||||
@@ -324,6 +487,10 @@ Motivo: %1$s."</string>
|
||||
<string name="dialog_unsaved_changes_description">"Tienes cambios sin guardar."</string>
|
||||
<string name="dialog_unsaved_changes_description_android">"Tus cambios no se han guardado. ¿Estás seguro de que quieres volver atrás?"</string>
|
||||
<string name="dialog_unsaved_changes_title">"¿Guardar cambios?"</string>
|
||||
<string name="dialog_video_quality_selector_subtitle_file_size">"El tamaño máximo de archivo permitido es: %1$s"</string>
|
||||
<string name="dialog_video_quality_selector_subtitle_no_file_size">"Selecciona la calidad del vídeo que quieres subir."</string>
|
||||
<string name="dialog_video_quality_selector_title">"Selecciona la calidad de subida del vídeo"</string>
|
||||
<string name="error_account_already_logged_in">"Ya has iniciado sesión en este dispositivo como %1$s."</string>
|
||||
<string name="error_account_creation_not_possible">"Tu servidor base debe actualizarse para admitir Matrix Authentication Service y la creación de cuentas."</string>
|
||||
<string name="error_failed_creating_the_permalink">"No se pudo crear el enlace permanente"</string>
|
||||
<string name="error_failed_loading_map">"%1$s no pudo cargar el mapa. Por favor vuelve a intentarlo más tarde."</string>
|
||||
@@ -331,6 +498,7 @@ Motivo: %1$s."</string>
|
||||
<string name="error_failed_locating_user">"%1$s no ha podido acceder a tu ubicación. Por favor vuelve a intentarlo más tarde."</string>
|
||||
<string name="error_failed_uploading_voice_message">"No se pudo cargar tu mensaje de voz."</string>
|
||||
<string name="error_invalid_invite">"La sala ya no existe o la invitación ya no es válida."</string>
|
||||
<string name="error_location_service_disabled_android">"Activa el GPS para acceder a las funciones basadas en la ubicación."</string>
|
||||
<string name="error_message_not_found">"Mensaje no encontrado"</string>
|
||||
<string name="error_missing_location_auth_android">"%1$s no tiene permiso para acceder a tu ubicación. Puedes habilitar el acceso en Ajustes."</string>
|
||||
<string name="error_missing_location_rationale_android">"%1$s no tiene permiso para acceder a tu ubicación. Habilita el acceso a continuación."</string>
|
||||
@@ -342,10 +510,34 @@ Motivo: %1$s."</string>
|
||||
<string name="error_unknown">"Lo siento, se ha producido un error"</string>
|
||||
<string name="invite_friends_rich_title">"🔐️ Únete a mí en %1$s"</string>
|
||||
<string name="invite_friends_text">"Hola, puedes hablar conmigo en %1$s: %2$s"</string>
|
||||
<string name="live_location_sharing_foreground_service_channel_title_android">"Compartir la ubicación en directo"</string>
|
||||
<string name="live_location_sharing_foreground_service_message_android">"Se está compartiendo actualmente la ubicación"</string>
|
||||
<string name="live_location_sharing_foreground_service_title_android">"%1$s Ubicación en tiempo real"</string>
|
||||
<string name="login_initial_device_name_android">"%1$s Android"</string>
|
||||
<string name="preference_rageshake">"Agitar con fuerza para informar de un error"</string>
|
||||
<string name="screen_bug_report_a11y_screenshot">"Captura de pantalla"</string>
|
||||
<string name="screen_change_server_navigation_title_login">"Iniciar sesión"</string>
|
||||
<string name="screen_change_server_navigation_title_register">"Crear cuenta"</string>
|
||||
<string name="screen_change_server_textfield_footer_login">"Si tu cuenta te la proporciona tu empresa o una comunidad, cambia el proveedor de la cuenta (ejemplo: nombredeempresa.com)."</string>
|
||||
<string name="screen_change_server_textfield_footer_register">"Crea una cuenta gratuita en matrix.org. Si deseas crear una cuenta con otro proveedor, modifícala según corresponda (por ejemplo: communityname.org)."</string>
|
||||
<string name="screen_change_server_textfield_header">"Proveedor de cuentas"</string>
|
||||
<string name="screen_change_server_textfield_placeholder">"ejemplo.com"</string>
|
||||
<string name="screen_change_server_title_login">"Introduce tu proveedor de cuenta"</string>
|
||||
<string name="screen_change_server_title_register">"Elegir proveedor de cuentas"</string>
|
||||
<string name="screen_create_poll_option_accessibility_label">"%1$s: %2$s"</string>
|
||||
<string name="screen_create_poll_options_section_title">"Opciones"</string>
|
||||
<string name="screen_create_poll_remove_accessibility_label">"Eliminar %1$s"</string>
|
||||
<string name="screen_create_poll_settings_section_title">"Ajustes"</string>
|
||||
<string name="screen_create_poll_votes_allowed_per_person">"Votos permitidos por persona"</string>
|
||||
<string name="screen_live_location_sheet_nobody_sharing">"Nadie está compartiendo su ubicación"</string>
|
||||
<string name="screen_live_location_sheet_sharing_live_location">"Compartiendo ubicación en tiempo real"</string>
|
||||
<plurals name="screen_live_location_sheet_subtitle">
|
||||
<item quantity="one">"%1$d persona"</item>
|
||||
<item quantity="other">"%1$d personas"</item>
|
||||
</plurals>
|
||||
<string name="screen_live_location_sheet_title">"En el mapa"</string>
|
||||
<string name="screen_local_network_opt_in_subtitle">"Tu servidor base está en tu red local. Para conectarse, %1$s necesita permiso para acceder a los dispositivos de esta red."</string>
|
||||
<string name="screen_local_network_opt_in_title">"Permite el acceso a la red local"</string>
|
||||
<string name="screen_media_picker_error_failed_selection">"Error al seleccionar archivos multimedia, por favor inténtalo de nuevo."</string>
|
||||
<string name="screen_pinned_timeline_empty_state_description">"Presiona sobre un mensaje y selecciona «%1$s» para incluirlo aquí."</string>
|
||||
<string name="screen_pinned_timeline_empty_state_headline">"Fija los mensajes importantes para que se puedan descubrir fácilmente"</string>
|
||||
@@ -354,21 +546,23 @@ Motivo: %1$s."</string>
|
||||
<item quantity="other">"%1$d mensajes fijados"</item>
|
||||
</plurals>
|
||||
<string name="screen_pinned_timeline_screen_title_empty">"Mensajes fijados"</string>
|
||||
<string name="screen_reset_identity_confirmation_subtitle">"Estás a punto de ir a tu cuenta de %1$s para restablecer tu identidad. Posteriormente volverás a la aplicación."</string>
|
||||
<string name="screen_reset_identity_confirmation_title">"¿No puedes confirmar? Ve a tu cuenta para restablecer tu identidad."</string>
|
||||
<string name="screen_reset_identity_confirmation_subtitle">"Estás a punto de ir a tu cuenta de %1$s para restablecer tu identidad digital. Posteriormente volverás a la aplicación."</string>
|
||||
<string name="screen_reset_identity_confirmation_title">"¿No puedes confirmarla? Ve a tu cuenta para restablecer tu identidad digital."</string>
|
||||
<string name="screen_resolve_send_failure_changed_identity_primary_button_title">"Retirar la verificación y enviar"</string>
|
||||
<string name="screen_resolve_send_failure_changed_identity_subtitle">"Puedes retirar tu verificación y enviar este mensaje de todos modos, o puedes cancelarlo por ahora e intentarlo de nuevo más tarde después de volver a verificar a %1$s."</string>
|
||||
<string name="screen_resolve_send_failure_changed_identity_title">"Tu mensaje no se envió porque la identidad verificada de %1$s fue restablecida"</string>
|
||||
<string name="screen_resolve_send_failure_changed_identity_title">"Tu mensaje no se envió porque la identidad digital verificada de %1$s fue restablecida"</string>
|
||||
<string name="screen_resolve_send_failure_unsigned_device_primary_button_title">"Enviar mensaje de todos modos"</string>
|
||||
<string name="screen_resolve_send_failure_unsigned_device_subtitle">"%1$s utiliza uno o más dispositivos no verificados. Puedes enviar el mensaje de todos modos, o puedes cancelarlo por ahora y volver a intentarlo más tarde, una vez %2$s haya verificado todos sus dispositivos."</string>
|
||||
<string name="screen_resolve_send_failure_unsigned_device_title">"Tu mensaje no se envió porque %1$s no ha verificado todos los dispositivos"</string>
|
||||
<string name="screen_resolve_send_failure_you_unsigned_device_subtitle">"Uno o más de tus dispositivos no están verificados. Puedes enviar el mensaje de todos modos, o puedes cancelarlo por ahora e intentarlo de nuevo más tarde, una vez hayas verificado todos tus dispositivos."</string>
|
||||
<string name="screen_resolve_send_failure_you_unsigned_device_title">"Tu mensaje no se envió porque no has verificado uno o más de tus dispositivos"</string>
|
||||
<string name="screen_room_change_role_administrators_or_owners_title">"Editar administradores o propietarios"</string>
|
||||
<string name="screen_room_error_failed_processing_media">"Error al procesar el contenido multimedia, por favor inténtalo de nuevo."</string>
|
||||
<string name="screen_room_error_failed_retrieving_user_details">"No se pudieron recuperar los detalles del usuario"</string>
|
||||
<string name="screen_room_event_pill">"Mensaje en %1$s"</string>
|
||||
<string name="screen_room_grouped_state_events_expand">"Expandir"</string>
|
||||
<string name="screen_room_grouped_state_events_reduce">"Reducir"</string>
|
||||
<string name="screen_room_live_location_banner">"Compartiendo ubicación en tiempo real"</string>
|
||||
<string name="screen_room_permalink_same_room_android">"¡Ya estás viendo esta sala!"</string>
|
||||
<string name="screen_room_pinned_banner_indicator">"%1$s de %2$s"</string>
|
||||
<string name="screen_room_pinned_banner_indicator_description">"%1$s mensajes fijados"</string>
|
||||
@@ -380,8 +574,20 @@ Motivo: %1$s."</string>
|
||||
<string name="screen_share_open_apple_maps">"Abrir en Apple Maps"</string>
|
||||
<string name="screen_share_open_google_maps">"Abrir en Google Maps"</string>
|
||||
<string name="screen_share_open_osm_maps">"Abrir en OpenStreetMap"</string>
|
||||
<string name="screen_share_this_location_action">"Compartir esta ubicación"</string>
|
||||
<string name="screen_timeline_item_menu_send_failure_changed_identity">"Mensaje no enviado porque la identidad verificada de %1$s fue restablecida."</string>
|
||||
<string name="screen_share_this_location_action">"Compartir ubicación seleccionada"</string>
|
||||
<string name="screen_sharing_location_option_sheet_title">"Cómo compartir"</string>
|
||||
<string name="screen_space_list_description">"Espacios que has creado o a los que te has unido."</string>
|
||||
<string name="screen_space_list_details">"%1$s • %2$s"</string>
|
||||
<string name="screen_space_list_empty_state_title">"Crea espacios para organizar salas"</string>
|
||||
<string name="screen_space_list_parent_space">"Espacio %1$s"</string>
|
||||
<string name="screen_space_list_title">"Espacios"</string>
|
||||
<string name="screen_static_location_sheet_timestamp_description">"Compartida %1$s"</string>
|
||||
<string name="screen_static_location_sheet_title">"En el mapa"</string>
|
||||
<plurals name="screen_timeline_active_call_joined_count">
|
||||
<item quantity="one">"Se unió %1$d"</item>
|
||||
<item quantity="other">"Se unieron %1$d"</item>
|
||||
</plurals>
|
||||
<string name="screen_timeline_item_menu_send_failure_changed_identity">"Mensaje no enviado porque la identidad digital verificada de %1$s fue restablecida."</string>
|
||||
<string name="screen_timeline_item_menu_send_failure_unsigned_device">"Mensaje no enviado porque %1$s no ha verificado todos los dispositivos."</string>
|
||||
<string name="screen_timeline_item_menu_send_failure_you_unsigned_device">"Mensaje no enviado porque no has verificado uno o más de tus dispositivos."</string>
|
||||
<string name="screen_view_location_title">"Ubicación"</string>
|
||||
@@ -391,5 +597,7 @@ Motivo: %1$s."</string>
|
||||
<string name="timeline_decryption_failure_historical_event_unverified_device">"Debes verificar este dispositivo para acceder a los mensajes históricos"</string>
|
||||
<string name="timeline_decryption_failure_historical_event_user_not_joined">"No tienes acceso a este mensaje"</string>
|
||||
<string name="timeline_decryption_failure_unable_to_decrypt">"No se ha podido descifrar el mensaje"</string>
|
||||
<string name="timeline_decryption_failure_withheld_unverified">"Este mensaje fue bloqueado bien sea porque no verificaste tu dispositivo o porque el remitente necesita verificar tu identidad."</string>
|
||||
<string name="timeline_decryption_failure_withheld_unverified">"Este mensaje fue bloqueado bien sea porque no verificaste tu dispositivo o porque el remitente necesita verificar tu identidad digital."</string>
|
||||
<string name="vulkan_not_supported_dialog_content_android">"Tu dispositivo es demasiado antiguo; necesitas un dispositivo con Android 8 o posterior."</string>
|
||||
<string name="vulkan_not_supported_dialog_title_android">"No se admite el renderizado de mapas"</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,18 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="a11y_add_avatar">"اضافه کردن آواتار"</string>
|
||||
<string name="a11y_add_reaction">"افزودن واکنش: %1$s"</string>
|
||||
<string name="a11y_address">"آدرس"</string>
|
||||
<string name="a11y_avatar">"چهرک"</string>
|
||||
<string name="a11y_clear_search_field">"پاک کردن فیلد جستجو"</string>
|
||||
<string name="a11y_collapse_message_text_field">"کوچک کردن فیلد متن پیام"</string>
|
||||
<string name="a11y_create_poll_votes_allowed_decrease">"کاهش آرای مجاز برای هر نفر"</string>
|
||||
<string name="a11y_create_poll_votes_allowed_increase">"افزایش تعداد آرای مجاز برای هر نفر"</string>
|
||||
<string name="a11y_custom_emoji">"ایموجیهای سفارشی"</string>
|
||||
<string name="a11y_delete">"حذف"</string>
|
||||
<plurals name="a11y_digits_entered">
|
||||
<item quantity="one">"%1$d رقم وارد شده"</item>
|
||||
<item quantity="other">"%1$d رقم وارد شده"</item>
|
||||
</plurals>
|
||||
<string name="a11y_duration">"مدت زمان: %1$s"</string>
|
||||
<string name="a11y_edit_avatar">"ویرایش چهرک"</string>
|
||||
<string name="a11y_edit_room_address_hint">"نشانی کامل %1$s خواهد بود"</string>
|
||||
<string name="a11y_encryption_details">"جزییات رمزنگاری"</string>
|
||||
<string name="a11y_expand_message_text_field">"فیلد متن پیام را گسترش دهید"</string>
|
||||
<string name="a11y_hide_password">"نهفتن گذرواژه"</string>
|
||||
<string name="a11y_info">"اطلاعات"</string>
|
||||
<string name="a11y_join_call">"پیوستن به تماس"</string>
|
||||
<string name="a11y_jump_to_bottom">"به پایین بروید"</string>
|
||||
<string name="a11y_jump_to_unread">"پرش به خوانده نشده"</string>
|
||||
<string name="a11y_jump_to_unread_messages">"پرش به اولین پیام خوانده نشده"</string>
|
||||
<string name="a11y_move_the_map_to_my_location">"جابهجایی نقشه به مکانم"</string>
|
||||
<string name="a11y_notifications_mentions_only">"فقط اشارهها"</string>
|
||||
<string name="a11y_notifications_muted">"خموش"</string>
|
||||
@@ -23,10 +35,15 @@
|
||||
<string name="a11y_page_n">"صفحهٔ %1$d"</string>
|
||||
<string name="a11y_pause">"مکث"</string>
|
||||
<string name="a11y_paused_voice_message">"پیام صوتی. طول %1$s. موقعیت کنونی: %2$s"</string>
|
||||
<string name="a11y_photo_preview">"پیشنمایش عکس"</string>
|
||||
<string name="a11y_pin_field">"زمینهٔ پین"</string>
|
||||
<string name="a11y_pinned_location">"مکان پین شده"</string>
|
||||
<string name="a11y_play">"پخش"</string>
|
||||
<string name="a11y_playback_speed">"سرعت پخش"</string>
|
||||
<string name="a11y_poll">"نظرسنجی"</string>
|
||||
<string name="a11y_poll_end">"نظرسنجی پایان یافته"</string>
|
||||
<string name="a11y_position">"موقعیت: %1$s"</string>
|
||||
<string name="a11y_qr_code">"کد QR"</string>
|
||||
<string name="a11y_react_with">"واکنش با %1$s"</string>
|
||||
<string name="a11y_react_with_other_emojis">"واکنش با شکلکهای دیگر"</string>
|
||||
<string name="a11y_read_receipts_multiple">"پیام پیشین به دست %1$s و %2$s خوانده شد"</string>
|
||||
@@ -35,15 +52,26 @@
|
||||
<item quantity="other">"پیام پیشین به دست %1$s و %2$d دیگر خوانده شد"</item>
|
||||
</plurals>
|
||||
<string name="a11y_read_receipts_single">"پیام قبلی به دست %1$s خوانده شد"</string>
|
||||
<string name="a11y_read_receipts_tap_to_show_all_android">"نمایش همه رسیدهای خوانده شده"</string>
|
||||
<string name="a11y_remove_reaction">"برداشتن واکنش با %1$s"</string>
|
||||
<string name="a11y_remove_reaction_with">"برداشتن واکنش با %1$s"</string>
|
||||
<string name="a11y_room_avatar">"چهرک اتاق"</string>
|
||||
<string name="a11y_send_files">"ارسال پروندهها"</string>
|
||||
<string name="a11y_session_verification_time_limited_action_required">"نیازمند کنش محدود به زمان"</string>
|
||||
<string name="a11y_sender_location">"مکان فرستنده"</string>
|
||||
<string name="a11y_sent_by_sender_at_date">"ارسال شده توسط %1$s در %2$s"</string>
|
||||
<string name="a11y_session_verification_time_limited_action_required">"اقدام مورد نیاز با محدودیت زمانی، شما یک دقیقه برای تأیید فرصت دارید"</string>
|
||||
<string name="a11y_settings_with_required_action">"تنظیمات، اقدام مورد نیاز"</string>
|
||||
<string name="a11y_show_password">"نمایش گذرواژه"</string>
|
||||
<string name="a11y_start_call">"آغاز یک تماس"</string>
|
||||
<string name="a11y_start_video_call">"شروع تماس ویدیویی"</string>
|
||||
<string name="a11y_start_voice_call">"شروع تماس صوتی"</string>
|
||||
<string name="a11y_status">"وضعیت"</string>
|
||||
<string name="a11y_thread_in_room">"رزوه در %1$s"</string>
|
||||
<string name="a11y_threads_in_room">"موضوعات در %1$s"</string>
|
||||
<string name="a11y_tombstoned_room">"اتاق سنگ قبر"</string>
|
||||
<string name="a11y_user_avatar">"چهرک کاربر"</string>
|
||||
<string name="a11y_user_menu">"فهرست کاربر"</string>
|
||||
<string name="a11y_video_preview">"پیشنمایش ویدیو"</string>
|
||||
<string name="a11y_view_avatar">"دیدن چهرک"</string>
|
||||
<string name="a11y_view_details">"دیدن جزییات"</string>
|
||||
<string name="a11y_voice_message">"پیام صوتی. طول %1$s"</string>
|
||||
@@ -52,11 +80,13 @@
|
||||
<string name="a11y_your_avatar">"چهرکتان"</string>
|
||||
<string name="action_accept">"پذیرش"</string>
|
||||
<string name="action_add_caption">"افزودن عنوان"</string>
|
||||
<string name="action_add_existing_rooms">"افزودن اتاقهای موجود"</string>
|
||||
<string name="action_add_to_timeline">"افزودن به خط زمانی"</string>
|
||||
<string name="action_back">"بازگشت"</string>
|
||||
<string name="action_call">"تماس"</string>
|
||||
<string name="action_cancel">"لغو"</string>
|
||||
<string name="action_cancel_for_now">"لغو برای امنون"</string>
|
||||
<string name="action_choose_file">"انتخاب فایل"</string>
|
||||
<string name="action_choose_photo">"گزینش عکس"</string>
|
||||
<string name="action_clear">"پاک سازی"</string>
|
||||
<string name="action_close">"بستن"</string>
|
||||
@@ -71,26 +101,34 @@
|
||||
<string name="action_copy_text">"رونوشت از متن"</string>
|
||||
<string name="action_create">"ایجاد"</string>
|
||||
<string name="action_create_room">"ایجاد اتاق"</string>
|
||||
<string name="action_create_space">"ایجاد فضا"</string>
|
||||
<string name="action_deactivate">"غیرفعّال"</string>
|
||||
<string name="action_deactivate_account">"غیرفعّالسازی حساب"</string>
|
||||
<string name="action_decline">"رد"</string>
|
||||
<string name="action_decline_and_block">"رد و انسداد"</string>
|
||||
<string name="action_delete">"پاککردن"</string>
|
||||
<string name="action_delete_account">"حذف حساب کاربری"</string>
|
||||
<string name="action_delete_file">"حذف فایل"</string>
|
||||
<string name="action_delete_poll">"حذف نظرسنجی"</string>
|
||||
<string name="action_deselect_all">"ناگزینش همه"</string>
|
||||
<string name="action_disable">"از کار انداختن"</string>
|
||||
<string name="action_discard">"دور ریختن"</string>
|
||||
<string name="action_dismiss">"دورانداختن"</string>
|
||||
<string name="action_done">"انجام شد"</string>
|
||||
<string name="action_download">"دانلود"</string>
|
||||
<string name="action_edit">"ویرایش"</string>
|
||||
<string name="action_edit_caption">"ویرایش عنوان"</string>
|
||||
<string name="action_edit_poll">"ویرایش نظرسنجی"</string>
|
||||
<string name="action_enable">"به کار انداختن"</string>
|
||||
<string name="action_end_poll">"پایان نظرسنجی"</string>
|
||||
<string name="action_enter_pin">"ورود پین"</string>
|
||||
<string name="action_explore_public_spaces">"کاوش در فضاهای عمومی"</string>
|
||||
<string name="action_finish">"پایان"</string>
|
||||
<string name="action_forgot_password">"گذرواژه را فراموش کردید؟"</string>
|
||||
<string name="action_forward">"پیشروی"</string>
|
||||
<string name="action_go_back">"پسروی"</string>
|
||||
<string name="action_go_to_roles_and_permissions">"به نقشها و مجوزها بروید"</string>
|
||||
<string name="action_go_to_settings">"به تنظیمات بروید"</string>
|
||||
<string name="action_ignore">"نادیدهگرفتن"</string>
|
||||
<string name="action_invite">"دعوت"</string>
|
||||
<string name="action_invite_friends">"دعوت افراد"</string>
|
||||
@@ -105,8 +143,12 @@
|
||||
<string name="action_leave_space">"ترک فضا"</string>
|
||||
<string name="action_load_more">"بار کردن بیشتر"</string>
|
||||
<string name="action_manage_account">"مدیریت حساب"</string>
|
||||
<string name="action_manage_account_and_devices">"مدیریت حساب و دستگاهها"</string>
|
||||
<string name="action_manage_devices">"مدیریت افزارهها"</string>
|
||||
<string name="action_manage_rooms">"مدیریت اتاقها"</string>
|
||||
<string name="action_mark_as_read">"علامتگذاری به عنوان خوانده شده"</string>
|
||||
<string name="action_message">"پیام"</string>
|
||||
<string name="action_minimize">"کوچک کردن"</string>
|
||||
<string name="action_next">"بعدی"</string>
|
||||
<string name="action_no">"نه"</string>
|
||||
<string name="action_not_now">"الآن نه"</string>
|
||||
@@ -120,8 +162,8 @@
|
||||
<string name="action_react">"واکنش"</string>
|
||||
<string name="action_reject">"رد کردن"</string>
|
||||
<string name="action_remove">"حذف"</string>
|
||||
<string name="action_remove_caption">"برداشتن عنوان"</string>
|
||||
<string name="action_remove_message">"برداشتن پیامها"</string>
|
||||
<string name="action_remove_caption">"حذف عنوان"</string>
|
||||
<string name="action_remove_message">"حذف پیام"</string>
|
||||
<string name="action_reply">"پاسخ"</string>
|
||||
<string name="action_reply_in_thread">"پاسخ در رشته"</string>
|
||||
<string name="action_report">"گزارش"</string>
|
||||
@@ -142,25 +184,31 @@
|
||||
<string name="action_send_voice_message">"فرستادن پیام صوتی"</string>
|
||||
<string name="action_share">"همرسانی"</string>
|
||||
<string name="action_share_link">"همرسانی پیوند"</string>
|
||||
<string name="action_share_live_location">"اشتراک گذاری موقعیت مکانی زنده"</string>
|
||||
<string name="action_show">"نمایش"</string>
|
||||
<string name="action_sign_in_again">"ورود دوباره"</string>
|
||||
<string name="action_signout">"برداشتن این افزاره"</string>
|
||||
<string name="action_signout_anyway">"به هر حال این دستگاه را حذف کنید"</string>
|
||||
<string name="action_skip">"پرش"</string>
|
||||
<string name="action_skip">"رد شدن"</string>
|
||||
<string name="action_start">"آغاز"</string>
|
||||
<string name="action_start_chat">"آغاز گپ"</string>
|
||||
<string name="action_start_over">"آغاز از نو"</string>
|
||||
<string name="action_start_verification">"آغاز تأیید"</string>
|
||||
<string name="action_static_map_load">"زدن برای بار کردن نقشه"</string>
|
||||
<string name="action_stop">"توقف"</string>
|
||||
<string name="action_take_photo">"عکس گرفتن"</string>
|
||||
<string name="action_tap_for_options">"زدن برای گزینهها"</string>
|
||||
<string name="action_translate">"ترجمه"</string>
|
||||
<string name="action_try_again">"تلاش دوباره"</string>
|
||||
<string name="action_unpin">"سنجاق نکردن"</string>
|
||||
<string name="action_video_call">"تماس تصویری"</string>
|
||||
<string name="action_view">"نما"</string>
|
||||
<string name="action_view_in_timeline">"دیدن در خط زمانی"</string>
|
||||
<string name="action_view_source">"دیدن منبع"</string>
|
||||
<string name="action_voice_call">"تماس صوتی"</string>
|
||||
<string name="action_yes">"بله"</string>
|
||||
<string name="action_yes_try_again">"بله. تلاش دوباره"</string>
|
||||
<string name="banner_migrate_to_native_sliding_sync_description">"سرور شما اکنون از یک پروتکل جدید و سریعتر پشتیبانی میکند. برای ارتقا، از سیستم خارج شوید و دوباره وارد شوید. انجام این کار در حال حاضر به شما کمک میکند تا از خروج اجباری هنگام حذف پروتکل قدیمی در آینده جلوگیری کنید."</string>
|
||||
<string name="banner_migrate_to_native_sliding_sync_title">"ارتقا موجود است"</string>
|
||||
<string name="common_about">"درباره"</string>
|
||||
<string name="common_acceptable_use_policy">"سیاست استفادهٔ پذیرفتنی"</string>
|
||||
@@ -168,18 +216,24 @@
|
||||
<string name="common_add_another_account">"افزودن حسابی دیگر"</string>
|
||||
<string name="common_adding_caption">"افزودن عنوان"</string>
|
||||
<string name="common_advanced_settings">"تنظیمات پیشرفته"</string>
|
||||
<string name="common_an_image">"یک تصویر"</string>
|
||||
<string name="common_analytics">"تجزیه و تحلیل"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_left_room">"اتاق را ترک کردید"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_session_logged_out">"شما از جلسه خارج شدید"</string>
|
||||
<string name="common_appearance">"ظاهر"</string>
|
||||
<string name="common_audio">"صدا"</string>
|
||||
<string name="common_beta">"آزمایشی"</string>
|
||||
<string name="common_blocked_users">"کاربران مسدود"</string>
|
||||
<string name="common_bubbles">"حبابها"</string>
|
||||
<string name="common_call_declined">"تماس رد شد"</string>
|
||||
<string name="common_call_in_progress">"تماس در جریان است"</string>
|
||||
<string name="common_call_started">"تماس آغاز شد"</string>
|
||||
<string name="common_call_you_declined">"شما یک تماس را رد کردید"</string>
|
||||
<string name="common_chat_backup">"پشتیبان گپ"</string>
|
||||
<string name="common_copied_to_clipboard">"در تختهگیره رونوشت شد"</string>
|
||||
<string name="common_copyright">"حق رونوشت"</string>
|
||||
<string name="common_creating_room">"ایجاد کردن اتاق…"</string>
|
||||
<string name="common_creating_space">"ایجاد فضای…"</string>
|
||||
<string name="common_current_user_canceled_knock">"درخواست لغو شد"</string>
|
||||
<string name="common_current_user_left_room">"اتاق را ترک کرد"</string>
|
||||
<string name="common_current_user_left_space">"فضا را ترک کرد"</string>
|
||||
@@ -199,19 +253,34 @@
|
||||
<string name="common_empty_file">"پروندهٔ خالی"</string>
|
||||
<string name="common_encryption">"رمزنگاری"</string>
|
||||
<string name="common_encryption_enabled">"رمزنگاری به کار افتاده"</string>
|
||||
<string name="common_ends_at">"در %1$s پایان مییابد"</string>
|
||||
<string name="common_enter_your_pin">"پینتان را وارد کنید"</string>
|
||||
<string name="common_error">"خطا"</string>
|
||||
<string name="common_error_registering_pusher_android">"خطایی رخ داده است، ممکن است اعلانهای مربوط به پیامهای جدید را دریافت نکنید. لطفاً اعلانها را از تنظیمات عیبیابی کنید.
|
||||
|
||||
دلیل: %1$s."</string>
|
||||
<string name="common_everyone">"هرکسی"</string>
|
||||
<string name="common_failed">"شکست خورد"</string>
|
||||
<string name="common_favourite">"برگزیده"</string>
|
||||
<string name="common_favourited">"برگزیده"</string>
|
||||
<string name="common_fetching_notifications_title_android">"همگامسازی اعلانها…"</string>
|
||||
<string name="common_file">"پرونده"</string>
|
||||
<string name="common_file_deleted">"پرونده حذف شد"</string>
|
||||
<string name="common_file_saved">"پرونده ذخیره شد"</string>
|
||||
<string name="common_file_saved_on_disk_android">"پرونده در بارگیریها ذخیره شد"</string>
|
||||
<string name="common_forward_message">"هدایت پیام"</string>
|
||||
<string name="common_frequently_used">"پراستفاده"</string>
|
||||
<string name="common_gallery">"گالری"</string>
|
||||
<plurals name="common_gallery_reply_attachments">
|
||||
<item quantity="one">"پیوست %1$d…"</item>
|
||||
<item quantity="other">"پیوستهای %1$d…"</item>
|
||||
</plurals>
|
||||
<plurals name="common_gallery_reply_media_items">
|
||||
<item quantity="one">"مورد رسانهای %1$d…"</item>
|
||||
<item quantity="other">"موارد رسانهای %1$d…"</item>
|
||||
</plurals>
|
||||
<string name="common_gif">"جیف"</string>
|
||||
<string name="common_group_call_in_progress">"تماس گروهی در جریان است"</string>
|
||||
<string name="common_image">"تصویر"</string>
|
||||
<string name="common_in_reply_to">"در پاسخ به %1$s"</string>
|
||||
<string name="common_install_apk_android">"نصب APK"</string>
|
||||
@@ -220,6 +289,9 @@
|
||||
<string name="common_leaving_space">"ترک کردن فضا"</string>
|
||||
<string name="common_line_copied_to_clipboard">"خط در تختهگیره رونوشت شد"</string>
|
||||
<string name="common_link_copied_to_clipboard">"پیوند در تختهگیره رونوشت شد"</string>
|
||||
<string name="common_link_new_device">"اتصال دستگاه جدید"</string>
|
||||
<string name="common_live_location">"مکان زنده"</string>
|
||||
<string name="common_live_location_ended">"مکان زنده به پایان رسید"</string>
|
||||
<string name="common_loading">"بار کردن…"</string>
|
||||
<string name="common_loading_more">"بار کردن بیشتر…"</string>
|
||||
<plurals name="common_many_members">
|
||||
@@ -232,18 +304,22 @@
|
||||
</plurals>
|
||||
<string name="common_message">"پیام"</string>
|
||||
<string name="common_message_actions">"کنشهای پیام"</string>
|
||||
<string name="common_message_failed_to_send">"پیام ارسال نشد"</string>
|
||||
<string name="common_message_layout">"جینش پیام"</string>
|
||||
<string name="common_message_removed">"پیام برداشته شد"</string>
|
||||
<string name="common_modern">"نوین"</string>
|
||||
<string name="common_mute">"بیصدا"</string>
|
||||
<string name="common_name">"نام"</string>
|
||||
<string name="common_name_and_id">"%1$s (%2$s)"</string>
|
||||
<string name="common_no_results">"بدون نتیجه"</string>
|
||||
<string name="common_no_room_name">"بدون نام اتاق"</string>
|
||||
<string name="common_no_space_name">"بدون نام فضا"</string>
|
||||
<string name="common_not_encrypted">"رمزنگاری نشده"</string>
|
||||
<string name="common_offline">"برونخط"</string>
|
||||
<string name="common_on_a_call">"در یک تماس"</string>
|
||||
<string name="common_open_source_licenses">"پروانههای نرمافزاری آزاد"</string>
|
||||
<string name="common_or">"یا"</string>
|
||||
<string name="common_other_options">"گزینههای دیگر"</string>
|
||||
<string name="common_password">"گذرواژه"</string>
|
||||
<string name="common_people">"افراد"</string>
|
||||
<string name="common_permalink">"پایاپیوند"</string>
|
||||
@@ -253,6 +329,7 @@
|
||||
<string name="common_please_wait">"لطفا صبر کنید…"</string>
|
||||
<string name="common_poll_end_confirmation">"مطئنید که میخواهید این نظرسنجی را پایان دهید؟"</string>
|
||||
<string name="common_poll_summary">"نظرسنجی: %1$s"</string>
|
||||
<string name="common_poll_summary_prefix">"نظرسنجی"</string>
|
||||
<string name="common_poll_total_votes">"مجموع آرا: %1$s"</string>
|
||||
<string name="common_poll_undisclosed_text">"نتیجهها پس از پایان نظرسنجی نشان داده خواهند شد"</string>
|
||||
<plurals name="common_poll_votes_count">
|
||||
@@ -261,8 +338,10 @@
|
||||
</plurals>
|
||||
<string name="common_preparing">"آماده سازی…"</string>
|
||||
<string name="common_privacy_policy">"سیاست محرمانگی"</string>
|
||||
<string name="common_private">"خصوصی"</string>
|
||||
<string name="common_private_room">"اتاق خصوصی"</string>
|
||||
<string name="common_private_space">"فضای خصوصی"</string>
|
||||
<string name="common_public">"عمومی"</string>
|
||||
<string name="common_public_room">"اتاق عمومی"</string>
|
||||
<string name="common_public_space">"فضای عمومی"</string>
|
||||
<string name="common_reaction">"واکنش"</string>
|
||||
@@ -270,13 +349,23 @@
|
||||
<string name="common_reason">"دلیل"</string>
|
||||
<string name="common_recovery_key">"کلید بازیابی"</string>
|
||||
<string name="common_refreshing">"تازه سازی…"</string>
|
||||
<string name="common_removing">"در حال حذف…"</string>
|
||||
<plurals name="common_replies">
|
||||
<item quantity="one">"پاسخ %1$d"</item>
|
||||
<item quantity="other">"پاسخهای %1$d"</item>
|
||||
</plurals>
|
||||
<string name="common_replying_to">"پاسخ دادن به %1$s"</string>
|
||||
<string name="common_report_a_problem">"گزارش مشکل"</string>
|
||||
<string name="common_report_submitted">"گزارش ثبت شد"</string>
|
||||
<string name="common_rich_text_editor">"ویرایشگر متن غنی"</string>
|
||||
<string name="common_role">"نقش"</string>
|
||||
<string name="common_room">"اتاق"</string>
|
||||
<string name="common_room_name">"نام اتاق"</string>
|
||||
<string name="common_room_name_placeholder">"برای نمونه نام پروژهتان"</string>
|
||||
<plurals name="common_rooms">
|
||||
<item quantity="one">"اتاق %1$d"</item>
|
||||
<item quantity="other">"اتاقهای %1$d"</item>
|
||||
</plurals>
|
||||
<string name="common_saved_changes">"تغییرات ذخیره شده"</string>
|
||||
<string name="common_saving">"ذخیره کردن"</string>
|
||||
<string name="common_screen_lock">"قفل صفحه"</string>
|
||||
@@ -285,6 +374,10 @@
|
||||
<string name="common_security">"امنیت"</string>
|
||||
<string name="common_seen_by">"دیده شده به دست"</string>
|
||||
<string name="common_select_account">"گزینش حساب"</string>
|
||||
<plurals name="common_selected_count">
|
||||
<item quantity="one">"%1$d انتخاب شد"</item>
|
||||
<item quantity="other">"%1$d انتخاب شد"</item>
|
||||
</plurals>
|
||||
<string name="common_send_to">"فرستادن به"</string>
|
||||
<string name="common_sending">"فرستادن…"</string>
|
||||
<string name="common_sending_failed">"فرستادن شکست خورد"</string>
|
||||
@@ -295,29 +388,43 @@
|
||||
<string name="common_server_url">"نشانی کارساز"</string>
|
||||
<string name="common_settings">"تنظیمات"</string>
|
||||
<string name="common_share_space">"همرسانی فضا"</string>
|
||||
<string name="common_shared_history">"اعضای جدید تاریخچه را میبینند"</string>
|
||||
<string name="common_shared_live_location">"مکان زنده به اشتراکگذاری شده"</string>
|
||||
<string name="common_shared_location">"مکان همرسانده"</string>
|
||||
<string name="common_shared_space">"فضای اشتراکی"</string>
|
||||
<string name="common_signing_out">"خارج شدن"</string>
|
||||
<string name="common_something_went_wrong">"چیزی اشتباه پیش رفت"</string>
|
||||
<string name="common_something_went_wrong_message">"با مشکلی مواجه شدیم. لطفا دوباره امتحان کنید."</string>
|
||||
<string name="common_space">"فاصله"</string>
|
||||
<string name="common_space_members">"اعضای فضا"</string>
|
||||
<string name="common_space_topic_placeholder">"این فضا مربوط به چیست؟"</string>
|
||||
<plurals name="common_spaces">
|
||||
<item quantity="one">"فضای %1$d"</item>
|
||||
<item quantity="other">"فضاهای %1$d"</item>
|
||||
</plurals>
|
||||
<string name="common_starting_chat">"آغازیدن گپ…"</string>
|
||||
<string name="common_sticker">"عکس برگردان"</string>
|
||||
<string name="common_success">"موفّقیت"</string>
|
||||
<string name="common_suggested">"پیشنهادی"</string>
|
||||
<string name="common_suggestions">"پیشنهادها"</string>
|
||||
<string name="common_syncing">"همگام ساختن"</string>
|
||||
<string name="common_text">"متن"</string>
|
||||
<string name="common_third_party_notices">"تذکّرهای سومشخص"</string>
|
||||
<string name="common_thread">"رشته"</string>
|
||||
<string name="common_threads">"موضوعات"</string>
|
||||
<string name="common_topic">"موضوع"</string>
|
||||
<string name="common_topic_placeholder">"این اتاق دربارهٔ چیست؟"</string>
|
||||
<string name="common_unable_to_decrypt">"ناتوان در رمزگشایی"</string>
|
||||
<string name="common_unable_to_decrypt_insecure_device">"ارسال شده از یک دستگاه ناامن"</string>
|
||||
<string name="common_unable_to_decrypt_no_access">"به این پیام دسترسی ندارید"</string>
|
||||
<string name="common_unable_to_decrypt_verification_violation">"هویت دیجیتال تأیید شده فرستنده بازنشانی شد"</string>
|
||||
<string name="common_unable_to_invite_message">"دعوتها نتوانستند به کاربرانی برسند."</string>
|
||||
<string name="common_unable_to_invite_title">"ناتوان در فرستادن دعوت(ها)"</string>
|
||||
<string name="common_unlock">"قفلگشایی"</string>
|
||||
<string name="common_unmute">"باصدا"</string>
|
||||
<string name="common_unsupported_call">"تماس پشتیبانی نشده"</string>
|
||||
<string name="common_unsupported_event">"رویداد پشتیبانی نشده"</string>
|
||||
<string name="common_user_started_a_call">"%1$s یک تماس را آغاز کرد"</string>
|
||||
<string name="common_username">"نام کاربری"</string>
|
||||
<string name="common_verification_cancelled">"تأیید لغو شد"</string>
|
||||
<string name="common_verification_complete">"تأیید کامل شد"</string>
|
||||
@@ -328,17 +435,40 @@
|
||||
<string name="common_verify_user">"تأیید کاربر"</string>
|
||||
<string name="common_video">"ویدیو"</string>
|
||||
<string name="common_video_quality_high">"کیفیت بالا"</string>
|
||||
<string name="common_video_quality_high_description">"بهترین کیفیت اما حجم فایل بیشتر"</string>
|
||||
<string name="common_video_quality_low">"کیفیت پایین"</string>
|
||||
<string name="common_video_quality_low_description">"سریعترین سرعت آپلود و کمترین حجم فایل"</string>
|
||||
<string name="common_video_quality_standard">"کیفیت استاندارد"</string>
|
||||
<string name="common_video_quality_standard_description">"تعادل بین کیفیت و سرعت آپلود"</string>
|
||||
<string name="common_voice_message">"پیام صوتی"</string>
|
||||
<string name="common_waiting">"در انتظار…"</string>
|
||||
<string name="common_waiting_for_decryption_key">"در انتظار این پیام"</string>
|
||||
<string name="common_waiting_live_location">"در انتظار موقعیت مکانی زنده…"</string>
|
||||
<string name="common_world_readable_history">"هر کسی میتواند تاریخچه را ببیند"</string>
|
||||
<string name="common_you">"شما"</string>
|
||||
<string name="crypto_identity_change_pin_violation">"هویت %1$s بازنشانی شد. %2$s"</string>
|
||||
<string name="content_scanner_not_found">"دانلود در دسترس نیست."</string>
|
||||
<string name="content_scanner_not_found_title">"چیزی اشتباه پیش رفت"</string>
|
||||
<string name="content_scanner_scanning">"اسکن…"</string>
|
||||
<string name="content_scanner_unsafe_message">"پیشنمایش و دانلود غیرفعال شدهاند."</string>
|
||||
<string name="content_scanner_unsafe_title">"فایل امن نیست"</string>
|
||||
<string name="crypto_event_key_forwarded_known_profile_dialog_content">"%1$s (%2$s) این پیام را به اشتراک گذاشته است زیرا شما هنگام ارسال آن در اتاق حضور نداشتید."</string>
|
||||
<string name="crypto_event_key_forwarded_unknown_profile_dialog_content">"%1$s این پیام را به اشتراک گذاشت زیرا شما هنگام ارسال آن در اتاق نبودید."</string>
|
||||
<string name="crypto_history_visible">"این اتاق طوری پیکربندی شده است که اعضای جدید بتوانند تاریخچه را بخوانند. %1$s"</string>
|
||||
<string name="crypto_identity_change_pin_violation">"هویت دیجیتال %1$s بازنشانی شد. %2$s"</string>
|
||||
<string name="crypto_identity_change_pin_violation_new">"هویت دیجیتال %2$s مربوط به %1$s بازنشانی شد. %3$s"</string>
|
||||
<string name="crypto_identity_change_pin_violation_new_user_id">"(%1$s)"</string>
|
||||
<string name="crypto_identity_change_profile_pin_violation">"هویت دیجیتال %1$s بازنشانی شد."</string>
|
||||
<string name="crypto_identity_change_verification_violation_new">"هویت دیجیتال %2$s مربوط به %1$s بازنشانی شد. %3$s"</string>
|
||||
<string name="crypto_identity_change_withdraw_verification_action">"انصراف از تأیید"</string>
|
||||
<string name="dialog_allow_access">"اجازه دسترسی"</string>
|
||||
<string name="dialog_confirm_link_message">"لینک %1$s شما را به سایت دیگری هدایت میکند %2$s
|
||||
|
||||
آیا مطمئنید که میخواهید ادامه دهید؟"</string>
|
||||
<string name="dialog_confirm_link_title">"این پیوند را دوباره بررسی کنید"</string>
|
||||
<string name="dialog_default_video_quality_selector_subtitle">"کیفیت پیشفرض ویدیوهایی که آپلود میکنید را انتخاب کنید."</string>
|
||||
<string name="dialog_default_video_quality_selector_title">"کیفیت بارگذاری ویدیو"</string>
|
||||
<string name="dialog_file_too_large_to_upload_subtitle">"حداکثر اندازه فایل مجاز: %1$s"</string>
|
||||
<string name="dialog_file_too_large_to_upload_title">"حجم فایل برای آپلود بسیار زیاد است"</string>
|
||||
<string name="dialog_room_reported">"اتاق گزارش شد"</string>
|
||||
<string name="dialog_room_reported_and_left">"گزارش و از اتاق خارج شد"</string>
|
||||
<string name="dialog_title_confirmation">"تایید"</string>
|
||||
@@ -348,35 +478,75 @@
|
||||
<string name="dialog_unsaved_changes_description">"تغییراتی ذخیره نشده دارید."</string>
|
||||
<string name="dialog_unsaved_changes_description_android">"تغییراتتان ذخیره نشدهاند. مطمئنید که میخواهید برگردید؟"</string>
|
||||
<string name="dialog_unsaved_changes_title">"ذخیرهٔ تغییرات؟"</string>
|
||||
<string name="dialog_video_quality_selector_subtitle_file_size">"حداکثر اندازه فایل مجاز: %1$s"</string>
|
||||
<string name="dialog_video_quality_selector_subtitle_no_file_size">"کیفیت ویدیویی که میخواهید آپلود کنید را انتخاب کنید."</string>
|
||||
<string name="dialog_video_quality_selector_title">"کیفیت آپلود ویدیو را انتخاب کنید"</string>
|
||||
<string name="error_account_already_logged_in">"شما قبلاً با نام کاربری %1$s در این دستگاه وارد سیستم شدهاید."</string>
|
||||
<string name="error_account_creation_not_possible">"سرور خانگی شما باید ارتقا یابد تا از سرویس احراز هویت ماتریکس و ایجاد حساب کاربری پشتیبانی کند."</string>
|
||||
<string name="error_failed_creating_the_permalink">"شکست در ایجاد پایاپیوند"</string>
|
||||
<string name="error_failed_loading_map">"%1$s نتوانست نقشه را بارگیری کند. لطفا بعدا دوباره امتحان کنید."</string>
|
||||
<string name="error_failed_loading_messages">"شکست در بار کردن پیامها"</string>
|
||||
<string name="error_failed_locating_user">"%1$s نمی تواند به مکانتان دسنترسی داشته باشد. لطفا بعدا دوباره امتحان کنید."</string>
|
||||
<string name="error_failed_uploading_voice_message">"شکست در بارگذاری پیام صوتیتان."</string>
|
||||
<string name="error_invalid_invite">"اتاق دیگر وجود ندارد یا دعوتنامه دیگر معتبر نیست."</string>
|
||||
<string name="error_location_service_disabled_android">"برای دسترسی به ویژگیهای مبتنی بر موقعیت مکانی، لطفاً GPS خود را فعال کنید."</string>
|
||||
<string name="error_message_not_found">"پیام پیدا نشد"</string>
|
||||
<string name="error_missing_location_auth_android">"%1$s اجازهٔ دسترسی به مکانتان را ندارد. می توانید دسترسی را در تنظیمات به کار بیندازید."</string>
|
||||
<string name="error_missing_location_rationale_android">"%1$s اجازهٔ دسترسی به مکانتان را ندارد. دسترسی را در زیر به کار بیندازید."</string>
|
||||
<string name="error_missing_microphone_voice_rationale_android">"%1$s اجازه دسترسی به میکروفون شما را ندارد. دسترسی را برای ضبط پیام صوتی فعال کنید."</string>
|
||||
<string name="error_network_or_server_issue">"این مشکل ممکن است به دلیل مشکلات شبکه یا سرور باشد."</string>
|
||||
<string name="error_room_address_already_exists">"این آدرس اتاق از قبل وجود دارد. لطفاً فیلد آدرس اتاق را ویرایش کنید یا نام اتاق را تغییر دهید."</string>
|
||||
<string name="error_room_address_invalid_symbols">"بعضی از کاراکترها مجاز نیستند. فقط حروف، ارقام و نمادهای زیر پشتیبانی میشوند! $ &amp; ' ( ) * + / ; = ? @ [ ] - . _"</string>
|
||||
<string name="error_some_messages_have_not_been_sent">"برخی پیامها ارسال نشدهاند"</string>
|
||||
<string name="error_unknown">"متأسفیم ، خطایی رخ داد"</string>
|
||||
<string name="invite_friends_rich_title">"🔐️ پییوستن به من روی %1$s"</string>
|
||||
<string name="invite_friends_text">"درود. با من روی %1$s صحبت کن: %2$s"</string>
|
||||
<string name="live_location_sharing_foreground_service_channel_title_android">"اشتراکگذاری موقعیت مکانی زنده"</string>
|
||||
<string name="live_location_sharing_foreground_service_message_android">"اشتراکگذاری موقعیت مکانی در حال انجام است"</string>
|
||||
<string name="live_location_sharing_foreground_service_title_android">"موقعیت مکانی زنده %1$s"</string>
|
||||
<string name="login_initial_device_name_android">"%1$s اندروید"</string>
|
||||
<string name="preference_rageshake">"Rageshake برای گزارش اشکال"</string>
|
||||
<string name="screen_bug_report_a11y_screenshot">"نماگرفت"</string>
|
||||
<string name="screen_create_poll_option_accessibility_label">"%1$s: %2$s"</string>
|
||||
<string name="screen_create_poll_options_section_title">"گزینهها"</string>
|
||||
<string name="screen_create_poll_remove_accessibility_label">"حذف %1$s"</string>
|
||||
<string name="screen_create_poll_settings_section_title">"تنظیمات"</string>
|
||||
<string name="screen_create_poll_votes_allowed_per_person">"تعداد آرای مجاز برای هر نفر"</string>
|
||||
<string name="screen_live_location_sheet_nobody_sharing">"هیچکس موقعیت مکانی خود را به اشتراک نمیگذارد"</string>
|
||||
<string name="screen_live_location_sheet_sharing_live_location">"اشتراکگذاری موقعیت مکانی زنده"</string>
|
||||
<plurals name="screen_live_location_sheet_subtitle">
|
||||
<item quantity="one">"شخص %1$d"</item>
|
||||
<item quantity="other">"افراد %1$d"</item>
|
||||
</plurals>
|
||||
<string name="screen_live_location_sheet_title">"روی نقشه"</string>
|
||||
<string name="screen_local_network_opt_in_subtitle">"سرور خانگی شما در شبکه محلی شما قرار دارد. برای اتصال، %1$s برای دسترسی به دستگاههای این شبکه به مجوز نیاز دارد."</string>
|
||||
<string name="screen_local_network_opt_in_title">"اجازه دسترسی به شبکه محلی"</string>
|
||||
<string name="screen_media_picker_error_failed_selection">"گزینش رسانه شکست خورد. لطفاً دوباره تلاش کنید."</string>
|
||||
<string name="screen_pinned_timeline_empty_state_description">"روی یک پیام کلیک کنید و «%1$s» را برای گنجاندن در اینجا انتخاب کنید."</string>
|
||||
<string name="screen_pinned_timeline_empty_state_headline">"پیامهای مهم را سنجاق کنید تا به راحتی قابل مشاهده باشند"</string>
|
||||
<plurals name="screen_pinned_timeline_screen_title">
|
||||
<item quantity="one">"پیام پین شده %1$d"</item>
|
||||
<item quantity="other">"پیامهای پینشده %1$d"</item>
|
||||
</plurals>
|
||||
<string name="screen_pinned_timeline_screen_title_empty">"پیامهای سنجاق شده"</string>
|
||||
<string name="screen_reset_identity_confirmation_subtitle">"داردید برای بازنشانی هویتتان به حساب %1$s میروید. پس از آن به کاره برگردانده خواهید شد."</string>
|
||||
<string name="screen_reset_identity_confirmation_subtitle">"شما در شرف رفتن به حساب %1$s خود برای تنظیم مجدد هویت دیجیتال خود هستید. پس از آن به برنامه بازگردانده خواهید شد."</string>
|
||||
<string name="screen_reset_identity_confirmation_title">"نمیتوانید تأیید کنید؟ برای بازنشانی هویت دیجیتال خود به حساب کاربری خود بروید."</string>
|
||||
<string name="screen_resolve_send_failure_changed_identity_primary_button_title">"تأیید را لغو و ارسال کنید"</string>
|
||||
<string name="screen_resolve_send_failure_changed_identity_subtitle">"شما میتوانید تأیید خود را پس بگیرید و در هر صورت این پیام را ارسال کنید، یا میتوانید فعلاً لغو کنید و پس از تأیید مجدد %1$s، بعداً دوباره امتحان کنید."</string>
|
||||
<string name="screen_resolve_send_failure_changed_identity_title">"پیام شما ارسال نشد زیرا هویت دیجیتال تأیید شده %1$s بازنشانی شده است."</string>
|
||||
<string name="screen_resolve_send_failure_unsigned_device_primary_button_title">"فرستادن پیام به هر روی"</string>
|
||||
<string name="screen_resolve_send_failure_unsigned_device_subtitle">"%1$s از یک یا چند دستگاه تأیید نشده استفاده میکند. در هر صورت میتوانید پیام را ارسال کنید، یا میتوانید فعلاً لغو کنید و بعداً پس از تأیید تمام دستگاههای %2$s دوباره امتحان کنید."</string>
|
||||
<string name="screen_resolve_send_failure_unsigned_device_title">"پیام شما ارسال نشد زیرا %1$s همه دستگاهها را تأیید نکرده است."</string>
|
||||
<string name="screen_resolve_send_failure_you_unsigned_device_subtitle">"یک یا چند دستگاه شما تأیید نشدهاند. در هر صورت میتوانید پیام را ارسال کنید، یا میتوانید فعلاً لغو کنید و بعداً پس از تأیید همه دستگاههایتان دوباره امتحان کنید."</string>
|
||||
<string name="screen_resolve_send_failure_you_unsigned_device_title">"پیام شما ارسال نشد زیرا یک یا چند دستگاه خود را تأیید نکردهاید"</string>
|
||||
<string name="screen_room_change_role_administrators_or_owners_title">"ویرایش مدیران یا مالکان"</string>
|
||||
<string name="screen_room_error_failed_processing_media">"پردازش رسانه برای بارگذاری شکست خورد. لطفاً دوباره تلاش کنید."</string>
|
||||
<string name="screen_room_error_failed_retrieving_user_details">"نمی توان جزئیات کاربر را بازیابی کرد"</string>
|
||||
<string name="screen_room_event_pill">"پیام در %1$s"</string>
|
||||
<string name="screen_room_grouped_state_events_expand">"گسترش"</string>
|
||||
<string name="screen_room_grouped_state_events_reduce">"کاهش"</string>
|
||||
<string name="screen_room_live_location_banner">"اشتراک گذاری موقعیت مکانی زنده"</string>
|
||||
<string name="screen_room_permalink_same_room_android">"درحال مشاهده این اتاق هستید!"</string>
|
||||
<string name="screen_room_pinned_banner_indicator">"%1$s از %2$s"</string>
|
||||
<string name="screen_room_pinned_banner_indicator_description">"%1$s پیامهای سنجاق شده"</string>
|
||||
<string name="screen_room_pinned_banner_loading_description">"بار کردن پیامها…"</string>
|
||||
@@ -388,13 +558,30 @@
|
||||
<string name="screen_share_open_google_maps">"گشودن در نقشههای گوگل"</string>
|
||||
<string name="screen_share_open_osm_maps">"گشودن در اوپناستریتمپ"</string>
|
||||
<string name="screen_share_this_location_action">"همرسانی مکان گزیده"</string>
|
||||
<string name="screen_sharing_location_option_sheet_title">"گزینههای اشتراکگذاری"</string>
|
||||
<string name="screen_space_list_description">"فضاهایی که ساخته یا پیوستهاید."</string>
|
||||
<string name="screen_space_list_details">"%1$s • %2$s"</string>
|
||||
<string name="screen_space_list_empty_state_title">"ایجاد فضاهایی برای سازماندهی اتاقها"</string>
|
||||
<string name="screen_space_list_parent_space">"%1$s فضا"</string>
|
||||
<string name="screen_space_list_title">"فضاها"</string>
|
||||
<string name="screen_static_location_sheet_timestamp_description">"%1$s اشتراکگذاری شده"</string>
|
||||
<string name="screen_static_location_sheet_title">"روی نقشه"</string>
|
||||
<plurals name="screen_timeline_active_call_joined_count">
|
||||
<item quantity="one">"%1$d عضو شد"</item>
|
||||
<item quantity="other">"%1$d عضو شد"</item>
|
||||
</plurals>
|
||||
<string name="screen_timeline_item_menu_send_failure_changed_identity">"پیام ارسال نشد زیرا هویت دیجیتال تأیید شده %1$s بازنشانی شده است."</string>
|
||||
<string name="screen_timeline_item_menu_send_failure_unsigned_device">"پیام ارسال نشد زیرا %1$s همه دستگاهها را تأیید نکرده است."</string>
|
||||
<string name="screen_timeline_item_menu_send_failure_you_unsigned_device">"پیام ارسال نشد زیرا شما یک یا چند دستگاه خود را تأیید نکردهاید."</string>
|
||||
<string name="screen_view_location_title">"مکان"</string>
|
||||
<string name="settings_version_number">"نگارش : %1$s (%2$s)"</string>
|
||||
<string name="test_language_identifier">"fa"</string>
|
||||
<string name="test_untranslated_default_language_identifier">"en"</string>
|
||||
<string name="timeline_decryption_failure_historical_event_no_key_backup">"پیامهای تاریخی در این دستگاه موجود نیست"</string>
|
||||
<string name="timeline_decryption_failure_historical_event_unverified_device">"برای دسترسی به پیامهای قدیمی، باید این دستگاه را تأیید کنید"</string>
|
||||
<string name="timeline_decryption_failure_historical_event_user_not_joined">"به این پیام دسترسی ندارید"</string>
|
||||
<string name="timeline_decryption_failure_unable_to_decrypt">"رمزگشایی پیام ممکن نیست"</string>
|
||||
<string name="timeline_decryption_failure_withheld_unverified">"این پیام یا به این دلیل مسدود شده است که شما دستگاه خود را تأیید نکردهاید یا به این دلیل که فرستنده باید هویت دیجیتال شما را تأیید کند."</string>
|
||||
<string name="vulkan_not_supported_dialog_content_android">"دستگاه شما خیلی قدیمی است، دستگاهی با اندروید ۸ یا جدیدتر مورد نیاز است."</string>
|
||||
<string name="vulkan_not_supported_dialog_title_android">"رندر کردن نقشهها پشتیبانی نمیشود"</string>
|
||||
</resources>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<string name="a11y_collapse_message_text_field">"Pienennä viestin tekstikenttä"</string>
|
||||
<string name="a11y_create_poll_votes_allowed_decrease">"Vähennä sallittujen äänien määrää per henkilö"</string>
|
||||
<string name="a11y_create_poll_votes_allowed_increase">"Lisää sallittujen äänien määrää per henkilö"</string>
|
||||
<string name="a11y_custom_emoji">"Mukautettu emoji"</string>
|
||||
<string name="a11y_delete">"Poista"</string>
|
||||
<plurals name="a11y_digits_entered">
|
||||
<item quantity="one">"%1$d numero syötetty"</item>
|
||||
@@ -18,11 +19,21 @@
|
||||
<string name="a11y_edit_room_address_hint">"Täysi osoite tulee olemaan %1$s"</string>
|
||||
<string name="a11y_encryption_details">"Salauksen tiedot"</string>
|
||||
<string name="a11y_expand_message_text_field">"Laajenna viestin tekstikenttä"</string>
|
||||
<string name="a11y_gallery_attachment">"Galleria, liite %1$d"</string>
|
||||
<string name="a11y_gallery_failed_scan">"Galleria, epäonnistunut skannaus %1$d"</string>
|
||||
<string name="a11y_gallery_image">"Galleria, kuva %1$d"</string>
|
||||
<plurals name="a11y_gallery_more_media">
|
||||
<item quantity="one">"Galleria, %1$d media lisää"</item>
|
||||
<item quantity="other">"Galleria, %1$d mediaa lisää"</item>
|
||||
</plurals>
|
||||
<string name="a11y_gallery_scanning">"Galleria, skannataan %1$d"</string>
|
||||
<string name="a11y_gallery_video">"Galleria, video %1$d"</string>
|
||||
<string name="a11y_hide_password">"Piilota salasana"</string>
|
||||
<string name="a11y_info">"Tiedot"</string>
|
||||
<string name="a11y_join_call">"Liity puheluun"</string>
|
||||
<string name="a11y_jump_to_bottom">"Siirry loppuun"</string>
|
||||
<string name="a11y_jump_to_unread">"Siirry lukemattomiin"</string>
|
||||
<string name="a11y_jump_to_unread_messages">"Siirry ensimmäiseen lukemattomaan viestiin"</string>
|
||||
<string name="a11y_move_the_map_to_my_location">"Siirrä kartta sijaintiini"</string>
|
||||
<string name="a11y_notifications_mentions_only">"Vain maininnat"</string>
|
||||
<string name="a11y_notifications_muted">"Mykistetty"</string>
|
||||
@@ -63,6 +74,7 @@
|
||||
<string name="a11y_start_call">"Aloita puhelu"</string>
|
||||
<string name="a11y_start_video_call">"Aloita videopuhelu"</string>
|
||||
<string name="a11y_start_voice_call">"Aloita äänipuhelu"</string>
|
||||
<string name="a11y_status">"Tila"</string>
|
||||
<string name="a11y_thread_in_room">"Viestiketju huoneessa %1$s"</string>
|
||||
<string name="a11y_threads_in_room">"Viestiketjut huoneessa %1$s"</string>
|
||||
<string name="a11y_tombstoned_room">"Haudattu huone"</string>
|
||||
@@ -143,6 +155,7 @@
|
||||
<string name="action_manage_account_and_devices">"Hallitse tiliä ja laitteita"</string>
|
||||
<string name="action_manage_devices">"Hallitse laitteita"</string>
|
||||
<string name="action_manage_rooms">"Huoneiden hallitseminen"</string>
|
||||
<string name="action_mark_as_read">"Merkitse luetuksi"</string>
|
||||
<string name="action_message">"Lähetä viesti"</string>
|
||||
<string name="action_minimize">"Pienennä"</string>
|
||||
<string name="action_next">"Seuraava"</string>
|
||||
@@ -503,6 +516,14 @@ Haluatko varmasti jatkaa?"</string>
|
||||
<string name="login_initial_device_name_android">"%1$s Android"</string>
|
||||
<string name="preference_rageshake">"Raivostunut ravistaminen ilmoittaa virheestä"</string>
|
||||
<string name="screen_bug_report_a11y_screenshot">"Näyttökuva"</string>
|
||||
<string name="screen_change_server_navigation_title_login">"Kirjaudu sisään"</string>
|
||||
<string name="screen_change_server_navigation_title_register">"Luo tili"</string>
|
||||
<string name="screen_change_server_textfield_footer_login">"Jos tilisi on yrityksesi tai yhteisön tarjoama, vaihda palveluntarjoaja (esimerkki: companyname.com)."</string>
|
||||
<string name="screen_change_server_textfield_footer_register">"Luo tili matrix.org -palvelimelle ilmaiseksi. Jos haluat luoda tilin eri palveluntarjoajan kautta, muuta sitä vastaavasti (esimerkiksi: communityname.org)."</string>
|
||||
<string name="screen_change_server_textfield_header">"Palveluntarjoaja"</string>
|
||||
<string name="screen_change_server_textfield_placeholder">"example.com"</string>
|
||||
<string name="screen_change_server_title_login">"Anna palveluntarjoajasi"</string>
|
||||
<string name="screen_change_server_title_register">"Valitse palveluntarjoaja"</string>
|
||||
<string name="screen_create_poll_option_accessibility_label">"%1$s: %2$s"</string>
|
||||
<string name="screen_create_poll_options_section_title">"Vaihtoehdot"</string>
|
||||
<string name="screen_create_poll_remove_accessibility_label">"Poista %1$s"</string>
|
||||
@@ -515,6 +536,8 @@ Haluatko varmasti jatkaa?"</string>
|
||||
<item quantity="other">"%1$d henkilöä"</item>
|
||||
</plurals>
|
||||
<string name="screen_live_location_sheet_title">"Kartalla"</string>
|
||||
<string name="screen_local_network_opt_in_subtitle">"Kotipalvelimesi on paikallisverkossasi. Yhdistääksesi, %1$s tarvitsee luvan tavoittaa laitteita tässä verkossa."</string>
|
||||
<string name="screen_local_network_opt_in_title">"Salli pääsy paikallisverkkoon"</string>
|
||||
<string name="screen_media_picker_error_failed_selection">"Median valinta epäonnistui, yritä uudelleen."</string>
|
||||
<string name="screen_pinned_timeline_empty_state_description">"Paina viestiä ja valitse “%1$s” lisätäksesi sen tänne."</string>
|
||||
<string name="screen_pinned_timeline_empty_state_headline">"Kiinnitä tärkeät viestit, jotta ne löytyvät helposti."</string>
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
<string name="a11y_avatar">"Avatar"</string>
|
||||
<string name="a11y_clear_search_field">"Effacer le champ de recherche"</string>
|
||||
<string name="a11y_collapse_message_text_field">"Réduire la taille du composeur"</string>
|
||||
<string name="a11y_create_poll_votes_allowed_decrease">"Diminuer le nombre de votes autorisés par personne"</string>
|
||||
<string name="a11y_create_poll_votes_allowed_increase">"Augmenter le nombre de votes autorisés par personne"</string>
|
||||
<string name="a11y_custom_emoji">"Émojis personnalisés"</string>
|
||||
<string name="a11y_delete">"Supprimer"</string>
|
||||
<plurals name="a11y_digits_entered">
|
||||
<item quantity="one">"%1$d chiffre saisi"</item>
|
||||
@@ -16,11 +19,21 @@
|
||||
<string name="a11y_edit_room_address_hint">"L’adresse complète sera %1$s"</string>
|
||||
<string name="a11y_encryption_details">"Détails du chiffrement"</string>
|
||||
<string name="a11y_expand_message_text_field">"Augmenter la taille du composeur"</string>
|
||||
<string name="a11y_gallery_attachment">"Galerie, élément %1$d"</string>
|
||||
<string name="a11y_gallery_failed_scan">"Galerie, échec de l’analyse de l’élément %1$d"</string>
|
||||
<string name="a11y_gallery_image">"Galerie, image %1$d"</string>
|
||||
<plurals name="a11y_gallery_more_media">
|
||||
<item quantity="one">"Galerie, %1$d média de plus"</item>
|
||||
<item quantity="other">"Galerie, %1$d média de plus"</item>
|
||||
</plurals>
|
||||
<string name="a11y_gallery_scanning">"Galerie, analyse en cours de l’élément %1$d"</string>
|
||||
<string name="a11y_gallery_video">"Galerie, vidéo %1$d"</string>
|
||||
<string name="a11y_hide_password">"Masquer le mot de passe"</string>
|
||||
<string name="a11y_info">"Info"</string>
|
||||
<string name="a11y_join_call">"Rejoindre l’appel"</string>
|
||||
<string name="a11y_jump_to_bottom">"Retourner à la fin de la conversation"</string>
|
||||
<string name="a11y_jump_to_unread">"Aller aux messages non lus"</string>
|
||||
<string name="a11y_jump_to_unread_messages">"Aller au premier message non lu"</string>
|
||||
<string name="a11y_move_the_map_to_my_location">"Déplacer la carte vers ma position"</string>
|
||||
<string name="a11y_notifications_mentions_only">"Mentions uniquement"</string>
|
||||
<string name="a11y_notifications_muted">"En sourdine"</string>
|
||||
@@ -31,6 +44,7 @@
|
||||
<string name="a11y_page_n">"Page %1$d"</string>
|
||||
<string name="a11y_pause">"Pause"</string>
|
||||
<string name="a11y_paused_voice_message">"Message vocal, durée: %1$s, position actuelle: %2$s"</string>
|
||||
<string name="a11y_photo_preview">"Aperçu de la photo"</string>
|
||||
<string name="a11y_pin_field">"Code PIN"</string>
|
||||
<string name="a11y_pinned_location">"Position épinglée"</string>
|
||||
<string name="a11y_play">"Lecture"</string>
|
||||
@@ -41,12 +55,13 @@
|
||||
<string name="a11y_qr_code">"Code QR"</string>
|
||||
<string name="a11y_react_with">"Réagir avec %1$s"</string>
|
||||
<string name="a11y_react_with_other_emojis">"Réagir avec d’autres émojis"</string>
|
||||
<string name="a11y_read_receipts_multiple">"Lu par %1$s et %2$s"</string>
|
||||
<string name="a11y_read_receipts_multiple">"Message précédent lu par %1$s et %2$s"</string>
|
||||
<plurals name="a11y_read_receipts_multiple_with_others">
|
||||
<item quantity="one">"Lu par %1$s et %2$d autre"</item>
|
||||
<item quantity="other">"Lu par %1$s et %2$d autres"</item>
|
||||
<item quantity="one">"Message précédent lu par %1$s et %2$d autre"</item>
|
||||
<item quantity="other">"Message précédent lu par %1$s et %2$d autres"</item>
|
||||
</plurals>
|
||||
<string name="a11y_read_receipts_single">"Lu par %1$s"</string>
|
||||
<string name="a11y_read_receipts_single">"Message précédent lu par %1$s"</string>
|
||||
<string name="a11y_read_receipts_tap_to_show_all_android">"afficher tous les accusés de réception"</string>
|
||||
<string name="a11y_remove_reaction">"Supprimer la réaction avec %1$s"</string>
|
||||
<string name="a11y_remove_reaction_with">"Supprimer la réaction avec %1$s"</string>
|
||||
<string name="a11y_room_avatar">"Avatar du salon"</string>
|
||||
@@ -59,11 +74,13 @@
|
||||
<string name="a11y_start_call">"Démarrer un appel"</string>
|
||||
<string name="a11y_start_video_call">"Passer un appel vidéo"</string>
|
||||
<string name="a11y_start_voice_call">"Lancer un appel vocal"</string>
|
||||
<string name="a11y_status">"Statut"</string>
|
||||
<string name="a11y_thread_in_room">"Discussion dans %1$s"</string>
|
||||
<string name="a11y_threads_in_room">"Discussions dans %1$s"</string>
|
||||
<string name="a11y_tombstoned_room">"Salon clôturé"</string>
|
||||
<string name="a11y_user_avatar">"Avatar de l’utilisateur"</string>
|
||||
<string name="a11y_user_menu">"Menu utilisateur"</string>
|
||||
<string name="a11y_video_preview">"Aperçu vidéo"</string>
|
||||
<string name="a11y_view_avatar">"Voir l’avatar"</string>
|
||||
<string name="a11y_view_details">"Afficher les détails"</string>
|
||||
<string name="a11y_voice_message">"Message vocal, durée: %1$s"</string>
|
||||
@@ -138,6 +155,7 @@
|
||||
<string name="action_manage_account_and_devices">"Gérer le compte et les appareils"</string>
|
||||
<string name="action_manage_devices">"Gérez les sessions"</string>
|
||||
<string name="action_manage_rooms">"Gérer les salons"</string>
|
||||
<string name="action_mark_as_read">"Marquer comme lu"</string>
|
||||
<string name="action_message">"Message"</string>
|
||||
<string name="action_minimize">"Minimiser"</string>
|
||||
<string name="action_next">"Suivant"</string>
|
||||
@@ -192,9 +210,11 @@
|
||||
<string name="action_translate">"Traduire"</string>
|
||||
<string name="action_try_again">"Essayer à nouveau"</string>
|
||||
<string name="action_unpin">"Désépingler"</string>
|
||||
<string name="action_video_call">"Appel vidéo"</string>
|
||||
<string name="action_view">"Voir"</string>
|
||||
<string name="action_view_in_timeline">"Voir dans la discussion"</string>
|
||||
<string name="action_view_source">"Afficher la source"</string>
|
||||
<string name="action_voice_call">"Appel audio"</string>
|
||||
<string name="action_yes">"Oui"</string>
|
||||
<string name="action_yes_try_again">"Oui, réessayez"</string>
|
||||
<string name="banner_migrate_to_native_sliding_sync_description">"Votre serveur prend désormais en charge un nouveau protocole plus rapide. Déconnectez-vous, puis reconnectez-vous pour effectuer la mise à niveau dès maintenant. En le faisant tout de suite, vous éviterez une déconnexion forcée lorsque l’ancien protocole sera supprimé."</string>
|
||||
@@ -215,6 +235,7 @@
|
||||
<string name="common_blocked_users">"Utilisateurs bloqués"</string>
|
||||
<string name="common_bubbles">"Bulles"</string>
|
||||
<string name="common_call_declined">"Appel rejeté"</string>
|
||||
<string name="common_call_in_progress">"Appel en cours"</string>
|
||||
<string name="common_call_started">"Appel démarré"</string>
|
||||
<string name="common_call_you_declined">"Vous avez rejeté un appel"</string>
|
||||
<string name="common_chat_backup">"Sauvegarde des discussions"</string>
|
||||
@@ -258,7 +279,17 @@ Raison : %1$s."</string>
|
||||
<string name="common_file_saved_on_disk_android">"Fichier enregistré dans Téléchargements"</string>
|
||||
<string name="common_forward_message">"Transférer le message"</string>
|
||||
<string name="common_frequently_used">"Fréquemment utilisé"</string>
|
||||
<string name="common_gallery">"Galerie"</string>
|
||||
<plurals name="common_gallery_reply_attachments">
|
||||
<item quantity="one">"%1$d élément…"</item>
|
||||
<item quantity="other">"%1$d éléments…"</item>
|
||||
</plurals>
|
||||
<plurals name="common_gallery_reply_media_items">
|
||||
<item quantity="one">"%1$d élément multimédia…"</item>
|
||||
<item quantity="other">"%1$d éléments multimédia…"</item>
|
||||
</plurals>
|
||||
<string name="common_gif">"GIF"</string>
|
||||
<string name="common_group_call_in_progress">"Appel de groupe en cours"</string>
|
||||
<string name="common_image">"Image"</string>
|
||||
<string name="common_in_reply_to">"En réponse à %1$s"</string>
|
||||
<string name="common_install_apk_android">"Installer l’APK"</string>
|
||||
@@ -294,6 +325,7 @@ Raison : %1$s."</string>
|
||||
<string name="common_no_space_name">"Espace sans nom"</string>
|
||||
<string name="common_not_encrypted">"Non chiffré"</string>
|
||||
<string name="common_offline">"Hors ligne"</string>
|
||||
<string name="common_on_a_call">"En appel"</string>
|
||||
<string name="common_open_source_licenses">"Licences open source"</string>
|
||||
<string name="common_or">"ou"</string>
|
||||
<string name="common_other_options">"Autres options"</string>
|
||||
@@ -401,6 +433,7 @@ Raison : %1$s."</string>
|
||||
<string name="common_unmute">"Retirer la sourdine"</string>
|
||||
<string name="common_unsupported_call">"Appel non pris en charge"</string>
|
||||
<string name="common_unsupported_event">"Événement non pris en charge"</string>
|
||||
<string name="common_user_started_a_call">"%1$s a commencé un appel"</string>
|
||||
<string name="common_username">"Nom d’utilisateur"</string>
|
||||
<string name="common_verification_cancelled">"Vérification annulée"</string>
|
||||
<string name="common_verification_complete">"Vérification terminée"</string>
|
||||
@@ -422,6 +455,11 @@ Raison : %1$s."</string>
|
||||
<string name="common_waiting_live_location">"En attente de la position en temps réel…"</string>
|
||||
<string name="common_world_readable_history">"Tout le monde peut voir les anciens messages"</string>
|
||||
<string name="common_you">"Vous"</string>
|
||||
<string name="content_scanner_not_found">"Téléchargement indisponible."</string>
|
||||
<string name="content_scanner_not_found_title">"Une erreur est survenue"</string>
|
||||
<string name="content_scanner_scanning">"Analyse en cours…"</string>
|
||||
<string name="content_scanner_unsafe_message">"L’aperçu et le téléchargement ont été désactivés."</string>
|
||||
<string name="content_scanner_unsafe_title">"Le fichier n’est pas sûr"</string>
|
||||
<string name="crypto_event_key_forwarded_known_profile_dialog_content">"%1$s (%2$s) a partagé ce message avec vous car vous n’étiez pas dans le salon lors de son envoi."</string>
|
||||
<string name="crypto_event_key_forwarded_unknown_profile_dialog_content">"%1$s a partagé ce message avec vous car vous n’étiez pas dans le salon lors de son envoi."</string>
|
||||
<string name="crypto_history_visible">"Ce salon a été configuré pour que les nouveaux membres puissent lire l’historique. %1$s"</string>
|
||||
@@ -478,10 +516,19 @@ Raison : %1$s."</string>
|
||||
<string name="login_initial_device_name_android">"%1$s Android"</string>
|
||||
<string name="preference_rageshake">"Rageshake pour signaler un problème"</string>
|
||||
<string name="screen_bug_report_a11y_screenshot">"Capture d’écran"</string>
|
||||
<string name="screen_change_server_navigation_title_login">"Se connecter"</string>
|
||||
<string name="screen_change_server_navigation_title_register">"Créer un compte"</string>
|
||||
<string name="screen_change_server_textfield_footer_login">"Si votre fournisseur de compte est fourni par votre entreprise ou une communauté, veuillez le saisir ici (exemple : monentreprise.com)."</string>
|
||||
<string name="screen_change_server_textfield_footer_register">"Créez un compte sur matrix.org gratuitement. Si vous souhaitez créer un compte auprès d’un autre fournisseur, veuillez modifier l’adresse ici (exemple : monassociation.org)."</string>
|
||||
<string name="screen_change_server_textfield_header">"Fournisseur de compte"</string>
|
||||
<string name="screen_change_server_textfield_placeholder">"exemple.com"</string>
|
||||
<string name="screen_change_server_title_login">"Saisissez votre fournisseur de compte"</string>
|
||||
<string name="screen_change_server_title_register">"Choisissez un fournisseur de compte"</string>
|
||||
<string name="screen_create_poll_option_accessibility_label">"%1$s: %2$s"</string>
|
||||
<string name="screen_create_poll_options_section_title">"Options"</string>
|
||||
<string name="screen_create_poll_remove_accessibility_label">"Supprimer %1$s"</string>
|
||||
<string name="screen_create_poll_settings_section_title">"Paramètres"</string>
|
||||
<string name="screen_create_poll_votes_allowed_per_person">"Nombre de votes autorisés par personne"</string>
|
||||
<string name="screen_live_location_sheet_nobody_sharing">"Personne ne partage sa position"</string>
|
||||
<string name="screen_live_location_sheet_sharing_live_location">"Partage de la position en direct"</string>
|
||||
<plurals name="screen_live_location_sheet_subtitle">
|
||||
@@ -489,6 +536,8 @@ Raison : %1$s."</string>
|
||||
<item quantity="other">"%1$d personnes"</item>
|
||||
</plurals>
|
||||
<string name="screen_live_location_sheet_title">"Sur la carte"</string>
|
||||
<string name="screen_local_network_opt_in_subtitle">"Votre fournisseur de compte se trouve sur votre réseau local. Pour pouvoir communiquer, %1$s a besoin de l’autorisation d’accéder aux appareils de ce réseau."</string>
|
||||
<string name="screen_local_network_opt_in_title">"Autoriser l’accès au réseau local"</string>
|
||||
<string name="screen_media_picker_error_failed_selection">"Échec de la sélection du média, veuillez réessayer."</string>
|
||||
<string name="screen_pinned_timeline_empty_state_description">"Cliquez (clic long) sur un message et choisissez « %1$s » pour qu‘il apparaisse ici."</string>
|
||||
<string name="screen_pinned_timeline_empty_state_headline">"Épinglez les messages importants pour leur donner plus de visibilité"</string>
|
||||
@@ -534,6 +583,10 @@ Raison : %1$s."</string>
|
||||
<string name="screen_space_list_title">"Espaces"</string>
|
||||
<string name="screen_static_location_sheet_timestamp_description">"Partagé %1$s"</string>
|
||||
<string name="screen_static_location_sheet_title">"Sur la carte"</string>
|
||||
<plurals name="screen_timeline_active_call_joined_count">
|
||||
<item quantity="one">"%1$d participant"</item>
|
||||
<item quantity="other">"%1$d participants"</item>
|
||||
</plurals>
|
||||
<string name="screen_timeline_item_menu_send_failure_changed_identity">"Le message n’a pas été envoyé car l’identité numérique vérifiée de %1$s a été réinitialisée."</string>
|
||||
<string name="screen_timeline_item_menu_send_failure_unsigned_device">"Le message n’a pas été envoyé car %1$s n’a pas vérifié tous ses appareils."</string>
|
||||
<string name="screen_timeline_item_menu_send_failure_you_unsigned_device">"Message non envoyé car vous n’avez pas vérifié tous vos appareils."</string>
|
||||
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.wellknown.api
|
||||
|
||||
/**
|
||||
* Server-driven settings for a user-chosen recovery passphrase, advertised under the well-known
|
||||
* `custom_recovery_passphrase` key. Today the only rule is a minimum character count; additional
|
||||
* settings can be added here as the schema grows.
|
||||
*/
|
||||
data class CustomRecoveryPassphrase(
|
||||
val minCharacterCount: Int,
|
||||
) {
|
||||
/** True when [input] meets every active rule. */
|
||||
fun isSatisfiedBy(input: String): Boolean = isSatisfiedBy(input.length)
|
||||
|
||||
/** True when an input of [length] characters meets every active rule. */
|
||||
fun isSatisfiedBy(length: Int): Boolean = length >= minCharacterCount
|
||||
}
|
||||
-36
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.wellknown.api
|
||||
|
||||
data class ElementWellKnown(
|
||||
val registrationHelperUrl: String?,
|
||||
val enforceElementPro: Boolean?,
|
||||
val rageshakeUrl: String?,
|
||||
val brandColor: String?,
|
||||
val notificationSound: String?,
|
||||
val identityProviderAppScheme: String?,
|
||||
val customRecoveryPassphrase: CustomRecoveryPassphrase?,
|
||||
val contentScannerUrl: String?,
|
||||
val forceDisableE2EE: Boolean?,
|
||||
val mapTilerConfig: MapTilerConfig?,
|
||||
)
|
||||
|
||||
/**
|
||||
* A `MapTiler` configuration received from the server. This configuration is used to display maps in the app.
|
||||
*/
|
||||
data class MapTilerConfig(
|
||||
/** The API key to use with MapTiler. This is always not null, but can be empty/blank. */
|
||||
val apiKey: String,
|
||||
/** The style ID to use for light mode. This is optional and can be null. */
|
||||
val lightStyleId: String?,
|
||||
/** The style ID to use for light mode. This is optional and can be null. */
|
||||
val darkStyleId: String?,
|
||||
/** The base URL to use for MapTiler. This is optional and can be null. */
|
||||
val baseUrl: String?,
|
||||
)
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.wellknown.api
|
||||
|
||||
/**
|
||||
* Parses the raw JSON of an Element `.well-known` document.
|
||||
*/
|
||||
fun interface ElementWellKnownParser {
|
||||
/**
|
||||
* Parses the document, failing when it is not valid JSON; unknown fields are ignored so a newer server does not break an older client.
|
||||
*
|
||||
* @param json the raw document as served by the server.
|
||||
*/
|
||||
fun parse(json: String): Result<ElementWellKnown>
|
||||
}
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.wellknown.api
|
||||
|
||||
/**
|
||||
* On-disk cache of the Element `.well-known` documents already fetched, so the app has a configuration to work with while offline.
|
||||
*/
|
||||
interface ElementWellknownStore {
|
||||
/**
|
||||
* Reads the cached document of a domain.
|
||||
* Entries older than a day are reported as outdated rather than missing, so the caller can use them while refreshing;
|
||||
* a document that no longer parses is reported as an error.
|
||||
*
|
||||
* @param domain the server whose cached document is requested.
|
||||
*/
|
||||
suspend fun get(domain: String): WellknownRetrieverResult<ElementWellKnown>
|
||||
|
||||
/**
|
||||
* Stores the document of a domain and stamps it as fetched now, replacing any previous entry.
|
||||
*
|
||||
* @param domain the server the document belongs to.
|
||||
* @param wellknown the raw document, stored as-is rather than parsed.
|
||||
*/
|
||||
suspend fun update(domain: String, wellknown: String): Result<Unit>
|
||||
|
||||
/**
|
||||
* Removes the cached document of a domain, used when the stored value turns out to be unusable.
|
||||
*
|
||||
* @param domain the server whose entry is removed.
|
||||
*/
|
||||
suspend fun delete(domain: String): Result<Unit>
|
||||
|
||||
/**
|
||||
* Creates a store, one per configuration source so that their entries never collide.
|
||||
*/
|
||||
fun interface Factory {
|
||||
/**
|
||||
* @param prefix namespaces the cache keys, or `null` for the default well-known endpoint.
|
||||
*/
|
||||
fun create(prefix: String?): ElementWellknownStore
|
||||
}
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.wellknown.api
|
||||
|
||||
/**
|
||||
* The source from which the enterprise remote configuration is retrieved.
|
||||
*/
|
||||
enum class EnterpriseRemoteConfigSource {
|
||||
/**
|
||||
* Retrieve the enterprise remote configuration from the Element Server Suite configuration (ESS_CONFIG) endpoint.
|
||||
*/
|
||||
ESS_CONFIG,
|
||||
|
||||
/**
|
||||
* Retrieve the enterprise remote configuration from the Element server's well-known endpoint.
|
||||
*/
|
||||
WELLKNOWN_ENDPOINT,
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.wellknown.api
|
||||
|
||||
import io.element.android.libraries.matrix.api.UrlContentFetcher
|
||||
|
||||
/**
|
||||
* Retrieves the Element specific `.well-known` configuration of a server, which is how a deployment advertises its own settings.
|
||||
*/
|
||||
interface WellknownRetriever {
|
||||
/**
|
||||
* Returns the configuration of a host, served from the local cache when possible.
|
||||
* A cached value that has gone stale is returned as outdated while a refresh runs in the background, so this rarely waits on the network.
|
||||
* An enterprise build with a hardcoded configuration always short-circuits and returns that instead.
|
||||
*
|
||||
* @param host the server to look up; a full URL is accepted and reduced to its host.
|
||||
* @param source which endpoint to read the configuration from, which also selects the cache it is stored in.
|
||||
*/
|
||||
suspend fun getElementWellKnown(
|
||||
host: String,
|
||||
source: EnterpriseRemoteConfigSource
|
||||
): WellknownRetrieverResult<ElementWellKnown>
|
||||
|
||||
/**
|
||||
* Creates a retriever, which needs a fetcher because the configuration is read over HTTP.
|
||||
*/
|
||||
interface Factory {
|
||||
/**
|
||||
* @param urlContentFetcher used to perform the request; a client that is not authenticated yet also works.
|
||||
*/
|
||||
fun create(urlContentFetcher: UrlContentFetcher): WellknownRetriever
|
||||
}
|
||||
}
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.wellknown.api
|
||||
|
||||
sealed interface WellknownRetrieverResult<out T> {
|
||||
/**
|
||||
* Well-known data has been successfully retrieved.
|
||||
*/
|
||||
data class Success<out T>(val data: T) : WellknownRetrieverResult<T>
|
||||
|
||||
/**
|
||||
* Well-known data has been retrieved from the local cache but is outdated and a manual refresh has been launched.
|
||||
*/
|
||||
data class Outdated<out T>(val data: T) : WellknownRetrieverResult<T>
|
||||
|
||||
/**
|
||||
* Well-known data is not found (file does not exist server side, we got a 404).
|
||||
*/
|
||||
data object NotFound : WellknownRetrieverResult<Nothing>
|
||||
|
||||
/**
|
||||
* Any other error.
|
||||
*/
|
||||
data class Error(val exception: Exception) : WellknownRetrieverResult<Nothing>
|
||||
|
||||
fun dataOrNull(): T? = when (this) {
|
||||
is Success<T> -> data
|
||||
is Outdated<T> -> data
|
||||
is Error -> null
|
||||
NotFound -> null
|
||||
}
|
||||
|
||||
fun upToDateDataOrNull(): T? = when (this) {
|
||||
is Success<T> -> data
|
||||
is Outdated<T> -> null
|
||||
is Error -> null
|
||||
NotFound -> null
|
||||
}
|
||||
}
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.wellknown.impl
|
||||
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import io.element.android.libraries.androidutils.json.JsonProvider
|
||||
import io.element.android.libraries.core.extensions.runCatchingExceptions
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnown
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnownParser
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultElementWellKnownParser(
|
||||
private val jsonProvider: JsonProvider,
|
||||
) : ElementWellKnownParser {
|
||||
override fun parse(json: String): Result<ElementWellKnown> {
|
||||
return runCatchingExceptions {
|
||||
val decoder = jsonProvider()
|
||||
decoder.decodeFromString<InternalElementWellKnown>(json).map()
|
||||
}
|
||||
}
|
||||
}
|
||||
-77
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.wellknown.impl
|
||||
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.AssistedFactory
|
||||
import dev.zacsweers.metro.AssistedInject
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import io.element.android.libraries.cachestore.api.CacheData
|
||||
import io.element.android.libraries.cachestore.api.CacheStore
|
||||
import io.element.android.libraries.core.extensions.runCatchingExceptions
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnown
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnownParser
|
||||
import io.element.android.libraries.wellknown.api.ElementWellknownStore
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetrieverResult
|
||||
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
||||
|
||||
@AssistedInject
|
||||
class DefaultWellKnownStore(
|
||||
@Assisted
|
||||
private val prefix: String?,
|
||||
private val cacheStore: CacheStore,
|
||||
private val elementWellKnownParser: ElementWellKnownParser,
|
||||
private val systemClock: SystemClock,
|
||||
) : ElementWellknownStore {
|
||||
@AssistedFactory
|
||||
@ContributesBinding(AppScope::class)
|
||||
fun interface Factory : ElementWellknownStore.Factory {
|
||||
override fun create(prefix: String?): DefaultWellKnownStore
|
||||
}
|
||||
override suspend fun get(domain: String): WellknownRetrieverResult<ElementWellKnown> {
|
||||
return runCatchingExceptions {
|
||||
val cachedData = cacheStore.getData(key(domain))
|
||||
if (cachedData != null) {
|
||||
val data = elementWellKnownParser.parse(cachedData.value).getOrThrow()
|
||||
if (systemClock.epochMillis() > cachedData.updatedAt + CACHE_VALIDITY_MILLIS) {
|
||||
WellknownRetrieverResult.Outdated(data)
|
||||
} else {
|
||||
WellknownRetrieverResult.Success(data)
|
||||
}
|
||||
} else {
|
||||
WellknownRetrieverResult.NotFound
|
||||
}
|
||||
}.recover {
|
||||
WellknownRetrieverResult.Error(it as Exception)
|
||||
}.getOrThrow()
|
||||
}
|
||||
|
||||
override suspend fun update(domain: String, wellknown: String): Result<Unit> {
|
||||
return runCatchingExceptions {
|
||||
cacheStore.storeData(key(domain), CacheData(wellknown, systemClock.epochMillis()))
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun delete(domain: String): Result<Unit> {
|
||||
return runCatchingExceptions {
|
||||
cacheStore.deleteData(key(domain))
|
||||
}
|
||||
}
|
||||
|
||||
private fun key(domain: String): String = if (prefix != null) {
|
||||
"$prefix-$domain"
|
||||
} else {
|
||||
"https://$domain/.well-known/element/element.json"
|
||||
}
|
||||
|
||||
companion object {
|
||||
// 1 day
|
||||
private const val CACHE_VALIDITY_MILLIS = 1 * 24 * 60 * 60 * 1000L
|
||||
}
|
||||
}
|
||||
-142
@@ -1,142 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.wellknown.impl
|
||||
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.AssistedFactory
|
||||
import dev.zacsweers.metro.AssistedInject
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import io.element.android.features.enterprise.api.EnterpriseService
|
||||
import io.element.android.libraries.androidutils.text.takeIfNotBlank
|
||||
import io.element.android.libraries.core.extensions.mapCatchingExceptions
|
||||
import io.element.android.libraries.core.extensions.runCatchingExceptions
|
||||
import io.element.android.libraries.core.uri.ensureProtocol
|
||||
import io.element.android.libraries.di.annotations.AppCoroutineScope
|
||||
import io.element.android.libraries.matrix.api.UrlContentFetcher
|
||||
import io.element.android.libraries.matrix.api.exception.ClientException
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnown
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnownParser
|
||||
import io.element.android.libraries.wellknown.api.ElementWellknownStore
|
||||
import io.element.android.libraries.wellknown.api.EnterpriseRemoteConfigSource
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetriever
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetrieverResult
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import java.net.URL
|
||||
|
||||
@AssistedInject
|
||||
class DefaultWellknownRetriever(
|
||||
private val elementWellknownStoreFactory: ElementWellknownStore.Factory,
|
||||
private val enterpriseService: EnterpriseService,
|
||||
private val elementWellKnownParser: ElementWellKnownParser,
|
||||
@Assisted private val urlContentFetcher: UrlContentFetcher,
|
||||
@AppCoroutineScope private val coroutineScope: CoroutineScope,
|
||||
) : WellknownRetriever {
|
||||
@ContributesBinding(AppScope::class)
|
||||
@AssistedFactory
|
||||
fun interface Factory : WellknownRetriever.Factory {
|
||||
override fun create(urlContentFetcher: UrlContentFetcher): DefaultWellknownRetriever
|
||||
}
|
||||
|
||||
override suspend fun getElementWellKnown(
|
||||
host: String,
|
||||
source: EnterpriseRemoteConfigSource
|
||||
): WellknownRetrieverResult<ElementWellKnown> {
|
||||
val overriddenElementWellKnown = enterpriseService.overriddenElementWellKnown()
|
||||
if (overriddenElementWellKnown != null) {
|
||||
return WellknownRetrieverResult.Success(overriddenElementWellKnown)
|
||||
}
|
||||
|
||||
// The passed `host` function may be a full URL, in that case we're only interested in the actual host
|
||||
val checkedHost = runCatchingExceptions { URL(host.ensureProtocol()).host.takeIfNotBlank() }
|
||||
.getOrElse { return WellknownRetrieverResult.Error(IllegalArgumentException("host parameter is not valid", it)) }
|
||||
?: host
|
||||
|
||||
// We instantiate different stores for different sources, so that we can cache them separately.
|
||||
// The ESS_CONFIG source is cached with a prefix to differentiate it from the WELLKNOWN_ENDPOINT.
|
||||
val prefix = when (source) {
|
||||
EnterpriseRemoteConfigSource.ESS_CONFIG -> "ess_config"
|
||||
EnterpriseRemoteConfigSource.WELLKNOWN_ENDPOINT -> null
|
||||
}
|
||||
val store = elementWellknownStoreFactory.create(prefix)
|
||||
return when (val cacheData = store.get(checkedHost)) {
|
||||
is WellknownRetrieverResult.Success -> {
|
||||
Timber.d("Using cached well-known for domain $checkedHost")
|
||||
cacheData
|
||||
}
|
||||
is WellknownRetrieverResult.Outdated -> {
|
||||
// Return the outdated data but refresh in the background
|
||||
// If the cache is missing or outdated, trigger a refresh in background but still return the cached value
|
||||
Timber.d("Outdated cached well-known for domain $checkedHost, returning existing value and fetching new one from network")
|
||||
coroutineScope.launch { fetchElementWellKnown(checkedHost, source, store) }
|
||||
cacheData
|
||||
}
|
||||
is WellknownRetrieverResult.NotFound -> {
|
||||
// Try to fetch from the server
|
||||
Timber.d("No cached well-known for domain $checkedHost, fetching from network")
|
||||
fetchElementWellKnown(checkedHost, source, store)
|
||||
}
|
||||
is WellknownRetrieverResult.Error -> {
|
||||
// Return the error
|
||||
Timber.e(cacheData.exception, "Error retrieving well-known for domain $checkedHost")
|
||||
cacheData.exception.toWellknownRetrieverResult()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun fetchElementWellKnown(
|
||||
host: String,
|
||||
source: EnterpriseRemoteConfigSource,
|
||||
store: ElementWellknownStore
|
||||
): WellknownRetrieverResult<ElementWellKnown> {
|
||||
return urlContentFetcher
|
||||
.getUrl(url(host, source))
|
||||
.mapCatchingExceptions {
|
||||
val data = String(it)
|
||||
val parsed = elementWellKnownParser.parse(data).getOrThrow()
|
||||
// Also store in cache, if valid
|
||||
store.update(host, data)
|
||||
.onFailure { exception ->
|
||||
Timber.e(exception, "Failed to parse cached Element .well-known data for $host, deleting cache")
|
||||
store.delete(host)
|
||||
}
|
||||
parsed
|
||||
}
|
||||
.toWellknownRetrieverResult(host)
|
||||
}
|
||||
|
||||
private fun <T> Result<T>.toWellknownRetrieverResult(host: String): WellknownRetrieverResult<T> = fold(
|
||||
onSuccess = {
|
||||
WellknownRetrieverResult.Success(it)
|
||||
},
|
||||
onFailure = {
|
||||
Timber.e(it, "Failed to retrieve Element .well-known from $host")
|
||||
// This check on message value is not ideal but this is what we got from the SDK.
|
||||
it.toWellknownRetrieverResult()
|
||||
}
|
||||
)
|
||||
|
||||
private fun <T> Throwable.toWellknownRetrieverResult(): WellknownRetrieverResult<T> {
|
||||
return if ((this as? ClientException.Generic)?.message?.contains("404") == true) {
|
||||
WellknownRetrieverResult.NotFound
|
||||
} else {
|
||||
WellknownRetrieverResult.Error(this as Exception)
|
||||
}
|
||||
}
|
||||
|
||||
private fun url(host: String, source: EnterpriseRemoteConfigSource): String {
|
||||
val elementWellKnownUrl = "https://$host/.well-known/element/element.json"
|
||||
return when (source) {
|
||||
EnterpriseRemoteConfigSource.ESS_CONFIG -> enterpriseService.essConfigEndpointUrl(host) ?: elementWellKnownUrl
|
||||
EnterpriseRemoteConfigSource.WELLKNOWN_ENDPOINT -> elementWellKnownUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
-71
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.wellknown.impl
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* Example:
|
||||
* <pre>
|
||||
* {
|
||||
* "registration_helper_url": "https://element.io",
|
||||
* "enforce_element_pro": true,
|
||||
* "rageshake_url": "https://example.org/rageshake",
|
||||
* "brand_color": "#FF0000",
|
||||
* "notification_sound": "ring.flac",
|
||||
* "idp_app_scheme": "io.element.app",
|
||||
* "custom_recovery_passphrase": {
|
||||
* "min_character_count": 8
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
* .
|
||||
*/
|
||||
@Serializable
|
||||
data class InternalElementWellKnown(
|
||||
@SerialName("registration_helper_url")
|
||||
val registrationHelperUrl: String? = null,
|
||||
@SerialName("enforce_element_pro")
|
||||
val enforceElementPro: Boolean? = null,
|
||||
@SerialName("rageshake_url")
|
||||
val rageshakeUrl: String? = null,
|
||||
@SerialName("brand_color")
|
||||
val brandColor: String? = null,
|
||||
@SerialName("notification_sound")
|
||||
val notificationSound: String? = null,
|
||||
@SerialName("idp_app_scheme")
|
||||
val identityProviderAppScheme: String? = null,
|
||||
@SerialName("custom_recovery_passphrase")
|
||||
val customRecoveryPassphrase: InternalCustomRecoveryPassphrase? = null,
|
||||
@SerialName("content_scanner_url")
|
||||
val contentScannerUrl: String? = null,
|
||||
@SerialName("force_disable_e2ee")
|
||||
val forceDisableE2EE: Boolean? = null,
|
||||
@SerialName("map_tiler")
|
||||
val mapTilerConfig: InternalMapTilerConfig? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class InternalCustomRecoveryPassphrase(
|
||||
@SerialName("min_character_count")
|
||||
val minCharacterCount: Int? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class InternalMapTilerConfig(
|
||||
@SerialName("api_key")
|
||||
val apiKey: String,
|
||||
@SerialName("light_style_id")
|
||||
val lightStyleId: String? = null,
|
||||
@SerialName("dark_style_id")
|
||||
val darkStyleId: String? = null,
|
||||
@SerialName("base_url")
|
||||
val baseUrl: String? = null,
|
||||
)
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.wellknown.impl
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* https://matrix.org/docs/spec/client_server/r0.4.0.html#server-discovery
|
||||
* <pre>
|
||||
* {
|
||||
* "m.homeserver": {
|
||||
* "base_url": "https://matrix.org"
|
||||
* },
|
||||
* "m.identity_server": {
|
||||
* "base_url": "https://vector.im"
|
||||
* },
|
||||
* }
|
||||
* </pre>
|
||||
* .
|
||||
*/
|
||||
@Serializable
|
||||
data class InternalWellKnown(
|
||||
@SerialName("m.homeserver")
|
||||
val homeServer: InternalWellKnownBaseConfig? = null,
|
||||
@SerialName("m.identity_server")
|
||||
val identityServer: InternalWellKnownBaseConfig? = null,
|
||||
)
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.wellknown.impl
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* https://matrix.org/docs/spec/client_server/r0.4.0.html#server-discovery
|
||||
* <pre>
|
||||
* {
|
||||
* "base_url": "https://element.io"
|
||||
* }
|
||||
* </pre>
|
||||
* .
|
||||
*/
|
||||
@Serializable
|
||||
data class InternalWellKnownBaseConfig(
|
||||
@SerialName("base_url")
|
||||
val baseURL: String? = null
|
||||
)
|
||||
-59
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.wellknown.impl
|
||||
|
||||
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||
import io.element.android.libraries.wellknown.api.CustomRecoveryPassphrase
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnown
|
||||
import io.element.android.libraries.wellknown.api.MapTilerConfig
|
||||
import timber.log.Timber
|
||||
|
||||
private val loggerTag = LoggerTag("Wellknown")
|
||||
|
||||
/**
|
||||
* Floor for the recovery passphrase minimum length. A value of 1 guarantees the derived passphrase is
|
||||
* never empty (an empty passphrase derives a recoverable but effectively unprotected secret-storage
|
||||
* key). Anything stronger than non-empty is left to the homeserver operator's configuration.
|
||||
*/
|
||||
private const val MINIMUM_PASSPHRASE_CHARACTER_COUNT = 1
|
||||
|
||||
fun InternalElementWellKnown.map() = ElementWellKnown(
|
||||
registrationHelperUrl = registrationHelperUrl,
|
||||
enforceElementPro = enforceElementPro,
|
||||
rageshakeUrl = rageshakeUrl,
|
||||
brandColor = brandColor,
|
||||
notificationSound = notificationSound,
|
||||
identityProviderAppScheme = identityProviderAppScheme,
|
||||
customRecoveryPassphrase = customRecoveryPassphrase?.toPublic(),
|
||||
contentScannerUrl = contentScannerUrl,
|
||||
forceDisableE2EE = forceDisableE2EE,
|
||||
mapTilerConfig = mapTilerConfig?.let {
|
||||
MapTilerConfig(
|
||||
apiKey = it.apiKey,
|
||||
lightStyleId = it.lightStyleId,
|
||||
darkStyleId = it.darkStyleId,
|
||||
baseUrl = it.baseUrl,
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
private fun InternalCustomRecoveryPassphrase.toPublic(): CustomRecoveryPassphrase {
|
||||
// Whenever the homeserver advertises the settings block we run the custom passphrase flow, flooring
|
||||
// the minimum at 1 so the passphrase can never be empty even if the server omits min_character_count
|
||||
// or advertises a non-positive value. The operator owns any stronger minimum.
|
||||
val min = (minCharacterCount ?: MINIMUM_PASSPHRASE_CHARACTER_COUNT).coerceAtLeast(MINIMUM_PASSPHRASE_CHARACTER_COUNT)
|
||||
if (min != minCharacterCount) {
|
||||
Timber.tag(loggerTag.value).w(
|
||||
"custom_recovery_passphrase.min_character_count was %s; flooring to %d",
|
||||
minCharacterCount,
|
||||
min,
|
||||
)
|
||||
}
|
||||
return CustomRecoveryPassphrase(minCharacterCount = min)
|
||||
}
|
||||
-41
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.wellknown.impl
|
||||
|
||||
import dev.zacsweers.metro.BindingContainer
|
||||
import dev.zacsweers.metro.ContributesTo
|
||||
import dev.zacsweers.metro.Provides
|
||||
import io.element.android.features.enterprise.api.EnterpriseService
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.di.annotations.SessionCoroutineScope
|
||||
import io.element.android.libraries.matrix.api.UrlContentFetcher
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnownParser
|
||||
import io.element.android.libraries.wellknown.api.ElementWellknownStore
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetriever
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
@BindingContainer
|
||||
@ContributesTo(SessionScope::class)
|
||||
object SessionWellknownModule {
|
||||
@Provides
|
||||
fun provideWellKnownRetriever(
|
||||
elementWellknownStoreFactory: ElementWellknownStore.Factory,
|
||||
enterpriseService: EnterpriseService,
|
||||
elementWellKnownParser: ElementWellKnownParser,
|
||||
urlContentFetcher: UrlContentFetcher,
|
||||
@SessionCoroutineScope coroutineScope: CoroutineScope,
|
||||
): WellknownRetriever {
|
||||
return DefaultWellknownRetriever(
|
||||
elementWellknownStoreFactory = elementWellknownStoreFactory,
|
||||
enterpriseService = enterpriseService,
|
||||
elementWellKnownParser = elementWellKnownParser,
|
||||
urlContentFetcher = urlContentFetcher,
|
||||
coroutineScope = coroutineScope
|
||||
)
|
||||
}
|
||||
}
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.wellknown.impl
|
||||
|
||||
import retrofit2.http.GET
|
||||
|
||||
internal interface WellknownAPI {
|
||||
@GET(".well-known/matrix/client")
|
||||
suspend fun getWellKnown(): InternalWellKnown
|
||||
|
||||
@GET(".well-known/element/element.json")
|
||||
suspend fun getElementWellKnown(): InternalElementWellKnown
|
||||
}
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.wellknown.api
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Test
|
||||
|
||||
class CustomRecoveryPassphraseTest {
|
||||
@Test
|
||||
fun `empty input never satisfies a positive minimum`() {
|
||||
assertThat(CustomRecoveryPassphrase(minCharacterCount = 1).isSatisfiedBy("")).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `input shorter than minimum is not satisfied`() {
|
||||
assertThat(CustomRecoveryPassphrase(minCharacterCount = 8).isSatisfiedBy("abc")).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `input exactly at minimum is satisfied`() {
|
||||
assertThat(CustomRecoveryPassphrase(minCharacterCount = 8).isSatisfiedBy("abcdefgh")).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `input longer than minimum is satisfied`() {
|
||||
assertThat(CustomRecoveryPassphrase(minCharacterCount = 4).isSatisfiedBy("abcdefgh")).isTrue()
|
||||
}
|
||||
}
|
||||
-174
@@ -1,174 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.wellknown.impl
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.wellknown.test.anElementWellKnown
|
||||
import io.element.android.libraries.androidutils.json.DefaultJsonProvider
|
||||
import io.element.android.libraries.cachestore.api.CacheData
|
||||
import io.element.android.libraries.sessionstorage.test.InMemoryCacheStore
|
||||
import io.element.android.libraries.wellknown.api.CustomRecoveryPassphrase
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnownParser
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetrieverResult
|
||||
import io.element.android.services.toolbox.test.systemclock.A_FAKE_TIMESTAMP
|
||||
import io.element.android.services.toolbox.test.systemclock.FakeSystemClock
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
|
||||
private const val A_DOMAIN = "matrix.example.com"
|
||||
private const val A_CACHE_KEY = "https://$A_DOMAIN/.well-known/element/element.json"
|
||||
|
||||
// 1 day in millis
|
||||
private const val CACHE_VALIDITY_MILLIS = 1 * 24 * 60 * 60 * 1000L
|
||||
|
||||
class DefaultWellKnownStoreTest {
|
||||
private val jsonProvider = DefaultJsonProvider()
|
||||
|
||||
@Test
|
||||
fun `get returns NotFound when cache is empty`() = runTest {
|
||||
val sut = createDefaultWellKnownStore()
|
||||
assertThat(sut.get(A_DOMAIN)).isEqualTo(WellknownRetrieverResult.NotFound)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get returns Success when cache has fresh data`() = runTest {
|
||||
val wellKnown = InternalElementWellKnown(rageshakeUrl = "https://rageshake.example.com")
|
||||
val jsonString = jsonProvider().encodeToString(wellKnown)
|
||||
val clock = FakeSystemClock(epochMillisResult = A_FAKE_TIMESTAMP)
|
||||
val cacheStore = InMemoryCacheStore(
|
||||
initialData = mapOf(A_CACHE_KEY to CacheData(jsonString, A_FAKE_TIMESTAMP))
|
||||
)
|
||||
val sut = createDefaultWellKnownStore(cacheStore = cacheStore, systemClock = clock)
|
||||
|
||||
val result = sut.get(A_DOMAIN)
|
||||
|
||||
assertThat(result).isEqualTo(WellknownRetrieverResult.Success(wellKnown.map()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get returns Outdated when cached data has expired`() = runTest {
|
||||
val wellKnown = InternalElementWellKnown(rageshakeUrl = "https://rageshake.example.com")
|
||||
val jsonString = jsonProvider().encodeToString(wellKnown)
|
||||
// Store data at timestamp 0, but clock is past the validity window
|
||||
val expiredTimestamp = 0L
|
||||
val nowTimestamp = expiredTimestamp + CACHE_VALIDITY_MILLIS + 1
|
||||
val clock = FakeSystemClock(epochMillisResult = nowTimestamp)
|
||||
val cacheStore = InMemoryCacheStore(
|
||||
initialData = mapOf(A_CACHE_KEY to CacheData(jsonString, expiredTimestamp))
|
||||
)
|
||||
val sut = createDefaultWellKnownStore(cacheStore = cacheStore, systemClock = clock)
|
||||
|
||||
val result = sut.get(A_DOMAIN)
|
||||
|
||||
assertThat(result).isEqualTo(WellknownRetrieverResult.Outdated(wellKnown.map()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get returns Error when cached data is invalid JSON`() = runTest {
|
||||
val cacheStore = InMemoryCacheStore(
|
||||
initialData = mapOf(A_CACHE_KEY to CacheData("not valid json at all", A_FAKE_TIMESTAMP))
|
||||
)
|
||||
val sut = createDefaultWellKnownStore(cacheStore = cacheStore)
|
||||
|
||||
val result = sut.get(A_DOMAIN)
|
||||
|
||||
assertThat(result).isInstanceOf(WellknownRetrieverResult.Error::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `update stores data and get returns Success`() = runTest {
|
||||
val wellKnown = """
|
||||
{
|
||||
"registration_helper_url": "https://element.io",
|
||||
"enforce_element_pro": true,
|
||||
"rageshake_url": "https://example.org/rageshake",
|
||||
"brand_color": "#FF0000",
|
||||
"notification_sound": "ring.flac",
|
||||
"idp_app_scheme": "io.element.app",
|
||||
"custom_recovery_passphrase": {
|
||||
"min_character_count": 8
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
val clock = FakeSystemClock(epochMillisResult = A_FAKE_TIMESTAMP)
|
||||
val cacheStore = InMemoryCacheStore()
|
||||
val sut = createDefaultWellKnownStore(cacheStore = cacheStore, systemClock = clock)
|
||||
|
||||
val updateResult = sut.update(A_DOMAIN, wellKnown)
|
||||
assertThat(updateResult.isSuccess).isTrue()
|
||||
|
||||
val result = sut.get(A_DOMAIN)
|
||||
assertThat(result).isEqualTo(WellknownRetrieverResult.Success(anElementWellKnown(
|
||||
registrationHelperUrl = "https://element.io",
|
||||
enforceElementPro = true,
|
||||
rageshakeUrl = "https://example.org/rageshake",
|
||||
brandColor = "#FF0000",
|
||||
notificationSound = "ring.flac",
|
||||
identityProviderAppScheme = "io.element.app",
|
||||
customRecoveryPassphrase = CustomRecoveryPassphrase(8),
|
||||
)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `delete removes data and get returns NotFound`() = runTest {
|
||||
val wellKnown = InternalElementWellKnown(rageshakeUrl = "https://rageshake.example.com")
|
||||
val jsonString = jsonProvider().encodeToString(wellKnown)
|
||||
val clock = FakeSystemClock(epochMillisResult = A_FAKE_TIMESTAMP)
|
||||
val cacheStore = InMemoryCacheStore(
|
||||
initialData = mapOf(A_CACHE_KEY to CacheData(jsonString, A_FAKE_TIMESTAMP))
|
||||
)
|
||||
val sut = createDefaultWellKnownStore(cacheStore = cacheStore, systemClock = clock)
|
||||
|
||||
val deleteResult = sut.delete(A_DOMAIN)
|
||||
assertThat(deleteResult.isSuccess).isTrue()
|
||||
|
||||
assertThat(sut.get(A_DOMAIN)).isEqualTo(WellknownRetrieverResult.NotFound)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get returns data at the exact cache validity boundary as Success`() = runTest {
|
||||
val wellKnown = InternalElementWellKnown(notificationSound = "ping.flac")
|
||||
val jsonString = jsonProvider().encodeToString(wellKnown)
|
||||
// Exactly at the boundary: epochMillis == updatedAt + CACHE_VALIDITY_MILLIS → not expired
|
||||
val storedAt = 1000L
|
||||
val nowAtBoundary = storedAt + CACHE_VALIDITY_MILLIS
|
||||
val clock = FakeSystemClock(epochMillisResult = nowAtBoundary)
|
||||
val cacheStore = InMemoryCacheStore(
|
||||
initialData = mapOf(A_CACHE_KEY to CacheData(jsonString, storedAt))
|
||||
)
|
||||
val sut = createDefaultWellKnownStore(cacheStore = cacheStore, systemClock = clock)
|
||||
|
||||
val result = sut.get(A_DOMAIN)
|
||||
|
||||
assertThat(result).isEqualTo(WellknownRetrieverResult.Success(wellKnown.map()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `prefix is used`() = runTest {
|
||||
val prefix = "test-prefix"
|
||||
val clock = FakeSystemClock(epochMillisResult = A_FAKE_TIMESTAMP)
|
||||
val cacheStore = InMemoryCacheStore(
|
||||
initialData = mapOf("$prefix-$A_DOMAIN" to CacheData("{}", A_FAKE_TIMESTAMP))
|
||||
)
|
||||
val sut = createDefaultWellKnownStore(prefix = prefix, cacheStore = cacheStore, systemClock = clock)
|
||||
|
||||
assertThat(sut.get(A_DOMAIN)).isInstanceOf(WellknownRetrieverResult.Success::class.java)
|
||||
}
|
||||
|
||||
private fun createDefaultWellKnownStore(
|
||||
prefix: String? = null,
|
||||
cacheStore: InMemoryCacheStore = InMemoryCacheStore(),
|
||||
systemClock: FakeSystemClock = FakeSystemClock(),
|
||||
elementWellKnownParser: ElementWellKnownParser = DefaultElementWellKnownParser(jsonProvider),
|
||||
) = DefaultWellKnownStore(
|
||||
prefix = prefix,
|
||||
cacheStore = cacheStore,
|
||||
systemClock = systemClock,
|
||||
elementWellKnownParser = elementWellKnownParser,
|
||||
)
|
||||
}
|
||||
-241
@@ -1,241 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
@file:OptIn(ExperimentalCoroutinesApi::class)
|
||||
|
||||
package io.element.android.libraries.wellknown.impl
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.enterprise.test.FakeEnterpriseService
|
||||
import io.element.android.features.wellknown.test.FakeElementWellknownStore
|
||||
import io.element.android.features.wellknown.test.aMapTilerConfig
|
||||
import io.element.android.features.wellknown.test.anElementWellKnown
|
||||
import io.element.android.libraries.core.uri.ensureProtocol
|
||||
import io.element.android.libraries.matrix.api.UrlContentFetcher
|
||||
import io.element.android.libraries.matrix.api.exception.ClientException
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnown
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnownParser
|
||||
import io.element.android.libraries.wellknown.api.ElementWellknownStore
|
||||
import io.element.android.libraries.wellknown.api.EnterpriseRemoteConfigSource
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetrieverResult
|
||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
import io.element.android.tests.testutils.lambda.value
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
import java.net.URL
|
||||
|
||||
class DefaultWellknownRetrieverTest {
|
||||
@Test
|
||||
fun `get element wellknown calls resolver and parser`() = runTest {
|
||||
val parser = lambdaRecorder<String, Result<ElementWellKnown>> { Result.success(anElementWellKnown()) }
|
||||
val resolver = SpyUrlContentFetcher { Result.success(WELLKNOWN_CONTENT.toByteArray()) }
|
||||
val sut = createDefaultWellknownRetriever(
|
||||
elementWellKnownParser = parser,
|
||||
urlResolver = resolver,
|
||||
)
|
||||
|
||||
sut.getElementWellKnown(WELLKNOWN_URL, EnterpriseRemoteConfigSource.WELLKNOWN_ENDPOINT)
|
||||
|
||||
resolver.assertions().isCalledOnce().with(value(WELLKNOWN_URL))
|
||||
parser.assertions().isCalledOnce().with(value(WELLKNOWN_CONTENT))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get element wellknown parser error`() = runTest {
|
||||
val sut = createDefaultWellknownRetriever(
|
||||
elementWellKnownParser = { Result.failure(IllegalStateException("Invalid JSON")) },
|
||||
)
|
||||
assertThat(sut.getElementWellKnown(WELLKNOWN_URL, EnterpriseRemoteConfigSource.WELLKNOWN_ENDPOINT))
|
||||
.isInstanceOf(WellknownRetrieverResult.Error::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get element wellknown network error`() = runTest {
|
||||
val resolver = SpyUrlContentFetcher { Result.failure(IllegalStateException("Network error")) }
|
||||
val sut = createDefaultWellknownRetriever(urlResolver = resolver)
|
||||
assertThat(sut.getElementWellKnown(WELLKNOWN_URL, EnterpriseRemoteConfigSource.WELLKNOWN_ENDPOINT))
|
||||
.isInstanceOf(WellknownRetrieverResult.Error::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get element wellknown 404 http error counts as not found`() = runTest {
|
||||
val resolver = SpyUrlContentFetcher { Result.failure(ClientException.Generic("Http error: 404", null)) }
|
||||
val sut = createDefaultWellknownRetriever(urlResolver = resolver)
|
||||
assertThat(sut.getElementWellKnown(WELLKNOWN_URL, EnterpriseRemoteConfigSource.WELLKNOWN_ENDPOINT))
|
||||
.isInstanceOf(WellknownRetrieverResult.NotFound::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get element wellknown will return an error if the provided host is not valid`() = runTest {
|
||||
val sut = createDefaultWellknownRetriever()
|
||||
assertThat(sut.getElementWellKnown("!not valid", EnterpriseRemoteConfigSource.WELLKNOWN_ENDPOINT))
|
||||
.isInstanceOf(WellknownRetrieverResult.Error::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get element wellknown will return a cached value if present instead of fetching`() = runTest {
|
||||
val host = URL(WELLKNOWN_URL).host.ensureProtocol()
|
||||
val sut = createDefaultWellknownRetriever(
|
||||
cacheStoreFactory = { FakeElementWellknownStore(initialData = mapOf(host to WellknownRetrieverResult.Success(expectedElementWellKnown))) }
|
||||
)
|
||||
assertThat(sut.getElementWellKnown(WELLKNOWN_URL, EnterpriseRemoteConfigSource.WELLKNOWN_ENDPOINT))
|
||||
.isInstanceOf(WellknownRetrieverResult.Success::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get element wellknown will return an outdated value first then fetch the current one`() = runTest {
|
||||
val host = URL(WELLKNOWN_URL).host.ensureProtocol()
|
||||
val resolver = SpyUrlContentFetcher { Result.success(WELLKNOWN_CONTENT.toByteArray()) }
|
||||
val sut = createDefaultWellknownRetriever(
|
||||
urlResolver = resolver,
|
||||
cacheStoreFactory = { FakeElementWellknownStore(initialData = mapOf(host to WellknownRetrieverResult.Outdated(expectedElementWellKnown))) }
|
||||
)
|
||||
// The first call returns the outdated value
|
||||
assertThat(sut.getElementWellKnown(WELLKNOWN_URL, EnterpriseRemoteConfigSource.WELLKNOWN_ENDPOINT))
|
||||
.isInstanceOf(WellknownRetrieverResult.Outdated::class.java)
|
||||
// The resolver is not called yet because the fetch is done in the background
|
||||
resolver.assertions().isNeverCalled()
|
||||
|
||||
// We give it some time to run the background fetch
|
||||
runCurrent()
|
||||
|
||||
// The resolver is called during the background fetch
|
||||
resolver.assertions().isCalledOnce().with(value(WELLKNOWN_URL))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get element wellknown will return an error if it happens when trying to retrieve the cached value`() = runTest {
|
||||
val host = URL(WELLKNOWN_URL).host.ensureProtocol()
|
||||
val sut = createDefaultWellknownRetriever(
|
||||
cacheStoreFactory = { FakeElementWellknownStore(initialData = mapOf(host to WellknownRetrieverResult.Error(IllegalStateException("BOOM")))) }
|
||||
)
|
||||
assertThat(sut.getElementWellKnown(WELLKNOWN_URL, EnterpriseRemoteConfigSource.WELLKNOWN_ENDPOINT))
|
||||
.isInstanceOf(WellknownRetrieverResult.Error::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get element wellknown will return an error if it fails to serialize the retrieved value into the cache`() = runTest {
|
||||
val sut = createDefaultWellknownRetriever(
|
||||
elementWellKnownParser = { Result.failure(IllegalStateException("BOOM")) },
|
||||
)
|
||||
assertThat(sut.getElementWellKnown(WELLKNOWN_URL, EnterpriseRemoteConfigSource.WELLKNOWN_ENDPOINT))
|
||||
.isInstanceOf(WellknownRetrieverResult.Error::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WELLKNOWN_ENDPOINT source creates a store with no prefix`() = runTest {
|
||||
val storeFactory = lambdaRecorder<String?, ElementWellknownStore> { FakeElementWellknownStore() }
|
||||
val sut = createDefaultWellknownRetriever(cacheStoreFactory = storeFactory)
|
||||
|
||||
sut.getElementWellKnown(WELLKNOWN_URL, EnterpriseRemoteConfigSource.WELLKNOWN_ENDPOINT)
|
||||
|
||||
storeFactory.assertions().isCalledOnce().with(value(null))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ESS_CONFIG source creates a store with ess prefix and checks the ESS config endpoint`() = runTest {
|
||||
val essConfigUrl = "https://ess-config.example.com"
|
||||
val storeFactory = lambdaRecorder<String?, ElementWellknownStore> { FakeElementWellknownStore() }
|
||||
val resolver = SpyUrlContentFetcher { Result.success(WELLKNOWN_CONTENT.toByteArray()) }
|
||||
val sut = createDefaultWellknownRetriever(
|
||||
cacheStoreFactory = storeFactory,
|
||||
enterpriseService = FakeEnterpriseService(
|
||||
overrideWellKnownResult = { null },
|
||||
essConfigEndpointUrlResult = { essConfigUrl },
|
||||
),
|
||||
urlResolver = resolver,
|
||||
)
|
||||
|
||||
sut.getElementWellKnown(WELLKNOWN_URL, EnterpriseRemoteConfigSource.ESS_CONFIG)
|
||||
|
||||
storeFactory.assertions().isCalledOnce().with(value("ess_config"))
|
||||
resolver.assertions().isCalledOnce().with(value(essConfigUrl))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get element wellknown was overridden`() = runTest {
|
||||
val wellKnown = anElementWellKnown()
|
||||
|
||||
val resolver = SpyUrlContentFetcher { Result.success(WELLKNOWN_CONTENT.toByteArray()) }
|
||||
|
||||
val sut = createDefaultWellknownRetriever(
|
||||
enterpriseService = FakeEnterpriseService(
|
||||
overrideWellKnownResult = { wellKnown },
|
||||
),
|
||||
urlResolver = resolver,
|
||||
)
|
||||
|
||||
// The overridden value is returned
|
||||
assertThat(sut.getElementWellKnown(WELLKNOWN_URL, EnterpriseRemoteConfigSource.WELLKNOWN_ENDPOINT)).isEqualTo(
|
||||
WellknownRetrieverResult.Success(wellKnown)
|
||||
)
|
||||
|
||||
// And the endpoint is never hit
|
||||
resolver.assertions().isNeverCalled()
|
||||
}
|
||||
|
||||
private fun TestScope.createDefaultWellknownRetriever(
|
||||
cacheStoreFactory: ElementWellknownStore.Factory = { FakeElementWellknownStore() },
|
||||
elementWellKnownParser: ElementWellKnownParser = { Result.success(expectedElementWellKnown) },
|
||||
enterpriseService: FakeEnterpriseService = FakeEnterpriseService(overrideWellKnownResult = { null }),
|
||||
urlResolver: UrlContentFetcher = SpyUrlContentFetcher { Result.success(WELLKNOWN_CONTENT.toByteArray()) },
|
||||
) = DefaultWellknownRetriever(
|
||||
elementWellknownStoreFactory = cacheStoreFactory,
|
||||
enterpriseService = enterpriseService,
|
||||
elementWellKnownParser = elementWellKnownParser,
|
||||
urlContentFetcher = urlResolver,
|
||||
coroutineScope = backgroundScope,
|
||||
)
|
||||
|
||||
companion object {
|
||||
private const val WELLKNOWN_URL = "https://user.domain.org/.well-known/element/element.json"
|
||||
private const val WELLKNOWN_CONTENT = """{
|
||||
"registration_helper_url": "a_registration_url",
|
||||
"enforce_element_pro": true,
|
||||
"rageshake_url": "a_rageshake_url",
|
||||
"brand_color": "#FF0000",
|
||||
"notification_sound": "a_notification_sound.flac",
|
||||
"idp_app_scheme": "an_app_scheme",
|
||||
"content_scanner_url": "https://content-scanner.example.com",
|
||||
"force_disable_e2ee": false,
|
||||
"map_tiler": {
|
||||
"api_key": "test_api_key",
|
||||
"base_url": "https://tile-server.example.com"
|
||||
}
|
||||
}"""
|
||||
|
||||
private val expectedElementWellKnown = ElementWellKnown(
|
||||
registrationHelperUrl = "a_registration_url",
|
||||
enforceElementPro = true,
|
||||
rageshakeUrl = "a_rageshake_url",
|
||||
brandColor = "#FF0000",
|
||||
notificationSound = "a_notification_sound.flac",
|
||||
identityProviderAppScheme = "an_app_scheme",
|
||||
contentScannerUrl = "https://content-scanner.example.com",
|
||||
customRecoveryPassphrase = null,
|
||||
forceDisableE2EE = false,
|
||||
mapTilerConfig = aMapTilerConfig(
|
||||
apiKey = "test_api_key",
|
||||
baseUrl = "https://tile-server.example.com",
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class SpyUrlContentFetcher(lambda: (String) -> Result<ByteArray>) : UrlContentFetcher {
|
||||
private val spy = lambdaRecorder<String, Result<ByteArray>> { lambda(it) }
|
||||
|
||||
override suspend fun getUrl(url: String): Result<ByteArray> {
|
||||
return spy(url)
|
||||
}
|
||||
|
||||
fun assertions() = spy.assertions()
|
||||
}
|
||||
-53
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.wellknown.test
|
||||
|
||||
import io.element.android.libraries.androidutils.json.DefaultJsonProvider
|
||||
import io.element.android.libraries.androidutils.json.JsonProvider
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnown
|
||||
import io.element.android.libraries.wellknown.api.ElementWellknownStore
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetrieverResult
|
||||
import io.element.android.libraries.wellknown.impl.InternalElementWellKnown
|
||||
import io.element.android.libraries.wellknown.impl.map
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.json.JsonDecodingException
|
||||
import java.net.URL
|
||||
|
||||
class FakeElementWellknownStore(
|
||||
initialData: Map<String, WellknownRetrieverResult<ElementWellKnown>> = emptyMap(),
|
||||
private val jsonProvider: JsonProvider = DefaultJsonProvider(),
|
||||
) : ElementWellknownStore {
|
||||
private val cachedData = mutableMapOf<String, WellknownRetrieverResult<ElementWellKnown>>()
|
||||
|
||||
init {
|
||||
initialData.forEach { (url, result) ->
|
||||
cachedData[URL(url).host] = result
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun get(domain: String): WellknownRetrieverResult<ElementWellKnown> {
|
||||
return cachedData[domain] ?: WellknownRetrieverResult.NotFound
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
override suspend fun update(domain: String, wellknown: String): Result<Unit> {
|
||||
val json = jsonProvider()
|
||||
val mapped = try {
|
||||
json.decodeFromString<InternalElementWellKnown>(wellknown).map()
|
||||
} catch (e: JsonDecodingException) {
|
||||
return Result.failure(e)
|
||||
}
|
||||
cachedData[domain] = WellknownRetrieverResult.Success(mapped)
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
override suspend fun delete(domain: String): Result<Unit> {
|
||||
cachedData.remove(domain)
|
||||
return Result.success(Unit)
|
||||
}
|
||||
}
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.wellknown.test
|
||||
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnown
|
||||
import io.element.android.libraries.wellknown.api.EnterpriseRemoteConfigSource
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetriever
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetrieverResult
|
||||
|
||||
class FakeWellknownRetriever(
|
||||
private val getElementWellKnownResult: (String, EnterpriseRemoteConfigSource) -> WellknownRetrieverResult<ElementWellKnown> = { _, _ ->
|
||||
WellknownRetrieverResult.NotFound
|
||||
},
|
||||
) : WellknownRetriever {
|
||||
override suspend fun getElementWellKnown(host: String, source: EnterpriseRemoteConfigSource): WellknownRetrieverResult<ElementWellKnown> {
|
||||
return getElementWellKnownResult(host, source)
|
||||
}
|
||||
}
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.wellknown.test
|
||||
|
||||
import io.element.android.libraries.matrix.api.UrlContentFetcher
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetriever
|
||||
|
||||
class FakeWellknownRetrieverFactory(
|
||||
private val wellknownRetriever: WellknownRetriever = FakeWellknownRetriever(),
|
||||
) : WellknownRetriever.Factory {
|
||||
override fun create(urlContentFetcher: UrlContentFetcher): WellknownRetriever = wellknownRetriever
|
||||
}
|
||||
-55
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.wellknown.test
|
||||
|
||||
import io.element.android.libraries.wellknown.api.CustomRecoveryPassphrase
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnown
|
||||
import io.element.android.libraries.wellknown.api.MapTilerConfig
|
||||
|
||||
fun anElementWellKnown(
|
||||
registrationHelperUrl: String? = null,
|
||||
enforceElementPro: Boolean? = null,
|
||||
rageshakeUrl: String? = null,
|
||||
brandColor: String? = null,
|
||||
notificationSound: String? = null,
|
||||
identityProviderAppScheme: String? = null,
|
||||
customRecoveryPassphrase: CustomRecoveryPassphrase? = null,
|
||||
contentScannerUrl: String? = null,
|
||||
forceDisableE2EE: Boolean? = null,
|
||||
mapTilerConfig: MapTilerConfig? = null,
|
||||
) = ElementWellKnown(
|
||||
registrationHelperUrl = registrationHelperUrl,
|
||||
enforceElementPro = enforceElementPro,
|
||||
rageshakeUrl = rageshakeUrl,
|
||||
brandColor = brandColor,
|
||||
notificationSound = notificationSound,
|
||||
identityProviderAppScheme = identityProviderAppScheme,
|
||||
customRecoveryPassphrase = customRecoveryPassphrase,
|
||||
contentScannerUrl = contentScannerUrl,
|
||||
forceDisableE2EE = forceDisableE2EE,
|
||||
mapTilerConfig = mapTilerConfig,
|
||||
)
|
||||
|
||||
fun aCustomRecoveryPassphrase(
|
||||
minCharacterCount: Int = 8,
|
||||
) = CustomRecoveryPassphrase(
|
||||
minCharacterCount = minCharacterCount,
|
||||
)
|
||||
|
||||
fun aMapTilerConfig(
|
||||
apiKey: String = "test_api_key",
|
||||
baseUrl: String? = null,
|
||||
lightStyleId: String? = null,
|
||||
darkStyleId: String? = null,
|
||||
) = MapTilerConfig(
|
||||
apiKey = apiKey,
|
||||
baseUrl = baseUrl,
|
||||
lightStyleId = lightStyleId,
|
||||
darkStyleId = darkStyleId,
|
||||
)
|
||||
Reference in New Issue
Block a user