mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-10-09 02:54:14 +00:00
add arabic language
This commit is contained in:
parent
c25d1eccbe
commit
f33ef22446
22 changed files with 3902 additions and 387 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -60,3 +60,4 @@ fastlane/repo/status/running.json
|
||||||
# Widget Preview related
|
# Widget Preview related
|
||||||
.widget_preview/
|
.widget_preview/
|
||||||
ios/build/
|
ios/build/
|
||||||
|
APKS/*.apk
|
||||||
|
|
|
||||||
9
android/app/src/main/res/values-ar/strings.xml
Normal file
9
android/app/src/main/res/values-ar/strings.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="widget_description">صور يرسلها إليك أصدقاؤك</string>
|
||||||
|
<string name="widget_choose_groups">اختر مجموعات جهات الاتصال</string>
|
||||||
|
<string name="widget_choose_groups_description">اختر من يمكنه إرسال الصور إلى هذه الأداة.</string>
|
||||||
|
<string name="widget_open_app_first">افتح twonly مرة واحدة لتحميل مجموعات جهات الاتصال الخاصة بك.</string>
|
||||||
|
<string name="widget_save">إضافة الأداة</string>
|
||||||
|
<string name="widget_image_description">أحدث صورة في أداتك</string>
|
||||||
|
</resources>
|
||||||
|
|
@ -107,11 +107,6 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
||||||
GlobalCupertinoLocalizations.delegate,
|
GlobalCupertinoLocalizations.delegate,
|
||||||
];
|
];
|
||||||
|
|
||||||
const supportedLocales = [
|
|
||||||
Locale('en', ''),
|
|
||||||
Locale('de', ''),
|
|
||||||
];
|
|
||||||
|
|
||||||
final settings = context.watch<SettingsChangeProvider>();
|
final settings = context.watch<SettingsChangeProvider>();
|
||||||
|
|
||||||
if (widget.storageError) {
|
if (widget.storageError) {
|
||||||
|
|
@ -119,6 +114,7 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
||||||
localizationsDelegates: localizationsDelegates,
|
localizationsDelegates: localizationsDelegates,
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
supportedLocales: supportedLocales,
|
supportedLocales: supportedLocales,
|
||||||
|
locale: settings.locale,
|
||||||
title: 'twonly',
|
title: 'twonly',
|
||||||
theme: getLightTheme(settings.primaryColor),
|
theme: getLightTheme(settings.primaryColor),
|
||||||
darkTheme: getDarkTheme(settings.primaryColor),
|
darkTheme: getDarkTheme(settings.primaryColor),
|
||||||
|
|
@ -132,6 +128,7 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
||||||
localizationsDelegates: localizationsDelegates,
|
localizationsDelegates: localizationsDelegates,
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
supportedLocales: supportedLocales,
|
supportedLocales: supportedLocales,
|
||||||
|
locale: settings.locale,
|
||||||
title: 'twonly',
|
title: 'twonly',
|
||||||
theme: getLightTheme(settings.primaryColor),
|
theme: getLightTheme(settings.primaryColor),
|
||||||
darkTheme: getDarkTheme(settings.primaryColor),
|
darkTheme: getDarkTheme(settings.primaryColor),
|
||||||
|
|
@ -145,6 +142,7 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
||||||
localizationsDelegates: localizationsDelegates,
|
localizationsDelegates: localizationsDelegates,
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
supportedLocales: supportedLocales,
|
supportedLocales: supportedLocales,
|
||||||
|
locale: settings.locale,
|
||||||
title: 'twonly',
|
title: 'twonly',
|
||||||
theme: getLightTheme(settings.primaryColor),
|
theme: getLightTheme(settings.primaryColor),
|
||||||
darkTheme: getDarkTheme(settings.primaryColor),
|
darkTheme: getDarkTheme(settings.primaryColor),
|
||||||
|
|
|
||||||
|
|
@ -7905,8 +7905,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
UserConfig dco_decode_user_config(dynamic raw) {
|
UserConfig dco_decode_user_config(dynamic raw) {
|
||||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
final arr = raw as List<dynamic>;
|
final arr = raw as List<dynamic>;
|
||||||
if (arr.length != 62)
|
if (arr.length != 63)
|
||||||
throw Exception('unexpected arr length: expect 62 but see ${arr.length}');
|
throw Exception('unexpected arr length: expect 63 but see ${arr.length}');
|
||||||
return UserConfig(
|
return UserConfig(
|
||||||
userId: dco_decode_i_64(arr[0]),
|
userId: dco_decode_i_64(arr[0]),
|
||||||
username: dco_decode_String(arr[1]),
|
username: dco_decode_String(arr[1]),
|
||||||
|
|
@ -7926,55 +7926,56 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
additionalUserInvites: dco_decode_opt_String(arr[15]),
|
additionalUserInvites: dco_decode_opt_String(arr[15]),
|
||||||
themeMode: dco_decode_theme_mode(arr[16]),
|
themeMode: dco_decode_theme_mode(arr[16]),
|
||||||
primaryColorValue: dco_decode_opt_box_autoadd_i_64(arr[17]),
|
primaryColorValue: dco_decode_opt_box_autoadd_i_64(arr[17]),
|
||||||
defaultShowTime: dco_decode_opt_box_autoadd_i_64(arr[18]),
|
language: dco_decode_opt_String(arr[18]),
|
||||||
requestedAudioPermission: dco_decode_bool(arr[19]),
|
defaultShowTime: dco_decode_opt_box_autoadd_i_64(arr[19]),
|
||||||
enableDatabaseLogging: dco_decode_bool(arr[20]),
|
requestedAudioPermission: dco_decode_bool(arr[20]),
|
||||||
automaticallyMarkEqualMediaFilesAsOpened: dco_decode_bool(arr[21]),
|
enableDatabaseLogging: dco_decode_bool(arr[21]),
|
||||||
showNewsShortcut: dco_decode_bool(arr[22]),
|
automaticallyMarkEqualMediaFilesAsOpened: dco_decode_bool(arr[22]),
|
||||||
showShowImagePreviewWhenSending: dco_decode_bool(arr[23]),
|
showNewsShortcut: dco_decode_bool(arr[23]),
|
||||||
startWithCameraOpen: dco_decode_bool(arr[24]),
|
showShowImagePreviewWhenSending: dco_decode_bool(arr[24]),
|
||||||
preSelectedEmojies: dco_decode_opt_list_String(arr[25]),
|
startWithCameraOpen: dco_decode_bool(arr[25]),
|
||||||
autoDownloadOptions: dco_decode_opt_Map_String_list_String_None(arr[26]),
|
preSelectedEmojies: dco_decode_opt_list_String(arr[26]),
|
||||||
storeMediaFilesInGallery: dco_decode_bool(arr[27]),
|
autoDownloadOptions: dco_decode_opt_Map_String_list_String_None(arr[27]),
|
||||||
storeLocationInMemories: dco_decode_bool(arr[28]),
|
storeMediaFilesInGallery: dco_decode_bool(arr[28]),
|
||||||
autoStoreAllSendUnlimitedMediaFiles: dco_decode_bool(arr[29]),
|
storeLocationInMemories: dco_decode_bool(arr[29]),
|
||||||
typingIndicators: dco_decode_bool(arr[30]),
|
autoStoreAllSendUnlimitedMediaFiles: dco_decode_bool(arr[30]),
|
||||||
showRestoreFlame: dco_decode_bool(arr[31]),
|
typingIndicators: dco_decode_bool(arr[31]),
|
||||||
myBestFriendGroupId: dco_decode_opt_String(arr[32]),
|
showRestoreFlame: dco_decode_bool(arr[32]),
|
||||||
|
myBestFriendGroupId: dco_decode_opt_String(arr[33]),
|
||||||
signalLastSignedPreKeyUpdated: dco_decode_opt_box_autoadd_Chrono_Utc(
|
signalLastSignedPreKeyUpdated: dco_decode_opt_box_autoadd_Chrono_Utc(
|
||||||
arr[33],
|
|
||||||
),
|
|
||||||
signalLastPqcPreKeysUploaded: dco_decode_opt_box_autoadd_Chrono_Utc(
|
|
||||||
arr[34],
|
arr[34],
|
||||||
),
|
),
|
||||||
allowErrorTrackingViaSentry: dco_decode_bool(arr[35]),
|
signalLastPqcPreKeysUploaded: dco_decode_opt_box_autoadd_Chrono_Utc(
|
||||||
screenLockEnabled: dco_decode_bool(arr[36]),
|
arr[35],
|
||||||
isCloudBackupEnabled: dco_decode_bool(arr[37]),
|
),
|
||||||
isUserDiscoveryEnabled: dco_decode_bool(arr[38]),
|
allowErrorTrackingViaSentry: dco_decode_bool(arr[36]),
|
||||||
requiredSendImages: dco_decode_i_64(arr[39]),
|
screenLockEnabled: dco_decode_bool(arr[37]),
|
||||||
userDiscoveryThreshold: dco_decode_u_8(arr[40]),
|
isCloudBackupEnabled: dco_decode_bool(arr[38]),
|
||||||
userDiscoveryRequiresManualApproval: dco_decode_bool(arr[41]),
|
isUserDiscoveryEnabled: dco_decode_bool(arr[39]),
|
||||||
userDiscoverySharePromotion: dco_decode_bool(arr[42]),
|
requiredSendImages: dco_decode_i_64(arr[40]),
|
||||||
userDiscoveryInitializationError: dco_decode_bool(arr[43]),
|
userDiscoveryThreshold: dco_decode_u_8(arr[41]),
|
||||||
askForFriendPromotions: dco_decode_bool(arr[44]),
|
userDiscoveryRequiresManualApproval: dco_decode_bool(arr[42]),
|
||||||
currentPreKeyIndexStart: dco_decode_i_64(arr[45]),
|
userDiscoverySharePromotion: dco_decode_bool(arr[43]),
|
||||||
currentSignedPreKeyIndexStart: dco_decode_i_64(arr[46]),
|
userDiscoveryInitializationError: dco_decode_bool(arr[44]),
|
||||||
lastChangeLogHash: dco_decode_opt_list_prim_u_8_strict(arr[47]),
|
askForFriendPromotions: dco_decode_bool(arr[45]),
|
||||||
hideChangeLog: dco_decode_bool(arr[48]),
|
currentPreKeyIndexStart: dco_decode_i_64(arr[46]),
|
||||||
hideMemoriesBackupPromo: dco_decode_bool(arr[49]),
|
currentSignedPreKeyIndexStart: dco_decode_i_64(arr[47]),
|
||||||
hideWidgetShareExplainer: dco_decode_bool(arr[50]),
|
lastChangeLogHash: dco_decode_opt_list_prim_u_8_strict(arr[48]),
|
||||||
updateFcmToken: dco_decode_bool(arr[51]),
|
hideChangeLog: dco_decode_bool(arr[49]),
|
||||||
canUseLoginTokenForAuth: dco_decode_bool(arr[52]),
|
hideMemoriesBackupPromo: dco_decode_bool(arr[50]),
|
||||||
twonlySafeBackup: dco_decode_opt_box_autoadd_twonly_safe_backup(arr[53]),
|
hideWidgetShareExplainer: dco_decode_bool(arr[51]),
|
||||||
isBackupEnabled: dco_decode_bool(arr[54]),
|
updateFcmToken: dco_decode_bool(arr[52]),
|
||||||
|
canUseLoginTokenForAuth: dco_decode_bool(arr[53]),
|
||||||
|
twonlySafeBackup: dco_decode_opt_box_autoadd_twonly_safe_backup(arr[54]),
|
||||||
|
isBackupEnabled: dco_decode_bool(arr[55]),
|
||||||
passwordLessRecovery:
|
passwordLessRecovery:
|
||||||
dco_decode_opt_box_autoadd_passwordless_recovery_config(arr[55]),
|
dco_decode_opt_box_autoadd_passwordless_recovery_config(arr[56]),
|
||||||
fcmToken: dco_decode_opt_String(arr[56]),
|
fcmToken: dco_decode_opt_String(arr[57]),
|
||||||
lastFcmWakeupAt: dco_decode_opt_box_autoadd_i_64(arr[57]),
|
lastFcmWakeupAt: dco_decode_opt_box_autoadd_i_64(arr[58]),
|
||||||
lastServerMessageAt: dco_decode_opt_box_autoadd_i_64(arr[58]),
|
lastServerMessageAt: dco_decode_opt_box_autoadd_i_64(arr[59]),
|
||||||
currentSetupPage: dco_decode_opt_String(arr[59]),
|
currentSetupPage: dco_decode_opt_String(arr[60]),
|
||||||
skipSetupPages: dco_decode_bool(arr[60]),
|
skipSetupPages: dco_decode_bool(arr[61]),
|
||||||
hasZoomed: dco_decode_bool(arr[61]),
|
hasZoomed: dco_decode_bool(arr[62]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -9241,6 +9242,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
var var_additionalUserInvites = sse_decode_opt_String(deserializer);
|
var var_additionalUserInvites = sse_decode_opt_String(deserializer);
|
||||||
var var_themeMode = sse_decode_theme_mode(deserializer);
|
var var_themeMode = sse_decode_theme_mode(deserializer);
|
||||||
var var_primaryColorValue = sse_decode_opt_box_autoadd_i_64(deserializer);
|
var var_primaryColorValue = sse_decode_opt_box_autoadd_i_64(deserializer);
|
||||||
|
var var_language = sse_decode_opt_String(deserializer);
|
||||||
var var_defaultShowTime = sse_decode_opt_box_autoadd_i_64(deserializer);
|
var var_defaultShowTime = sse_decode_opt_box_autoadd_i_64(deserializer);
|
||||||
var var_requestedAudioPermission = sse_decode_bool(deserializer);
|
var var_requestedAudioPermission = sse_decode_bool(deserializer);
|
||||||
var var_enableDatabaseLogging = sse_decode_bool(deserializer);
|
var var_enableDatabaseLogging = sse_decode_bool(deserializer);
|
||||||
|
|
@ -9315,6 +9317,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
additionalUserInvites: var_additionalUserInvites,
|
additionalUserInvites: var_additionalUserInvites,
|
||||||
themeMode: var_themeMode,
|
themeMode: var_themeMode,
|
||||||
primaryColorValue: var_primaryColorValue,
|
primaryColorValue: var_primaryColorValue,
|
||||||
|
language: var_language,
|
||||||
defaultShowTime: var_defaultShowTime,
|
defaultShowTime: var_defaultShowTime,
|
||||||
requestedAudioPermission: var_requestedAudioPermission,
|
requestedAudioPermission: var_requestedAudioPermission,
|
||||||
enableDatabaseLogging: var_enableDatabaseLogging,
|
enableDatabaseLogging: var_enableDatabaseLogging,
|
||||||
|
|
@ -10604,6 +10607,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
sse_encode_opt_String(self.additionalUserInvites, serializer);
|
sse_encode_opt_String(self.additionalUserInvites, serializer);
|
||||||
sse_encode_theme_mode(self.themeMode, serializer);
|
sse_encode_theme_mode(self.themeMode, serializer);
|
||||||
sse_encode_opt_box_autoadd_i_64(self.primaryColorValue, serializer);
|
sse_encode_opt_box_autoadd_i_64(self.primaryColorValue, serializer);
|
||||||
|
sse_encode_opt_String(self.language, serializer);
|
||||||
sse_encode_opt_box_autoadd_i_64(self.defaultShowTime, serializer);
|
sse_encode_opt_box_autoadd_i_64(self.defaultShowTime, serializer);
|
||||||
sse_encode_bool(self.requestedAudioPermission, serializer);
|
sse_encode_bool(self.requestedAudioPermission, serializer);
|
||||||
sse_encode_bool(self.enableDatabaseLogging, serializer);
|
sse_encode_bool(self.enableDatabaseLogging, serializer);
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,9 @@ class UserConfig {
|
||||||
String? additionalUserInvites;
|
String? additionalUserInvites;
|
||||||
ThemeMode themeMode;
|
ThemeMode themeMode;
|
||||||
PlatformInt64? primaryColorValue;
|
PlatformInt64? primaryColorValue;
|
||||||
|
|
||||||
|
/// Language code the app is shown in. `None` follows the device.
|
||||||
|
String? language;
|
||||||
PlatformInt64? defaultShowTime;
|
PlatformInt64? defaultShowTime;
|
||||||
bool requestedAudioPermission;
|
bool requestedAudioPermission;
|
||||||
bool enableDatabaseLogging;
|
bool enableDatabaseLogging;
|
||||||
|
|
@ -200,6 +203,7 @@ class UserConfig {
|
||||||
this.additionalUserInvites,
|
this.additionalUserInvites,
|
||||||
required this.themeMode,
|
required this.themeMode,
|
||||||
this.primaryColorValue,
|
this.primaryColorValue,
|
||||||
|
this.language,
|
||||||
this.defaultShowTime,
|
this.defaultShowTime,
|
||||||
required this.requestedAudioPermission,
|
required this.requestedAudioPermission,
|
||||||
required this.enableDatabaseLogging,
|
required this.enableDatabaseLogging,
|
||||||
|
|
@ -266,6 +270,7 @@ class UserConfig {
|
||||||
additionalUserInvites.hashCode ^
|
additionalUserInvites.hashCode ^
|
||||||
themeMode.hashCode ^
|
themeMode.hashCode ^
|
||||||
primaryColorValue.hashCode ^
|
primaryColorValue.hashCode ^
|
||||||
|
language.hashCode ^
|
||||||
defaultShowTime.hashCode ^
|
defaultShowTime.hashCode ^
|
||||||
requestedAudioPermission.hashCode ^
|
requestedAudioPermission.hashCode ^
|
||||||
enableDatabaseLogging.hashCode ^
|
enableDatabaseLogging.hashCode ^
|
||||||
|
|
@ -334,6 +339,7 @@ class UserConfig {
|
||||||
additionalUserInvites == other.additionalUserInvites &&
|
additionalUserInvites == other.additionalUserInvites &&
|
||||||
themeMode == other.themeMode &&
|
themeMode == other.themeMode &&
|
||||||
primaryColorValue == other.primaryColorValue &&
|
primaryColorValue == other.primaryColorValue &&
|
||||||
|
language == other.language &&
|
||||||
defaultShowTime == other.defaultShowTime &&
|
defaultShowTime == other.defaultShowTime &&
|
||||||
requestedAudioPermission == other.requestedAudioPermission &&
|
requestedAudioPermission == other.requestedAudioPermission &&
|
||||||
enableDatabaseLogging == other.enableDatabaseLogging &&
|
enableDatabaseLogging == other.enableDatabaseLogging &&
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import 'package:flutter/widgets.dart';
|
||||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||||
import 'package:intl/intl.dart' as intl;
|
import 'package:intl/intl.dart' as intl;
|
||||||
|
|
||||||
|
import 'app_localizations_ar.dart';
|
||||||
import 'app_localizations_de.dart';
|
import 'app_localizations_de.dart';
|
||||||
import 'app_localizations_en.dart';
|
import 'app_localizations_en.dart';
|
||||||
|
|
||||||
|
|
@ -94,6 +95,7 @@ abstract class AppLocalizations {
|
||||||
|
|
||||||
/// A list of this localizations delegate's supported locales.
|
/// A list of this localizations delegate's supported locales.
|
||||||
static const List<Locale> supportedLocales = <Locale>[
|
static const List<Locale> supportedLocales = <Locale>[
|
||||||
|
Locale('ar'),
|
||||||
Locale('de'),
|
Locale('de'),
|
||||||
Locale('en'),
|
Locale('en'),
|
||||||
];
|
];
|
||||||
|
|
@ -716,12 +718,6 @@ abstract class AppLocalizations {
|
||||||
/// **'FAQ'**
|
/// **'FAQ'**
|
||||||
String get settingsHelpFAQ;
|
String get settingsHelpFAQ;
|
||||||
|
|
||||||
/// No description provided for @feedbackTooltip.
|
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'Give Feedback to improve twonly.'**
|
|
||||||
String get feedbackTooltip;
|
|
||||||
|
|
||||||
/// No description provided for @settingsHelpContactUs.
|
/// No description provided for @settingsHelpContactUs.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
|
|
@ -866,6 +862,12 @@ abstract class AppLocalizations {
|
||||||
/// **'Theme'**
|
/// **'Theme'**
|
||||||
String get settingsAppearanceTheme;
|
String get settingsAppearanceTheme;
|
||||||
|
|
||||||
|
/// No description provided for @settingsAppearanceLanguage.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Language'**
|
||||||
|
String get settingsAppearanceLanguage;
|
||||||
|
|
||||||
/// No description provided for @settingsAccountDeleteAccount.
|
/// No description provided for @settingsAccountDeleteAccount.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
|
|
@ -1436,48 +1438,12 @@ abstract class AppLocalizations {
|
||||||
/// **'Your additional users'**
|
/// **'Your additional users'**
|
||||||
String get additionalUsersList;
|
String get additionalUsersList;
|
||||||
|
|
||||||
/// No description provided for @galleryDelete.
|
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'Delete file'**
|
|
||||||
String get galleryDelete;
|
|
||||||
|
|
||||||
/// No description provided for @galleryExport.
|
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'Export to gallery'**
|
|
||||||
String get galleryExport;
|
|
||||||
|
|
||||||
/// No description provided for @galleryExportSuccess.
|
/// No description provided for @galleryExportSuccess.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Successfully saved in the Gallery.'**
|
/// **'Successfully saved in the Gallery.'**
|
||||||
String get galleryExportSuccess;
|
String get galleryExportSuccess;
|
||||||
|
|
||||||
/// No description provided for @gallerySelectAll.
|
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'Select all'**
|
|
||||||
String get gallerySelectAll;
|
|
||||||
|
|
||||||
/// No description provided for @galleryDeselectAll.
|
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'Deselect all'**
|
|
||||||
String get galleryDeselectAll;
|
|
||||||
|
|
||||||
/// No description provided for @galleryFavorite.
|
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'Favorite'**
|
|
||||||
String get galleryFavorite;
|
|
||||||
|
|
||||||
/// No description provided for @galleryUnfavorite.
|
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'Unfavorite'**
|
|
||||||
String get galleryUnfavorite;
|
|
||||||
|
|
||||||
/// No description provided for @galleryCancel.
|
/// No description provided for @galleryCancel.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
|
|
@ -1526,12 +1492,6 @@ abstract class AppLocalizations {
|
||||||
/// **'Are you sure?'**
|
/// **'Are you sure?'**
|
||||||
String get deleteImageTitle;
|
String get deleteImageTitle;
|
||||||
|
|
||||||
/// No description provided for @deleteImageBody.
|
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'The image will be irrevocably deleted.'**
|
|
||||||
String get deleteImageBody;
|
|
||||||
|
|
||||||
/// No description provided for @deleteMemoriesBody.
|
/// No description provided for @deleteMemoriesBody.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
|
|
@ -1598,66 +1558,12 @@ abstract class AppLocalizations {
|
||||||
/// **'Backup'**
|
/// **'Backup'**
|
||||||
String get settingsBackup;
|
String get settingsBackup;
|
||||||
|
|
||||||
/// No description provided for @backupPending.
|
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'Pending'**
|
|
||||||
String get backupPending;
|
|
||||||
|
|
||||||
/// No description provided for @backupFailed.
|
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'Failed'**
|
|
||||||
String get backupFailed;
|
|
||||||
|
|
||||||
/// No description provided for @backupSuccess.
|
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'Success'**
|
|
||||||
String get backupSuccess;
|
|
||||||
|
|
||||||
/// No description provided for @backupTwonlySafeDesc.
|
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'Back up your twonly identity, as this is the only way to restore your account if you uninstall the app or lose your phone.'**
|
|
||||||
String get backupTwonlySafeDesc;
|
|
||||||
|
|
||||||
/// No description provided for @backupNoPasswordRecovery.
|
/// No description provided for @backupNoPasswordRecovery.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Due to twonly\'s security system, there is (currently) no password recovery function. Therefore, you must remember your password or, better yet, write it down.'**
|
/// **'Due to twonly\'s security system, there is (currently) no password recovery function. Therefore, you must remember your password or, better yet, write it down.'**
|
||||||
String get backupNoPasswordRecovery;
|
String get backupNoPasswordRecovery;
|
||||||
|
|
||||||
/// No description provided for @backupIdentityHeader.
|
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'Identity'**
|
|
||||||
String get backupIdentityHeader;
|
|
||||||
|
|
||||||
/// No description provided for @backupArchiveHeader.
|
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'Contacts & Messages'**
|
|
||||||
String get backupArchiveHeader;
|
|
||||||
|
|
||||||
/// No description provided for @backupLastBackupDate.
|
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'Last backup'**
|
|
||||||
String get backupLastBackupDate;
|
|
||||||
|
|
||||||
/// No description provided for @backupLastBackupSize.
|
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'Backup size'**
|
|
||||||
String get backupLastBackupSize;
|
|
||||||
|
|
||||||
/// No description provided for @backupLastBackupResult.
|
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'Result'**
|
|
||||||
String get backupLastBackupResult;
|
|
||||||
|
|
||||||
/// No description provided for @backupInsecurePassword.
|
/// No description provided for @backupInsecurePassword.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
|
|
@ -2318,12 +2224,6 @@ abstract class AppLocalizations {
|
||||||
/// **'Messages'**
|
/// **'Messages'**
|
||||||
String get notificationCategoryMessageTitle;
|
String get notificationCategoryMessageTitle;
|
||||||
|
|
||||||
/// No description provided for @notificationCategoryMessageDesc.
|
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'Messages from other users.'**
|
|
||||||
String get notificationCategoryMessageDesc;
|
|
||||||
|
|
||||||
/// No description provided for @notificationConnectionFallback.
|
/// No description provided for @notificationConnectionFallback.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
|
|
@ -4382,12 +4282,6 @@ abstract class AppLocalizations {
|
||||||
/// **'Local storage'**
|
/// **'Local storage'**
|
||||||
String get settingsStorageLocal;
|
String get settingsStorageLocal;
|
||||||
|
|
||||||
/// No description provided for @settingsStorageNoCloudBackupTitle.
|
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'No Cloud Backup'**
|
|
||||||
String get settingsStorageNoCloudBackupTitle;
|
|
||||||
|
|
||||||
/// No description provided for @settingsStorageNoCloudBackupCard.
|
/// No description provided for @settingsStorageNoCloudBackupCard.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
|
|
@ -4802,12 +4696,6 @@ abstract class AppLocalizations {
|
||||||
/// **'Contacts & Messages'**
|
/// **'Contacts & Messages'**
|
||||||
String get backupCloudContactsMessages;
|
String get backupCloudContactsMessages;
|
||||||
|
|
||||||
/// No description provided for @backupCloudFreeActive.
|
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'Free Active'**
|
|
||||||
String get backupCloudFreeActive;
|
|
||||||
|
|
||||||
/// No description provided for @backupCloudImagesMedia.
|
/// No description provided for @backupCloudImagesMedia.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
|
|
@ -4934,17 +4822,11 @@ abstract class AppLocalizations {
|
||||||
/// **'Already added to this chat'**
|
/// **'Already added to this chat'**
|
||||||
String get webxdcStoreAlreadyAdded;
|
String get webxdcStoreAlreadyAdded;
|
||||||
|
|
||||||
/// No description provided for @webxdcChatAppsMenu.
|
/// No description provided for @webxdcChatApps.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Chat apps'**
|
/// **'Chat apps'**
|
||||||
String get webxdcChatAppsMenu;
|
String get webxdcChatApps;
|
||||||
|
|
||||||
/// No description provided for @webxdcChatAppsTitle.
|
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'Chat apps'**
|
|
||||||
String get webxdcChatAppsTitle;
|
|
||||||
|
|
||||||
/// No description provided for @webxdcChatAppsEmpty.
|
/// No description provided for @webxdcChatAppsEmpty.
|
||||||
///
|
///
|
||||||
|
|
@ -4988,7 +4870,7 @@ class _AppLocalizationsDelegate
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool isSupported(Locale locale) =>
|
bool isSupported(Locale locale) =>
|
||||||
<String>['de', 'en'].contains(locale.languageCode);
|
<String>['ar', 'de', 'en'].contains(locale.languageCode);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool shouldReload(_AppLocalizationsDelegate old) => false;
|
bool shouldReload(_AppLocalizationsDelegate old) => false;
|
||||||
|
|
@ -4997,6 +4879,8 @@ class _AppLocalizationsDelegate
|
||||||
AppLocalizations lookupAppLocalizations(Locale locale) {
|
AppLocalizations lookupAppLocalizations(Locale locale) {
|
||||||
// Lookup logic when only language code is specified.
|
// Lookup logic when only language code is specified.
|
||||||
switch (locale.languageCode) {
|
switch (locale.languageCode) {
|
||||||
|
case 'ar':
|
||||||
|
return AppLocalizationsAr();
|
||||||
case 'de':
|
case 'de':
|
||||||
return AppLocalizationsDe();
|
return AppLocalizationsDe();
|
||||||
case 'en':
|
case 'en':
|
||||||
|
|
|
||||||
2854
lib/src/localization/generated/app_localizations_ar.dart
Normal file
2854
lib/src/localization/generated/app_localizations_ar.dart
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -339,9 +339,6 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get settingsHelpFAQ => 'FAQ';
|
String get settingsHelpFAQ => 'FAQ';
|
||||||
|
|
||||||
@override
|
|
||||||
String get feedbackTooltip => 'Feedback zur Verbesserung von twonly geben.';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get settingsHelpContactUs => 'Kontaktiere uns';
|
String get settingsHelpContactUs => 'Kontaktiere uns';
|
||||||
|
|
||||||
|
|
@ -416,6 +413,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get settingsAppearanceTheme => 'Theme';
|
String get settingsAppearanceTheme => 'Theme';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get settingsAppearanceLanguage => 'Sprache';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get settingsAccountDeleteAccount => 'Konto löschen';
|
String get settingsAccountDeleteAccount => 'Konto löschen';
|
||||||
|
|
||||||
|
|
@ -743,27 +743,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get additionalUsersList => 'Deine zusätzlichen Benutzer';
|
String get additionalUsersList => 'Deine zusätzlichen Benutzer';
|
||||||
|
|
||||||
@override
|
|
||||||
String get galleryDelete => 'Datei löschen';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get galleryExport => 'In Galerie exportieren';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get galleryExportSuccess => 'Erfolgreich in der Gallery gespeichert.';
|
String get galleryExportSuccess => 'Erfolgreich in der Gallery gespeichert.';
|
||||||
|
|
||||||
@override
|
|
||||||
String get gallerySelectAll => 'Alle auswählen';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get galleryDeselectAll => 'Auswahl aufheben';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get galleryFavorite => 'Als Favorit markieren';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get galleryUnfavorite => 'Favorit entfernen';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get galleryCancel => 'Abbrechen';
|
String get galleryCancel => 'Abbrechen';
|
||||||
|
|
||||||
|
|
@ -797,9 +779,6 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get deleteImageTitle => 'Bist du dir sicher?';
|
String get deleteImageTitle => 'Bist du dir sicher?';
|
||||||
|
|
||||||
@override
|
|
||||||
String get deleteImageBody => 'Das Bild wird unwiderruflich gelöscht.';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String deleteMemoriesBody(num count) {
|
String deleteMemoriesBody(num count) {
|
||||||
String _temp0 = intl.Intl.pluralLogic(
|
String _temp0 = intl.Intl.pluralLogic(
|
||||||
|
|
@ -849,38 +828,10 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get settingsBackup => 'Backup';
|
String get settingsBackup => 'Backup';
|
||||||
|
|
||||||
@override
|
|
||||||
String get backupPending => 'Ausstehend';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get backupFailed => 'Fehlgeschlagen';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get backupSuccess => 'Erfolgreich';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get backupTwonlySafeDesc =>
|
|
||||||
'Sichere deine twonly-Identität, da dies die einzige Möglichkeit ist, dein Konto wiederherzustellen, wenn du die App deinstallierst oder dein Handy verlierst.';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get backupNoPasswordRecovery =>
|
String get backupNoPasswordRecovery =>
|
||||||
'Aufgrund des Sicherheitssystems von twonly gibt es (derzeit) keine Funktion zur Wiederherstellung des Passworts. Daher musst du dir dein Passwort merken oder, besser noch, aufschreiben.';
|
'Aufgrund des Sicherheitssystems von twonly gibt es (derzeit) keine Funktion zur Wiederherstellung des Passworts. Daher musst du dir dein Passwort merken oder, besser noch, aufschreiben.';
|
||||||
|
|
||||||
@override
|
|
||||||
String get backupIdentityHeader => 'Identität';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get backupArchiveHeader => 'Kontakte & Nachrichten';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get backupLastBackupDate => 'Letztes Backup';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get backupLastBackupSize => 'Backup-Größe';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get backupLastBackupResult => 'Ergebnis';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get backupInsecurePassword => 'Unsicheres Passwort';
|
String get backupInsecurePassword => 'Unsicheres Passwort';
|
||||||
|
|
||||||
|
|
@ -1290,10 +1241,6 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get notificationCategoryMessageTitle => 'Nachrichten';
|
String get notificationCategoryMessageTitle => 'Nachrichten';
|
||||||
|
|
||||||
@override
|
|
||||||
String get notificationCategoryMessageDesc =>
|
|
||||||
'Nachrichten von anderen Benutzern.';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get notificationConnectionFallback =>
|
String get notificationConnectionFallback =>
|
||||||
'Du könntest neue Nachrichten haben.';
|
'Du könntest neue Nachrichten haben.';
|
||||||
|
|
@ -2546,9 +2493,6 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get settingsStorageLocal => 'Lokaler Speicherplatz';
|
String get settingsStorageLocal => 'Lokaler Speicherplatz';
|
||||||
|
|
||||||
@override
|
|
||||||
String get settingsStorageNoCloudBackupTitle => 'Kein Cloud-Backup';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get settingsStorageNoCloudBackupCard =>
|
String get settingsStorageNoCloudBackupCard =>
|
||||||
'Sichere deine Erinnerungen in der Cloud, um lokalen Speicherplatz freizugeben und deine Bilder nicht zu verlieren. Alles Ende-zu-Ende verschlüsselt.';
|
'Sichere deine Erinnerungen in der Cloud, um lokalen Speicherplatz freizugeben und deine Bilder nicht zu verlieren. Alles Ende-zu-Ende verschlüsselt.';
|
||||||
|
|
@ -2796,9 +2740,6 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get backupCloudContactsMessages => 'Kontakte & Nachrichten';
|
String get backupCloudContactsMessages => 'Kontakte & Nachrichten';
|
||||||
|
|
||||||
@override
|
|
||||||
String get backupCloudFreeActive => 'Kostenlos aktiv';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get backupCloudImagesMedia => 'Bilder & Medien';
|
String get backupCloudImagesMedia => 'Bilder & Medien';
|
||||||
|
|
||||||
|
|
@ -2891,10 +2832,7 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
String get webxdcStoreAlreadyAdded => 'Bereits zu diesem Chat hinzugefügt';
|
String get webxdcStoreAlreadyAdded => 'Bereits zu diesem Chat hinzugefügt';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get webxdcChatAppsMenu => 'Chat-Apps';
|
String get webxdcChatApps => 'Chat-Apps';
|
||||||
|
|
||||||
@override
|
|
||||||
String get webxdcChatAppsTitle => 'Chat-Apps';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get webxdcChatAppsEmpty =>
|
String get webxdcChatAppsEmpty =>
|
||||||
|
|
|
||||||
|
|
@ -336,9 +336,6 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get settingsHelpFAQ => 'FAQ';
|
String get settingsHelpFAQ => 'FAQ';
|
||||||
|
|
||||||
@override
|
|
||||||
String get feedbackTooltip => 'Give Feedback to improve twonly.';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get settingsHelpContactUs => 'Contact us';
|
String get settingsHelpContactUs => 'Contact us';
|
||||||
|
|
||||||
|
|
@ -413,6 +410,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get settingsAppearanceTheme => 'Theme';
|
String get settingsAppearanceTheme => 'Theme';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get settingsAppearanceLanguage => 'Language';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get settingsAccountDeleteAccount => 'Delete account';
|
String get settingsAccountDeleteAccount => 'Delete account';
|
||||||
|
|
||||||
|
|
@ -739,27 +739,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get additionalUsersList => 'Your additional users';
|
String get additionalUsersList => 'Your additional users';
|
||||||
|
|
||||||
@override
|
|
||||||
String get galleryDelete => 'Delete file';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get galleryExport => 'Export to gallery';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get galleryExportSuccess => 'Successfully saved in the Gallery.';
|
String get galleryExportSuccess => 'Successfully saved in the Gallery.';
|
||||||
|
|
||||||
@override
|
|
||||||
String get gallerySelectAll => 'Select all';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get galleryDeselectAll => 'Deselect all';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get galleryFavorite => 'Favorite';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get galleryUnfavorite => 'Unfavorite';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get galleryCancel => 'Cancel';
|
String get galleryCancel => 'Cancel';
|
||||||
|
|
||||||
|
|
@ -793,9 +775,6 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get deleteImageTitle => 'Are you sure?';
|
String get deleteImageTitle => 'Are you sure?';
|
||||||
|
|
||||||
@override
|
|
||||||
String get deleteImageBody => 'The image will be irrevocably deleted.';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String deleteMemoriesBody(num count) {
|
String deleteMemoriesBody(num count) {
|
||||||
String _temp0 = intl.Intl.pluralLogic(
|
String _temp0 = intl.Intl.pluralLogic(
|
||||||
|
|
@ -845,38 +824,10 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get settingsBackup => 'Backup';
|
String get settingsBackup => 'Backup';
|
||||||
|
|
||||||
@override
|
|
||||||
String get backupPending => 'Pending';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get backupFailed => 'Failed';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get backupSuccess => 'Success';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get backupTwonlySafeDesc =>
|
|
||||||
'Back up your twonly identity, as this is the only way to restore your account if you uninstall the app or lose your phone.';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get backupNoPasswordRecovery =>
|
String get backupNoPasswordRecovery =>
|
||||||
'Due to twonly\'s security system, there is (currently) no password recovery function. Therefore, you must remember your password or, better yet, write it down.';
|
'Due to twonly\'s security system, there is (currently) no password recovery function. Therefore, you must remember your password or, better yet, write it down.';
|
||||||
|
|
||||||
@override
|
|
||||||
String get backupIdentityHeader => 'Identity';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get backupArchiveHeader => 'Contacts & Messages';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get backupLastBackupDate => 'Last backup';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get backupLastBackupSize => 'Backup size';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get backupLastBackupResult => 'Result';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get backupInsecurePassword => 'Insecure password';
|
String get backupInsecurePassword => 'Insecure password';
|
||||||
|
|
||||||
|
|
@ -1284,9 +1235,6 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get notificationCategoryMessageTitle => 'Messages';
|
String get notificationCategoryMessageTitle => 'Messages';
|
||||||
|
|
||||||
@override
|
|
||||||
String get notificationCategoryMessageDesc => 'Messages from other users.';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get notificationConnectionFallback => 'You may have new messages.';
|
String get notificationConnectionFallback => 'You may have new messages.';
|
||||||
|
|
||||||
|
|
@ -2523,9 +2471,6 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get settingsStorageLocal => 'Local storage';
|
String get settingsStorageLocal => 'Local storage';
|
||||||
|
|
||||||
@override
|
|
||||||
String get settingsStorageNoCloudBackupTitle => 'No Cloud Backup';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get settingsStorageNoCloudBackupCard =>
|
String get settingsStorageNoCloudBackupCard =>
|
||||||
'Back up your memories to the cloud to free up local space and ensure you never lose your pictures. All end-to-end encrypted.';
|
'Back up your memories to the cloud to free up local space and ensure you never lose your pictures. All end-to-end encrypted.';
|
||||||
|
|
@ -2770,9 +2715,6 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get backupCloudContactsMessages => 'Contacts & Messages';
|
String get backupCloudContactsMessages => 'Contacts & Messages';
|
||||||
|
|
||||||
@override
|
|
||||||
String get backupCloudFreeActive => 'Free Active';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get backupCloudImagesMedia => 'Images & Media';
|
String get backupCloudImagesMedia => 'Images & Media';
|
||||||
|
|
||||||
|
|
@ -2862,10 +2804,7 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
String get webxdcStoreAlreadyAdded => 'Already added to this chat';
|
String get webxdcStoreAlreadyAdded => 'Already added to this chat';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get webxdcChatAppsMenu => 'Chat apps';
|
String get webxdcChatApps => 'Chat apps';
|
||||||
|
|
||||||
@override
|
|
||||||
String get webxdcChatAppsTitle => 'Chat apps';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get webxdcChatAppsEmpty =>
|
String get webxdcChatAppsEmpty =>
|
||||||
|
|
|
||||||
796
lib/src/localization/translations/ar.arb
Normal file
796
lib/src/localization/translations/ar.arb
Normal file
|
|
@ -0,0 +1,796 @@
|
||||||
|
{
|
||||||
|
"subscriptionAllApps": "الوصول إلى جميع التطبيقات",
|
||||||
|
"@@locale": "ar",
|
||||||
|
"registerSlogan": "ابقَ على تواصل بخصوصية.",
|
||||||
|
"onboardingWelcomeTitle": "مرحبًا بك في twonly!",
|
||||||
|
"onboardingWelcomeBody": "اكتشف طريقة خاصة وآمنة للبقاء على تواصل مع أصدقائك من خلال مشاركة الصور الفورية.",
|
||||||
|
"onboardingE2eTitle": "مشاركة بلا قلق",
|
||||||
|
"onboardingE2eBody": "بفضل التشفير التام بين الطرفين، اطمئن إلى أن اللحظات التي تشاركها لا يراها أحد سواك وسوى أصدقائك.",
|
||||||
|
"onboardingFocusTitle": "ركّز على مشاركة اللحظات",
|
||||||
|
"onboardingFocusBody": "وداعًا للميزات التي تسبب الإدمان! صُمّم twonly لمشاركة اللحظات، بعيدًا عن المشتتات غير المفيدة والإعلانات.",
|
||||||
|
"onboardingNotProductTitle": "أنت لست المنتَج!",
|
||||||
|
"onboardingNotProductBody": "يُموَّل twonly من خلال اشتراك اختياري. لن تُباع بياناتك أبدًا.",
|
||||||
|
"registerUsernameSlogan": "أنشئ حسابك",
|
||||||
|
"registerUsernameDecoration": "اسم المستخدم",
|
||||||
|
"registerUsernameLimits": "3 أحرف على الأقل.",
|
||||||
|
"registerProofOfWorkFailed": "حدثت مشكلة في اختبار التحقق. يُرجى المحاولة مرة أخرى.",
|
||||||
|
"registerSubmitButton": "سجّل الآن!",
|
||||||
|
"chatsTapToSend": "اضغط لإرسال صورتك الأولى",
|
||||||
|
"cameraPreviewSendTo": "إرسال إلى",
|
||||||
|
"cameraPermissionsBody": "يحتاج twonly إلى الوصول إلى الكاميرا والميكروفون.",
|
||||||
|
"cameraPermissionsRequestButton": "طلب الأذونات",
|
||||||
|
"shareImageTitle": "مشاركة مع",
|
||||||
|
"shareImageBestFriends": "أفضل الأصدقاء",
|
||||||
|
"shareImagePinnedContacts": "المثبّتة",
|
||||||
|
"shareImagedEditorSendImage": "إرسال",
|
||||||
|
"shareImagedEditorShareWith": "مشاركة مع",
|
||||||
|
"shareImagedEditorSaveImage": "حفظ",
|
||||||
|
"shareImagedEditorSavedImage": "تم الحفظ",
|
||||||
|
"shareImageSearchAllContacts": "البحث في جميع جهات الاتصال",
|
||||||
|
"startNewChatSearchHint": "الاسم أو اسم المستخدم أو اسم المجموعة",
|
||||||
|
"shareImagedSelectAll": "تحديد الكل",
|
||||||
|
"startNewChatTitle": "اختر جهة اتصال",
|
||||||
|
"startNewChatNewContact": "جهة اتصال جديدة",
|
||||||
|
"shareImageAllUsers": "جميع جهات الاتصال",
|
||||||
|
"shareImageShowArchived": "إظهار المستخدمين المؤرشفين",
|
||||||
|
"shareImageSendToWidget": "إرسال إلى أداة الشاشة الرئيسية",
|
||||||
|
"shareImageWidgetExplainerTitle": "إرسال إلى أداة",
|
||||||
|
"shareImageWidgetExplainerBody": "يُرسل الصورة مباشرةً إلى أدوات الشاشة الرئيسية لدى أصدقائك. لا يمكن اختيار سوى الأصدقاء الذين يسمحون بذلك.",
|
||||||
|
"shareImageWidgetExplainerDismiss": "فهمت",
|
||||||
|
"searchUsernameInput": "اسم المستخدم",
|
||||||
|
"addFriendTitle": "إضافة أصدقاء",
|
||||||
|
"searchUserNamePending": "الطلب قيد الانتظار",
|
||||||
|
"searchUsernameNotFound": "اسم المستخدم غير موجود",
|
||||||
|
"searchUsernameNewFollowerTitle": "الطلبات المفتوحة",
|
||||||
|
"chatListDetailInput": "اكتب رسالة",
|
||||||
|
"userDeletedAccount": "تم حذف حساب هذا المستخدم.",
|
||||||
|
"contextMenuUserProfile": "الملف الشخصي",
|
||||||
|
"contextMenuArchiveUser": "أرشفة",
|
||||||
|
"contextMenuUndoArchiveUser": "إلغاء الأرشفة",
|
||||||
|
"contextMenuOpenChat": "فتح المحادثة",
|
||||||
|
"contextMenuPin": "تثبيت",
|
||||||
|
"contextMenuUnpin": "إلغاء التثبيت",
|
||||||
|
"contextMenuViewAgain": "عرض مرة أخرى",
|
||||||
|
"mediaViewerAuthReason": "يُرجى المصادقة لعرض رسالة twonly هذه!",
|
||||||
|
"mediaViewerTwonlyTapToOpen": "اضغط لفتح رسالة twonly!",
|
||||||
|
"messageSendState_Received": "تم الاستلام",
|
||||||
|
"messageSendState_Opened": "تم الفتح",
|
||||||
|
"messageSendState_Send": "تم الإرسال",
|
||||||
|
"messageSendState_Delivered": "تم الاستلام",
|
||||||
|
"messageSendState_Sending": "جارٍ الإرسال",
|
||||||
|
"messageSendState_TapToLoad": "اضغط للتحميل",
|
||||||
|
"messageSendState_Loading": "جارٍ التنزيل",
|
||||||
|
"messageStoredInGallery": "حُفظت في المعرض",
|
||||||
|
"messageReopened": "أُعيد فتحها",
|
||||||
|
"imageEditorDrawOk": "اعتماد الرسم",
|
||||||
|
"settingsTitle": "الإعدادات",
|
||||||
|
"settingsChats": "المحادثات",
|
||||||
|
"settingsPreSelectedReactions": "رموز التفاعل المحددة مسبقًا",
|
||||||
|
"settingsAutomaticallyMarkEqualMediaFilesAsOpenedTitle": "تمييز المكررات كمفتوحة",
|
||||||
|
"settingsAutomaticallyMarkEqualMediaFilesAsOpenedSubtitle": "إذا استلمت الوسائط نفسها في عدة محادثات، فإن فتحها في إحداها يميّزها كمفتوحة في البقية.",
|
||||||
|
"settingsPreSelectedReactionsError": "يمكن اختيار 12 تفاعلًا كحد أقصى.",
|
||||||
|
"settingsProfile": "الملف الشخصي",
|
||||||
|
"settingsStorageData": "الذكريات والتخزين",
|
||||||
|
"memoryLocationTitle": "حفظ الموقع في الذكريات",
|
||||||
|
"memoryLocationSubtitle": "الموقع للذكريات وللتصدير إلى المعرض. لا يُرسل أبدًا إلى جهات الاتصال.",
|
||||||
|
"memoryLocationPermissionDenied": "لم يُمنح إذن الوصول إلى الموقع الدقيق. سيبقى هذا الإعداد معطّلًا.",
|
||||||
|
"settingsStorageDataStoreInGTitle": "الحفظ في المعرض",
|
||||||
|
"settingsStorageDataMediaAutoDownload": "التنزيل التلقائي للوسائط",
|
||||||
|
"settingsStorageDataAutoDownMobile": "عند استخدام بيانات الجوال",
|
||||||
|
"settingsStorageDataAutoDownWifi": "عند استخدام Wi-Fi",
|
||||||
|
"settingsStorageManageTitle": "إدارة التخزين",
|
||||||
|
"settingsStorageUsed": "المساحة المستخدمة",
|
||||||
|
"settingsStorageImages": "الصور",
|
||||||
|
"settingsStorageVideos": "مقاطع الفيديو",
|
||||||
|
"settingsStorageGifs": "صور GIF",
|
||||||
|
"settingsProfileCustomizeAvatar": "خصّص صورتك الرمزية",
|
||||||
|
"settingsProfileEditDisplayName": "الاسم المعروض",
|
||||||
|
"settingsProfileEditDisplayNameNew": "اسم معروض جديد",
|
||||||
|
"settingsAccount": "الحساب",
|
||||||
|
"settingsSubscription": "الاشتراك",
|
||||||
|
"settingsAppearance": "المظهر",
|
||||||
|
"settingsPrivacy": "الخصوصية والأمان",
|
||||||
|
"settingsPrivacyBlockUsers": "حظر جهات الاتصال",
|
||||||
|
"settingsPrivacyBlockUsersDesc": "لن تتمكن جهات الاتصال المحظورة من التواصل معك. يمكنك إلغاء حظر أي جهة اتصال في أي وقت.",
|
||||||
|
"settingsPrivacyBlockUsersCount": "جهات الاتصال: {len}",
|
||||||
|
"settingsNotification": "الإشعارات",
|
||||||
|
"settingsNotifyPermission": "أذونات الإشعارات",
|
||||||
|
"settingsNotifyPermissionDesc": "افتح إعدادات النظام للسماح بالإشعارات الفورية.",
|
||||||
|
"settingsNotifyResetTitle": "إعادة تعيين رموز الإشعارات",
|
||||||
|
"settingsNotifyResetTitleSubtitle": "أعد تعيين رموز الإشعارات إذا واجهت مشكلات في استلام الإشعارات الفورية.",
|
||||||
|
"settingsNotifyResetTitleReset": "تمت إعادة تعيين رموز الإشعارات الخاصة بك.",
|
||||||
|
"settingsNotifyResetTitleResetDesc": "إذا استمرت المشكلة، يُرجى إرسال سجل تصحيح الأخطاء إلينا عبر الإعدادات > المساعدة حتى نتمكن من فحص المشكلة.",
|
||||||
|
"settingsHelp": "المساعدة",
|
||||||
|
"settingsHelpDiagnostics": "سجل التشخيص",
|
||||||
|
"settingsHelpFAQ": "الأسئلة الشائعة",
|
||||||
|
"settingsHelpContactUs": "اتصل بنا",
|
||||||
|
"settingsHelpVersion": "الإصدار",
|
||||||
|
"settingsHelpLicenses": "التراخيص (الشيفرة المصدرية)",
|
||||||
|
"settingsHelpCredits": "التراخيص (الصور)",
|
||||||
|
"settingsHelpImprint": "بيانات الناشر وسياسة الخصوصية",
|
||||||
|
"contactUsFaq": "هل قرأت الأسئلة الشائعة؟",
|
||||||
|
"contactUsEmojis": "كيف تشعر؟ (اختياري)",
|
||||||
|
"contactUsSelectOption": "يُرجى اختيار أحد الخيارات",
|
||||||
|
"contactUsReason": "أخبرنا عن سبب تواصلك معنا",
|
||||||
|
"contactUsMessage": "إذا كنت ترغب في تلقي رد، يُرجى إضافة عنوان بريدك الإلكتروني حتى نتمكن من التواصل معك.",
|
||||||
|
"contactUsYourMessage": "رسالتك",
|
||||||
|
"contactUsMessageTitle": "أخبرنا بما يحدث",
|
||||||
|
"contactUsReasonNotWorking": "شيء ما لا يعمل",
|
||||||
|
"contactUsReasonFeatureRequest": "طلب ميزة",
|
||||||
|
"contactUsReasonQuestion": "سؤال",
|
||||||
|
"contactUsReasonFeedback": "ملاحظات",
|
||||||
|
"contactUsReasonOther": "أخرى",
|
||||||
|
"contactUsIncludeLog": "إرفاق سجل تصحيح الأخطاء",
|
||||||
|
"contactUsWhatsThat": "ما هذا؟",
|
||||||
|
"contactUsLastWarning": "هذه هي المعلومات التي سيتم إرسالها إلينا. يُرجى مراجعتها ثم الضغط على إرسال.",
|
||||||
|
"contactUsSuccess": "تم إرسال ملاحظاتك بنجاح!",
|
||||||
|
"hideNewsIcon": "إخفاء أيقونة الأخبار",
|
||||||
|
"settingsHelpTerms": "شروط الخدمة",
|
||||||
|
"settingsAppearanceTheme": "السمة",
|
||||||
|
"settingsAppearanceLanguage": "اللغة",
|
||||||
|
"settingsAccountDeleteAccount": "حذف الحساب",
|
||||||
|
"settingsAccountDeleteAccountNoBallance": "بمجرد حذف حسابك، لا يمكن التراجع عن ذلك.",
|
||||||
|
"settingsAccountDeleteModalTitle": "هل أنت متأكد؟",
|
||||||
|
"settingsAccountDeleteModalBody": "سيتم حذف حسابك، ولن تكون هناك أي إمكانية لاستعادته.",
|
||||||
|
"contactVerifyNumberTitle": "التحقق من جهات الاتصال",
|
||||||
|
"verifyUserIdentity": "التحقق من هوية {username}",
|
||||||
|
"contactVerifyNumberSubtitle": "تحقق من هوية جهات اتصالك للتأكد من أنك تراسل الشخص الصحيح.",
|
||||||
|
"inChatContactNotVerified": "جهة الاتصال غير موثّقة.",
|
||||||
|
"groupMembersNotVerified": "أعضاء غير موثّقين: {count}.",
|
||||||
|
"userVerifiedTitle": "تم التحقق من جهة الاتصال",
|
||||||
|
"scanUserQrCode": "امسح رمز QR الخاص بـ {username}",
|
||||||
|
"openOwnQrCode": "افتح رمز QR الخاص بك",
|
||||||
|
"contactVerifiedBy": "تم التحقق بواسطة {username}",
|
||||||
|
"contactSharedByUnknown": "تمت مشاركتها من جهة اتصال موثّقة (اسم المستخدم غير متاح)",
|
||||||
|
"verificationTypeQrScanned": "لقد مسحت رمز QR الخاص بجهة الاتصال.",
|
||||||
|
"verificationTypeSecretQrToken": "تم مسح رمز QR الخاص بك من قِبل {username}.",
|
||||||
|
"verificationTypeLink": "تم التحقق عبر رابط.",
|
||||||
|
"verificationTypeManual": "تمت مقارنة رقم الأمان يدويًا.",
|
||||||
|
"verificationTypeMigratedFromOldVersion": "تم النقل من إصدار قديم.",
|
||||||
|
"contactViewMessage": "رسالة",
|
||||||
|
"contactNickname": "الاسم المستعار",
|
||||||
|
"contactNicknameNew": "اسم مستعار جديد",
|
||||||
|
"contactBlock": "حظر",
|
||||||
|
"contactTroubleshoot": "استكشاف مشكلات الاتصال وإصلاحها",
|
||||||
|
"contactResetSessionTitle": "إعادة تعيين الاتصال مع {username}؟",
|
||||||
|
"contactResetSessionBody": "سيزيل twonly الاتصال المشفّر الحالي وينشئ اتصالًا جديدًا. قد تُفقد الرسائل التي لا تزال قيد الإرسال.",
|
||||||
|
"contactResetSessionConfirm": "إعادة تعيين الاتصال",
|
||||||
|
"contactResetSessionSuccess": "تمت إعادة إنشاء الاتصال المشفّر مع {username}.",
|
||||||
|
"contactResetSessionFailed": "تعذّرت إعادة تعيين الاتصال. تحقق من اتصالك بالإنترنت وحاول مرة أخرى.",
|
||||||
|
"contactBlockTitle": "حظر {username}",
|
||||||
|
"contactBlockBody": "لن تتمكن جهة الاتصال المحظورة من إرسال رسائل إليك بعد الآن، وسيتم إخفاء ملفها الشخصي. لإلغاء حظر جهة اتصال، انتقل إلى الإعدادات > الخصوصية > جهات الاتصال المحظورة.",
|
||||||
|
"contactRemove": "إزالة جهة الاتصال",
|
||||||
|
"contactRemoveTitle": "إزالة {username}",
|
||||||
|
"contactRemoveBody": "إزالة جهة الاتصال نهائيًا. إذا حاولت جهة الاتصال إرسال رسالة جديدة إليك، فسيتعيّن عليك قبولها مرة أخرى أولًا.",
|
||||||
|
"undo": "تراجع",
|
||||||
|
"redo": "إعادة",
|
||||||
|
"next": "التالي",
|
||||||
|
"finishSetup": "إكمال الإعداد",
|
||||||
|
"submit": "إرسال",
|
||||||
|
"close": "إغلاق",
|
||||||
|
"disable": "تعطيل",
|
||||||
|
"enable": "تفعيل",
|
||||||
|
"cancel": "إلغاء",
|
||||||
|
"now": "الآن",
|
||||||
|
"you": "أنت",
|
||||||
|
"minutesShort": "د",
|
||||||
|
"image": "صورة",
|
||||||
|
"video": "فيديو",
|
||||||
|
"react": "تفاعل",
|
||||||
|
"reply": "رد",
|
||||||
|
"copy": "نسخ",
|
||||||
|
"edit": "تعديل",
|
||||||
|
"delete": "حذف",
|
||||||
|
"info": "معلومات",
|
||||||
|
"ok": "حسنًا",
|
||||||
|
"switchFrontAndBackCamera": "التبديل بين الكاميرا الأمامية والخلفية.",
|
||||||
|
"addTextItem": "نص",
|
||||||
|
"protectAsARealTwonly": "إرسال كرسالة twonly حقيقية!",
|
||||||
|
"addDrawing": "رسم",
|
||||||
|
"addEmoji": "رمز تعبيري",
|
||||||
|
"toggleFlashLight": "تشغيل الفلاش أو إيقافه",
|
||||||
|
"userFound": "تم العثور على {username}",
|
||||||
|
"userFoundBody": "هل تريد التواصل مع {username}؟",
|
||||||
|
"errorInternalError": "الخادم غير متاح حاليًا. يُرجى المحاولة لاحقًا.",
|
||||||
|
"errorInvalidInvitationCode": "رمز الدعوة الذي أدخلته غير صالح. يُرجى التحقق من الرمز والمحاولة مرة أخرى.",
|
||||||
|
"errorUsernameAlreadyTaken": "اسم المستخدم مستخدم بالفعل.",
|
||||||
|
"errorUsernameNotValid": "اسم المستخدم الذي أدخلته لا يستوفي المعايير المطلوبة. يُرجى اختيار اسم مستخدم صالح.",
|
||||||
|
"errorNotEnoughCredit": "ليس لديك رصيد twonly كافٍ.",
|
||||||
|
"errorVoucherInvalid": "رمز القسيمة الذي أدخلته غير صالح.",
|
||||||
|
"errorPlanLimitReached": "لقد وصلت إلى حد خطتك. يُرجى ترقية خطتك.",
|
||||||
|
"errorPlanNotAllowed": "هذه الميزة غير متاحة في خطتك الحالية.",
|
||||||
|
"errorPlanUpgradeNotYearly": "يجب دفع قيمة ترقية الخطة سنويًا، لأن الخطة الحالية تُدفع سنويًا أيضًا.",
|
||||||
|
"upgradeToPaidPlanButton": "الترقية إلى {planId}{sufix}",
|
||||||
|
"partOfPaidPlanFrom": "ضمن الخطة المدفوعة لـ",
|
||||||
|
"subscriptionCurrentPlanBadge": "الحالية",
|
||||||
|
"year": "سنة",
|
||||||
|
"yearly": "سنويًا",
|
||||||
|
"month": "شهر",
|
||||||
|
"monthly": "شهريًا",
|
||||||
|
"proFeature1": "رفع غير محدود لملفات الوسائط",
|
||||||
|
"proFeature2": "مستخدم Plus إضافي واحد",
|
||||||
|
"proFeature3": "مساحة 25 GB لتخزين الذكريات",
|
||||||
|
"proFeature4": "استعادة الشعلات",
|
||||||
|
"familyFeature1": "رفع غير محدود لملفات الوسائط",
|
||||||
|
"familyFeature2": "4 مستخدمين Plus إضافيين",
|
||||||
|
"familyFeature3": "مساحة 50 GB لتخزين الذكريات",
|
||||||
|
"familyFeature4": "استعادة الشعلات",
|
||||||
|
"freeFeature1": "رفع 10 ملفات وسائط يوميًا",
|
||||||
|
"plusFeature1": "رفع غير محدود لملفات الوسائط",
|
||||||
|
"plusFeature2": "ميزات إضافية (قريبًا)",
|
||||||
|
"manageAdditionalUsers": "إدارة المستخدمين الإضافيين",
|
||||||
|
"open": "فتح",
|
||||||
|
"buy": "شراء",
|
||||||
|
"autoRenewal": "التجديد التلقائي",
|
||||||
|
"additionalUsersList": "مستخدموك الإضافيون",
|
||||||
|
"galleryExportSuccess": "تم الحفظ في المعرض بنجاح.",
|
||||||
|
"galleryCancel": "إلغاء",
|
||||||
|
"memoriesEmpty": "بمجرد حفظ الصور أو مقاطع الفيديو، ستظهر هنا في ذكرياتك.",
|
||||||
|
"deleteTitle": "هل أنت متأكد؟",
|
||||||
|
"deleteOkBtnForAll": "حذف لدى الجميع",
|
||||||
|
"memoriesDeleteSnackbarSuccess": "{count, plural, =1{تم حذف عنصر واحد بنجاح} =2{تم حذف عنصرين بنجاح} few{تم حذف {count} عناصر بنجاح} many{تم حذف {count} عنصرًا بنجاح} other{تم حذف {count} عنصر بنجاح}}",
|
||||||
|
"deleteOkBtnForMe": "حذف لديّ",
|
||||||
|
"deleteOnlyForMe": "حذف لديّ فقط",
|
||||||
|
"deleteImageTitle": "هل أنت متأكد؟",
|
||||||
|
"deleteMemoriesBody": "{count, plural, =1{سيتم حذف الصورة نهائيًا.} =2{سيتم حذف الصورتين نهائيًا.} few{سيتم حذف {count} صور نهائيًا.} many{سيتم حذف {count} صورة نهائيًا.} other{سيتم حذف {count} صورة نهائيًا.}}",
|
||||||
|
"deleteMemoriesLocalOnly": "محليًا فقط",
|
||||||
|
"deleteMemoriesCompletely": "بالكامل",
|
||||||
|
"memoriesSelectedCount": "{count, plural, =1{عنصر واحد} =2{عنصران} few{{count} عناصر} many{{count} عنصرًا} other{{count} عنصر}}",
|
||||||
|
"memoriesMenuSelectAll": "تحديد الكل",
|
||||||
|
"memoriesMenuDeselectAll": "إلغاء تحديد الكل",
|
||||||
|
"memoriesMenuExport": "تصدير إلى المعرض",
|
||||||
|
"memoriesMenuFavorite": "إضافة إلى المفضلة",
|
||||||
|
"memoriesMenuDelete": "حذف بالكامل",
|
||||||
|
"memoriesMenuDeleteLocal": "حذف محليًا",
|
||||||
|
"settingsBackup": "النسخ الاحتياطي",
|
||||||
|
"backupNoPasswordRecovery": "بسبب نظام الأمان في twonly، لا توجد (حاليًا) وظيفة لاستعادة كلمة المرور. لذلك يجب عليك تذكّر كلمة مرورك، أو الأفضل من ذلك أن تدوّنها.",
|
||||||
|
"backupInsecurePassword": "كلمة مرور غير آمنة",
|
||||||
|
"backupInsecurePasswordDesc": "كلمة المرور المختارة غير آمنة إطلاقًا، ويمكن للمهاجمين تخمينها بسهولة. يُرجى اختيار كلمة مرور آمنة.",
|
||||||
|
"backupInsecurePasswordOk": "المتابعة على أي حال",
|
||||||
|
"backupInsecurePasswordCancel": "حاول مرة أخرى",
|
||||||
|
"backupTwonlySafeLongDesc": "لا يستخدم twonly أي حسابات مستخدمين مركزية. عند التثبيت يتم إنشاء زوج مفاتيح يتكوّن من مفتاح عام ومفتاح خاص. يُخزَّن المفتاح الخاص على جهازك فقط لحمايته من الوصول غير المصرّح به. أما المفتاح العام فيُرفع إلى الخادم ويُربط باسم المستخدم الذي اخترته حتى يتمكن الآخرون من العثور عليك.\n\nيُنشئ النسخ الاحتياطي في twonly بانتظام نسخة احتياطية مشفّرة ومجهولة الهوية من مفتاحك الخاص مع جهات اتصالك وإعداداتك. يكفي اسم المستخدم وكلمة المرور التي اخترتها لاستعادة هذه البيانات على جهاز آخر.",
|
||||||
|
"backupSelectStrongPassword": "اختر كلمة مرور آمنة. يُنصح بإنشائها وحفظها باستخدام مدير كلمات المرور الذي تفضّله.",
|
||||||
|
"password": "كلمة المرور",
|
||||||
|
"passwordRepeated": "أعد إدخال كلمة المرور",
|
||||||
|
"passwordRepeatedNotEqual": "كلمتا المرور غير متطابقتين.",
|
||||||
|
"backupPasswordRequirement": "يجب أن تتكوّن كلمة المرور من 10 أحرف على الأقل.",
|
||||||
|
"backupEnableBackup": "تفعيل النسخ الاحتياطي بكلمة مرور",
|
||||||
|
"backupTwonlySaveNow": "احفظ الآن",
|
||||||
|
"backupChangePassword": "تغيير كلمة المرور",
|
||||||
|
"backupChangePasswordAuthReason": "تغيير كلمة مرور النسخ الاحتياطي",
|
||||||
|
"backupChangePasswordAuthFailed": "لا يمكنك تغيير كلمة المرور إلا بعد المصادقة!",
|
||||||
|
"backupFreeSpaceWithCloud": "وفّر المساحة بالنسخ الاحتياطي السحابي",
|
||||||
|
"backupMemoriesNotEnabled": "غير مفعّل",
|
||||||
|
"backupMemoriesUpgradeRequired": "يتطلب ترقية",
|
||||||
|
"todayAt": "اليوم الساعة {time}",
|
||||||
|
"yesterdayAt": "أمس الساعة {time}",
|
||||||
|
"twonlySafeRecoverTitle": "استعادة النسخة الاحتياطية",
|
||||||
|
"twonlySafeRecoverBtn": "استعادة النسخة الاحتياطية",
|
||||||
|
"inviteFriends": "ادعُ أصدقاءك",
|
||||||
|
"inviteFriendsShareBtn": "مشاركة",
|
||||||
|
"inviteFriendsShareText": "لننتقل إلى twonly: {url}",
|
||||||
|
"appOutdated": "إصدار twonly لديك قديم.",
|
||||||
|
"appOutdatedBtn": "حدّث الآن",
|
||||||
|
"doubleClickToReopen": "انقر مرتين\nلفتحها مجددًا",
|
||||||
|
"uploadLimitReached": "تم الوصول إلى حد الرفع.\nقم بالترقية إلى Pro\nأو انتظر حتى الغد.",
|
||||||
|
"fileLimitReached": "تم تجاوز الحد الأقصى\nلحجم الملف",
|
||||||
|
"retransmissionRequested": "تم طلب إعادة الإرسال",
|
||||||
|
"reportUserTitle": "الإبلاغ عن {username}",
|
||||||
|
"reportUserReason": "سبب الإبلاغ",
|
||||||
|
"reportUser": "الإبلاغ عن جهة الاتصال",
|
||||||
|
"newDeviceRegistered": "لقد سجّلت الدخول على جهاز آخر، لذلك تم تسجيل خروجك هنا.",
|
||||||
|
"tabToRemoveEmoji": "اضغط للإزالة",
|
||||||
|
"quotedMessageWasDeleted": "تم حذف الرسالة المقتبسة.",
|
||||||
|
"messageWasDeleted": "تم حذف الرسالة.",
|
||||||
|
"messageWasDeletedShort": "محذوفة",
|
||||||
|
"sent": "تم التسليم",
|
||||||
|
"sentTo": "تم التسليم إلى",
|
||||||
|
"received": "تم الاستلام",
|
||||||
|
"opened": "تم الفتح",
|
||||||
|
"waitingForInternet": "في انتظار الاتصال بالإنترنت",
|
||||||
|
"editHistory": "سجل التعديلات",
|
||||||
|
"fileSize": "حجم الملف",
|
||||||
|
"archivedChats": "المحادثات المؤرشفة",
|
||||||
|
"durationShortSecond": "ث",
|
||||||
|
"durationShortMinute": "د",
|
||||||
|
"durationShortHour": "س",
|
||||||
|
"durationShortDays": "{count, plural, =1{يوم واحد} =2{يومان} few{{count} أيام} many{{count} يومًا} other{{count} يوم}}",
|
||||||
|
"contacts": "جهات الاتصال",
|
||||||
|
"groups": "المجموعات",
|
||||||
|
"newGroup": "مجموعة جديدة",
|
||||||
|
"selectMembers": "اختر الأعضاء",
|
||||||
|
"selectGroupName": "اختر اسم المجموعة",
|
||||||
|
"groupNameInput": "اسم المجموعة",
|
||||||
|
"groupMembers": "الأعضاء",
|
||||||
|
"addMember": "إضافة عضو",
|
||||||
|
"createGroup": "إنشاء مجموعة",
|
||||||
|
"leaveGroup": "مغادرة المجموعة",
|
||||||
|
"createContactRequest": "إنشاء طلب تواصل",
|
||||||
|
"contactRequestSend": "تم إرسال طلب التواصل",
|
||||||
|
"makeAdmin": "تعيين كمشرف",
|
||||||
|
"removeAdmin": "إزالة من الإشراف",
|
||||||
|
"removeFromGroup": "إزالة من المجموعة",
|
||||||
|
"admin": "مشرف",
|
||||||
|
"revokeAdminRightsTitle": "سحب صلاحيات الإشراف من {username}؟",
|
||||||
|
"revokeAdminRightsOkBtn": "إزالة من الإشراف",
|
||||||
|
"makeAdminRightsTitle": "تعيين {username} مشرفًا؟",
|
||||||
|
"makeAdminRightsBody": "سيتمكن {username} من تعديل هذه المجموعة وأعضائها.",
|
||||||
|
"makeAdminRightsOkBtn": "تعيين كمشرف",
|
||||||
|
"updateGroup": "تحديث المجموعة",
|
||||||
|
"alreadyInGroup": "موجود في المجموعة بالفعل",
|
||||||
|
"contactNotVerified": "غير موثّق",
|
||||||
|
"removeContactFromGroupTitle": "إزالة {username} من هذه المجموعة؟",
|
||||||
|
"youChangedGroupName": "لقد غيّرت اسم المجموعة إلى «{newGroupName}».",
|
||||||
|
"makerChangedGroupName": "غيّر {maker} اسم المجموعة إلى «{newGroupName}».",
|
||||||
|
"youCreatedGroup": "لقد أنشأت المجموعة.",
|
||||||
|
"makerCreatedGroup": "أنشأ {maker} المجموعة.",
|
||||||
|
"youRemovedMember": "لقد أزلت {affected} من المجموعة.",
|
||||||
|
"makerRemovedMember": "أزال {maker} {affected} من المجموعة.",
|
||||||
|
"youAddedMember": "لقد أضفت {affected} إلى المجموعة.",
|
||||||
|
"makerAddedMember": "أضاف {maker} {affected} إلى المجموعة.",
|
||||||
|
"youMadeAdmin": "لقد منحت {affected} صلاحيات الإشراف.",
|
||||||
|
"makerMadeAdmin": "منح {maker} {affected} صلاحيات الإشراف.",
|
||||||
|
"youRevokedAdminRights": "لقد سحبت صلاحيات الإشراف من {affectedR}.",
|
||||||
|
"makerRevokedAdminRights": "سحب {maker} صلاحيات الإشراف من {affectedR}.",
|
||||||
|
"youLeftGroup": "لقد غادرت المجموعة.",
|
||||||
|
"makerLeftGroup": "غادر {maker} المجموعة.",
|
||||||
|
"groupActionYou": "حسابك",
|
||||||
|
"groupActionYour": "حسابك",
|
||||||
|
"notificationFillerIn": "في",
|
||||||
|
"notificationText": "رسالة جديدة{inGroup}.",
|
||||||
|
"notificationTwonly": "رسالة twonly جديدة{inGroup}.",
|
||||||
|
"notificationVideo": "فيديو جديد{inGroup}.",
|
||||||
|
"notificationImage": "صورة جديدة{inGroup}.",
|
||||||
|
"notificationAudio": "رسالة صوتية جديدة{inGroup}.",
|
||||||
|
"notificationAddedToGroup": "تمت إضافتك إلى «{groupname}»",
|
||||||
|
"notificationContactRequest": "طلب جديد للتواصل معك.",
|
||||||
|
"notificationAcceptRequest": "أنتما متصلان الآن.",
|
||||||
|
"notificationStoredMediaFile": "تم حفظ صورتك.",
|
||||||
|
"notificationReaction": "تفاعل جديد مع صورتك.",
|
||||||
|
"notificationReopenedMedia": "تمت إعادة فتح صورتك.",
|
||||||
|
"notificationReactionToVideo": "تفاعل {reaction} مع الفيديو الخاص بك.",
|
||||||
|
"notificationReactionToText": "تفاعل {reaction} مع رسالتك.",
|
||||||
|
"notificationReactionToImage": "تفاعل {reaction} مع صورتك.",
|
||||||
|
"notificationReactionToAudio": "تفاعل {reaction} مع رسالتك الصوتية.",
|
||||||
|
"notificationResponse": "رد جديد{inGroup}.",
|
||||||
|
"notificationCategoryMessageTitle": "الرسائل",
|
||||||
|
"notificationConnectionFallback": "قد تكون لديك رسائل جديدة.",
|
||||||
|
"groupContextMenuDeleteGroup": "سيؤدي هذا إلى حذف جميع الرسائل في هذه المحادثة نهائيًا.",
|
||||||
|
"groupYouAreNowLongerAMember": "لم تعد عضوًا في هذه المجموعة.",
|
||||||
|
"groupNetworkIssue": "مشكلة في الشبكة. حاول مرة أخرى لاحقًا.",
|
||||||
|
"leaveGroupSelectOtherAdminTitle": "اختر مشرفًا آخر",
|
||||||
|
"leaveGroupSelectOtherAdminBody": "لمغادرة المجموعة، يجب عليك أولًا اختيار مشرف جديد.",
|
||||||
|
"leaveGroupSureTitle": "مغادرة المجموعة",
|
||||||
|
"leaveGroupSureBody": "هل تريد حقًا مغادرة المجموعة؟",
|
||||||
|
"leaveGroupSureOkBtn": "مغادرة المجموعة",
|
||||||
|
"changeDisplayMaxTime": "سيتم الآن حذف المحادثات بعد {time} ({username}).",
|
||||||
|
"youChangedDisplayMaxTime": "سيتم الآن حذف المحادثات بعد {time}.",
|
||||||
|
"userGotReported": "تم الإبلاغ عن المستخدم.",
|
||||||
|
"deleteChatAfter": "حذف المحادثة بعد...",
|
||||||
|
"deleteChatAfterAnHour": "ساعة واحدة.",
|
||||||
|
"deleteChatAfterADay": "يوم واحد.",
|
||||||
|
"deleteChatAfterAWeek": "أسبوع واحد.",
|
||||||
|
"deleteChatAfterAMonth": "شهر واحد.",
|
||||||
|
"deleteChatAfterAYear": "سنة واحدة.",
|
||||||
|
"yourTwonlyScore": "نقاط twonly الخاصة بك",
|
||||||
|
"registrationClosed": "نظرًا للعدد الكبير من التسجيلات حاليًا، أوقفنا التسجيل مؤقتًا لضمان استمرار موثوقية الخدمة. يُرجى المحاولة مرة أخرى بعد بضعة أيام.",
|
||||||
|
"dialogAskDeleteMediaFilePopTitle": "هل أنت متأكد أنك تريد حذف تحفتك الفنية؟",
|
||||||
|
"dialogAskDeleteMediaFilePopDelete": "حذف",
|
||||||
|
"allowErrorTracking": "شارك الأخطاء والأعطال معنا",
|
||||||
|
"allowErrorTrackingSubtitle": "إذا تعطّل twonly أو حدثت أخطاء، يتم الإبلاغ عنها تلقائيًا إلى خادم Glitchtip الذي نستضيفه بأنفسنا. لا يتم رفع البيانات الشخصية مثل الرسائل أو الصور أبدًا.",
|
||||||
|
"avatarSaveChanges": "هل تريد حفظ التغييرات؟",
|
||||||
|
"avatarSaveChangesStore": "حفظ",
|
||||||
|
"avatarSaveChangesDiscard": "تجاهل",
|
||||||
|
"inProcess": "قيد المعالجة",
|
||||||
|
"draftMessage": "مسودة",
|
||||||
|
"voiceMessageSlideToCancel": "اسحب للإلغاء",
|
||||||
|
"voiceMessageCancel": "إلغاء",
|
||||||
|
"shareYourProfile": "شارك ملفك الشخصي",
|
||||||
|
"scanOtherProfile": "امسح ملفًا شخصيًا آخر",
|
||||||
|
"openYourOwnQRcode": "افتح رمز QR الخاص بك",
|
||||||
|
"addContactQrSheetSubtext": "اطلب من صديقك مسح رمز QR هذا لإضافتك",
|
||||||
|
"letUserScanQrCode": "اطلب من {username} مسح رمز QR هذا",
|
||||||
|
"finishSetupCardTitle": "أكمل ملفك الشخصي",
|
||||||
|
"finishSetupCardDesc": "أوشكت على الانتهاء! أكمل إعداد حسابك للاستفادة القصوى من twonly.",
|
||||||
|
"finishSetupCardAction": "متابعة الإعداد",
|
||||||
|
"missingBackupCardTitle": "إعداد النسخ الاحتياطي",
|
||||||
|
"missingBackupCardDesc": "لقد حسّنّا آلية النسخ الاحتياطي، ولهذا يلزمك إعدادها من جديد.",
|
||||||
|
"missingBackupCardAction": "أعدّه الآن",
|
||||||
|
"onboardingFinishLater": "الإكمال لاحقًا",
|
||||||
|
"onboardingProfileTitle": "اختر مظهرك",
|
||||||
|
"onboardingProfileBody": "اختر صورة رمزية واسمًا معروضًا سيراه أصدقاؤك.",
|
||||||
|
"onboardingBackupBody": "احتفظ بنسخة احتياطية من هويتك في twonly، فهذه هي الطريقة الوحيدة لاستعادة حسابك إذا ألغيت تثبيت التطبيق أو فقدت هاتفك.",
|
||||||
|
"onboardingUserDiscoveryShareFriends": "شارك أصدقاءك",
|
||||||
|
"onboardingUserDiscoveryShareFriendsDesc": "شارك مع أصدقائك من تعرفهم ومن تحققت منهم. لا يمكن للأصدقاء *رؤية سوى الأصدقاء المشتركين* من قائمة أصدقائك. يمكنك تغيير رأيك *في أي وقت* أو *إخفاء أشخاص محددين*.",
|
||||||
|
"onboardingUserDiscoveryContactsVerifiedBadge": "تحصل جهات الاتصال التي تحقق منها أصدقاؤك على شارة",
|
||||||
|
"onboardingUserDiscoveryWhoIsRequesting": "اعرف من يرسل الطلب",
|
||||||
|
"userDiscoverySettingsManualApproval": "اسألني في كل مرة قبل المشاركة",
|
||||||
|
"userDiscoverySettingsManualApprovalDesc": "سيُطلب منك التأكيد في كل مرة قبل مشاركة أحد أصدقائك.",
|
||||||
|
"onboardingUserDiscoveryLetFriendsFindYou": "دع أصدقاءك يعثرون عليك",
|
||||||
|
"onboardingUserDiscoveryBeRecommended": "اظهر في اقتراحات الآخرين",
|
||||||
|
"onboardingUserDiscoveryWhatOthersSee": "ما سيراه الآخرون",
|
||||||
|
"onboardingUserDiscoveryWhatYouSee": "هذا ما ستراه عند الطلب",
|
||||||
|
"onboardingAddContactsTitle": "أضف جهات اتصال جديدة",
|
||||||
|
"onboardingAddContactsAcceptDesc": "في twonly، يجب قبول كل جهة اتصال أولًا قبل أن تتمكن من التواصل.",
|
||||||
|
"onboardingAddContactsMethodHeading": "إضافة جهات اتصال",
|
||||||
|
"onboardingAddContactsMethodScan": "امسح رمز QR الخاص بجهة الاتصال.",
|
||||||
|
"onboardingAddContactsMethodSearch": "ابحث عن اسم المستخدم.",
|
||||||
|
"onboardingAddContactsMethodShare": "شارك جهة اتصال في المحادثات.",
|
||||||
|
"linkFromUsername": "هل الرابط من {username}؟",
|
||||||
|
"linkFromUsernameLong": "إذا تلقيت الرابط من صديقك، يمكنك تمييز المستخدم كموثّق، لأن المفتاح العام في الرابط يطابق المفتاح العام المحفوظ مسبقًا لهذا المستخدم.",
|
||||||
|
"gotLinkFromFriend": "نعم، حصلت على الرابط من صديقي!",
|
||||||
|
"couldNotVerifyUsername": "تعذّر التحقق من {username}",
|
||||||
|
"linkPubkeyDoesNotMatch": "المفتاح العام في الرابط لا يطابق المفتاح العام المحفوظ لجهة الاتصال هذه. حاول مقابلة صديقك شخصيًا ومسح رمز QR مباشرةً!",
|
||||||
|
"verificationMissingSession": "لا توجد جلسة آمنة محفوظة لجهة الاتصال هذه بعد. تبادلا رسالة أولًا، ثم اطلب من الشخص مشاركة رابط تحقق جديد.",
|
||||||
|
"verificationLinkInvalidTitle": "رابط تحقق غير صالح",
|
||||||
|
"verificationLinkInvalid": "رابط التحقق غير مكتمل أو غير صالح. اطلب من الشخص مشاركته مرة أخرى من ملفه الشخصي في twonly.",
|
||||||
|
"verificationLinkErrorTitle": "التحقق غير متاح",
|
||||||
|
"verificationLinkError": "تعذّر على twonly فحص رابط التحقق هذا. يُرجى المحاولة مرة أخرى.",
|
||||||
|
"verificationOwnProfileTitle": "هذا ملفك الشخصي",
|
||||||
|
"verificationOwnProfile": "لقد مسحت رمز التحقق الخاص بك.",
|
||||||
|
"startWithCameraOpen": "البدء والكاميرا مفتوحة",
|
||||||
|
"showImagePreviewWhenSending": "عرض معاينة الصورة عند اختيار المستلمين",
|
||||||
|
"verifiedPublicKey": "تم التحقق من هوية {username} بنجاح.",
|
||||||
|
"memoriesAYearAgo": "قبل عام",
|
||||||
|
"memoriesXYearsAgo": "قبل {years} سنوات",
|
||||||
|
"migrationOfMemories": "نقل ملفات الوسائط: {open} بانتظار المعالجة.",
|
||||||
|
"autoStoreAllSendUnlimitedMediaFiles": "حفظ جميع الوسائط المرسلة",
|
||||||
|
"autoStoreAllSendUnlimitedMediaFilesSubtitle": "إذا فعّلت هذا الخيار، فسيتم حفظ جميع الصور التي ترسلها، طالما أُرسلت بعدّ تنازلي غير محدود وليس في وضع twonly.",
|
||||||
|
"termsOfService": "شروط الخدمة",
|
||||||
|
"privacyPolicy": "سياسة الخصوصية",
|
||||||
|
"additionalUserAddError": "تعذّرت إضافة {username}، يُرجى المحاولة لاحقًا.",
|
||||||
|
"additionalUserAddErrorNotInFreePlan": "تعذّرت إضافة {username} لأن الحساب مشترك بالفعل في خطة مدفوعة.",
|
||||||
|
"additionalUserAddButton": "إضافة مستخدم إضافي ({used}/{limit})",
|
||||||
|
"additionalUserRemoveTitle": "إزالة هذا المستخدم الإضافي",
|
||||||
|
"additionalUserRemoveDesc": "بعد الإزالة، سيُنقل المستخدم الإضافي تلقائيًا إلى الخطة المجانية، ويمكنك إضافة شخص آخر.",
|
||||||
|
"additionalUserSelectTitle": "اختر مستخدمين إضافيين",
|
||||||
|
"additionalUserSelectButton": "اختر المستخدمين ({used}/{limit})",
|
||||||
|
"storeAsDefault": "حفظ كافتراضي",
|
||||||
|
"deleteUserErrorMessage": "لا يمكنك حذف جهة الاتصال إلا بعد حذف المحادثة المباشرة، وعندما لا تعود جهة الاتصال عضوًا في أي مجموعة.",
|
||||||
|
"groupSizeLimitError": "الحد الأقصى لعدد أعضاء المجموعة حاليًا: {size}!",
|
||||||
|
"authRequestReopenImage": "يجب عليك المصادقة لإعادة فتح الصورة.",
|
||||||
|
"shareContactsMenu": "جهة اتصال",
|
||||||
|
"shareContactsTitle": "اختر جهات الاتصال",
|
||||||
|
"shareContactsSubmit": "شارك الآن",
|
||||||
|
"updateTwonlyMessage": "لرؤية هذه الرسالة، تحتاج إلى تحديث twonly.",
|
||||||
|
"verificationBadgeNote": "يمكنك التحقق من أصدقائك عن طريق مسح رمز QR العام الخاص بهم. اضغط لمعرفة المزيد.",
|
||||||
|
"verificationBadgeTitle": "التحقق",
|
||||||
|
"verificationBadgeGeneralDesc": "تمنحك الشارة راحة البال بأنك تراسل *الشخص الصحيح* وأن *رسائلك تبقى سرية*.",
|
||||||
|
"verificationBadgeGreenDesc": "جهة اتصال *تحققت منها بنفسك* باستخدام رمز QR.",
|
||||||
|
"verificationBadgeYellowDesc": "جهة اتصال تحقق منها واحد على الأقل من *جهات اتصالك*.",
|
||||||
|
"verificationBadgeRedDesc": "جهة اتصال *لم* يتم التحقق من هويتها بعد.",
|
||||||
|
"manualVerificationOpen": "أرقام الأمان",
|
||||||
|
"manualVerificationTitle": "مقارنة رقم الأمان",
|
||||||
|
"manualVerificationMarkVerified": "تمييز كموثّق",
|
||||||
|
"manualVerificationDescription": "قارن رقم الأمان هذا مع {username}. إذا عرض الجهازان الرقم نفسه، فهذا يعني أنه تم التحقق من تشفيرك التام بين الطرفين.",
|
||||||
|
"manualVerificationMissingKeyTitle": "لا يتوفر رقم أمان",
|
||||||
|
"manualVerificationMissingKeyDescription": "لا توجد جلسة Signal مع {username} بعد. تبادلا رسالة أولًا، ثم حاول مرة أخرى.",
|
||||||
|
"manualVerificationLoadFailed": "تعذّر تحميل رقم الأمان.",
|
||||||
|
"manualVerificationRetry": "حاول مرة أخرى",
|
||||||
|
"manualVerificationSuccess": "لقد قارنت رقم الأمان مع {username}، وتم تأكيد الهوية.",
|
||||||
|
"scanNow": "امسح الآن",
|
||||||
|
"qrScannerVerifyHint": "للتحقق، يجب على الشخص الآخر فتح رمز QR الخاص به (قائمة المحادثات > زر رمز QR في الأسفل)",
|
||||||
|
"qrScannerVerifyUserHint": "للتحقق، يجب على {username} فتح رمز QR (قائمة المحادثات > زر رمز QR في الأسفل)",
|
||||||
|
"openQrCode": "فتح رمز QR",
|
||||||
|
"letFriendScanQrToVerify": "اطلب من صديقك مسح رمز QR هذا للتحقق منك",
|
||||||
|
"deleteVerificationTitle": "حذف التحقق؟",
|
||||||
|
"deleteVerificationBody": "هل أنت متأكد أنك تريد حذف هذا التحقق؟",
|
||||||
|
"secretQrTokenVerifiedSnackbar": "تم مسح رمز QR الخاص بك من قِبل {username}. أصبحت جهة الاتصال موثّقة الآن.",
|
||||||
|
"askForFriendPromotionsPrompt": "ساعد {username} في العثور على وجوه مألوفة على twonly من خلال مشاركة الأصدقاء المشتركين.",
|
||||||
|
"mutualGroupsTitle": "{count, plural, =1{مجموعة مشتركة واحدة} =2{مجموعتان مشتركتان} few{{count} مجموعات مشتركة} many{{count} مجموعة مشتركة} other{{count} مجموعة مشتركة}}",
|
||||||
|
"chatEntryFlameRestored": "تمت استعادة الشعلات: {count}",
|
||||||
|
"requestedUserToastText": "تم إرسال طلب إلى {username} بنجاح.",
|
||||||
|
"profileYourQrCode": "رمز QR الخاص بك",
|
||||||
|
"settingsScreenLock": "قفل الشاشة",
|
||||||
|
"settingsScreenLockSubtitle": "لفتح twonly، ستحتاج إلى استخدام ميزة فتح القفل في هاتفك.",
|
||||||
|
"settingsScreenLockAuthMessageEnable": "استخدام قفل الشاشة في twonly.",
|
||||||
|
"settingsScreenLockAuthMessageDisable": "تعطيل قفل الشاشة في twonly.",
|
||||||
|
"unlockTwonly": "فتح قفل twonly",
|
||||||
|
"unlockTwonlyTryAgain": "حاول مرة أخرى",
|
||||||
|
"unlockTwonlyDesc": "استخدم إعدادات فتح القفل في هاتفك لفتح twonly",
|
||||||
|
"settingsTypingIndication": "مؤشرات الكتابة",
|
||||||
|
"settingsTypingIndicationSubtitle": "عند إيقاف مؤشر الكتابة، لن تتمكن من رؤية متى يكتب الآخرون رسالة.",
|
||||||
|
"contactActionBlock": "حظر",
|
||||||
|
"contactActionAccept": "قبول",
|
||||||
|
"userDiscoverySettingsMutualFriends": "اختر عدد الأصدقاء المشتركين الذين يجب أن يكونوا لدى الشخص حتى يتم اقتراحك عليه.",
|
||||||
|
"userDiscoverySettingsApply": "تطبيق التغييرات",
|
||||||
|
"userDiscoveryEnabledDisableWarning": "إذا عطّلت ميزة «الأصدقاء المشتركون»، فلن ترى الاقتراحات بعد الآن. كما ستتوقف عن مشاركة أصدقائك مع جهات الاتصال الجديدة.",
|
||||||
|
"userDiscoveryEnabledChangeSettings": "تغيير الإعدادات",
|
||||||
|
"userDiscoveryEnabledFaq": "نشرح في الأسئلة الشائعة كيف تعمل ميزة «الأصدقاء المشتركون».",
|
||||||
|
"userDiscoveryDisabledIntro": "لا يجمع twonly رقم هاتفك *ولا* يحتاج إلى الوصول إلى جهات اتصالك. بدلًا من ذلك، يمكن لـ twonly *العثور على أصدقائك من خلال الأصدقاء المشتركين*.",
|
||||||
|
"userDiscoverySettingsTitle": "الأصدقاء المشتركون",
|
||||||
|
"userDiscoveryFeatureOffers": "مزاياك في لمحة",
|
||||||
|
"userDiscoveryDisabledLearnMore": "اعرف المزيد",
|
||||||
|
"userDiscoveryEnabledDialogTitle": "هل تريد التعطيل حقًا؟",
|
||||||
|
"userDiscoveryEnabledFriendsShared": "الأصدقاء الذين تشاركهم",
|
||||||
|
"userDiscoveryEnabledFriendsSharedDesc": "أنت تشارك فقط الأصدقاء الذين فعّلوا هذه الميزة أيضًا ووصلوا إلى الحد الذي حددته.",
|
||||||
|
"userDiscoverySettingsCurrentlyDisabled": "ميزة «الأصدقاء المشتركون» معطّلة حاليًا.",
|
||||||
|
"userDiscoveryEnabledNoFriendsShared": "أنت لا تشارك أحدًا بعد.",
|
||||||
|
"userDiscoveryActionDisable": "تعطيل",
|
||||||
|
"friendSuggestionsTitle": "اقتراحات الأصدقاء",
|
||||||
|
"andWord": "و",
|
||||||
|
"friendSuggestionsFriendsWith": "أصدقاء مشتركون: {friends}.",
|
||||||
|
"friendSuggestionsGroupMemberIn": " مجموعات مشتركة: {groups}.",
|
||||||
|
"friendSuggestionsRequest": "إرسال طلب",
|
||||||
|
"friendSuggestionsAskFriend": "اسأل أصدقاءك",
|
||||||
|
"askFriendsDialogTitle": "اسأل عن {username}",
|
||||||
|
"askFriendsDialogDescription": "اختر الأصدقاء الذين تريد سؤالهم عن هذا المستخدم:",
|
||||||
|
"askFriendsDialogConfirm": "اسأل",
|
||||||
|
"askFriendsDialogCancel": "إلغاء",
|
||||||
|
"chatAskAFriendReceivedDescription": "تلقّى صديقك هذا الاقتراح للتو ويريد أن يعرف ما إذا كان يعرف هذا الشخص.",
|
||||||
|
"chatAskAFriendAddedDescription": "لقد أضفت هذا المستخدم إلى جهات اتصالك.",
|
||||||
|
"chatAskAFriendHide": "إخفاء",
|
||||||
|
"chatAskAFriendRequest": "إرسال طلب",
|
||||||
|
"chatAskAFriendUnknownUser": "المستخدم {userId}",
|
||||||
|
"contactUserDiscoveryImagesLeft": "الصور المتبقية قبل مشاركة أصدقائك مع {username}: {imagesLeft}.",
|
||||||
|
"userDiscoveryEnabledVersion": "الإصدار: {version}",
|
||||||
|
"userDiscoveryEnabledYourVersion": "إصدارك: {version}",
|
||||||
|
"userDiscoveryEnabledStopSharing": "إيقاف المشاركة",
|
||||||
|
"userDiscoveryManualApprovalReachedThreshold": "هل ترغب في مشاركة {username} مع أصدقائك؟",
|
||||||
|
"userDiscoveryManualApprovalHideContact": "إخفاء جهة الاتصال",
|
||||||
|
"userDiscoveryManualApprovalShareContact": "مشاركة جهة الاتصال",
|
||||||
|
"onboardingSetupCompleteTitle": "كل شيء جاهز يا {username}!",
|
||||||
|
"onboardingSetupCompleteDesc": "يمكنك الآن مشاركة لحظاتك مع أصدقائك بأمان ودون مشتتات مثل الإعلانات.",
|
||||||
|
"contactUserDiscoveryManualApprovalPending": "لم تتم الموافقة على جهة الاتصال يدويًا بعد.",
|
||||||
|
"contactUserDiscoveryManualApprovalApprove": "موافقة",
|
||||||
|
"exampleUserName1": "ahmed",
|
||||||
|
"exampleUserName2": "fatima",
|
||||||
|
"exampleUserName3": "omar",
|
||||||
|
"exampleUserName4": "layla",
|
||||||
|
"exampleUserName5": "youssef",
|
||||||
|
"exampleUserName6": "mariam",
|
||||||
|
"exampleUserName7": "khaled",
|
||||||
|
"exampleUserName8": "nour",
|
||||||
|
"exampleUserName9": "hassan",
|
||||||
|
"exampleUserName10": "lena",
|
||||||
|
"exampleUserName11": "david",
|
||||||
|
"exampleJane": "sara",
|
||||||
|
"back": "رجوع",
|
||||||
|
"makerChangedUsername": "غيّر {maker} اسم المستخدم من {oldName} إلى {newName}.",
|
||||||
|
"makerChangedDisplayName": "غيّر {maker} الاسم المعروض من {oldName} إلى {newName}.",
|
||||||
|
"recoverErrorNoInternet": "لا يوجد اتصال بالإنترنت. يُرجى التحقق من الشبكة والمحاولة مرة أخرى.",
|
||||||
|
"recoverErrorUsernameNotValid": "اسم المستخدم المُدخل غير صالح أو غير موجود.",
|
||||||
|
"recoverErrorPasswordInvalid": "كلمة المرور المُدخلة غير صحيحة.",
|
||||||
|
"recoverErrorTryAgainLater": "الخادم غير متاح حاليًا. يُرجى المحاولة لاحقًا.",
|
||||||
|
"recoverErrorUnknown": "حدث خطأ غير معروف. يُرجى المحاولة مرة أخرى.",
|
||||||
|
"recoverSuccessTitle": "تمت استعادة النسخة الاحتياطية بنجاح.",
|
||||||
|
"recoverSuccessBody": "اضغط هنا لفتح التطبيق مرة أخرى",
|
||||||
|
"recoverProgressTitle": "جارٍ استعادة نسختك الاحتياطية",
|
||||||
|
"recoverProgressSubtitle": "قد يستغرق هذا بعض الوقت، يُرجى إبقاء التطبيق مفتوحًا.",
|
||||||
|
"recoverProgressResolvingAccount": "جارٍ التحقق من الحساب",
|
||||||
|
"recoverProgressRestoringIdentity": "جارٍ استعادة هويتك",
|
||||||
|
"recoverProgressDownloadingArchive": "جارٍ تنزيل الرسائل وجهات الاتصال وفك تشفيرها",
|
||||||
|
"recoverProgressExtractingData": "جارٍ استخراج البيانات",
|
||||||
|
"recoverProgressFinishing": "جارٍ الإنهاء",
|
||||||
|
"iosRecoveryWelcomeBack": "مرحبًا بعودتك",
|
||||||
|
"iosRecoveryPrompt": "اكتشفنا هوية twonly مؤمّنة سابقًا على هذا الجهاز. هل تريد تنزيل جهات اتصالك ورسائلك وإعداداتك واستعادتها تلقائيًا من أرشيفك السحابي؟",
|
||||||
|
"iosRecoveryNoBackupFound": "تعذّر استرداد أي أرشيف نسخ احتياطي من الخادم لهذا الجهاز.\n\nالخطأ: {error}\n\nيُرجى المتابعة لتسجيل حساب twonly جديد.",
|
||||||
|
"registerNewAccount": "تسجيل حساب جديد",
|
||||||
|
"tryRestoreAgain": "إعادة محاولة الاستعادة",
|
||||||
|
"registeringNewAccount": "جارٍ تسجيل حساب جديد",
|
||||||
|
"selectEmoji": "اختر رمزًا تعبيريًا",
|
||||||
|
"subscriptionPledgeSecureTitle": "آمن من حيث التصميم",
|
||||||
|
"subscriptionPledgeSecureDesc": "رسائلك ولحظاتك المشتركة مشفّرة بالكامل بين الطرفين.",
|
||||||
|
"subscriptionPledgeNoAdsTitle": "لا إعلانات ولا بيع للبيانات",
|
||||||
|
"subscriptionPledgeNoAdsDesc": "لن يعرض twonly إعلانات أبدًا ولن يبيع بياناتك الخاصة.",
|
||||||
|
"subscriptionPledgeSubtitle": "بلا إعلانات. خصوصية تامة.",
|
||||||
|
"subscriptionManage": "إدارة الاشتراك",
|
||||||
|
"dragToZoom": "اسحب للتكبير",
|
||||||
|
"onboardingProfileSelectionTitle": "اختر طريقة الإعداد",
|
||||||
|
"onboardingProfileSelectionSubtitle": "اختر كيف تريد ضبط إعدادات الأمان والخصوصية.",
|
||||||
|
"onboardingProfileSelectionDefaultTitle": "افتراضي",
|
||||||
|
"onboardingProfileSelectionDefaultDesc": "يطبّق الإعدادات الموصى بها فورًا لتبدأ باستخدام التطبيق.",
|
||||||
|
"onboardingProfileSelectionDefaultBadge": "إعداد سريع",
|
||||||
|
"onboardingProfileSelectionCustomizeTitle": "تخصيص",
|
||||||
|
"onboardingProfileSelectionCustomizeDesc": "إعداد خطوة بخطوة لتقرر بنفسك.",
|
||||||
|
"replyFlameRestored": "تمت استعادة الشعلات",
|
||||||
|
"replyAskAFriend": "اسأل صديقًا",
|
||||||
|
"unverifiedWarningButton": "تحقق الآن",
|
||||||
|
"today": "اليوم",
|
||||||
|
"yesterday": "أمس",
|
||||||
|
"galleryDisableWarningTitle": "تعطيل الحفظ في المعرض؟",
|
||||||
|
"galleryDisableWarningBody": "إذا عطّلت هذا الخيار، فلن تُحفظ ملفات الوسائط في معرضك، وقد تُفقد نهائيًا إذا أُزيل twonly أو واجه مشكلة، لأن ملفات الوسائط لا تُنسخ احتياطيًا بعد.",
|
||||||
|
"galleryDisableWarningConfirm": "تعطيل",
|
||||||
|
"settingsStorageScanGalleryTitle": "استيراد من المعرض",
|
||||||
|
"importGalleryDeselectAll": "إلغاء تحديد الكل",
|
||||||
|
"importGallerySelectAll": "تحديد الكل",
|
||||||
|
"importGalleryPermissionRequired": "يلزم إذن الوصول إلى معرضك لاستيراد ملفات وسائط twonly السابقة.",
|
||||||
|
"importGalleryPermissionError": "حدث خطأ أثناء طلب الإذن: {error}",
|
||||||
|
"importGalleryLoadError": "تعذّر تحميل الملفات: {error}",
|
||||||
|
"importGalleryImportingOf": "جارٍ استيراد {current} من {total}...",
|
||||||
|
"importGalleryStarting": "جارٍ بدء الاستيراد...",
|
||||||
|
"importGalleryComplete": "اكتمل الاستيراد: نجح استيراد {imported} وفشل {failed}.",
|
||||||
|
"importGalleryGrantAccess": "منح الوصول",
|
||||||
|
"importGalleryOpenSettings": "فتح الإعدادات",
|
||||||
|
"importGalleryPermissionDenied": "تم رفض إذن الوصول إلى المعرض.",
|
||||||
|
"importGalleryTryAgain": "حاول مرة أخرى",
|
||||||
|
"importGalleryAlbumNotFound": "لم يتم العثور على ألبوم «twonly»",
|
||||||
|
"importGalleryAlbumNotFoundDesc": "إذا لم يكن لديك هذا الألبوم بعد، يمكنك أيضًا إنشاؤه لاستيراد الصور إلى twonly.",
|
||||||
|
"importGalleryNoImagesFound": "لم يتم العثور على صور",
|
||||||
|
"importGalleryNoImagesFoundDesc": "لا توجد صور على جهازك.",
|
||||||
|
"importGalleryFilterTwonly": "عرض ألبوم twonly فقط",
|
||||||
|
"importGalleryRefresh": "تحديث",
|
||||||
|
"importGallerySelectToImport": "اختر العناصر المراد استيرادها",
|
||||||
|
"importGalleryImportCount": "{count, plural, =1{استيراد عنصر واحد} =2{استيراد عنصرين} few{استيراد {count} عناصر} many{استيراد {count} عنصرًا} other{استيراد {count} عنصر}}",
|
||||||
|
"emptyChatListTitle": "ابحث عن صديقك الأول",
|
||||||
|
"emptyChatListDesc": "اطلب من أصدقائك مسح رمز QR الخاص بك، أو شارك ملفك الشخصي معهم.",
|
||||||
|
"emptyChatListShareBtn": "شارك ملفك الشخصي",
|
||||||
|
"emptyChatListScanBtn": "رمز QR",
|
||||||
|
"emptyChatListAddUsernameBtn": "باسم المستخدم",
|
||||||
|
"avatarCustomizeRandomize": "عشوائي",
|
||||||
|
"avatarCustomizeReset": "إعادة تعيين",
|
||||||
|
"passwordlessRecovery": "الأصدقاء الموثوقون",
|
||||||
|
"passwordlessRecoveryNotConfigured": "غير مُعدّ",
|
||||||
|
"passwordlessRecoveryTestPin": "اختبار رمز PIN",
|
||||||
|
"passwordlessRecoveryTestPinTitle": "اختبار رمز PIN",
|
||||||
|
"passwordlessRecoveryTestPinHint": "أدخل رمز PIN",
|
||||||
|
"passwordlessRecoveryTestPinCorrect": "رمز PIN صحيح!",
|
||||||
|
"passwordlessRecoveryTestPinIncorrect": "رمز PIN غير صحيح.",
|
||||||
|
"passwordlessRecoveryTest": "اختبار",
|
||||||
|
"passwordlessRecoverySecondFactorNone": "لا شيء",
|
||||||
|
"passwordlessRecoverySecondFactorEmailLabel": "البريد الإلكتروني ({email})",
|
||||||
|
"passwordlessRecoverySecondFactorPin": "رمز PIN",
|
||||||
|
"passwordlessRecoverySecondFactorEmail": "البريد الإلكتروني",
|
||||||
|
"passwordlessRecoveryModify": "تعديل إعدادات الاستعادة",
|
||||||
|
"passwordlessRecoveryModifyDesc": "حدّث إعدادات الاستعادة الخاصة بك",
|
||||||
|
"passwordlessRecoverySecondFactor": "العامل الثاني",
|
||||||
|
"passwordlessRecoveryNoFriendsFound": "لم يتم العثور على أصدقاء موثوقين.",
|
||||||
|
"passwordlessRecoveryActiveFriends": "الأصدقاء النشطون",
|
||||||
|
"passwordlessRecoveryActiveFriendsDesc": "هؤلاء الأصدقاء الموثوقون يستخدمون twonly بنشاط، ومن المرجح أن يتمكنوا من مساعدتك في استعادة حسابك.",
|
||||||
|
"passwordlessRecoveryInactiveFriends": "الأصدقاء غير النشطين",
|
||||||
|
"passwordlessRecoveryInactiveFriendsDesc": "هؤلاء الأصدقاء إما لم يتلقوا حصتهم بعد أو لم يعودوا يستخدمون twonly بنشاط، مما قد يعني أنهم لا يستطيعون المساعدة.",
|
||||||
|
"passwordlessRecoveryEnableSuccess": "تم إعداد الأصدقاء الموثوقين بنجاح!",
|
||||||
|
"passwordlessRecoveryEnterPin": "يُرجى إدخال رمز PIN.",
|
||||||
|
"passwordlessRecoveryEnterEmail": "يُرجى إدخال عنوان بريد إلكتروني.",
|
||||||
|
"passwordlessRecoveryEnableBtn": "تفعيل الأصدقاء الموثوقين",
|
||||||
|
"passwordlessRecoveryRecoverBtn": "الاستعادة عبر الأصدقاء الموثوقين",
|
||||||
|
"passwordlessRecoveryModifyBtn": "تعديل الأصدقاء الموثوقين",
|
||||||
|
"passwordlessRecoveryStatusEnabled": "مفعّل • الأصدقاء الموثوقون: {count}",
|
||||||
|
"passwordlessRecoveryInfoHowItWorks": "كيف يعمل",
|
||||||
|
"passwordlessRecoveryInfoHowItWorksDesc": "يعمل twonly دون أرقام هواتف، ولهذا نعتمد على آلية استعادة لامركزية. باستخدام مخطط شامير لتقاسم الأسرار (Shamir's Secret Sharing)، تُقسَّم هويتك التشفيرية إلى حصص مستقلة وتُوزَّع على أصدقائك الموثوقين. لاستعادة الوصول، يجب أن يجمع عدد محدد مسبقًا من هؤلاء الأصدقاء حصصهم.",
|
||||||
|
"passwordlessRecoveryInfoWhySecondFactor": "لماذا العامل الثاني؟",
|
||||||
|
"passwordlessRecoveryInfoWhySecondFactorDesc": "يوفّر العامل الثاني (البريد الإلكتروني أو رمز PIN) حماية إضافية مهمة. فحتى لو اتفق أصدقاؤك سرًّا فيما بينهم، فلن يتمكنوا من الوصول إلى حسابك دون هذا العامل الثاني.",
|
||||||
|
"passwordlessRecoveryInfoGotIt": "فهمت",
|
||||||
|
"passwordlessRecoveryMethod": "طريقة العامل الثاني",
|
||||||
|
"passwordlessRecoveryMethodNoneDesc": "بدون عامل ثانٍ، يمكن لأصدقائك التعاون لاستعادة حسابك. لذلك يُنصح بإعداد عامل ثانٍ.",
|
||||||
|
"passwordlessRecoveryMethodPinHint": "أدخل رمز PIN",
|
||||||
|
"passwordlessRecoveryMethodEmailHint": "أدخل البريد الإلكتروني للاستعادة",
|
||||||
|
"passwordlessRecoveryMethodEmailDesc": "لا يتم *تخزين عنوان بريدك الإلكتروني على الخادم أبدًا*، ولا يُرسل إليه إلا في حالة الاستعادة.",
|
||||||
|
"passwordlessRecoveryThresholdDesc": "لاستعادة حسابك، تحتاج إلى {count} من أصدقائك الموثوقين المختارين.",
|
||||||
|
"passwordlessRecoveryThresholdTitle": "عدد الأصدقاء الموثوقين المطلوب للاستعادة",
|
||||||
|
"passwordlessRecoverySelectFriendsNeeded": "اختر الأصدقاء (المتبقي: {count})",
|
||||||
|
"passwordlessRecoverySelectFriends": "اختر الأصدقاء الموثوقين",
|
||||||
|
"passwordlessRecoveryTrustedFriends": "استعادة الحساب",
|
||||||
|
"passwordlessRecoveryDoneBtn": "تم ({count})",
|
||||||
|
"passwordlessRecoveryNoFriendsSelected": "لم يتم اختيار أي أصدقاء موثوقين بعد",
|
||||||
|
"passwordlessRecoverySubtitle": "استعد هويتك دون كلمة مرور.",
|
||||||
|
"recoverPasswordlessExplanation": "عند التفعيل، يمكنك استعادة حسابك بطلب المساعدة من أصدقائك المختارين.",
|
||||||
|
"recoverPasswordlessNotificationCardTitle": "تفعيل الإشعارات",
|
||||||
|
"recoverPasswordlessNotificationCardSubtitle": "احصل على إشعار عندما يساعدك صديق في استعادة حسابك.",
|
||||||
|
"recoverPasswordlessNotificationCardBtn": "تفعيل الإشعارات الفورية",
|
||||||
|
"recoverPasswordlessQrInstructions": "اطلب من أصدقائك مسح رمز QR أو شارك الرابط.",
|
||||||
|
"recoverPasswordlessShareBtn": "مشاركة رابط الاستعادة",
|
||||||
|
"recoverPasswordlessCopyBtn": "نسخ",
|
||||||
|
"recoverPasswordlessCopiedSnackbar": "تم نسخ الرابط إلى الحافظة!",
|
||||||
|
"passwordlessRecoveryNoShareStored": "لا توجد حصة استعادة محفوظة لجهة الاتصال هذه.",
|
||||||
|
"passwordlessRecoveryEmailSent": "تم إرسال بريد الاستعادة!",
|
||||||
|
"passwordlessRecoveryShareSent": "تم إرسال حصة الاستعادة!",
|
||||||
|
"passwordlessRecoveryAuthReason": "قم بالمصادقة لإرسال حصة الاستعادة الخاصة بك",
|
||||||
|
"passwordlessRecoveryAuthFailed": "فشلت المصادقة، ولم يتم إرسال حصة الاستعادة.",
|
||||||
|
"passwordlessRecoveryNetworkError": "خطأ في الشبكة، يُرجى التأكد من اتصالك بالإنترنت",
|
||||||
|
"passwordlessRecoveryInvalidEmail": "عنوان البريد الإلكتروني غير صالح.",
|
||||||
|
"passwordlessRecoveryResendEmail": "إعادة إرسال بريد الاستعادة",
|
||||||
|
"passwordlessRecoveryHelpAFriend": "ساعد صديقًا",
|
||||||
|
"passwordlessRecoverySelectContactDesc": "يُرجى اختيار جهة الاتصال التي طلبت الاستعادة أدناه لإرسال مفتاح الاستعادة إليها.",
|
||||||
|
"passwordlessRecoverySearchContacts": "البحث في جهات الاتصال...",
|
||||||
|
"passwordlessRecoveryNoContactsFound": "لم يتم العثور على جهات اتصال",
|
||||||
|
"passwordlessRecoveryCantHelpHim": "لا يمكنك مساعدة هذا الشخص",
|
||||||
|
"passwordlessRecoveryDoesAskedYou": "هل وصلك هذا الطلب من {username}؟",
|
||||||
|
"passwordlessRecoveryVerifySourceDesc": "يُرجى التأكد من أن هذا الطلب جاء فعلًا من هذا الشخص. إذا كنت في شك، فاسأله عبر وسيلة أخرى!",
|
||||||
|
"passwordlessRecoveryNo": "لا",
|
||||||
|
"passwordlessRecoveryYes": "نعم",
|
||||||
|
"passwordlessRecoveryYesWithTimer": "نعم ({seconds} ث)",
|
||||||
|
"recoverPasswordlessSharesReceived": "الأصدقاء الذين ساعدوك: {received} من {threshold}",
|
||||||
|
"recoverPasswordlessRecoverNowBtn": "استعد الآن",
|
||||||
|
"missingRecoveryContactsCardTitle": "استعادة الحساب",
|
||||||
|
"missingRecoveryContactsCardDesc": "اختر جهات اتصال للاستعادة لتساعدك في استعادة حسابك دون الحاجة إلى كلمة مرور.",
|
||||||
|
"missingRecoveryContactsCardAction": "اختر جهات الاتصال",
|
||||||
|
"memoriesBackupLimitReached": "تم الوصول إلى حد النسخ الاحتياطي السحابي! يُرجى ترقية خطتك أو إخلاء بعض المساحة.",
|
||||||
|
"settingsStorageLocal": "التخزين المحلي",
|
||||||
|
"settingsStorageNoCloudBackupCard": "انسخ ذكرياتك احتياطيًا إلى السحابة لتوفير المساحة المحلية وضمان عدم فقدان صورك أبدًا. كل ذلك بتشفير تام بين الطرفين.",
|
||||||
|
"galleryActionSave": "حفظ",
|
||||||
|
"galleryActionExport": "تصدير",
|
||||||
|
"galleryActionFavorite": "إضافة إلى المفضلة",
|
||||||
|
"galleryActionUnfavorite": "إزالة من المفضلة",
|
||||||
|
"galleryActionDelete": "حذف",
|
||||||
|
"galleryActionShare": "مشاركة",
|
||||||
|
"settingsStorageHidePromo": "إخفاء",
|
||||||
|
"memoriesBackupTitle": "النسخ الاحتياطي للذكريات",
|
||||||
|
"settingsHelpNews": "الأخبار",
|
||||||
|
"settingsStorageContents": "إخلاء مساحة",
|
||||||
|
"settingsStorageSortStorage": "المساحة المشغولة",
|
||||||
|
"settingsStorageSortNewest": "الأحدث",
|
||||||
|
"settingsStorageSortOldest": "الأقدم",
|
||||||
|
"settingsStorageNoContents": "لم يتم العثور على محتويات في التخزين.",
|
||||||
|
"settingsStorageCloudOnly": "في السحابة فقط",
|
||||||
|
"settingsStorageLocalAndCloud": "محليًا وفي السحابة",
|
||||||
|
"settingsStorageLocalOnly": "محليًا فقط",
|
||||||
|
"settingsStorageByChat": "التخزين حسب المحادثة",
|
||||||
|
"settingsStorageTemporaryMediaDescription": "ملفات الوسائط المؤقتة هي ملفات وسائط مرسلة لم يتم حفظها. تبقى على جهازك حتى يستلمها المستلم ويفتحها.",
|
||||||
|
"settingsStorageNoChats": "لم يتم العثور على محادثات.",
|
||||||
|
"settingsStorageStoredMediaCount": "{count, plural, =1{ملف محفوظ واحد} =2{ملفان محفوظان} few{{count} ملفات محفوظة} many{{count} ملفًا محفوظًا} other{{count} ملف محفوظ}}",
|
||||||
|
"settingsStorageTemporaryMediaCount": "{count, plural, =1{ملف مؤقت واحد} =2{ملفان مؤقتان} few{{count} ملفات مؤقتة} many{{count} ملفًا مؤقتًا} other{{count} ملف مؤقت}}",
|
||||||
|
"settingsStorageDisableBackupTitle": "تعطيل النسخ الاحتياطي؟",
|
||||||
|
"settingsStorageDisableBackupBody": "سيؤدي هذا إلى حذف جميع الذكريات المنسوخة احتياطيًا من السحابة. {count, plural, =1{توجد *صورة واحدة* مخزّنة في السحابة فقط وستُفقد *نهائيًا*.} =2{توجد *صورتان* مخزّنتان في السحابة فقط وستُفقدان *نهائيًا*.} few{توجد *{count} صور* مخزّنة في السحابة فقط وستُفقد *نهائيًا*.} many{توجد *{count} صورة* مخزّنة في السحابة فقط وستُفقد *نهائيًا*.} other{توجد *{count} صورة* مخزّنة في السحابة فقط وستُفقد *نهائيًا*.}} هل أنت متأكد أنك تريد المتابعة؟",
|
||||||
|
"settingsStorageDisableBackupBtn": "تعطيل",
|
||||||
|
"settingsStorageDisableBackupAction": "تعطيل النسخ الاحتياطي السحابي",
|
||||||
|
"settingsStorageSyncNow": "مزامنة الآن",
|
||||||
|
"settingsStorageSyncUpToDate": "جميع الذكريات محدّثة.",
|
||||||
|
"restoreLostFlames": "استعد شعلاتك المفقودة ({count})",
|
||||||
|
"settingsShowRestoreFlameTitle": "إظهار تحذير استعادة الشعلات",
|
||||||
|
"contactGroupsTitle": "مجموعات جهات الاتصال",
|
||||||
|
"contactGroupsSubtitleEmpty": "لم يتم اختيار مجموعات جهات اتصال ظاهرة",
|
||||||
|
"createContactGroup": "إنشاء مجموعة جهات اتصال",
|
||||||
|
"editContactGroup": "تعديل مجموعة جهات الاتصال",
|
||||||
|
"deleteContactGroup": "حذف مجموعة جهات الاتصال",
|
||||||
|
"deleteContactGroupConfirmation": "هل أنت متأكد أنك تريد حذف مجموعة جهات الاتصال هذه؟ ستتم إزالتها من جميع جهات الاتصال والمجموعات.",
|
||||||
|
"contactGroupTextColor": "لون النص",
|
||||||
|
"contactGroupBackgroundColor": "لون الخلفية",
|
||||||
|
"contactGroupNoBackground": "بلا خلفية",
|
||||||
|
"contactGroupFeatures": "الميزات",
|
||||||
|
"contactGroupShowAsLabel": "إظهار كتسمية ظاهرة",
|
||||||
|
"contactGroupShowAsLabelSubtitle": "عرض مجموعة جهات الاتصال هذه بجوار جهات الاتصال التابعة لها.",
|
||||||
|
"contactGroupShowAsShortcut": "إظهار كاختصار",
|
||||||
|
"contactGroupShowAsShortcutSubtitle": "استخدم رمزها التعبيري لتحديد جميع الأعضاء عند المشاركة.",
|
||||||
|
"contactGroupShortcutNeedsEmoji": "اختر رمزًا تعبيريًا قبل تفعيل الاختصار.",
|
||||||
|
"contactGroupMembers": "الأعضاء",
|
||||||
|
"contactGroupLabelFeature": "تسمية ظاهرة",
|
||||||
|
"contactGroupShortcutFeature": "اختصار",
|
||||||
|
"contactGroupSettings": "تعديل مجموعة جهات الاتصال",
|
||||||
|
"save": "حفظ",
|
||||||
|
"customColor": "لون مخصص",
|
||||||
|
"hue": "درجة اللون",
|
||||||
|
"saturation": "التشبع",
|
||||||
|
"brightness": "السطوع",
|
||||||
|
"settingsAppearancePrimaryColor": "اللون الأساسي",
|
||||||
|
"themeSystemDefault": "افتراضي النظام",
|
||||||
|
"themeLight": "فاتح",
|
||||||
|
"themeDark": "داكن",
|
||||||
|
"backupRecoverySectionTitle": "وصول آمن إلى الحساب",
|
||||||
|
"backupRecoverySectionDescNone": "يجب عليك اختيار خيار استعادة واحد على الأقل، وإلا فلن يتمكن أحد من مساعدتك إذا فقدت الوصول إلى جهازك.",
|
||||||
|
"backupRecoverySectionDescSome": "يمكنك استعادة حسابك باستخدام خيارات الاستعادة أدناه. يُنصح بتفعيل الخيارين كليهما.",
|
||||||
|
"backupRecoveryOptionAFriends": "عبر الأصدقاء الموثوقين",
|
||||||
|
"backupRecoveryOptionAMicrocopy": "اختر أصدقاء يمكنهم مساعدتك في استعادة حسابك.",
|
||||||
|
"backupRecoveryOptionBPassword": "كلمة مرور تقليدية",
|
||||||
|
"backupRecoveryOptionBMicrocopy": "عيّن كلمة مرور للوصول إلى حسابك.",
|
||||||
|
"backupCloudSectionTitle": "انسخ بياناتك احتياطيًا",
|
||||||
|
"backupCloudSectionDesc": "انسخ محتواك احتياطيًا حتى لا يضيع شيء.",
|
||||||
|
"backupCloudContactsMessages": "جهات الاتصال والرسائل",
|
||||||
|
"backupCloudImagesMedia": "الصور والوسائط",
|
||||||
|
"backupCloudProBadge": "Pro",
|
||||||
|
"memoriesAddingToFavorites": "جارٍ الإضافة إلى المفضلة...",
|
||||||
|
"memoriesRemovingFromFavorites": "جارٍ الإزالة من المفضلة...",
|
||||||
|
"memoriesDeletingProgress": "جارٍ حذف الذكريات...",
|
||||||
|
"memoriesExportingProgress": "جارٍ تصدير الذكريات...",
|
||||||
|
"fileLimitReachedTitle": "الملف أكبر من أن يُرسل",
|
||||||
|
"fileLimitReachedDetail": "حجم هذا الملف {size}، لكن خطتك تسمح بـ {limit} كحد أقصى لكل إرسال.",
|
||||||
|
"fileLimitReachedDetailNoSize": "تسمح خطتك بـ {limit} كحد أقصى لكل إرسال.",
|
||||||
|
"fileLimitReachedHint": "سجّل فيديو أقصر وأرسله مرة أخرى.",
|
||||||
|
"fileLimitReachedHintFree": "سجّل فيديو أقصر، أو قم بترقية خطتك لإرسال ملفات أكبر.",
|
||||||
|
"fileLimitReachedUpgrade": "ترقية الخطة",
|
||||||
|
"contactGroupUsedByWidget": "أداة الشاشة الرئيسية",
|
||||||
|
"contactGroupUsedByWidgetSubtitle": "{count, plural, =1{تعرض أداة على شاشتك الرئيسية صورًا من هذه المجموعة.} =2{تعرض أداتان على شاشتك الرئيسية صورًا من هذه المجموعة.} few{تعرض {count} أدوات على شاشتك الرئيسية صورًا من هذه المجموعة.} many{تعرض {count} أداةً على شاشتك الرئيسية صورًا من هذه المجموعة.} other{تعرض {count} أداة على شاشتك الرئيسية صورًا من هذه المجموعة.}}",
|
||||||
|
"contactGroupDeleteBlockedByWidget": "{count, plural, =1{تستخدم أداةٌ على شاشتك الرئيسية مجموعة جهات الاتصال هذه. أزل تلك الأداة أولًا، ثم يمكنك حذف المجموعة.} =2{تستخدم أداتان على شاشتك الرئيسية مجموعة جهات الاتصال هذه. أزل هاتين الأداتين أولًا، ثم يمكنك حذف المجموعة.} few{تستخدم {count} أدوات على شاشتك الرئيسية مجموعة جهات الاتصال هذه. أزل تلك الأدوات أولًا، ثم يمكنك حذف المجموعة.} many{تستخدم {count} أداةً على شاشتك الرئيسية مجموعة جهات الاتصال هذه. أزل تلك الأدوات أولًا، ثم يمكنك حذف المجموعة.} other{تستخدم {count} أداة على شاشتك الرئيسية مجموعة جهات الاتصال هذه. أزل تلك الأدوات أولًا، ثم يمكنك حذف المجموعة.}}",
|
||||||
|
"webxdcStoreMenu": "تطبيق",
|
||||||
|
"webxdcStoreTitle": "إضافة تطبيق",
|
||||||
|
"webxdcStoreEmpty": "لا توجد تطبيقات متاحة بعد.",
|
||||||
|
"webxdcStoreOffline": "تعذّر تحميل قائمة التطبيقات. تحقق من اتصالك وحاول مرة أخرى.",
|
||||||
|
"webxdcStoreFailed": "تعذّرت إضافة التطبيق إلى هذه المحادثة.",
|
||||||
|
"webxdcStoreAlreadyAdded": "مضاف بالفعل إلى هذه المحادثة",
|
||||||
|
"webxdcChatApps": "تطبيقات المحادثة",
|
||||||
|
"webxdcChatAppsEmpty": "لم تتم إضافة أي تطبيقات لمرة واحدة إلى هذه المحادثة بعد.",
|
||||||
|
"webxdcUnavailable": "تعذّر تحميل هذا التطبيق.",
|
||||||
|
"webxdcDeleteConfirm": "سيتم حذف كل ما حفظه هذا التطبيق على هذا الجهاز. يحتفظ الأعضاء الآخرون بنسختهم الخاصة.",
|
||||||
|
"webxdcExternalLinkTitle": "مغادرة twonly؟",
|
||||||
|
"webxdcExternalLinkBody": "يُفتح هذا الرابط خارج twonly، في متصفحك:"
|
||||||
|
}
|
||||||
|
|
@ -111,7 +111,6 @@
|
||||||
"settingsNotifyResetTitleResetDesc": "Sollte das Problem weiterhin bestehen, sende uns bitte dein Debug-Protokoll über „Einstellungen“ > „Hilfe“, damit wir das Problem untersuchen können.",
|
"settingsNotifyResetTitleResetDesc": "Sollte das Problem weiterhin bestehen, sende uns bitte dein Debug-Protokoll über „Einstellungen“ > „Hilfe“, damit wir das Problem untersuchen können.",
|
||||||
"settingsHelp": "Hilfe",
|
"settingsHelp": "Hilfe",
|
||||||
"settingsHelpFAQ": "FAQ",
|
"settingsHelpFAQ": "FAQ",
|
||||||
"feedbackTooltip": "Feedback zur Verbesserung von twonly geben.",
|
|
||||||
"settingsHelpContactUs": "Kontaktiere uns",
|
"settingsHelpContactUs": "Kontaktiere uns",
|
||||||
"contactUsFaq": "FAQ schon gelesen?",
|
"contactUsFaq": "FAQ schon gelesen?",
|
||||||
"contactUsEmojis": "Wie fühlst du dich? (optional)",
|
"contactUsEmojis": "Wie fühlst du dich? (optional)",
|
||||||
|
|
@ -137,6 +136,7 @@
|
||||||
"settingsHelpImprint": "Impressum & Datenschutzrichtlinie",
|
"settingsHelpImprint": "Impressum & Datenschutzrichtlinie",
|
||||||
"settingsHelpTerms": "Nutzungsbedingungen",
|
"settingsHelpTerms": "Nutzungsbedingungen",
|
||||||
"settingsAppearanceTheme": "Theme",
|
"settingsAppearanceTheme": "Theme",
|
||||||
|
"settingsAppearanceLanguage": "Sprache",
|
||||||
"settingsAccountDeleteAccount": "Konto löschen",
|
"settingsAccountDeleteAccount": "Konto löschen",
|
||||||
"settingsAccountDeleteAccountNoBallance": "Wenn du dein Konto gelöscht hast, gibt es keinen Weg zurück.",
|
"settingsAccountDeleteAccountNoBallance": "Wenn du dein Konto gelöscht hast, gibt es keinen Weg zurück.",
|
||||||
"settingsAccountDeleteModalTitle": "Bist du sicher?",
|
"settingsAccountDeleteModalTitle": "Bist du sicher?",
|
||||||
|
|
@ -264,13 +264,7 @@
|
||||||
"buy": "Kaufen",
|
"buy": "Kaufen",
|
||||||
"autoRenewal": "Automatische Verlängerung",
|
"autoRenewal": "Automatische Verlängerung",
|
||||||
"additionalUsersList": "Deine zusätzlichen Benutzer",
|
"additionalUsersList": "Deine zusätzlichen Benutzer",
|
||||||
"galleryDelete": "Datei löschen",
|
|
||||||
"galleryExport": "In Galerie exportieren",
|
|
||||||
"galleryExportSuccess": "Erfolgreich in der Gallery gespeichert.",
|
"galleryExportSuccess": "Erfolgreich in der Gallery gespeichert.",
|
||||||
"gallerySelectAll": "Alle auswählen",
|
|
||||||
"galleryDeselectAll": "Auswahl aufheben",
|
|
||||||
"galleryFavorite": "Als Favorit markieren",
|
|
||||||
"galleryUnfavorite": "Favorit entfernen",
|
|
||||||
"galleryCancel": "Abbrechen",
|
"galleryCancel": "Abbrechen",
|
||||||
"memoriesEmpty": "Sobald du Bilder oder Videos speicherst, landen sie hier in deinen Erinnerungen.",
|
"memoriesEmpty": "Sobald du Bilder oder Videos speicherst, landen sie hier in deinen Erinnerungen.",
|
||||||
"memoriesDeleteSnackbarSuccess": "{count, plural, =1 {1 Element erfolgreich gelöscht} other {{count} Elemente erfolgreich gelöscht}}",
|
"memoriesDeleteSnackbarSuccess": "{count, plural, =1 {1 Element erfolgreich gelöscht} other {{count} Elemente erfolgreich gelöscht}}",
|
||||||
|
|
@ -279,7 +273,6 @@
|
||||||
"deleteOkBtnForMe": "Für mich löschen",
|
"deleteOkBtnForMe": "Für mich löschen",
|
||||||
"deleteOnlyForMe": "Nur für mich löschen",
|
"deleteOnlyForMe": "Nur für mich löschen",
|
||||||
"deleteImageTitle": "Bist du dir sicher?",
|
"deleteImageTitle": "Bist du dir sicher?",
|
||||||
"deleteImageBody": "Das Bild wird unwiderruflich gelöscht.",
|
|
||||||
"deleteMemoriesBody": "{count, plural, =1 {Das Bild wird unwiderruflich gelöscht.} other {Die {count} Bilder werden unwiderruflich gelöscht.}}",
|
"deleteMemoriesBody": "{count, plural, =1 {Das Bild wird unwiderruflich gelöscht.} other {Die {count} Bilder werden unwiderruflich gelöscht.}}",
|
||||||
"@deleteMemoriesBody": {
|
"@deleteMemoriesBody": {
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
|
|
@ -304,15 +297,6 @@
|
||||||
"memoriesMenuFavorite": "Favorisieren",
|
"memoriesMenuFavorite": "Favorisieren",
|
||||||
"memoriesMenuDelete": "Löschen",
|
"memoriesMenuDelete": "Löschen",
|
||||||
"memoriesMenuDeleteLocal": "Lokal löschen",
|
"memoriesMenuDeleteLocal": "Lokal löschen",
|
||||||
"backupPending": "Ausstehend",
|
|
||||||
"backupFailed": "Fehlgeschlagen",
|
|
||||||
"backupSuccess": "Erfolgreich",
|
|
||||||
"backupTwonlySafeDesc": "Sichere deine twonly-Identität, da dies die einzige Möglichkeit ist, dein Konto wiederherzustellen, wenn du die App deinstallierst oder dein Handy verlierst.",
|
|
||||||
"backupIdentityHeader": "Identität",
|
|
||||||
"backupArchiveHeader": "Kontakte & Nachrichten",
|
|
||||||
"backupLastBackupDate": "Letztes Backup",
|
|
||||||
"backupLastBackupSize": "Backup-Größe",
|
|
||||||
"backupLastBackupResult": "Ergebnis",
|
|
||||||
"backupNoPasswordRecovery": "Aufgrund des Sicherheitssystems von twonly gibt es (derzeit) keine Funktion zur Wiederherstellung des Passworts. Daher musst du dir dein Passwort merken oder, besser noch, aufschreiben.",
|
"backupNoPasswordRecovery": "Aufgrund des Sicherheitssystems von twonly gibt es (derzeit) keine Funktion zur Wiederherstellung des Passworts. Daher musst du dir dein Passwort merken oder, besser noch, aufschreiben.",
|
||||||
"backupInsecurePassword": "Unsicheres Passwort",
|
"backupInsecurePassword": "Unsicheres Passwort",
|
||||||
"backupInsecurePasswordDesc": "Das gewählte Passwort ist sehr unsicher und kann daher leicht von Angreifern erraten werden. Bitte wähle ein sicheres Passwort.",
|
"backupInsecurePasswordDesc": "Das gewählte Passwort ist sehr unsicher und kann daher leicht von Angreifern erraten werden. Bitte wähle ein sicheres Passwort.",
|
||||||
|
|
@ -435,7 +419,6 @@
|
||||||
"notificationReactionToAudio": "hat mit {reaction} auf deine Sprachnachricht reagiert.",
|
"notificationReactionToAudio": "hat mit {reaction} auf deine Sprachnachricht reagiert.",
|
||||||
"notificationResponse": "hat dir{inGroup} geantwortet.",
|
"notificationResponse": "hat dir{inGroup} geantwortet.",
|
||||||
"notificationCategoryMessageTitle": "Nachrichten",
|
"notificationCategoryMessageTitle": "Nachrichten",
|
||||||
"notificationCategoryMessageDesc": "Nachrichten von anderen Benutzern.",
|
|
||||||
"notificationConnectionFallback": "Du könntest neue Nachrichten haben.",
|
"notificationConnectionFallback": "Du könntest neue Nachrichten haben.",
|
||||||
"groupContextMenuDeleteGroup": "Dadurch werden alle Nachrichten in diesem Chat dauerhaft gelöscht.",
|
"groupContextMenuDeleteGroup": "Dadurch werden alle Nachrichten in diesem Chat dauerhaft gelöscht.",
|
||||||
"groupYouAreNowLongerAMember": "Du bist nicht mehr Mitglied dieser Gruppe.",
|
"groupYouAreNowLongerAMember": "Du bist nicht mehr Mitglied dieser Gruppe.",
|
||||||
|
|
@ -970,7 +953,6 @@
|
||||||
"missingRecoveryContactsCardAction": "Kontakte auswählen",
|
"missingRecoveryContactsCardAction": "Kontakte auswählen",
|
||||||
"memoriesBackupLimitReached": "Cloud-Backup-Limit erreicht! Bitte aktualisiere dein Abonnement oder gib Speicherplatz frei.",
|
"memoriesBackupLimitReached": "Cloud-Backup-Limit erreicht! Bitte aktualisiere dein Abonnement oder gib Speicherplatz frei.",
|
||||||
"settingsStorageLocal": "Lokaler Speicherplatz",
|
"settingsStorageLocal": "Lokaler Speicherplatz",
|
||||||
"settingsStorageNoCloudBackupTitle": "Kein Cloud-Backup",
|
|
||||||
"settingsStorageNoCloudBackupCard": "Sichere deine Erinnerungen in der Cloud, um lokalen Speicherplatz freizugeben und deine Bilder nicht zu verlieren. Alles Ende-zu-Ende verschlüsselt.",
|
"settingsStorageNoCloudBackupCard": "Sichere deine Erinnerungen in der Cloud, um lokalen Speicherplatz freizugeben und deine Bilder nicht zu verlieren. Alles Ende-zu-Ende verschlüsselt.",
|
||||||
"galleryActionSave": "Sichern",
|
"galleryActionSave": "Sichern",
|
||||||
"galleryActionExport": "Exportieren",
|
"galleryActionExport": "Exportieren",
|
||||||
|
|
@ -1066,7 +1048,6 @@
|
||||||
"backupCloudSectionTitle": "Deine Daten sichern",
|
"backupCloudSectionTitle": "Deine Daten sichern",
|
||||||
"backupCloudSectionDesc": "Sichere deine Inhalte, damit nichts verloren geht.",
|
"backupCloudSectionDesc": "Sichere deine Inhalte, damit nichts verloren geht.",
|
||||||
"backupCloudContactsMessages": "Kontakte & Nachrichten",
|
"backupCloudContactsMessages": "Kontakte & Nachrichten",
|
||||||
"backupCloudFreeActive": "Kostenlos aktiv",
|
|
||||||
"backupCloudImagesMedia": "Bilder & Medien",
|
"backupCloudImagesMedia": "Bilder & Medien",
|
||||||
"backupCloudProBadge": "Pro",
|
"backupCloudProBadge": "Pro",
|
||||||
"memoriesAddingToFavorites": "Zu Favoriten hinzufügen...",
|
"memoriesAddingToFavorites": "Zu Favoriten hinzufügen...",
|
||||||
|
|
@ -1119,8 +1100,7 @@
|
||||||
"webxdcStoreOffline": "Die App-Liste konnte nicht geladen werden. Prüfe deine Verbindung und versuche es erneut.",
|
"webxdcStoreOffline": "Die App-Liste konnte nicht geladen werden. Prüfe deine Verbindung und versuche es erneut.",
|
||||||
"webxdcStoreFailed": "Die App konnte diesem Chat nicht hinzugefügt werden.",
|
"webxdcStoreFailed": "Die App konnte diesem Chat nicht hinzugefügt werden.",
|
||||||
"webxdcStoreAlreadyAdded": "Bereits zu diesem Chat hinzugefügt",
|
"webxdcStoreAlreadyAdded": "Bereits zu diesem Chat hinzugefügt",
|
||||||
"webxdcChatAppsMenu": "Chat-Apps",
|
"webxdcChatApps": "Chat-Apps",
|
||||||
"webxdcChatAppsTitle": "Chat-Apps",
|
|
||||||
"webxdcChatAppsEmpty": "Diesem Chat wurden noch keine einmaligen Apps hinzugefügt.",
|
"webxdcChatAppsEmpty": "Diesem Chat wurden noch keine einmaligen Apps hinzugefügt.",
|
||||||
"webxdcUnavailable": "Diese App konnte nicht geladen werden.",
|
"webxdcUnavailable": "Diese App konnte nicht geladen werden.",
|
||||||
"webxdcDeleteConfirm": "Alles, was diese App auf diesem Gerät gespeichert hat, wird gelöscht. Andere Mitglieder behalten ihre eigene Kopie.",
|
"webxdcDeleteConfirm": "Alles, was diese App auf diesem Gerät gespeichert hat, wird gelöscht. Andere Mitglieder behalten ihre eigene Kopie.",
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,6 @@
|
||||||
"settingsHelp": "Help",
|
"settingsHelp": "Help",
|
||||||
"settingsHelpDiagnostics": "Diagnostic protocol",
|
"settingsHelpDiagnostics": "Diagnostic protocol",
|
||||||
"settingsHelpFAQ": "FAQ",
|
"settingsHelpFAQ": "FAQ",
|
||||||
"feedbackTooltip": "Give Feedback to improve twonly.",
|
|
||||||
"settingsHelpContactUs": "Contact us",
|
"settingsHelpContactUs": "Contact us",
|
||||||
"settingsHelpVersion": "Version",
|
"settingsHelpVersion": "Version",
|
||||||
"settingsHelpLicenses": "Licenses (Source-Code)",
|
"settingsHelpLicenses": "Licenses (Source-Code)",
|
||||||
|
|
@ -133,6 +132,7 @@
|
||||||
"hideNewsIcon": "Hide News Icon",
|
"hideNewsIcon": "Hide News Icon",
|
||||||
"settingsHelpTerms": "Terms of Service",
|
"settingsHelpTerms": "Terms of Service",
|
||||||
"settingsAppearanceTheme": "Theme",
|
"settingsAppearanceTheme": "Theme",
|
||||||
|
"settingsAppearanceLanguage": "Language",
|
||||||
"settingsAccountDeleteAccount": "Delete account",
|
"settingsAccountDeleteAccount": "Delete account",
|
||||||
"settingsAccountDeleteAccountNoBallance": "Once you delete your account, there is no going back.",
|
"settingsAccountDeleteAccountNoBallance": "Once you delete your account, there is no going back.",
|
||||||
"settingsAccountDeleteModalTitle": "Are you sure?",
|
"settingsAccountDeleteModalTitle": "Are you sure?",
|
||||||
|
|
@ -274,13 +274,7 @@
|
||||||
"buy": "Buy",
|
"buy": "Buy",
|
||||||
"autoRenewal": "Auto renewal",
|
"autoRenewal": "Auto renewal",
|
||||||
"additionalUsersList": "Your additional users",
|
"additionalUsersList": "Your additional users",
|
||||||
"galleryDelete": "Delete file",
|
|
||||||
"galleryExport": "Export to gallery",
|
|
||||||
"galleryExportSuccess": "Successfully saved in the Gallery.",
|
"galleryExportSuccess": "Successfully saved in the Gallery.",
|
||||||
"gallerySelectAll": "Select all",
|
|
||||||
"galleryDeselectAll": "Deselect all",
|
|
||||||
"galleryFavorite": "Favorite",
|
|
||||||
"galleryUnfavorite": "Unfavorite",
|
|
||||||
"galleryCancel": "Cancel",
|
"galleryCancel": "Cancel",
|
||||||
"memoriesEmpty": "As soon as you save pictures or videos, they end up here in your memories.",
|
"memoriesEmpty": "As soon as you save pictures or videos, they end up here in your memories.",
|
||||||
"deleteTitle": "Are you sure?",
|
"deleteTitle": "Are you sure?",
|
||||||
|
|
@ -289,7 +283,6 @@
|
||||||
"deleteOkBtnForMe": "Delete for me",
|
"deleteOkBtnForMe": "Delete for me",
|
||||||
"deleteOnlyForMe": "Delete only for me",
|
"deleteOnlyForMe": "Delete only for me",
|
||||||
"deleteImageTitle": "Are you sure?",
|
"deleteImageTitle": "Are you sure?",
|
||||||
"deleteImageBody": "The image will be irrevocably deleted.",
|
|
||||||
"deleteMemoriesBody": "{count, plural, =1 {The image will be irrevocably deleted.} other {The {count} images will be irrevocably deleted.}}",
|
"deleteMemoriesBody": "{count, plural, =1 {The image will be irrevocably deleted.} other {The {count} images will be irrevocably deleted.}}",
|
||||||
"@deleteMemoriesBody": {
|
"@deleteMemoriesBody": {
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
|
|
@ -315,16 +308,7 @@
|
||||||
"memoriesMenuDelete": "Delete completely",
|
"memoriesMenuDelete": "Delete completely",
|
||||||
"memoriesMenuDeleteLocal": "Delete locally",
|
"memoriesMenuDeleteLocal": "Delete locally",
|
||||||
"settingsBackup": "Backup",
|
"settingsBackup": "Backup",
|
||||||
"backupPending": "Pending",
|
|
||||||
"backupFailed": "Failed",
|
|
||||||
"backupSuccess": "Success",
|
|
||||||
"backupTwonlySafeDesc": "Back up your twonly identity, as this is the only way to restore your account if you uninstall the app or lose your phone.",
|
|
||||||
"backupNoPasswordRecovery": "Due to twonly's security system, there is (currently) no password recovery function. Therefore, you must remember your password or, better yet, write it down.",
|
"backupNoPasswordRecovery": "Due to twonly's security system, there is (currently) no password recovery function. Therefore, you must remember your password or, better yet, write it down.",
|
||||||
"backupIdentityHeader": "Identity",
|
|
||||||
"backupArchiveHeader": "Contacts & Messages",
|
|
||||||
"backupLastBackupDate": "Last backup",
|
|
||||||
"backupLastBackupSize": "Backup size",
|
|
||||||
"backupLastBackupResult": "Result",
|
|
||||||
"backupInsecurePassword": "Insecure password",
|
"backupInsecurePassword": "Insecure password",
|
||||||
"backupInsecurePasswordDesc": "The chosen password is very insecure and can therefore easily be guessed by attackers. Please choose a secure password.",
|
"backupInsecurePasswordDesc": "The chosen password is very insecure and can therefore easily be guessed by attackers. Please choose a secure password.",
|
||||||
"backupInsecurePasswordOk": "Continue anyway",
|
"backupInsecurePasswordOk": "Continue anyway",
|
||||||
|
|
@ -445,7 +429,6 @@
|
||||||
"notificationReactionToAudio": "has reacted with {reaction} to your audio message.",
|
"notificationReactionToAudio": "has reacted with {reaction} to your audio message.",
|
||||||
"notificationResponse": "has responded{inGroup}.",
|
"notificationResponse": "has responded{inGroup}.",
|
||||||
"notificationCategoryMessageTitle": "Messages",
|
"notificationCategoryMessageTitle": "Messages",
|
||||||
"notificationCategoryMessageDesc": "Messages from other users.",
|
|
||||||
"notificationConnectionFallback": "You may have new messages.",
|
"notificationConnectionFallback": "You may have new messages.",
|
||||||
"groupContextMenuDeleteGroup": "This will permanently delete all messages in this chat.",
|
"groupContextMenuDeleteGroup": "This will permanently delete all messages in this chat.",
|
||||||
"groupYouAreNowLongerAMember": "You are no longer part of this group.",
|
"groupYouAreNowLongerAMember": "You are no longer part of this group.",
|
||||||
|
|
@ -980,7 +963,6 @@
|
||||||
"missingRecoveryContactsCardAction": "Select Contacts",
|
"missingRecoveryContactsCardAction": "Select Contacts",
|
||||||
"memoriesBackupLimitReached": "Cloud backup limit reached! Please upgrade your plan or free up space.",
|
"memoriesBackupLimitReached": "Cloud backup limit reached! Please upgrade your plan or free up space.",
|
||||||
"settingsStorageLocal": "Local storage",
|
"settingsStorageLocal": "Local storage",
|
||||||
"settingsStorageNoCloudBackupTitle": "No Cloud Backup",
|
|
||||||
"settingsStorageNoCloudBackupCard": "Back up your memories to the cloud to free up local space and ensure you never lose your pictures. All end-to-end encrypted.",
|
"settingsStorageNoCloudBackupCard": "Back up your memories to the cloud to free up local space and ensure you never lose your pictures. All end-to-end encrypted.",
|
||||||
"galleryActionSave": "Save",
|
"galleryActionSave": "Save",
|
||||||
"galleryActionExport": "Export",
|
"galleryActionExport": "Export",
|
||||||
|
|
@ -1076,7 +1058,6 @@
|
||||||
"backupCloudSectionTitle": "Backup Your Data",
|
"backupCloudSectionTitle": "Backup Your Data",
|
||||||
"backupCloudSectionDesc": "Backup your content so nothing gets lost.",
|
"backupCloudSectionDesc": "Backup your content so nothing gets lost.",
|
||||||
"backupCloudContactsMessages": "Contacts & Messages",
|
"backupCloudContactsMessages": "Contacts & Messages",
|
||||||
"backupCloudFreeActive": "Free Active",
|
|
||||||
"backupCloudImagesMedia": "Images & Media",
|
"backupCloudImagesMedia": "Images & Media",
|
||||||
"backupCloudProBadge": "Pro",
|
"backupCloudProBadge": "Pro",
|
||||||
"memoriesAddingToFavorites": "Adding to favorites...",
|
"memoriesAddingToFavorites": "Adding to favorites...",
|
||||||
|
|
@ -1129,8 +1110,7 @@
|
||||||
"webxdcStoreOffline": "The app list could not be loaded. Check your connection and try again.",
|
"webxdcStoreOffline": "The app list could not be loaded. Check your connection and try again.",
|
||||||
"webxdcStoreFailed": "The app could not be added to this chat.",
|
"webxdcStoreFailed": "The app could not be added to this chat.",
|
||||||
"webxdcStoreAlreadyAdded": "Already added to this chat",
|
"webxdcStoreAlreadyAdded": "Already added to this chat",
|
||||||
"webxdcChatAppsMenu": "Chat apps",
|
"webxdcChatApps": "Chat apps",
|
||||||
"webxdcChatAppsTitle": "Chat apps",
|
|
||||||
"webxdcChatAppsEmpty": "No one-time apps have been added to this chat yet.",
|
"webxdcChatAppsEmpty": "No one-time apps have been added to this chat yet.",
|
||||||
"webxdcUnavailable": "This app could not be loaded.",
|
"webxdcUnavailable": "This app could not be loaded.",
|
||||||
"webxdcDeleteConfirm": "Everything this app saved on this device is deleted. Other members keep their own copy.",
|
"webxdcDeleteConfirm": "Everything this app saved on this device is deleted. Other members keep their own copy.",
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,25 @@ import 'package:twonly/locator.dart';
|
||||||
import 'package:twonly/src/services/user.service.dart';
|
import 'package:twonly/src/services/user.service.dart';
|
||||||
import 'package:twonly/src/visual/themes/light.dart';
|
import 'package:twonly/src/visual/themes/light.dart';
|
||||||
|
|
||||||
|
/// Languages the app can be shown in. The first one is used when the device
|
||||||
|
/// language is none of them.
|
||||||
|
const supportedLocales = [
|
||||||
|
Locale('en'),
|
||||||
|
Locale('de'),
|
||||||
|
Locale('ar'),
|
||||||
|
];
|
||||||
|
|
||||||
class SettingsChangeProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
class SettingsChangeProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
||||||
late ThemeMode _themeMode;
|
late ThemeMode _themeMode;
|
||||||
late Color _primaryColor;
|
late Color _primaryColor;
|
||||||
|
Locale? _locale;
|
||||||
|
|
||||||
ThemeMode get themeMode => _themeMode;
|
ThemeMode get themeMode => _themeMode;
|
||||||
Color get primaryColor => _primaryColor;
|
Color get primaryColor => _primaryColor;
|
||||||
|
|
||||||
|
/// The language picked in the settings, or null to follow the device.
|
||||||
|
Locale? get locale => _locale;
|
||||||
|
|
||||||
void loadSettings() {
|
void loadSettings() {
|
||||||
if (userService.isUserCreated) {
|
if (userService.isUserCreated) {
|
||||||
_themeMode = switch (userService.currentUser.themeMode) {
|
_themeMode = switch (userService.currentUser.themeMode) {
|
||||||
|
|
@ -23,10 +35,15 @@ class SettingsChangeProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
||||||
_primaryColor = primaryColorValue == null
|
_primaryColor = primaryColorValue == null
|
||||||
? defaultPrimaryColor
|
? defaultPrimaryColor
|
||||||
: Color(primaryColorValue);
|
: Color(primaryColorValue);
|
||||||
|
final language = userService.currentUser.language;
|
||||||
|
_locale = supportedLocales
|
||||||
|
.where((locale) => locale.languageCode == language)
|
||||||
|
.firstOrNull;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
} else {
|
} else {
|
||||||
_themeMode = ThemeMode.system;
|
_themeMode = ThemeMode.system;
|
||||||
_primaryColor = defaultPrimaryColor;
|
_primaryColor = defaultPrimaryColor;
|
||||||
|
_locale = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,4 +76,16 @@ class SettingsChangeProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
||||||
(u) => u.primaryColorValue = newColor.toARGB32(),
|
(u) => u.primaryColorValue = newColor.toARGB32(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> updateLocale(Locale? newLocale) async {
|
||||||
|
if (newLocale == _locale) return;
|
||||||
|
|
||||||
|
_locale = newLocale;
|
||||||
|
|
||||||
|
notifyListeners();
|
||||||
|
|
||||||
|
await UserService.update(
|
||||||
|
(u) => u.language = newLocale?.languageCode,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -266,7 +266,7 @@ class _ContactViewState extends State<ContactView> {
|
||||||
),
|
),
|
||||||
BetterListTile(
|
BetterListTile(
|
||||||
icon: FontAwesomeIcons.layerGroup,
|
icon: FontAwesomeIcons.layerGroup,
|
||||||
text: context.lang.webxdcChatAppsMenu,
|
text: context.lang.webxdcChatApps,
|
||||||
onTap: () => context.navPush(
|
onTap: () => context.navPush(
|
||||||
WebxdcChatAppsView(
|
WebxdcChatAppsView(
|
||||||
groupId: getUUIDforDirectChat(
|
groupId: getUUIDforDirectChat(
|
||||||
|
|
|
||||||
|
|
@ -216,7 +216,7 @@ class _GroupViewState extends State<GroupView> {
|
||||||
),
|
),
|
||||||
BetterListTile(
|
BetterListTile(
|
||||||
icon: FontAwesomeIcons.layerGroup,
|
icon: FontAwesomeIcons.layerGroup,
|
||||||
text: context.lang.webxdcChatAppsMenu,
|
text: context.lang.webxdcChatApps,
|
||||||
onTap: () => context.navPush(
|
onTap: () => context.navPush(
|
||||||
WebxdcChatAppsView(groupId: widget.groupId),
|
WebxdcChatAppsView(groupId: widget.groupId),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,14 @@ import 'package:twonly/src/utils/misc.dart';
|
||||||
import 'package:twonly/src/visual/components/custom_color_picker_dialog.comp.dart';
|
import 'package:twonly/src/visual/components/custom_color_picker_dialog.comp.dart';
|
||||||
import 'package:twonly/src/visual/elements/radio_button.element.dart';
|
import 'package:twonly/src/visual/elements/radio_button.element.dart';
|
||||||
|
|
||||||
|
/// Each language is listed in its own name, so it can be found again after
|
||||||
|
/// switching to a language the user cannot read.
|
||||||
|
const _languageNames = {
|
||||||
|
'en': 'English',
|
||||||
|
'de': 'Deutsch',
|
||||||
|
'ar': 'العربية',
|
||||||
|
};
|
||||||
|
|
||||||
class AppearanceView extends StatefulWidget {
|
class AppearanceView extends StatefulWidget {
|
||||||
const AppearanceView({super.key});
|
const AppearanceView({super.key});
|
||||||
|
|
||||||
|
|
@ -73,6 +81,47 @@ class _AppearanceViewState extends State<AppearanceView> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _showSelectLanguage(BuildContext context) async {
|
||||||
|
final currentLocale = context.read<SettingsChangeProvider>().locale;
|
||||||
|
|
||||||
|
// A record distinguishes picking the system default (null) from dismissing.
|
||||||
|
final selected = await showDialog<({Locale? locale})>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text(context.lang.settingsAppearanceLanguage),
|
||||||
|
content: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
RadioButton<Locale?>(
|
||||||
|
value: null,
|
||||||
|
groupValue: currentLocale,
|
||||||
|
label: context.lang.themeSystemDefault,
|
||||||
|
onChanged: (value) {
|
||||||
|
Navigator.of(context).pop((locale: value));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
for (final locale in supportedLocales)
|
||||||
|
RadioButton<Locale?>(
|
||||||
|
value: locale,
|
||||||
|
groupValue: currentLocale,
|
||||||
|
label: _languageName(locale),
|
||||||
|
onChanged: (value) {
|
||||||
|
Navigator.of(context).pop((locale: value));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (selected != null && context.mounted) {
|
||||||
|
await context.read<SettingsChangeProvider>().updateLocale(
|
||||||
|
selected.locale,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _showSelectPrimaryColor(BuildContext context) async {
|
Future<void> _showSelectPrimaryColor(BuildContext context) async {
|
||||||
const presetColors = <Color>[
|
const presetColors = <Color>[
|
||||||
Color(0xFF57CC99), // Original Twonly Green
|
Color(0xFF57CC99), // Original Twonly Green
|
||||||
|
|
@ -221,9 +270,13 @@ class _AppearanceViewState extends State<AppearanceView> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _languageName(Locale locale) =>
|
||||||
|
_languageNames[locale.languageCode] ?? locale.languageCode;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final selectedTheme = context.watch<SettingsChangeProvider>().themeMode;
|
final selectedTheme = context.watch<SettingsChangeProvider>().themeMode;
|
||||||
|
final selectedLocale = context.watch<SettingsChangeProvider>().locale;
|
||||||
final primaryColor = context.watch<SettingsChangeProvider>().primaryColor;
|
final primaryColor = context.watch<SettingsChangeProvider>().primaryColor;
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
|
@ -251,6 +304,18 @@ class _AppearanceViewState extends State<AppearanceView> {
|
||||||
await _showSelectThemeMode(context);
|
await _showSelectThemeMode(context);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
ListTile(
|
||||||
|
title: Text(context.lang.settingsAppearanceLanguage),
|
||||||
|
subtitle: Text(
|
||||||
|
selectedLocale == null
|
||||||
|
? context.lang.themeSystemDefault
|
||||||
|
: _languageName(selectedLocale),
|
||||||
|
style: const TextStyle(color: Colors.grey),
|
||||||
|
),
|
||||||
|
onTap: () async {
|
||||||
|
await _showSelectLanguage(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(context.lang.settingsAppearancePrimaryColor),
|
title: Text(context.lang.settingsAppearancePrimaryColor),
|
||||||
trailing: Container(
|
trailing: Container(
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ class _WebxdcChatAppsViewState extends State<WebxdcChatAppsView> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final apps = _apps;
|
final apps = _apps;
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: Text(context.lang.webxdcChatAppsTitle)),
|
appBar: AppBar(title: Text(context.lang.webxdcChatApps)),
|
||||||
body: apps == null
|
body: apps == null
|
||||||
? const Center(child: CircularProgressIndicator())
|
? const Center(child: CircularProgressIndicator())
|
||||||
: apps.isEmpty
|
: apps.isEmpty
|
||||||
|
|
|
||||||
|
|
@ -7663,6 +7663,7 @@ impl SseDecode for crate::user_config::UserConfig {
|
||||||
let mut var_additionalUserInvites = <Option<String>>::sse_decode(deserializer);
|
let mut var_additionalUserInvites = <Option<String>>::sse_decode(deserializer);
|
||||||
let mut var_themeMode = <crate::user_config::ThemeMode>::sse_decode(deserializer);
|
let mut var_themeMode = <crate::user_config::ThemeMode>::sse_decode(deserializer);
|
||||||
let mut var_primaryColorValue = <Option<i64>>::sse_decode(deserializer);
|
let mut var_primaryColorValue = <Option<i64>>::sse_decode(deserializer);
|
||||||
|
let mut var_language = <Option<String>>::sse_decode(deserializer);
|
||||||
let mut var_defaultShowTime = <Option<i64>>::sse_decode(deserializer);
|
let mut var_defaultShowTime = <Option<i64>>::sse_decode(deserializer);
|
||||||
let mut var_requestedAudioPermission = <bool>::sse_decode(deserializer);
|
let mut var_requestedAudioPermission = <bool>::sse_decode(deserializer);
|
||||||
let mut var_enableDatabaseLogging = <bool>::sse_decode(deserializer);
|
let mut var_enableDatabaseLogging = <bool>::sse_decode(deserializer);
|
||||||
|
|
@ -7731,6 +7732,7 @@ impl SseDecode for crate::user_config::UserConfig {
|
||||||
additional_user_invites: var_additionalUserInvites,
|
additional_user_invites: var_additionalUserInvites,
|
||||||
theme_mode: var_themeMode,
|
theme_mode: var_themeMode,
|
||||||
primary_color_value: var_primaryColorValue,
|
primary_color_value: var_primaryColorValue,
|
||||||
|
language: var_language,
|
||||||
default_show_time: var_defaultShowTime,
|
default_show_time: var_defaultShowTime,
|
||||||
requested_audio_permission: var_requestedAudioPermission,
|
requested_audio_permission: var_requestedAudioPermission,
|
||||||
enable_database_logging: var_enableDatabaseLogging,
|
enable_database_logging: var_enableDatabaseLogging,
|
||||||
|
|
@ -8941,6 +8943,7 @@ impl flutter_rust_bridge::IntoDart for crate::user_config::UserConfig {
|
||||||
self.additional_user_invites.into_into_dart().into_dart(),
|
self.additional_user_invites.into_into_dart().into_dart(),
|
||||||
self.theme_mode.into_into_dart().into_dart(),
|
self.theme_mode.into_into_dart().into_dart(),
|
||||||
self.primary_color_value.into_into_dart().into_dart(),
|
self.primary_color_value.into_into_dart().into_dart(),
|
||||||
|
self.language.into_into_dart().into_dart(),
|
||||||
self.default_show_time.into_into_dart().into_dart(),
|
self.default_show_time.into_into_dart().into_dart(),
|
||||||
self.requested_audio_permission.into_into_dart().into_dart(),
|
self.requested_audio_permission.into_into_dart().into_dart(),
|
||||||
self.enable_database_logging.into_into_dart().into_dart(),
|
self.enable_database_logging.into_into_dart().into_dart(),
|
||||||
|
|
@ -10096,6 +10099,7 @@ impl SseEncode for crate::user_config::UserConfig {
|
||||||
<Option<String>>::sse_encode(self.additional_user_invites, serializer);
|
<Option<String>>::sse_encode(self.additional_user_invites, serializer);
|
||||||
<crate::user_config::ThemeMode>::sse_encode(self.theme_mode, serializer);
|
<crate::user_config::ThemeMode>::sse_encode(self.theme_mode, serializer);
|
||||||
<Option<i64>>::sse_encode(self.primary_color_value, serializer);
|
<Option<i64>>::sse_encode(self.primary_color_value, serializer);
|
||||||
|
<Option<String>>::sse_encode(self.language, serializer);
|
||||||
<Option<i64>>::sse_encode(self.default_show_time, serializer);
|
<Option<i64>>::sse_encode(self.default_show_time, serializer);
|
||||||
<bool>::sse_encode(self.requested_audio_permission, serializer);
|
<bool>::sse_encode(self.requested_audio_permission, serializer);
|
||||||
<bool>::sse_encode(self.enable_database_logging, serializer);
|
<bool>::sse_encode(self.enable_database_logging, serializer);
|
||||||
|
|
|
||||||
|
|
@ -107,9 +107,11 @@ pub unsafe extern "C" fn twonly_notification_process(
|
||||||
widget_refresh: true,
|
widget_refresh: true,
|
||||||
batch: Some(batch),
|
batch: Some(batch),
|
||||||
fallback: Some(notifications::fallback_presentation(
|
fallback: Some(notifications::fallback_presentation(
|
||||||
|
¬ifications::app_locale(
|
||||||
unsafe { required_string(locale, "locale") }
|
unsafe { required_string(locale, "locale") }
|
||||||
.as_deref()
|
.as_deref()
|
||||||
.unwrap_or("en"),
|
.unwrap_or("en"),
|
||||||
|
),
|
||||||
)),
|
)),
|
||||||
error: None,
|
error: None,
|
||||||
}),
|
}),
|
||||||
|
|
@ -118,9 +120,11 @@ pub unsafe extern "C" fn twonly_notification_process(
|
||||||
widget_refresh: false,
|
widget_refresh: false,
|
||||||
batch: None,
|
batch: None,
|
||||||
fallback: Some(notifications::fallback_presentation(
|
fallback: Some(notifications::fallback_presentation(
|
||||||
|
¬ifications::app_locale(
|
||||||
unsafe { required_string(locale, "locale") }
|
unsafe { required_string(locale, "locale") }
|
||||||
.as_deref()
|
.as_deref()
|
||||||
.unwrap_or("en"),
|
.unwrap_or("en"),
|
||||||
|
),
|
||||||
)),
|
)),
|
||||||
error: Some(error),
|
error: Some(error),
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,14 @@ use std::sync::{Arc, LazyLock};
|
||||||
const MAX_BATCH_SIZE: i64 = 100;
|
const MAX_BATCH_SIZE: i64 = 100;
|
||||||
const EN_ARB: &str = include_str!("../../../lib/src/localization/translations/en.arb");
|
const EN_ARB: &str = include_str!("../../../lib/src/localization/translations/en.arb");
|
||||||
const DE_ARB: &str = include_str!("../../../lib/src/localization/translations/de.arb");
|
const DE_ARB: &str = include_str!("../../../lib/src/localization/translations/de.arb");
|
||||||
|
const AR_ARB: &str = include_str!("../../../lib/src/localization/translations/ar.arb");
|
||||||
|
|
||||||
static EN_TRANSLATIONS: LazyLock<HashMap<String, String>> =
|
static EN_TRANSLATIONS: LazyLock<HashMap<String, String>> =
|
||||||
LazyLock::new(|| parse_arb(EN_ARB, "en"));
|
LazyLock::new(|| parse_arb(EN_ARB, "en"));
|
||||||
static DE_TRANSLATIONS: LazyLock<HashMap<String, String>> =
|
static DE_TRANSLATIONS: LazyLock<HashMap<String, String>> =
|
||||||
LazyLock::new(|| parse_arb(DE_ARB, "de"));
|
LazyLock::new(|| parse_arb(DE_ARB, "de"));
|
||||||
|
static AR_TRANSLATIONS: LazyLock<HashMap<String, String>> =
|
||||||
|
LazyLock::new(|| parse_arb(AR_ARB, "ar"));
|
||||||
|
|
||||||
/// The announcement a webxdc update carries, if it has one.
|
/// The announcement a webxdc update carries, if it has one.
|
||||||
///
|
///
|
||||||
|
|
@ -529,6 +532,7 @@ pub async fn process_wakeup(
|
||||||
) -> Result<NotificationBatch> {
|
) -> Result<NotificationBatch> {
|
||||||
Context::init_notification(config).await?;
|
Context::init_notification(config).await?;
|
||||||
let ctx = Context::get_static()?.clone();
|
let ctx = Context::get_static()?.clone();
|
||||||
|
let locale = &app_locale(locale);
|
||||||
|
|
||||||
// The FCM health check used to be fed by the Dart background isolate, which
|
// The FCM health check used to be fed by the Dart background isolate, which
|
||||||
// no longer runs. Record the wake-up here so both platforms report it.
|
// no longer runs. Record the wake-up here so both platforms report it.
|
||||||
|
|
@ -760,16 +764,26 @@ fn parse_arb(source: &str, locale: &str) -> HashMap<String, String> {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The language picked in the app's settings, or the device's locale when the
|
||||||
|
/// user left it on the system default or the configuration is not readable.
|
||||||
|
pub fn app_locale(device_locale: &str) -> String {
|
||||||
|
Context::get_static()
|
||||||
|
.ok()
|
||||||
|
.and_then(|ctx| UserConfig::load_from(ctx).ok().flatten())
|
||||||
|
.and_then(|user| user.language)
|
||||||
|
.unwrap_or_else(|| device_locale.to_owned())
|
||||||
|
}
|
||||||
|
|
||||||
fn translation(locale: &str, key: &str) -> &'static str {
|
fn translation(locale: &str, key: &str) -> &'static str {
|
||||||
let language = locale
|
let language = locale
|
||||||
.split(['-', '_'])
|
.split(['-', '_'])
|
||||||
.next()
|
.next()
|
||||||
.unwrap_or("en")
|
.unwrap_or("en")
|
||||||
.to_ascii_lowercase();
|
.to_ascii_lowercase();
|
||||||
let translations = if language == "de" {
|
let translations = match language.as_str() {
|
||||||
&*DE_TRANSLATIONS
|
"de" => &*DE_TRANSLATIONS,
|
||||||
} else {
|
"ar" => &*AR_TRANSLATIONS,
|
||||||
&*EN_TRANSLATIONS
|
_ => &*EN_TRANSLATIONS,
|
||||||
};
|
};
|
||||||
translations
|
translations
|
||||||
.get(key)
|
.get(key)
|
||||||
|
|
@ -999,6 +1013,7 @@ mod tests {
|
||||||
group.conversation_name = Some("Friends".into());
|
group.conversation_name = Some("Friends".into());
|
||||||
group.is_direct_chat = 0;
|
group.is_direct_chat = 0;
|
||||||
assert_eq!(localized_body("en", &group), "sent a message in Friends.");
|
assert_eq!(localized_body("en", &group), "sent a message in Friends.");
|
||||||
|
assert_eq!(localized_body("ar", &group), "رسالة جديدة في Friends.");
|
||||||
|
|
||||||
let mut reaction = pending_row("reaction");
|
let mut reaction = pending_row("reaction");
|
||||||
reaction.content = Some("🔥".into());
|
reaction.content = Some("🔥".into());
|
||||||
|
|
|
||||||
|
|
@ -217,6 +217,10 @@ pub struct UserConfig {
|
||||||
pub theme_mode: ThemeMode,
|
pub theme_mode: ThemeMode,
|
||||||
#[frb(non_final)]
|
#[frb(non_final)]
|
||||||
pub primary_color_value: Option<i64>,
|
pub primary_color_value: Option<i64>,
|
||||||
|
/// Language code the app is shown in. `None` follows the device.
|
||||||
|
#[serde(default)]
|
||||||
|
#[frb(non_final)]
|
||||||
|
pub language: Option<String>,
|
||||||
#[frb(non_final)]
|
#[frb(non_final)]
|
||||||
pub default_show_time: Option<i64>,
|
pub default_show_time: Option<i64>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,11 @@ import re
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
ARB_DIR = 'lib/src/localization/translations'
|
ARB_DIR = 'lib/src/localization/translations'
|
||||||
LIB_DIR = 'lib'
|
# (directory, file extension) pairs whose sources may reference ARB keys.
|
||||||
|
SOURCE_DIRS = [
|
||||||
|
('lib', '.dart'),
|
||||||
|
('rust/src', '.rs'),
|
||||||
|
]
|
||||||
|
|
||||||
def get_arb_data(filepath):
|
def get_arb_data(filepath):
|
||||||
try:
|
try:
|
||||||
|
|
@ -34,18 +38,19 @@ def main():
|
||||||
en_keys = get_keys(en_data)
|
en_keys = get_keys(en_data)
|
||||||
print(f"Found {len(en_keys)} keys in en.arb")
|
print(f"Found {len(en_keys)} keys in en.arb")
|
||||||
|
|
||||||
# 1. Check for unused keys in Dart files
|
# 1. Check for unused keys in Dart and Rust files
|
||||||
print("\n--- Checking for unused keys in Dart files ---")
|
print("\n--- Checking for unused keys in Dart and Rust files ---")
|
||||||
all_dart_text = ""
|
all_source_text = ""
|
||||||
for root, _, files in os.walk(LIB_DIR):
|
for source_dir, extension in SOURCE_DIRS:
|
||||||
|
for root, _, files in os.walk(source_dir):
|
||||||
for file in files:
|
for file in files:
|
||||||
if file.endswith('.dart'):
|
if file.endswith(extension):
|
||||||
filepath = os.path.join(root, file)
|
filepath = os.path.join(root, file)
|
||||||
if "generated" in str(filepath):
|
if "generated" in str(filepath):
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
with open(filepath, 'r', encoding='utf-8') as f:
|
with open(filepath, 'r', encoding='utf-8') as f:
|
||||||
all_dart_text += f.read() + "\n"
|
all_source_text += f.read() + "\n"
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Could not read {filepath}: {e}")
|
print(f"Could not read {filepath}: {e}")
|
||||||
|
|
||||||
|
|
@ -53,11 +58,11 @@ def main():
|
||||||
for key in sorted(en_keys):
|
for key in sorted(en_keys):
|
||||||
# Using word boundary to avoid partial matches
|
# Using word boundary to avoid partial matches
|
||||||
pattern = r'\b' + re.escape(key) + r'\b'
|
pattern = r'\b' + re.escape(key) + r'\b'
|
||||||
if not re.search(pattern, all_dart_text):
|
if not re.search(pattern, all_source_text):
|
||||||
unused_keys.add(key)
|
unused_keys.add(key)
|
||||||
|
|
||||||
if unused_keys:
|
if unused_keys:
|
||||||
print(f"Found {len(unused_keys)} keys in en.arb that do not appear to be used in the Dart code:")
|
print(f"Found {len(unused_keys)} keys in en.arb that do not appear to be used in the Dart or Rust code:")
|
||||||
for k in sorted(unused_keys):
|
for k in sorted(unused_keys):
|
||||||
print(f" - {k}")
|
print(f" - {k}")
|
||||||
|
|
||||||
|
|
@ -86,7 +91,7 @@ def main():
|
||||||
else:
|
else:
|
||||||
print("\nRun with --fix to automatically delete these unused keys.")
|
print("\nRun with --fix to automatically delete these unused keys.")
|
||||||
else:
|
else:
|
||||||
print("All keys in en.arb seem to be used in the Dart files.")
|
print("All keys in en.arb seem to be used in the Dart or Rust files.")
|
||||||
|
|
||||||
# 2. Compare other .arb files with en.arb
|
# 2. Compare other .arb files with en.arb
|
||||||
print("\n--- Comparing other .arb files with en.arb ---")
|
print("\n--- Comparing other .arb files with en.arb ---")
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue