mirror of
https://github.com/spalencsar/bearhub.git
synced 2026-07-08 22:24:14 +02:00
[wgem] custom icon selector
This commit is contained in:
@@ -123,3 +123,12 @@ class FormComponent(ViewComponent):
|
|||||||
super(FormComponent, self).__init__(id_=id_)
|
super(FormComponent, self).__init__(id_=id_)
|
||||||
self.label = label
|
self.label = label
|
||||||
self.components = components
|
self.components = components
|
||||||
|
|
||||||
|
|
||||||
|
class FileChooserComponent(ViewComponent):
|
||||||
|
|
||||||
|
def __init__(self, allowed_extensions: Set[str] = None, label: str = None, id_: str = None):
|
||||||
|
super(FileChooserComponent, self).__init__(id_=id_)
|
||||||
|
self.label = label
|
||||||
|
self.allowed_extensions = allowed_extensions
|
||||||
|
self.file_path = None
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ from bauh.api.abstract.disk import DiskCacheLoader
|
|||||||
from bauh.api.abstract.handler import ProcessWatcher
|
from bauh.api.abstract.handler import ProcessWatcher
|
||||||
from bauh.api.abstract.model import SoftwarePackage, PackageAction, PackageSuggestion, PackageUpdate, PackageHistory
|
from bauh.api.abstract.model import SoftwarePackage, PackageAction, PackageSuggestion, PackageUpdate, PackageHistory
|
||||||
from bauh.api.abstract.view import MessageType, MultipleSelectComponent, InputOption, SingleSelectComponent, \
|
from bauh.api.abstract.view import MessageType, MultipleSelectComponent, InputOption, SingleSelectComponent, \
|
||||||
SelectViewType, TextInputComponent, FormComponent
|
SelectViewType, TextInputComponent, FormComponent, FileChooserComponent
|
||||||
from bauh.api.constants import DESKTOP_ENTRIES_DIR
|
from bauh.api.constants import DESKTOP_ENTRIES_DIR
|
||||||
from bauh.commons.html import bold
|
from bauh.commons.html import bold
|
||||||
from bauh.commons.system import ProcessHandler, get_dir_size, get_human_size_str
|
from bauh.commons.system import ProcessHandler, get_dir_size, get_human_size_str
|
||||||
@@ -100,6 +100,9 @@ class WebApplicationManager(SoftwareManager):
|
|||||||
def _strip_url_protocol(self, url: str) -> str:
|
def _strip_url_protocol(self, url: str) -> str:
|
||||||
return RE_PROTOCOL_STRIP.split(url)[1].strip().lower()
|
return RE_PROTOCOL_STRIP.split(url)[1].strip().lower()
|
||||||
|
|
||||||
|
def serialize_to_disk(self, pkg: SoftwarePackage, icon_bytes: bytes, only_icon: bool):
|
||||||
|
super(WebApplicationManager, self).serialize_to_disk(pkg=pkg, icon_bytes=None, only_icon=False)
|
||||||
|
|
||||||
def search(self, words: str, disk_loader: DiskCacheLoader, limit: int = -1, is_url: bool = False) -> SearchResult:
|
def search(self, words: str, disk_loader: DiskCacheLoader, limit: int = -1, is_url: bool = False) -> SearchResult:
|
||||||
res = SearchResult([], [], 0)
|
res = SearchResult([], [], 0)
|
||||||
|
|
||||||
@@ -243,7 +246,9 @@ class WebApplicationManager(SoftwareManager):
|
|||||||
options=[tray_op_off, tray_op_default, tray_op_min],
|
options=[tray_op_off, tray_op_default, tray_op_min],
|
||||||
label=self.i18n['web.install.option.tray.label'])
|
label=self.i18n['web.install.option.tray.label'])
|
||||||
|
|
||||||
form_1 = FormComponent(components=[inp_url, inp_name, inp_desc, inp_cat, inp_tray], label="Basic")
|
icon_chooser = FileChooserComponent(allowed_extensions={'png'}, label=self.i18n['web.install.option.icon.label'])
|
||||||
|
|
||||||
|
form_1 = FormComponent(components=[inp_url, inp_name, inp_desc, inp_cat, icon_chooser, inp_tray], label=self.i18n['web.install.options.basic'].capitalize())
|
||||||
|
|
||||||
op_single = InputOption(id_='single', label=self.i18n['web.install.option.single.label'], value="--single-instance", tooltip=self.i18n['web.install.option.single.tip'])
|
op_single = InputOption(id_='single', label=self.i18n['web.install.option.single.label'], value="--single-instance", tooltip=self.i18n['web.install.option.single.tip'])
|
||||||
op_max = InputOption(id_='max', label=self.i18n['web.install.option.max.label'], value="--maximize", tooltip=self.i18n['web.install.option.max.tip'])
|
op_max = InputOption(id_='max', label=self.i18n['web.install.option.max.label'], value="--maximize", tooltip=self.i18n['web.install.option.max.tip'])
|
||||||
@@ -254,7 +259,7 @@ class WebApplicationManager(SoftwareManager):
|
|||||||
op_insecure = InputOption(id_='insecure', label=self.i18n['web.install.option.insecure.label'], value="--insecure", tooltip=self.i18n['web.install.option.insecure.tip'])
|
op_insecure = InputOption(id_='insecure', label=self.i18n['web.install.option.insecure.label'], value="--insecure", tooltip=self.i18n['web.install.option.insecure.tip'])
|
||||||
op_igcert = InputOption(id_='ignore_certs', label=self.i18n['web.install.option.ignore_certificate.label'], value="--ignore-certificate", tooltip=self.i18n['web.install.option.ignore_certificate.tip'])
|
op_igcert = InputOption(id_='ignore_certs', label=self.i18n['web.install.option.ignore_certificate.label'], value="--ignore-certificate", tooltip=self.i18n['web.install.option.ignore_certificate.tip'])
|
||||||
|
|
||||||
check_options = MultipleSelectComponent(options=[op_single, op_allow_urls, op_max, op_fs, op_nframe, op_ncache, op_insecure, op_igcert], default_options={op_single}, label='Advanced')
|
check_options = MultipleSelectComponent(options=[op_single, op_allow_urls, op_max, op_fs, op_nframe, op_ncache, op_insecure, op_igcert], default_options={op_single}, label=self.i18n['web.install.options.advanced'].capitalize())
|
||||||
|
|
||||||
res = watcher.request_confirmation(title=self.i18n['web.install.options_dialog.title'],
|
res = watcher.request_confirmation(title=self.i18n['web.install.options_dialog.title'],
|
||||||
body=None,
|
body=None,
|
||||||
@@ -287,6 +292,10 @@ class WebApplicationManager(SoftwareManager):
|
|||||||
if cat != 0:
|
if cat != 0:
|
||||||
app.categories = [cat]
|
app.categories = [cat]
|
||||||
|
|
||||||
|
if icon_chooser.file_path:
|
||||||
|
app.set_custom_icon(icon_chooser.file_path)
|
||||||
|
selected.append('--icon={}'.format(icon_chooser.file_path))
|
||||||
|
|
||||||
return res, selected
|
return res, selected
|
||||||
|
|
||||||
return False, []
|
return False, []
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import re
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
@@ -11,13 +10,14 @@ class WebApplication(SoftwarePackage):
|
|||||||
|
|
||||||
def __init__(self, id: str = None, url: str = None, name: str = None, description: str = None, icon_url: str = None,
|
def __init__(self, id: str = None, url: str = None, name: str = None, description: str = None, icon_url: str = None,
|
||||||
installation_dir: str = None, desktop_entry: str = None, installed: bool = False, version: str = None,
|
installation_dir: str = None, desktop_entry: str = None, installed: bool = False, version: str = None,
|
||||||
categories: List[str] = None):
|
categories: List[str] = None, custom_icon: str = None):
|
||||||
super(WebApplication, self).__init__(id=id if id else url, name=name, description=description,
|
super(WebApplication, self).__init__(id=id if id else url, name=name, description=description,
|
||||||
icon_url=icon_url, installed=installed, version=version,
|
icon_url=icon_url, installed=installed, version=version,
|
||||||
categories=categories)
|
categories=categories)
|
||||||
self.url = url
|
self.url = url
|
||||||
self.installation_dir = installation_dir
|
self.installation_dir = installation_dir
|
||||||
self.desktop_entry = desktop_entry
|
self.desktop_entry = desktop_entry
|
||||||
|
self.set_custom_icon(custom_icon)
|
||||||
|
|
||||||
def has_history(self):
|
def has_history(self):
|
||||||
return False
|
return False
|
||||||
@@ -27,7 +27,7 @@ class WebApplication(SoftwarePackage):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_cached_attrs() -> tuple:
|
def _get_cached_attrs() -> tuple:
|
||||||
return 'id', 'name', 'version', 'url', 'description', 'icon_url', 'installation_dir', 'desktop_entry', 'categories'
|
return 'id', 'name', 'version', 'url', 'description', 'icon_url', 'installation_dir', 'desktop_entry', 'categories', 'custom_icon'
|
||||||
|
|
||||||
def can_be_downgraded(self):
|
def can_be_downgraded(self):
|
||||||
return False
|
return False
|
||||||
@@ -45,9 +45,15 @@ class WebApplication(SoftwarePackage):
|
|||||||
def get_default_icon_path(self) -> str:
|
def get_default_icon_path(self) -> str:
|
||||||
return resource.get_path('img/web.png', ROOT_DIR)
|
return resource.get_path('img/web.png', ROOT_DIR)
|
||||||
|
|
||||||
def get_disk_data_path(self):
|
def get_disk_data_path(self) -> str:
|
||||||
return '{}/data.yml'.format(self.get_disk_cache_path())
|
return '{}/data.yml'.format(self.get_disk_cache_path())
|
||||||
|
|
||||||
|
def get_disk_icon_path(self) -> str:
|
||||||
|
if self.custom_icon:
|
||||||
|
return self.custom_icon
|
||||||
|
else:
|
||||||
|
super(WebApplication, self).get_disk_icon_path()
|
||||||
|
|
||||||
def is_application(self):
|
def is_application(self):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -76,6 +82,8 @@ class WebApplication(SoftwarePackage):
|
|||||||
if val and hasattr(self, attr):
|
if val and hasattr(self, attr):
|
||||||
setattr(self, attr, val)
|
setattr(self, attr, val)
|
||||||
|
|
||||||
|
self.set_custom_icon(self.custom_icon)
|
||||||
|
|
||||||
def can_be_run(self) -> bool:
|
def can_be_run(self) -> bool:
|
||||||
return self.installed and self.installation_dir
|
return self.installed and self.installation_dir
|
||||||
|
|
||||||
@@ -91,3 +99,10 @@ class WebApplication(SoftwarePackage):
|
|||||||
def get_autostart_path(self) -> str:
|
def get_autostart_path(self) -> str:
|
||||||
if self.desktop_entry:
|
if self.desktop_entry:
|
||||||
return '{}/.config/autostart/{}'.format(Path.home(), self.desktop_entry.split('/')[-1])
|
return '{}/.config/autostart/{}'.format(Path.home(), self.desktop_entry.split('/')[-1])
|
||||||
|
|
||||||
|
def set_custom_icon(self, custom_icon: str):
|
||||||
|
self.custom_icon = custom_icon
|
||||||
|
|
||||||
|
if custom_icon:
|
||||||
|
self.icon_url = custom_icon
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ web.environment.install=Installing {}
|
|||||||
web.waiting.env_updater=Updating environment
|
web.waiting.env_updater=Updating environment
|
||||||
web.env.checking=Checking the Web installation environment
|
web.env.checking=Checking the Web installation environment
|
||||||
web.env.error=It seems there are issues with the Web installation environment. It wil not be possible to install {}.
|
web.env.error=It seems there are issues with the Web installation environment. It wil not be possible to install {}.
|
||||||
|
web.install.options.basic=basic
|
||||||
|
web.install.options.advanced=advanced
|
||||||
web.install.options_dialog.title=Installation options
|
web.install.options_dialog.title=Installation options
|
||||||
web.install.error=An error has happened during the {} installation
|
web.install.error=An error has happened during the {} installation
|
||||||
web.install.nativefier.error.unknown=Have a look at the {} to identify the reason
|
web.install.nativefier.error.unknown=Have a look at the {} to identify the reason
|
||||||
@@ -35,6 +37,7 @@ web.install.option.tray.default.tip=The app icon will be attached to the system
|
|||||||
web.install.option.tray.min.label=Start minimized
|
web.install.option.tray.min.label=Start minimized
|
||||||
web.install.option.tray.min.tip=The app will be started minimized as an icon in the system tray
|
web.install.option.tray.min.tip=The app will be started minimized as an icon in the system tray
|
||||||
web.install.option.category.none=none
|
web.install.option.category.none=none
|
||||||
|
web.install.option.icon.label=Custom icon
|
||||||
web.uninstall.error.install_dir.not_found=The installation directory {} was not found
|
web.uninstall.error.install_dir.not_found=The installation directory {} was not found
|
||||||
web.uninstall.error.remove_dir=It was not possible to remove {}
|
web.uninstall.error.remove_dir=It was not possible to remove {}
|
||||||
web.info.1_url=URL
|
web.info.1_url=URL
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ web.environment.nativefier=Instalando {}
|
|||||||
web.waiting.env_updater=Atualizando ambiente
|
web.waiting.env_updater=Atualizando ambiente
|
||||||
web.env.checking=Verificando o ambiente de instalação Web
|
web.env.checking=Verificando o ambiente de instalação Web
|
||||||
web.env.error=Parce que existem problemas com o ambiente de instalação Web. Não será possível instalar {}.
|
web.env.error=Parce que existem problemas com o ambiente de instalação Web. Não será possível instalar {}.
|
||||||
|
web.install.options.basic=básicas
|
||||||
|
web.install.options.advanced=avançadas
|
||||||
web.install.options_dialog.title=Opções de instalação
|
web.install.options_dialog.title=Opções de instalação
|
||||||
wen.install.error=Ocorreu um erro durante a instalação de {}
|
wen.install.error=Ocorreu um erro durante a instalação de {}
|
||||||
web.install.nativefier.error.unknown=Dê uma olhada em {} para identificar o motivo
|
web.install.nativefier.error.unknown=Dê uma olhada em {} para identificar o motivo
|
||||||
@@ -35,6 +37,7 @@ web.install.option.tray.default.tip=O ícone do aplicativo será anexado a bande
|
|||||||
web.install.option.tray.min.label=Iniciar minimizado
|
web.install.option.tray.min.label=Iniciar minimizado
|
||||||
web.install.option.tray.min.tip=O aplicativo será iniciado minimizado como um ícone da bandeja do sistema
|
web.install.option.tray.min.tip=O aplicativo será iniciado minimizado como um ícone da bandeja do sistema
|
||||||
web.install.option.category.none=nenhuma
|
web.install.option.category.none=nenhuma
|
||||||
|
web.install.option.icon.label=Ícone alternativo
|
||||||
web.uninstall.error.install_dir.not_found=O diretório de instalação {} não foi encontrado
|
web.uninstall.error.install_dir.not_found=O diretório de instalação {} não foi encontrado
|
||||||
web.uninstall.error.remove=Não foi possível remover {}
|
web.uninstall.error.remove=Não foi possível remover {}
|
||||||
web.info.1_url=URL
|
web.info.1_url=URL
|
||||||
@@ -45,4 +48,4 @@ web.info.5_installation_dir=diretório de instalação
|
|||||||
web.info.6_desktop_entry=atalho
|
web.info.6_desktop_entry=atalho
|
||||||
web.info.7_exec_file=executável
|
web.info.7_exec_file=executável
|
||||||
web.info.8_icon_path=ícone
|
web.info.8_icon_path=ícone
|
||||||
web.info.9_size=tamanho
|
web.info.9_size=tamanho
|
||||||
@@ -1,14 +1,16 @@
|
|||||||
|
from pathlib import Path
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
|
|
||||||
from PyQt5.QtCore import Qt
|
from PyQt5.QtCore import Qt
|
||||||
from PyQt5.QtGui import QIcon, QPixmap
|
from PyQt5.QtGui import QIcon, QPixmap
|
||||||
from PyQt5.QtWidgets import QRadioButton, QGroupBox, QCheckBox, QComboBox, QGridLayout, QWidget, \
|
from PyQt5.QtWidgets import QRadioButton, QGroupBox, QCheckBox, QComboBox, QGridLayout, QWidget, \
|
||||||
QLabel, QSizePolicy, QLineEdit, QToolButton, QHBoxLayout, QFormLayout
|
QLabel, QSizePolicy, QLineEdit, QToolButton, QHBoxLayout, QFormLayout, QFileDialog
|
||||||
|
|
||||||
from bauh.api.abstract.view import SingleSelectComponent, InputOption, MultipleSelectComponent, SelectViewType, \
|
from bauh.api.abstract.view import SingleSelectComponent, InputOption, MultipleSelectComponent, SelectViewType, \
|
||||||
TextInputComponent, FormComponent
|
TextInputComponent, FormComponent, FileChooserComponent
|
||||||
from bauh.view.qt import css
|
from bauh.view.qt import css
|
||||||
from bauh.view.util import resource
|
from bauh.view.util import resource
|
||||||
|
from bauh.view.util.translation import I18n
|
||||||
|
|
||||||
|
|
||||||
class RadioButtonQt(QRadioButton):
|
class RadioButtonQt(QRadioButton):
|
||||||
@@ -257,9 +259,10 @@ class IconButton(QWidget):
|
|||||||
|
|
||||||
class FormQt(QGroupBox):
|
class FormQt(QGroupBox):
|
||||||
|
|
||||||
def __init__(self, model: FormComponent):
|
def __init__(self, model: FormComponent, i18n: I18n):
|
||||||
super(FormQt, self).__init__(model.label if model.label else '')
|
super(FormQt, self).__init__(model.label if model.label else '')
|
||||||
self.model = model
|
self.model = model
|
||||||
|
self.i18n = i18n
|
||||||
self.setLayout(QFormLayout())
|
self.setLayout(QFormLayout())
|
||||||
self.setStyleSheet(css.GROUP_BOX)
|
self.setStyleSheet(css.GROUP_BOX)
|
||||||
|
|
||||||
@@ -273,6 +276,9 @@ class FormQt(QGroupBox):
|
|||||||
label = QLabel(c.label.capitalize() if c.label else '')
|
label = QLabel(c.label.capitalize() if c.label else '')
|
||||||
field = ComboBoxQt(c)
|
field = ComboBoxQt(c)
|
||||||
self.layout().addRow(label, field)
|
self.layout().addRow(label, field)
|
||||||
|
elif isinstance(c, FileChooserComponent):
|
||||||
|
label, field = self._new_file_chooser(c)
|
||||||
|
self.layout().addRow(label, field)
|
||||||
else:
|
else:
|
||||||
raise Exception('Unsupported component type {}'.format(c.__class__.__name__))
|
raise Exception('Unsupported component type {}'.format(c.__class__.__name__))
|
||||||
|
|
||||||
@@ -300,6 +306,35 @@ class FormQt(QGroupBox):
|
|||||||
line_edit.textChanged.connect(update_model)
|
line_edit.textChanged.connect(update_model)
|
||||||
return QLabel(c.label.capitalize() if c.label else ''), line_edit
|
return QLabel(c.label.capitalize() if c.label else ''), line_edit
|
||||||
|
|
||||||
|
def _new_file_chooser(self, c: FileChooserComponent) -> Tuple[QLabel, QLineEdit]:
|
||||||
|
chooser = QLineEdit()
|
||||||
|
chooser.setReadOnly(True)
|
||||||
|
|
||||||
|
chooser.setPlaceholderText(self.i18n['view.components.file_chooser.placeholder'])
|
||||||
|
|
||||||
|
def open_chooser(e):
|
||||||
|
options = QFileDialog.Options()
|
||||||
|
|
||||||
|
if c.allowed_extensions:
|
||||||
|
exts = ';;'.join({'{} {} (*.{})'.format(self.i18n['files'].capitalize(), e.upper(), e) for e in c.allowed_extensions})
|
||||||
|
else:
|
||||||
|
exts = '{}} (*);;'.format(self.i18n['all_files'].capitalize())
|
||||||
|
|
||||||
|
file_path, _ = QFileDialog.getOpenFileName(self, self.i18n['file_chooser.title'], str(Path.home()), exts, options=options)
|
||||||
|
|
||||||
|
if file_path:
|
||||||
|
c.file_path = file_path
|
||||||
|
chooser.setText(file_path)
|
||||||
|
else:
|
||||||
|
c.file_path = None
|
||||||
|
chooser.setText('')
|
||||||
|
|
||||||
|
chooser.setCursorPosition(0)
|
||||||
|
|
||||||
|
chooser.mousePressEvent = open_chooser
|
||||||
|
|
||||||
|
return QLabel(c.label if c.label else ''), chooser
|
||||||
|
|
||||||
|
|
||||||
def new_single_select(model: SingleSelectComponent):
|
def new_single_select(model: SingleSelectComponent):
|
||||||
if model.type == SelectViewType.RADIO:
|
if model.type == SelectViewType.RADIO:
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class ConfirmationDialog(QMessageBox):
|
|||||||
elif isinstance(comp, TextInputComponent):
|
elif isinstance(comp, TextInputComponent):
|
||||||
inst = TextInputQt(comp)
|
inst = TextInputQt(comp)
|
||||||
elif isinstance(comp, FormComponent):
|
elif isinstance(comp, FormComponent):
|
||||||
inst = FormQt(comp)
|
inst = FormQt(comp, i18n)
|
||||||
else:
|
else:
|
||||||
raise Exception("Cannot render instances of " + comp.__class__.__name__)
|
raise Exception("Cannot render instances of " + comp.__class__.__name__)
|
||||||
|
|
||||||
|
|||||||
@@ -208,4 +208,8 @@ details=detalls
|
|||||||
communication=comunicació
|
communication=comunicació
|
||||||
administration=administració
|
administration=administració
|
||||||
settings=configuració
|
settings=configuració
|
||||||
address=adreça
|
address=adreça
|
||||||
|
view.components.file_chooser.placeholder=Feu clic aquí per seleccionar
|
||||||
|
files=fitxers
|
||||||
|
all_files=tots els fitxers
|
||||||
|
file_chooser.title=Selector de fitxers
|
||||||
@@ -162,4 +162,8 @@ details=details
|
|||||||
communication=Kommunikation
|
communication=Kommunikation
|
||||||
administration=Verwaltung
|
administration=Verwaltung
|
||||||
settings=Einstellungen
|
settings=Einstellungen
|
||||||
address=Adresse
|
address=Adresse
|
||||||
|
view.components.file_chooser.placeholder=Klicken Sie hier, um auszuwählen
|
||||||
|
files=Dateien
|
||||||
|
all_files=Alle Dateien
|
||||||
|
file_chooser.title=Dateiauswahl
|
||||||
@@ -166,4 +166,8 @@ administration=administration
|
|||||||
audio=audio
|
audio=audio
|
||||||
video=video
|
video=video
|
||||||
settings=settings
|
settings=settings
|
||||||
address=address
|
address=address
|
||||||
|
view.components.file_chooser.placeholder=Click here to select
|
||||||
|
files=files
|
||||||
|
all_files=all files
|
||||||
|
file_chooser.title=File selector
|
||||||
@@ -207,4 +207,8 @@ details=detalles
|
|||||||
communication=comunicación
|
communication=comunicación
|
||||||
administration=administración
|
administration=administración
|
||||||
settings=configuraciones
|
settings=configuraciones
|
||||||
address=dirección
|
address=dirección
|
||||||
|
view.components.file_chooser.placeholder=Pulse aquí para seleccionar
|
||||||
|
files=archivos
|
||||||
|
all_files=todos los archivos
|
||||||
|
file_chooser.title=Selector de archivos
|
||||||
@@ -163,4 +163,8 @@ details=dettagli
|
|||||||
communication=comunicazione
|
communication=comunicazione
|
||||||
administration=amministrazione
|
administration=amministrazione
|
||||||
settings=impostazioni
|
settings=impostazioni
|
||||||
address=indirizzo
|
address=indirizzo
|
||||||
|
view.components.file_chooser.placeholder=Fai clic qui per selezionare
|
||||||
|
files=files
|
||||||
|
all_files=tutti i files
|
||||||
|
file_chooser.title=Selettore file
|
||||||
@@ -210,4 +210,8 @@ details=detalhes
|
|||||||
communication=comunicação
|
communication=comunicação
|
||||||
messaging=mensagem
|
messaging=mensagem
|
||||||
administration=administração
|
administration=administração
|
||||||
address=endereço
|
address=endereço
|
||||||
|
view.components.file_chooser.placeholder=Clique aqui para selecionar
|
||||||
|
files=arquivos
|
||||||
|
all_files=todos os arquivos
|
||||||
|
file_chooser.title=Seletor arquivos
|
||||||
Reference in New Issue
Block a user