Compare commits
1 Commits
2025-08-01
...
system-loc
| Author | SHA1 | Date | |
|---|---|---|---|
|
c1d3be4c07
|
10
Cargo.lock
generated
10
Cargo.lock
generated
@@ -3517,6 +3517,7 @@ dependencies = [
|
||||
"sha2",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"sys-locale",
|
||||
"tempfile",
|
||||
"thiserror 2.0.12",
|
||||
"tokenator",
|
||||
@@ -5721,6 +5722,15 @@ dependencies = [
|
||||
"syn 2.0.104",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sys-locale"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.30.13"
|
||||
|
||||
@@ -69,6 +69,7 @@ tracing-appender = "0.2.3"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
tempfile = "3.13.0"
|
||||
unic-langid = { version = "0.9.6", features = ["macros"] }
|
||||
sys-locale = "0.3"
|
||||
url = "2.5.2"
|
||||
urlencoding = "2.1.3"
|
||||
uuid = { version = "1.10.0", features = ["v4"] }
|
||||
|
||||
@@ -241,9 +241,6 @@ Enter_your_public_key__npub___nostr_address__e_g___address____or_private_key__ns
|
||||
# Label for find user button
|
||||
Find_User_bd12 = Find User
|
||||
|
||||
# Label for font size, Appearance settings section
|
||||
Font_size_dd73 = Font size:
|
||||
|
||||
# Title for hashtags column
|
||||
Hashtags_f8e0 = Hashtags
|
||||
|
||||
@@ -355,9 +352,6 @@ Notifications_ef56 = Notifications
|
||||
# Relative time for very recent events (less than 3 seconds)
|
||||
now_2181 = now
|
||||
|
||||
# Setting to turn on sorting replies so that the newest are shown first
|
||||
On_f412 = On
|
||||
|
||||
# Button label to open email client
|
||||
Open_Email_25e9 = Open Email
|
||||
|
||||
@@ -436,9 +430,6 @@ Repost_this_note_8e56 = Repost this note
|
||||
# Label for reposted notes
|
||||
Reposted_61c8 = Reposted
|
||||
|
||||
# Label for reset note body font size, Appearance settings section
|
||||
Reset_4e60 = Reset
|
||||
|
||||
# Label for reset zoom level, Appearance settings section
|
||||
Reset_62d4 = Reset
|
||||
|
||||
@@ -478,6 +469,9 @@ Send_1ea4 = Send
|
||||
# Column title for app settings
|
||||
Settings_7a4f = Settings
|
||||
|
||||
# Label for Show source client, others settings section
|
||||
Show_source_client_9e31 = Show source client
|
||||
|
||||
# Description for last note per user column
|
||||
Show_the_last_note_for_each_user_from_a_list_50e7 = Show the last note for each user from a list
|
||||
|
||||
@@ -490,12 +484,6 @@ Someone_else_s_Notes_7e5f = Someone else's Notes
|
||||
# Title for someone else's notifications column
|
||||
Someone_else_s_Notifications_82e6 = Someone else's Notifications
|
||||
|
||||
# Label for Sort replies newest first, others settings section
|
||||
Sort_replies_newest_first_b6c3 = Sort replies newest first:
|
||||
|
||||
# Label for Source client, others settings section
|
||||
Source_client_fb2b = Source client:
|
||||
|
||||
# Description for contact list column
|
||||
Source_the_last_note_for_each_user_in_your_contact_list_e157 = Source the last note for each user in your contact list
|
||||
|
||||
@@ -532,9 +520,6 @@ Subscribe_to_someone_else_s_notes_d1e9 = Subscribe to someone else's notes
|
||||
# Column title for subscribing to individual user
|
||||
Subscribe_to_someone_s_notes_b3c8 = Subscribe to someone's notes
|
||||
|
||||
# Support email address
|
||||
Support_email_44d9 = Support email:
|
||||
|
||||
# Hover text for dark mode toggle button
|
||||
Switch_to_dark_mode_4dec = Switch to dark mode
|
||||
|
||||
@@ -575,7 +560,7 @@ username___at___domain___will_be_used_for_identification_a4fd = "{$username}" at
|
||||
Username_daa7 = Username
|
||||
|
||||
# Label for view folder button, Storage settings section
|
||||
View_folder_9742 = View folder
|
||||
View_folder_9742 = View folder:
|
||||
|
||||
# Column title for wallet management
|
||||
Wallet_5e50 = Wallet
|
||||
|
||||
@@ -241,9 +241,6 @@ Enter_your_public_key__npub___nostr_address__e_g___address____or_private_key__ns
|
||||
# Label for find user button
|
||||
Find_User_bd12 = {"["}Fíñd Úsér{"]"}
|
||||
|
||||
# Label for font size, Appearance settings section
|
||||
Font_size_dd73 = {"["}Fóñt sízé:{"]"}
|
||||
|
||||
# Title for hashtags column
|
||||
Hashtags_f8e0 = {"["}Hàshtàgs{"]"}
|
||||
|
||||
@@ -355,9 +352,6 @@ Notifications_ef56 = {"["}Ñótífíçàtíóñs{"]"}
|
||||
# Relative time for very recent events (less than 3 seconds)
|
||||
now_2181 = {"["}ñów{"]"}
|
||||
|
||||
# Setting to turn on sorting replies so that the newest are shown first
|
||||
On_f412 = {"["}Óñ{"]"}
|
||||
|
||||
# Button label to open email client
|
||||
Open_Email_25e9 = {"["}Ópéñ Émàíl{"]"}
|
||||
|
||||
@@ -436,9 +430,6 @@ Repost_this_note_8e56 = {"["}Répóst thís ñóté{"]"}
|
||||
# Label for reposted notes
|
||||
Reposted_61c8 = {"["}Répóstéd{"]"}
|
||||
|
||||
# Label for reset note body font size, Appearance settings section
|
||||
Reset_4e60 = {"["}Rését{"]"}
|
||||
|
||||
# Label for reset zoom level, Appearance settings section
|
||||
Reset_62d4 = {"["}Rését{"]"}
|
||||
|
||||
@@ -478,6 +469,9 @@ Send_1ea4 = {"["}Séñd{"]"}
|
||||
# Column title for app settings
|
||||
Settings_7a4f = {"["}Séttíñgs{"]"}
|
||||
|
||||
# Label for Show source client, others settings section
|
||||
Show_source_client_9e31 = {"["}Shów sóúrçé çlíéñt{"]"}
|
||||
|
||||
# Description for last note per user column
|
||||
Show_the_last_note_for_each_user_from_a_list_50e7 = {"["}Shów thé làst ñóté fór éàçh úsér fróm à líst{"]"}
|
||||
|
||||
@@ -490,12 +484,6 @@ Someone_else_s_Notes_7e5f = {"["}Sóméóñé élsé's Ñótés{"]"}
|
||||
# Title for someone else's notifications column
|
||||
Someone_else_s_Notifications_82e6 = {"["}Sóméóñé élsé's Ñótífíçàtíóñs{"]"}
|
||||
|
||||
# Label for Sort replies newest first, others settings section
|
||||
Sort_replies_newest_first_b6c3 = {"["}Sórt réplíés ñéwést fírst:{"]"}
|
||||
|
||||
# Label for Source client, others settings section
|
||||
Source_client_fb2b = {"["}Sóúrçé çlíéñt:{"]"}
|
||||
|
||||
# Description for contact list column
|
||||
Source_the_last_note_for_each_user_in_your_contact_list_e157 = {"["}Sóúrçé thé làst ñóté fór éàçh úsér íñ yóúr çóñtàçt líst{"]"}
|
||||
|
||||
@@ -532,9 +520,6 @@ Subscribe_to_someone_else_s_notes_d1e9 = {"["}Súbsçríbé tó sóméóñé él
|
||||
# Column title for subscribing to individual user
|
||||
Subscribe_to_someone_s_notes_b3c8 = {"["}Súbsçríbé tó sóméóñé's ñótés{"]"}
|
||||
|
||||
# Support email address
|
||||
Support_email_44d9 = {"["}Súppórt émàíl:{"]"}
|
||||
|
||||
# Hover text for dark mode toggle button
|
||||
Switch_to_dark_mode_4dec = {"["}Swítçh tó dàrk módé{"]"}
|
||||
|
||||
@@ -575,7 +560,7 @@ username___at___domain___will_be_used_for_identification_a4fd = {"["}"{$username
|
||||
Username_daa7 = {"["}Úsérñàmé{"]"}
|
||||
|
||||
# Label for view folder button, Storage settings section
|
||||
View_folder_9742 = {"["}Víéw fóldér{"]"}
|
||||
View_folder_9742 = {"["}Víéw fóldér:{"]"}
|
||||
|
||||
# Column title for wallet management
|
||||
Wallet_5e50 = {"["}Wàllét{"]"}
|
||||
|
||||
@@ -45,8 +45,6 @@ Algo_2452 = Algo
|
||||
Algorithmic_feeds_to_aid_in_note_discovery_d344 = Feeds algorítmicos para ayudar en el descubrimiento de notas
|
||||
# Label for zap amount input field
|
||||
Amount_70f0 = Cantidad
|
||||
# Label for appearance settings section
|
||||
Appearance_4c7f = Aspecto
|
||||
# Button to send message to Dave AI assistant
|
||||
Ask_b7f4 = Preguntar
|
||||
# Placeholder text for Dave AI input field
|
||||
@@ -55,26 +53,16 @@ Ask_dave_anything_33d1 = Pregúntale cualquier cosa a Dave...
|
||||
Banner_52ef = Banner
|
||||
# Beta version label
|
||||
BETA_8e5d = BETA
|
||||
# Option in settings section to show the source client label at the bottom of the note
|
||||
Bottom_33c8 = Parte inferior
|
||||
# Broadcast the note to all connected relays
|
||||
Broadcast_fe43 = Transmitir
|
||||
# Broadcast the note only to local network relays
|
||||
Broadcast_Local_7e50 = Transmitir localmente
|
||||
# Button label to cancel an action
|
||||
Cancel_ed3b = Cancelar
|
||||
# Label for cancel clear cache, Storage settings section
|
||||
Cancel_fd8b = Cancelar
|
||||
# Label for clear cache button, Storage settings section
|
||||
Clear_cache_dccb = Limpiar caché
|
||||
# Hover text for editable zap amount
|
||||
Click_to_edit_0414 = Haz clic para editar
|
||||
# Column title for note composition
|
||||
Compose_Note_c094 = Redactar nota
|
||||
# Label for configure relays, settings section
|
||||
Configure_relays_d156 = Configurar relés
|
||||
# Label for confirm clear cache, Storage settings section
|
||||
Confirm_9d9d = Confirmar
|
||||
# Button label to confirm an action
|
||||
Confirm_f8a6 = Confirmar
|
||||
# Status label for connected relay
|
||||
@@ -123,8 +111,6 @@ Custom_a69e = Personalizado
|
||||
Customize_Zap_Amount_cfc4 = Personalizar cantidad de zap
|
||||
# Column title for support page
|
||||
Damus_Support_27c0 = Ayuda de Damus
|
||||
# Label for Theme Dark, Appearance settings section
|
||||
Dark_85fe = Oscuro
|
||||
# Label for deck name input field
|
||||
Deck_name_cd32 = Nombre del deck
|
||||
# Label for decks section in side panel
|
||||
@@ -165,14 +151,10 @@ Enter_your_public_key__npub___nostr_address__e_g___address____or_private_key__ns
|
||||
Find_User_bd12 = Buscar usuario
|
||||
# Title for hashtags column
|
||||
Hashtags_f8e0 = Hashtags
|
||||
# Option in settings section to hide the source client label in note display
|
||||
Hide_281d = Ocultar
|
||||
# Title for Home column
|
||||
Home_8c19 = Inicio
|
||||
# Label for deck icon selection
|
||||
Icon_b0ab = Ícono
|
||||
# Label for Image cache size, Storage settings section
|
||||
Image_cache_size_3004 = Tamaño de caché de imágenes:
|
||||
# Title for individual user column
|
||||
Individual_b776 = Individual
|
||||
# Error message for invalid zap amount
|
||||
@@ -193,12 +175,8 @@ k_50K_c2dc = 50.000
|
||||
k_5K_f7e6 = 5.000
|
||||
# Description for your notes column
|
||||
Keep_track_of_your_notes___replies_a334 = Haz seguimiento de tus notas y respuestas
|
||||
# Label for language, Appearance settings section
|
||||
Language_e264 = Idioma:
|
||||
# Title for last note per user column
|
||||
Last_Note_per_User_17ad = Última nota por usuario
|
||||
# Label for Theme Light, Appearance settings section
|
||||
Light_7475 = Claro
|
||||
# Bitcoin Lightning network address field label
|
||||
Lightning_network_address__lud16_ea51 = Dirección de la red Lightning (lud16)
|
||||
# Login page title
|
||||
@@ -241,8 +219,6 @@ now_2181 = ahora
|
||||
Open_Email_25e9 = Abrir correo electrónico
|
||||
# Instruction to open email client
|
||||
Open_your_default_email_client_to_get_help_from_the_Damus_team_68dc = Abre tu cliente de correo predeterminado para recibir ayuda del equipo de Damus
|
||||
# Label for others settings section
|
||||
Others_7267 = Otros
|
||||
# Placeholder text for NWC URI input
|
||||
Paste_your_NWC_URI_here_b471 = Pega tu NWC URI aquí...
|
||||
# Error message for missing deck name
|
||||
@@ -289,8 +265,6 @@ replying_to_a_note_e0bc = respondiendo a una nota
|
||||
Repost_this_note_8e56 = Volver a publicar esta nota
|
||||
# Label for reposted notes
|
||||
Reposted_61c8 = Publicadas de nuevo
|
||||
# Label for reset zoom level, Appearance settings section
|
||||
Reset_62d4 = Restablecer
|
||||
# Heading for support section
|
||||
Running_into_a_bug_1796 = ¿Encontraste un error?
|
||||
# Label for satoshis (Bitcoin unit) for custom zap amount input field
|
||||
@@ -313,10 +287,6 @@ See_notes_from_your_contacts_ac16 = Ver notas de tus contactos
|
||||
See_the_whole_nostr_universe_7694 = Ver todo el universo de nostr
|
||||
# Button label to send a zap
|
||||
Send_1ea4 = Enviar
|
||||
# Column title for app settings
|
||||
Settings_7a4f = Configuración
|
||||
# Label for Show source client, others settings section
|
||||
Show_source_client_9e31 = Mostrar cliente de origen
|
||||
# Description for last note per user column
|
||||
Show_the_last_note_for_each_user_from_a_list_50e7 = Mostrar la última nota para cada usuario de una lista
|
||||
# Button label to sign out of account
|
||||
@@ -343,8 +313,6 @@ Stay_up_to_date_with_your_notifications_and_mentions_e73e = Mantente al día con
|
||||
Step_1_8656 = Paso 1
|
||||
# Step 2 label in support instructions
|
||||
Step_2_d08d = Paso 2
|
||||
# Label for storage settings section
|
||||
Storage_ed65 = Almacenamiento
|
||||
# Column title for subscribing to external user
|
||||
Subscribe_to_someone_else_s_notes_d1e9 = Suscribirse a las notas de otra persona
|
||||
# Column title for subscribing to individual user
|
||||
@@ -357,14 +325,10 @@ Switch_to_light_mode_72ce = Cambiar a modo claro
|
||||
Tap_to_Load_4b05 = Toca para cargar
|
||||
# Message shown when Dave trial period has ended
|
||||
The_Dave_Nostr_AI_assistant_trial_has_ended_____Thanks_for_testing__Zap-enabled_Dave_coming_soon_c6c7 = La prueba del asistente de IA Dave de Nostr finalizó :(. ¡Gracias por probarlo! ¡Dave con zaps estará disponible muy pronto!
|
||||
# Label for theme, Appearance settings section
|
||||
Theme_4aac = Tema:
|
||||
# Column title for note thread view
|
||||
Thread_0f20 = Conversación
|
||||
# Link text for thread references
|
||||
thread_ad1f = conversación
|
||||
# Option in settings section to show the source client label at the top of the note
|
||||
Top_6aeb = Parte superior
|
||||
# Title for universe column
|
||||
Universe_e01e = Universo
|
||||
# Column title for universe feed
|
||||
@@ -375,8 +339,6 @@ Use_this_wallet_for_the_current_account_only_61dc = Usar esta billetera solo par
|
||||
username___at___domain___will_be_used_for_identification_a4fd = Se utilizará "{ $username }" en "{ $domain }" para la identificación
|
||||
# Profile username field label
|
||||
Username_daa7 = Nombre de usuario
|
||||
# Label for view folder button, Storage settings section
|
||||
View_folder_9742 = Ver carpeta
|
||||
# Column title for wallet management
|
||||
Wallet_5e50 = Billetera
|
||||
# Hint for deck name input field
|
||||
@@ -395,8 +357,6 @@ Your_Notifications_080d = Tus notificaciones
|
||||
Zap_16b4 = Zap
|
||||
# Hover text for zap button
|
||||
Zap_this_note_42b2 = Enviar un zap a esta nota
|
||||
# Label for zoom level, Appearance settings section
|
||||
Zoom_Level_29a8 = Nivel de zoom:
|
||||
|
||||
# Pluralized strings
|
||||
|
||||
|
||||
@@ -45,8 +45,6 @@ Algo_2452 = Algo
|
||||
Algorithmic_feeds_to_aid_in_note_discovery_d344 = Feeds algorítmicos para ayudar en el descubrimiento de notas
|
||||
# Label for zap amount input field
|
||||
Amount_70f0 = Cantidad
|
||||
# Label for appearance settings section
|
||||
Appearance_4c7f = Aspecto
|
||||
# Button to send message to Dave AI assistant
|
||||
Ask_b7f4 = Preguntar
|
||||
# Placeholder text for Dave AI input field
|
||||
@@ -55,26 +53,16 @@ Ask_dave_anything_33d1 = Pregúntale cualquier cosa a Dave...
|
||||
Banner_52ef = Banner
|
||||
# Beta version label
|
||||
BETA_8e5d = BETA
|
||||
# Option in settings section to show the source client label at the bottom of the note
|
||||
Bottom_33c8 = Parte inferior
|
||||
# Broadcast the note to all connected relays
|
||||
Broadcast_fe43 = Transmitir
|
||||
# Broadcast the note only to local network relays
|
||||
Broadcast_Local_7e50 = Transmitir localmente
|
||||
# Button label to cancel an action
|
||||
Cancel_ed3b = Cancelar
|
||||
# Label for cancel clear cache, Storage settings section
|
||||
Cancel_fd8b = Cancelar
|
||||
# Label for clear cache button, Storage settings section
|
||||
Clear_cache_dccb = Limpiar caché
|
||||
# Hover text for editable zap amount
|
||||
Click_to_edit_0414 = Haz clic para editar
|
||||
# Column title for note composition
|
||||
Compose_Note_c094 = Redactar nota
|
||||
# Label for configure relays, settings section
|
||||
Configure_relays_d156 = Configurar relés
|
||||
# Label for confirm clear cache, Storage settings section
|
||||
Confirm_9d9d = Confirmar
|
||||
# Button label to confirm an action
|
||||
Confirm_f8a6 = Confirmar
|
||||
# Status label for connected relay
|
||||
@@ -123,8 +111,6 @@ Custom_a69e = Personalizado
|
||||
Customize_Zap_Amount_cfc4 = Personalizar cantidad de zap
|
||||
# Column title for support page
|
||||
Damus_Support_27c0 = Ayuda de Damus
|
||||
# Label for Theme Dark, Appearance settings section
|
||||
Dark_85fe = Oscuro
|
||||
# Label for deck name input field
|
||||
Deck_name_cd32 = Nombre del deck
|
||||
# Label for decks section in side panel
|
||||
@@ -165,14 +151,10 @@ Enter_your_public_key__npub___nostr_address__e_g___address____or_private_key__ns
|
||||
Find_User_bd12 = Buscar usuario
|
||||
# Title for hashtags column
|
||||
Hashtags_f8e0 = Hashtags
|
||||
# Option in settings section to hide the source client label in note display
|
||||
Hide_281d = Ocultar
|
||||
# Title for Home column
|
||||
Home_8c19 = Inicio
|
||||
# Label for deck icon selection
|
||||
Icon_b0ab = Icono
|
||||
# Label for Image cache size, Storage settings section
|
||||
Image_cache_size_3004 = Tamaño de caché de imágenes:
|
||||
# Title for individual user column
|
||||
Individual_b776 = Individual
|
||||
# Error message for invalid zap amount
|
||||
@@ -193,12 +175,8 @@ k_50K_c2dc = 50.000
|
||||
k_5K_f7e6 = 5.000
|
||||
# Description for your notes column
|
||||
Keep_track_of_your_notes___replies_a334 = Haz seguimiento de tus notas y respuestas
|
||||
# Label for language, Appearance settings section
|
||||
Language_e264 = Idioma:
|
||||
# Title for last note per user column
|
||||
Last_Note_per_User_17ad = Última nota por usuario
|
||||
# Label for Theme Light, Appearance settings section
|
||||
Light_7475 = Claro
|
||||
# Bitcoin Lightning network address field label
|
||||
Lightning_network_address__lud16_ea51 = Dirección de la red Lightning (lud16)
|
||||
# Login page title
|
||||
@@ -241,8 +219,6 @@ now_2181 = ahora
|
||||
Open_Email_25e9 = Abrir correo electrónico
|
||||
# Instruction to open email client
|
||||
Open_your_default_email_client_to_get_help_from_the_Damus_team_68dc = Abre tu cliente de correo predeterminado para recibir ayuda del equipo de Damus
|
||||
# Label for others settings section
|
||||
Others_7267 = Otros
|
||||
# Placeholder text for NWC URI input
|
||||
Paste_your_NWC_URI_here_b471 = Pega tu NWC URI aquí...
|
||||
# Error message for missing deck name
|
||||
@@ -289,8 +265,6 @@ replying_to_a_note_e0bc = respondiendo a una nota
|
||||
Repost_this_note_8e56 = Volver a publicar esta nota
|
||||
# Label for reposted notes
|
||||
Reposted_61c8 = Publicadas de nuevo
|
||||
# Label for reset zoom level, Appearance settings section
|
||||
Reset_62d4 = Restablecer
|
||||
# Heading for support section
|
||||
Running_into_a_bug_1796 = ¿Has encontrado un error?
|
||||
# Label for satoshis (Bitcoin unit) for custom zap amount input field
|
||||
@@ -313,10 +287,6 @@ See_notes_from_your_contacts_ac16 = Ver notas de tus contactos
|
||||
See_the_whole_nostr_universe_7694 = Ver todo el universo de nostr
|
||||
# Button label to send a zap
|
||||
Send_1ea4 = Enviar
|
||||
# Column title for app settings
|
||||
Settings_7a4f = Configuración
|
||||
# Label for Show source client, others settings section
|
||||
Show_source_client_9e31 = Mostrar cliente de origen
|
||||
# Description for last note per user column
|
||||
Show_the_last_note_for_each_user_from_a_list_50e7 = Mostrar la última nota para cada usuario de una lista
|
||||
# Button label to sign out of account
|
||||
@@ -343,8 +313,6 @@ Stay_up_to_date_with_your_notifications_and_mentions_e73e = Mantente al día con
|
||||
Step_1_8656 = Paso 1
|
||||
# Step 2 label in support instructions
|
||||
Step_2_d08d = Paso 2
|
||||
# Label for storage settings section
|
||||
Storage_ed65 = Almacenamiento
|
||||
# Column title for subscribing to external user
|
||||
Subscribe_to_someone_else_s_notes_d1e9 = Suscribirse a las notas de otra persona
|
||||
# Column title for subscribing to individual user
|
||||
@@ -357,14 +325,10 @@ Switch_to_light_mode_72ce = Cambiar a modo claro
|
||||
Tap_to_Load_4b05 = Toca para cargar
|
||||
# Message shown when Dave trial period has ended
|
||||
The_Dave_Nostr_AI_assistant_trial_has_ended_____Thanks_for_testing__Zap-enabled_Dave_coming_soon_c6c7 = La prueba del asistente de IA Dave de Nostr ha finalizado :(. ¡Gracias por probarlo! ¡Dave con zaps estará disponible muy pronto!
|
||||
# Label for theme, Appearance settings section
|
||||
Theme_4aac = Tema:
|
||||
# Column title for note thread view
|
||||
Thread_0f20 = Conversación
|
||||
# Link text for thread references
|
||||
thread_ad1f = conversación
|
||||
# Option in settings section to show the source client label at the top of the note
|
||||
Top_6aeb = Parte superior
|
||||
# Title for universe column
|
||||
Universe_e01e = Universo
|
||||
# Column title for universe feed
|
||||
@@ -375,8 +339,6 @@ Use_this_wallet_for_the_current_account_only_61dc = Usar este monedero solo para
|
||||
username___at___domain___will_be_used_for_identification_a4fd = Se utilizará "{ $username }" en "{ $domain }" para la identificación
|
||||
# Profile username field label
|
||||
Username_daa7 = Nombre de usuario
|
||||
# Label for view folder button, Storage settings section
|
||||
View_folder_9742 = Ver carpeta
|
||||
# Column title for wallet management
|
||||
Wallet_5e50 = Monedero
|
||||
# Hint for deck name input field
|
||||
@@ -395,8 +357,6 @@ Your_Notifications_080d = Tus notificaciones
|
||||
Zap_16b4 = Zap
|
||||
# Hover text for zap button
|
||||
Zap_this_note_42b2 = Enviar un zap a esta nota
|
||||
# Label for zoom level, Appearance settings section
|
||||
Zoom_Level_29a8 = Nivel de zoom:
|
||||
|
||||
# Pluralized strings
|
||||
|
||||
|
||||
@@ -376,7 +376,7 @@ username___at___domain___will_be_used_for_identification_a4fd = "{ $username }"
|
||||
# Profile username field label
|
||||
Username_daa7 = Nom d'utilisateur
|
||||
# Label for view folder button, Storage settings section
|
||||
View_folder_9742 = Voir le dossier
|
||||
View_folder_9742 = Voir le dossier :
|
||||
# Column title for wallet management
|
||||
Wallet_5e50 = Portefeuille
|
||||
# Hint for deck name input field
|
||||
|
||||
@@ -376,7 +376,7 @@ username___at___domain___will_be_used_for_identification_a4fd = d = "{ $username
|
||||
# Profile username field label
|
||||
Username_daa7 = Usuário
|
||||
# Label for view folder button, Storage settings section
|
||||
View_folder_9742 = Visualizar pasta
|
||||
View_folder_9742 = Visualizar pasta:
|
||||
# Column title for wallet management
|
||||
Wallet_5e50 = Carteira
|
||||
# Hint for deck name input field
|
||||
|
||||
@@ -378,7 +378,7 @@ username___at___domain___will_be_used_for_identification_a4fd = "{ $username }"
|
||||
# Profile username field label
|
||||
Username_daa7 = ชื่อผู้ใช้
|
||||
# Label for view folder button, Storage settings section
|
||||
View_folder_9742 = ดูโฟลเดอร์
|
||||
View_folder_9742 = ดูโฟลเดอร์:
|
||||
# Column title for wallet management
|
||||
Wallet_5e50 = วอลเล็ต
|
||||
# Hint for deck name input field
|
||||
|
||||
@@ -376,7 +376,7 @@ username___at___domain___will_be_used_for_identification_a4fd = "{ $username }"
|
||||
# Profile username field label
|
||||
Username_daa7 = 用户名
|
||||
# Label for view folder button, Storage settings section
|
||||
View_folder_9742 = 查看文件夹
|
||||
View_folder_9742 = 查看文件夹:
|
||||
# Column title for wallet management
|
||||
Wallet_5e50 = 钱包
|
||||
# Hint for deck name input field
|
||||
|
||||
@@ -376,7 +376,7 @@ username___at___domain___will_be_used_for_identification_a4fd = "{ $username }"
|
||||
# Profile username field label
|
||||
Username_daa7 = 用戶名
|
||||
# Label for view folder button, Storage settings section
|
||||
View_folder_9742 = 查看文件夾
|
||||
View_folder_9742 = 查看文件夾:
|
||||
# Column title for wallet management
|
||||
Wallet_5e50 = 錢包
|
||||
# Hint for deck name input field
|
||||
|
||||
@@ -45,6 +45,7 @@ fluent = { workspace = true }
|
||||
fluent-resmgr = { workspace = true }
|
||||
fluent-langneg = { workspace = true }
|
||||
unic-langid = { workspace = true }
|
||||
sys-locale = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
md5 = { workspace = true }
|
||||
bitflags = { workspace = true }
|
||||
|
||||
@@ -3,6 +3,7 @@ use fluent::{FluentArgs, FluentBundle, FluentResource};
|
||||
use fluent_langneg::negotiate_languages;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use sys_locale;
|
||||
use unic_langid::{langid, LanguageIdentifier};
|
||||
|
||||
const EN_US: LanguageIdentifier = langid!("en-US");
|
||||
@@ -101,10 +102,6 @@ pub struct Localization {
|
||||
|
||||
impl Default for Localization {
|
||||
fn default() -> Self {
|
||||
// Default to English (US)
|
||||
let default_locale = &EN_US;
|
||||
let fallback_locale = default_locale.to_owned();
|
||||
|
||||
// Build available locales list
|
||||
let available_locales = vec![
|
||||
EN_US.clone(),
|
||||
@@ -132,8 +129,20 @@ impl Default for Localization {
|
||||
(ZH_TW, ZH_TW_NATIVE_NAME.to_owned()),
|
||||
]);
|
||||
|
||||
// Detect system locale and find best match
|
||||
let current_locale = Self::negotiate_system_locale_with_preferences(&available_locales);
|
||||
|
||||
// Fallback locale is always EN_US
|
||||
let fallback_locale = EN_US.clone();
|
||||
|
||||
tracing::info!(
|
||||
"Localization initialized - Selected locale: {}, Fallback: {}",
|
||||
current_locale,
|
||||
fallback_locale
|
||||
);
|
||||
|
||||
Self {
|
||||
current_locale: default_locale.to_owned(),
|
||||
current_locale,
|
||||
available_locales,
|
||||
fallback_locale,
|
||||
locale_native_names,
|
||||
@@ -159,6 +168,150 @@ impl Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract just the language and region from locale string (e.g., "fr-FR-u-mu-celsius" -> "fr-FR")
|
||||
fn extract_language_region(locale_str: &str) -> String {
|
||||
// Split by '-' and analyze the parts
|
||||
let parts: Vec<&str> = locale_str.split('-').collect();
|
||||
|
||||
if parts.len() >= 2 {
|
||||
// Check if the second part looks like a region
|
||||
let second_part = parts[1];
|
||||
if (second_part.len() >= 2) {
|
||||
format!("{}-{}", parts[0], parts[1])
|
||||
} else {
|
||||
// Second part is not a region, probably an extension (e.g., "u", "t", "x")
|
||||
// Just return the language part
|
||||
parts[0].to_string()
|
||||
}
|
||||
} else {
|
||||
// Only one part, return as is
|
||||
locale_str.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// Negotiate the best locale from all system preferences against available locales
|
||||
fn negotiate_system_locale_with_preferences(
|
||||
available_locales: &[LanguageIdentifier],
|
||||
) -> LanguageIdentifier {
|
||||
// Get all system preferred locales in descending order
|
||||
let mut system_locales: Vec<String> = sys_locale::get_locales().collect();
|
||||
if system_locales.is_empty() {
|
||||
tracing::info!("No system locales detected, using fallback: en-US");
|
||||
return EN_US.clone();
|
||||
}
|
||||
|
||||
tracing::info!("System preferred locales: {:?}", system_locales);
|
||||
|
||||
// If we only got one locale, it might be that the system only returns the primary locale
|
||||
// In this case, we can try to add common fallbacks based on the detected locale
|
||||
if system_locales.len() == 1 {
|
||||
let primary = &system_locales[0];
|
||||
|
||||
// Try to parse the primary locale, handling extensions
|
||||
let primary_lang = if let Ok(locale) = primary.parse::<LanguageIdentifier>() {
|
||||
locale.language.as_str().to_string()
|
||||
} else {
|
||||
// If parsing fails, try extracting language-region
|
||||
// let stripped = Self::extract_language_region(primary);
|
||||
// if let Ok(locale) = stripped.parse::<LanguageIdentifier>() {
|
||||
// locale.language.as_str().to_string()
|
||||
// } else {
|
||||
tracing::info!("Could not parse primary locale: {}", primary);
|
||||
"unknown".to_string()
|
||||
// }
|
||||
};
|
||||
|
||||
tracing::info!(
|
||||
"Only one system locale detected: {} (language: {})",
|
||||
primary,
|
||||
primary_lang
|
||||
);
|
||||
|
||||
// Add common fallbacks for the detected language
|
||||
match primary_lang.as_str() {
|
||||
"uk" => {
|
||||
// For Ukrainian, add common fallbacks
|
||||
system_locales.push("es-ES".to_string());
|
||||
system_locales.push("en-US".to_string());
|
||||
tracing::info!("Added fallbacks for Ukrainian: {:?}", system_locales);
|
||||
}
|
||||
"es" => {
|
||||
// For Spanish, add English fallback
|
||||
system_locales.push("en-US".to_string());
|
||||
tracing::info!("Added fallback for Spanish: {:?}", system_locales);
|
||||
}
|
||||
_ => {
|
||||
// For other languages, add English fallback
|
||||
system_locales.push("en-US".to_string());
|
||||
tracing::info!("Added fallback for {}: {:?}", primary_lang, system_locales);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert system locale strings to LanguageIdentifiers, handling extensions
|
||||
let mut parsed_system_locales = Vec::new();
|
||||
for locale_str in system_locales {
|
||||
// Try to parse the locale string directly first
|
||||
if let Ok(locale) = locale_str.parse::<LanguageIdentifier>() {
|
||||
parsed_system_locales.push(locale);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If parsing fails, try extracting just language-region
|
||||
// let stripped_locale = Self::extract_language_region(&locale_str);
|
||||
// if let Ok(locale) = stripped_locale.parse::<LanguageIdentifier>() {
|
||||
// parsed_system_locales.push(locale);
|
||||
// continue;
|
||||
// }
|
||||
|
||||
tracing::info!("Failed to parse locale string: {}", locale_str);
|
||||
}
|
||||
|
||||
if parsed_system_locales.is_empty() {
|
||||
tracing::info!("No valid system locales parsed, using fallback: en-US");
|
||||
return EN_US.clone();
|
||||
}
|
||||
|
||||
// First try exact matches with fluent_langneg
|
||||
let fallback = &EN_US;
|
||||
let negotiated = negotiate_languages(
|
||||
&parsed_system_locales,
|
||||
available_locales,
|
||||
Some(fallback),
|
||||
fluent_langneg::NegotiationStrategy::Filtering,
|
||||
);
|
||||
|
||||
if let Some(result) = negotiated.first() {
|
||||
tracing::info!(
|
||||
"Exact match found: {} from preferences: {:?}",
|
||||
result,
|
||||
parsed_system_locales
|
||||
);
|
||||
return (*result).clone();
|
||||
}
|
||||
|
||||
// If no exact match, try language-only fallbacks
|
||||
tracing::info!("No exact matches found, trying language-only fallbacks");
|
||||
for system_locale in &parsed_system_locales {
|
||||
let system_lang = system_locale.language.as_str();
|
||||
|
||||
// Look for any available locale with the same language
|
||||
for available_locale in available_locales {
|
||||
if available_locale.language.as_str() == system_lang {
|
||||
tracing::debug!(
|
||||
"Language match found: {} (system: {})",
|
||||
available_locale,
|
||||
system_locale
|
||||
);
|
||||
return available_locale.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tracing::info!("No language matches found, using fallback: en-US");
|
||||
EN_US.clone()
|
||||
}
|
||||
|
||||
/// Gets a localized string by its ID
|
||||
pub fn get_string(&mut self, id: IntlKey<'_>) -> Result<String, IntlError> {
|
||||
self.get_cached_string(id, None)
|
||||
@@ -458,20 +611,6 @@ impl Localization {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Negotiates the best locale from a list of preferred locales
|
||||
pub fn negotiate_locale(&self, preferred: &[LanguageIdentifier]) -> LanguageIdentifier {
|
||||
let available = self.available_locales.clone();
|
||||
let negotiated = negotiate_languages(
|
||||
preferred,
|
||||
&available,
|
||||
Some(&self.fallback_locale),
|
||||
fluent_langneg::NegotiationStrategy::Filtering,
|
||||
);
|
||||
negotiated
|
||||
.first()
|
||||
.map_or(self.fallback_locale.clone(), |v| (*v).clone())
|
||||
}
|
||||
}
|
||||
|
||||
/// Statistics about cache usage
|
||||
@@ -484,6 +623,80 @@ pub struct CacheStats {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_extract_language_region() {
|
||||
// Test that we extract just language and region from various locale formats
|
||||
|
||||
// Test locales with extensions
|
||||
let unicode_locale = "fr-FR-u-mu-celsius";
|
||||
let extracted = Localization::extract_language_region(unicode_locale);
|
||||
assert_eq!(extracted, "fr-FR");
|
||||
|
||||
let transformed_locale = "en-US-t-0-abc123";
|
||||
let extracted = Localization::extract_language_region(transformed_locale);
|
||||
assert_eq!(extracted, "en-US");
|
||||
|
||||
let private_locale = "de-DE-x-phonebk";
|
||||
let extracted = Localization::extract_language_region(private_locale);
|
||||
assert_eq!(extracted, "de-DE");
|
||||
|
||||
// Test simple locale (no extensions)
|
||||
let simple_locale = "en-US";
|
||||
let extracted = Localization::extract_language_region(simple_locale);
|
||||
assert_eq!(extracted, "en-US");
|
||||
|
||||
// Test language-only locale
|
||||
let lang_only = "en";
|
||||
let extracted = Localization::extract_language_region(lang_only);
|
||||
assert_eq!(extracted, "en");
|
||||
|
||||
// Test language with extensions (no region)
|
||||
let lang_with_extensions = "fr-u-mu-celsius";
|
||||
let extracted = Localization::extract_language_region(lang_with_extensions);
|
||||
assert_eq!(extracted, "fr");
|
||||
|
||||
// Test language with other extension types (no region)
|
||||
let lang_with_t_ext = "en-t-0-abc123";
|
||||
let extracted = Localization::extract_language_region(lang_with_t_ext);
|
||||
assert_eq!(extracted, "en");
|
||||
|
||||
let lang_with_x_ext = "de-x-phonebk";
|
||||
let extracted = Localization::extract_language_region(lang_with_x_ext);
|
||||
assert_eq!(extracted, "de");
|
||||
|
||||
// Test locale with numeric region code
|
||||
let numeric_region = "es-419-u-mu-celsius";
|
||||
let extracted = Localization::extract_language_region(numeric_region);
|
||||
assert_eq!(extracted, "es-419");
|
||||
|
||||
// Test locale with 3-letter region code
|
||||
let three_letter_region = "en-USA-t-0-abc123";
|
||||
let extracted = Localization::extract_language_region(three_letter_region);
|
||||
assert_eq!(extracted, "en-USA");
|
||||
|
||||
// Test locale with 2-letter region code
|
||||
let two_letter_region = "fr-FR-u-mu-celsius";
|
||||
let extracted = Localization::extract_language_region(two_letter_region);
|
||||
assert_eq!(extracted, "fr-FR");
|
||||
|
||||
// Test complex locale with multiple parts
|
||||
let complex_locale = "zh-CN-u-ca-chinese-x-private";
|
||||
let extracted = Localization::extract_language_region(complex_locale);
|
||||
assert_eq!(extracted, "zh-CN");
|
||||
|
||||
// Verify that extracted locales can be parsed
|
||||
let test_cases = ["fr-FR", "en-US", "de-DE", "en", "zh-CN"];
|
||||
for extracted in test_cases {
|
||||
if let Ok(locale) = extracted.parse::<LanguageIdentifier>() {
|
||||
tracing::info!("Successfully parsed extracted locale: {}", locale);
|
||||
} else {
|
||||
tracing::error!("Failed to parse extracted locale: {}", extracted);
|
||||
panic!("Should parse locale after extraction");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// TODO(jb55): write tests that work, i broke all these during the refacto
|
||||
|
||||
@@ -16,6 +16,9 @@ use crate::{nav::RouterAction, Damus, Route};
|
||||
|
||||
const PREVIEW_NOTE_ID: &str = "note1edjc8ggj07hwv77g2405uh6j2jkk5aud22gktxrvc2wnre4vdwgqzlv2gw";
|
||||
|
||||
const THEME_LIGHT: &str = "Light";
|
||||
const THEME_DARK: &str = "Dark";
|
||||
|
||||
const MIN_ZOOM: f32 = 0.5;
|
||||
const MAX_ZOOM: f32 = 3.0;
|
||||
const ZOOM_STEP: f32 = 0.1;
|
||||
@@ -386,7 +389,7 @@ impl<'a> SettingsView<'a> {
|
||||
ThemePreference::Light,
|
||||
richtext_small(tr!(
|
||||
self.note_context.i18n,
|
||||
"Light",
|
||||
THEME_LIGHT,
|
||||
"Label for Theme Light, Appearance settings section",
|
||||
)),
|
||||
)
|
||||
@@ -401,7 +404,7 @@ impl<'a> SettingsView<'a> {
|
||||
ThemePreference::Dark,
|
||||
richtext_small(tr!(
|
||||
self.note_context.i18n,
|
||||
"Dark",
|
||||
THEME_DARK,
|
||||
"Label for Theme Dark, Appearance settings section",
|
||||
)),
|
||||
)
|
||||
@@ -529,19 +532,15 @@ impl<'a> SettingsView<'a> {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label(richtext_small(tr!(
|
||||
self.note_context.i18n,
|
||||
"Sort replies newest first:",
|
||||
"Sort replies newest first",
|
||||
"Label for Sort replies newest first, others settings section",
|
||||
)));
|
||||
|
||||
if ui
|
||||
.toggle_value(
|
||||
&mut self.settings.show_replies_newest_first,
|
||||
RichText::new(tr!(
|
||||
self.note_context.i18n,
|
||||
"On",
|
||||
"Setting to turn on sorting replies so that the newest are shown first"
|
||||
))
|
||||
.text_style(NotedeckTextStyle::Small.text_style()),
|
||||
RichText::new(tr!(self.note_context.i18n, "ON", "ON"))
|
||||
.text_style(NotedeckTextStyle::Small.text_style()),
|
||||
)
|
||||
.changed()
|
||||
{
|
||||
@@ -554,7 +553,7 @@ impl<'a> SettingsView<'a> {
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
ui.label(richtext_small(tr!(
|
||||
self.note_context.i18n,
|
||||
"Source client:",
|
||||
"Source client",
|
||||
"Label for Source client, others settings section",
|
||||
)));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user