Add support for locales
This commit is contained in:
parent
118395df71
commit
1a5c2031f3
|
@ -1,3 +1,7 @@
|
|||
v 0.4.0 [14-sep-2019]
|
||||
---------------------
|
||||
- Add support for locales
|
||||
|
||||
v 0.3.0 [10-sep-2019]
|
||||
---------------------
|
||||
- Add support for dialogs
|
||||
|
|
|
@ -34,6 +34,12 @@ NAME = 'TestMacro'
|
|||
# ~ Should be unique, used URL inverse
|
||||
ID = 'org.myextension.test'
|
||||
|
||||
# ~ If you extension will be multilanguage set: True
|
||||
# ~ This feature used gettext, set pythonpath and easymacro in True
|
||||
USE_LOCALES = True
|
||||
DOMAIN = 'base'
|
||||
PATH_LOCALES = 'locales'
|
||||
|
||||
PUBLISHER = {
|
||||
'en': {'text': 'El Mau', 'link': 'https://elmau.net'},
|
||||
'es': {'text': 'El Mau', 'link': 'https://elmau.net'},
|
||||
|
@ -131,11 +137,12 @@ EXTENSION = {
|
|||
'name': NAME,
|
||||
'id': ID,
|
||||
'icon': (ICON, ICON_EXT),
|
||||
'languages': tuple(INFO.keys())
|
||||
}
|
||||
|
||||
|
||||
# ~ If used more libraries set python path in True and copy inside
|
||||
# ~ If used easymacro pythonpath always is True
|
||||
# ~ If used easymacro pythonpath always is True, recommended
|
||||
DIRS = {
|
||||
'meta': 'META-INF',
|
||||
'source': 'source',
|
||||
|
@ -143,7 +150,8 @@ DIRS = {
|
|||
'images': 'images',
|
||||
'registration': 'registration',
|
||||
'files': 'files',
|
||||
'pythonpath': False,
|
||||
'pythonpath': True,
|
||||
'locales': PATH_LOCALES,
|
||||
}
|
||||
|
||||
|
||||
|
@ -335,6 +343,8 @@ if PARENT == 'OfficeMenuBar':
|
|||
|
||||
|
||||
def _get_context(args):
|
||||
if not args:
|
||||
return ''
|
||||
c = []
|
||||
for v in args.split(','):
|
||||
c.append(CONTEXT[v])
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
# ~ along with ZAZ. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
|
||||
import ctypes
|
||||
import datetime
|
||||
import errno
|
||||
import getpass
|
||||
import logging
|
||||
|
@ -45,6 +46,7 @@ from com.sun.star.awt import MessageBoxButtons as MSG_BUTTONS
|
|||
from com.sun.star.awt.MessageBoxResults import YES
|
||||
from com.sun.star.awt.PosSize import POSSIZE, SIZE
|
||||
from com.sun.star.awt import Size, Point
|
||||
from com.sun.star.datatransfer import XTransferable, DataFlavor
|
||||
from com.sun.star.table.CellContentType import EMPTY, VALUE, TEXT, FORMULA
|
||||
|
||||
from com.sun.star.text.TextContentAnchorType import AS_CHARACTER
|
||||
|
@ -79,9 +81,12 @@ log = logging.getLogger(__name__)
|
|||
OS = platform.system()
|
||||
USER = getpass.getuser()
|
||||
PC = platform.node()
|
||||
DESKTOP = os.environ.get('DESKTOP_SESSION', '')
|
||||
INFO_DEBUG = '{}\n\n{}\n\n{}'.format(sys.version, platform.platform(), '\n'.join(sys.path))
|
||||
|
||||
IS_WIN = OS == 'Windows'
|
||||
LOG_NAME = 'ZAZ'
|
||||
CLIPBOARD_FORMAT_TEXT = 'text/plain;charset=utf-16'
|
||||
|
||||
CALC = 'calc'
|
||||
WRITER = 'writer'
|
||||
|
@ -119,10 +124,9 @@ def _get_config(key, node_name):
|
|||
|
||||
|
||||
LANGUAGE = _get_config('ooLocale', 'org.openoffice.Setup/L10N/')
|
||||
LANG = LANGUAGE.split('-')[0]
|
||||
NAME = TITLE = _get_config('ooName', 'org.openoffice.Setup/Product')
|
||||
VERSION = _get_config('ooSetupVersion', 'org.openoffice.Setup/Product')
|
||||
INFO_DEBUG = '{}\n\n{}\n\n{}'.format(
|
||||
sys.version, platform.platform(), '\n'.join(sys.path))
|
||||
|
||||
|
||||
def mri(obj):
|
||||
|
@ -238,6 +242,10 @@ def get_desktop():
|
|||
return create_instance('com.sun.star.frame.Desktop', True)
|
||||
|
||||
|
||||
def get_dispatch():
|
||||
return create_instance('com.sun.star.frame.DispatchHelper')
|
||||
|
||||
|
||||
def get_temp_file():
|
||||
return tempfile.NamedTemporaryFile()
|
||||
|
||||
|
@ -315,6 +323,10 @@ class LODocument(object):
|
|||
def title(self):
|
||||
return self.obj.getTitle()
|
||||
|
||||
@property
|
||||
def frame(self):
|
||||
return self._cc.getFrame()
|
||||
|
||||
@property
|
||||
def is_saved(self):
|
||||
return self.obj.hasLocation()
|
||||
|
@ -368,6 +380,12 @@ class LODocument(object):
|
|||
w.setFocus()
|
||||
return
|
||||
|
||||
def paste(self):
|
||||
sc = create_instance('com.sun.star.datatransfer.clipboard.SystemClipboard')
|
||||
transferable = sc.getContents()
|
||||
self._cc.insertTransferable(transferable)
|
||||
return self.obj.getCurrentSelection()
|
||||
|
||||
|
||||
class LOCalc(LODocument):
|
||||
|
||||
|
@ -400,9 +418,14 @@ class LOCalc(LODocument):
|
|||
cell = LOCellRange(self.active[index].obj, self)
|
||||
return cell
|
||||
|
||||
# ~ def create_instance(self, name):
|
||||
# ~ obj = self.obj.createInstance(name)
|
||||
# ~ return obj
|
||||
def select(self, rango):
|
||||
r = rango
|
||||
if hasattr(rango, 'obj'):
|
||||
r = rango.obj
|
||||
elif isinstance(rango, str):
|
||||
r = self.get_cell(rango).obj
|
||||
self._cc.select(r)
|
||||
return
|
||||
|
||||
|
||||
class LOCalcSheet(object):
|
||||
|
@ -551,6 +574,11 @@ class LOBasicIde(LODocument):
|
|||
def __init__(self, obj):
|
||||
super().__init__(obj)
|
||||
|
||||
@property
|
||||
def selection(self):
|
||||
sel = self._cc.getSelection()
|
||||
return sel
|
||||
|
||||
|
||||
class LOCellRange(object):
|
||||
|
||||
|
@ -674,6 +702,10 @@ class LOCellRange(object):
|
|||
img.setSize(Size(w, h))
|
||||
return
|
||||
|
||||
def select(self):
|
||||
self.doc._cc.select(self.obj)
|
||||
return
|
||||
|
||||
|
||||
class EventsListenerBase(unohelper.Base, XEventListener):
|
||||
|
||||
|
@ -1198,6 +1230,9 @@ def open_doc(path, **kwargs):
|
|||
Password: super_secret
|
||||
MacroExecutionMode: 4 = Activate macros
|
||||
Preview: True or False
|
||||
|
||||
http://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1frame_1_1XComponentLoader.html
|
||||
http://api.libreoffice.org/docs/idl/ref/servicecom_1_1sun_1_1star_1_1document_1_1MediaDescriptor.html
|
||||
"""
|
||||
path = _path_url(path)
|
||||
opt = _properties(kwargs)
|
||||
|
@ -1252,12 +1287,13 @@ def run(command, wait=False):
|
|||
# ~ debug(shlex.split(command))
|
||||
try:
|
||||
if wait:
|
||||
p = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE)
|
||||
p.wait()
|
||||
# ~ p = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE)
|
||||
# ~ p.wait()
|
||||
result = subprocess.check_output(command, shell=True)
|
||||
else:
|
||||
p = subprocess.Popen(shlex.split(command), stdin=None,
|
||||
stdout=None, stderr=None, close_fds=True)
|
||||
result, er = p.communicate()
|
||||
result, er = p.communicate()
|
||||
except subprocess.CalledProcessError as e:
|
||||
msg = ("run [ERROR]: output = %s, error code = %s\n"
|
||||
% (e.output, e.returncode))
|
||||
|
@ -1366,3 +1402,93 @@ def merge_zip(target, zips):
|
|||
|
||||
return True
|
||||
|
||||
|
||||
def kill(path):
|
||||
p = Path(path)
|
||||
if p.is_file():
|
||||
try:
|
||||
p.unlink()
|
||||
except:
|
||||
pass
|
||||
elif p.is_dir():
|
||||
p.rmdir()
|
||||
return
|
||||
|
||||
|
||||
def get_size_screen():
|
||||
if IS_WIN:
|
||||
user32 = ctypes.windll.user32
|
||||
res = '{}x{}'.format(user32.GetSystemMetrics(0), user32.GetSystemMetrics(1))
|
||||
else:
|
||||
args = 'xrandr | grep "*" | cut -d " " -f4'
|
||||
res = run(args, True)
|
||||
return res.strip()
|
||||
|
||||
|
||||
def get_clipboard():
|
||||
df = None
|
||||
text = ''
|
||||
sc = create_instance('com.sun.star.datatransfer.clipboard.SystemClipboard')
|
||||
transferable = sc.getContents()
|
||||
data = transferable.getTransferDataFlavors()
|
||||
for df in data:
|
||||
if df.MimeType == CLIPBOARD_FORMAT_TEXT:
|
||||
break
|
||||
if df:
|
||||
text = transferable.getTransferData(df)
|
||||
return text
|
||||
|
||||
|
||||
class TextTransferable(unohelper.Base, XTransferable):
|
||||
"""Keep clipboard data and provide them."""
|
||||
|
||||
def __init__(self, text):
|
||||
df = DataFlavor()
|
||||
df.MimeType = CLIPBOARD_FORMAT_TEXT
|
||||
df.HumanPresentableName = "encoded text utf-16"
|
||||
self.flavors = [df]
|
||||
self.data = [text]
|
||||
|
||||
def getTransferData(self, flavor):
|
||||
if not flavor:
|
||||
return
|
||||
for i, f in enumerate(self.flavors):
|
||||
if flavor.MimeType == f.MimeType:
|
||||
return self.data[i]
|
||||
return
|
||||
|
||||
def getTransferDataFlavors(self):
|
||||
return tuple(self.flavors)
|
||||
|
||||
def isDataFlavorSupported(self, flavor):
|
||||
if not flavor:
|
||||
return False
|
||||
mtype = flavor.MimeType
|
||||
for f in self.flavors:
|
||||
if mtype == f.MimeType:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def set_clipboard(text):
|
||||
ts = TextTransferable(text)
|
||||
sc = create_instance('com.sun.star.datatransfer.clipboard.SystemClipboard')
|
||||
sc.setContents(ts, None)
|
||||
return
|
||||
|
||||
|
||||
def copy(doc=None):
|
||||
if doc is None:
|
||||
doc = get_document()
|
||||
if hasattr(doc, 'frame'):
|
||||
frame = doc.frame
|
||||
else:
|
||||
frame = doc.getCurrentController().getFrame()
|
||||
dispatch = get_dispatch()
|
||||
dispatch.executeDispatch(frame, '.uno:Copy', '', 0, ())
|
||||
return
|
||||
|
||||
|
||||
def get_epoch():
|
||||
now = datetime.datetime.now()
|
||||
return int(time.mktime(now.timetuple()))
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<oor:component-data xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema" oor:name="Addons" oor:package="org.openoffice.Office">
|
||||
<node oor:name="AddonUI">
|
||||
<node oor:name="OfficeMenuBar">
|
||||
<node oor:name="org.myextension.test" oor:op="replace">
|
||||
<prop oor:name="Title" oor:type="xs:string">
|
||||
<value xml:lang="en">My Extension</value>
|
||||
<value xml:lang="es">Mi Extensión</value>
|
||||
</prop>
|
||||
<prop oor:name="Target" oor:type="xs:string">
|
||||
<value>_self</value>
|
||||
</prop>
|
||||
<node oor:name="Submenu">
|
||||
<node oor:name="org.myextension.test.101" oor:op="replace">
|
||||
<prop oor:name="Title" oor:type="xs:string">
|
||||
<value xml:lang="en">Option 1</value>
|
||||
<value xml:lang="es">Opción 1</value>
|
||||
</prop>
|
||||
<prop oor:name="URL" oor:type="xs:string">
|
||||
<value>service:org.myextension.test?option1</value>
|
||||
</prop>
|
||||
<prop oor:name="Target" oor:type="xs:string">
|
||||
<value>_self</value>
|
||||
</prop>
|
||||
<prop oor:name="Context" oor:type="xs:string">
|
||||
<value>com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument</value>
|
||||
</prop>
|
||||
<prop oor:name="ImageIdentifier" oor:type="xs:string">
|
||||
<value>%origin%/images/icon</value>
|
||||
</prop>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node oor:name="OfficeToolBar">
|
||||
<node oor:name="org.myextension.test" oor:op="replace">
|
||||
<node oor:name="org.myextension.test.t1" oor:op="replace">
|
||||
<prop oor:name="Title" oor:type="xs:string">
|
||||
<value xml:lang="en">Option 1</value>
|
||||
<value xml:lang="es">Opción 1</value>
|
||||
</prop>
|
||||
<prop oor:name="URL" oor:type="xs:string">
|
||||
<value>service:org.myextension.test?option1</value>
|
||||
</prop>
|
||||
<prop oor:name="Target" oor:type="xs:string">
|
||||
<value>_self</value>
|
||||
</prop>
|
||||
<prop oor:name="Context" oor:type="xs:string">
|
||||
<value>com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument</value>
|
||||
</prop>
|
||||
<prop oor:name="ImageIdentifier" oor:type="xs:string">
|
||||
<value>%origin%/images/icon</value>
|
||||
</prop>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</oor:component-data>
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<manifest:manifest>
|
||||
<manifest:file-entry manifest:full-path="TestMacro.py" manifest:media-type="application/vnd.sun.star.uno-component;type=Python"/>
|
||||
<manifest:file-entry manifest:full-path="Addons.xcu" manifest:media-type="application/vnd.sun.star.configuration-data"/>
|
||||
</manifest:manifest>
|
|
@ -0,0 +1,33 @@
|
|||
import gettext
|
||||
import uno
|
||||
import unohelper
|
||||
from com.sun.star.task import XJobExecutor
|
||||
import easymacro as app
|
||||
|
||||
|
||||
ID_EXTENSION = 'org.myextension.test'
|
||||
SERVICE = ('com.sun.star.task.Job',)
|
||||
|
||||
|
||||
p, *_ = app.get_info_path(__file__)
|
||||
path_locales = app.join(p, 'locales')
|
||||
try:
|
||||
lang = gettext.translation('base', path_locales, languages=[app.LANG])
|
||||
lang.install()
|
||||
_ = lang.gettext
|
||||
except Exception as e:
|
||||
app.error(e)
|
||||
|
||||
|
||||
class TestMacro(unohelper.Base, XJobExecutor):
|
||||
|
||||
def __init__(self, ctx):
|
||||
self.ctx = ctx
|
||||
|
||||
def trigger(self, args='pyUNO'):
|
||||
print('Hello World', args)
|
||||
return
|
||||
|
||||
|
||||
g_ImplementationHelper = unohelper.ImplementationHelper()
|
||||
g_ImplementationHelper.addImplementation(TestMacro, ID_EXTENSION, SERVICE)
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<description xmlns="http://openoffice.org/extensions/description/2006" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:d="http://openoffice.org/extensions/description/2006">
|
||||
<identifier value="org.myextension.test" />
|
||||
<version value="0.1.0" />
|
||||
<display-name>
|
||||
<name lang="en">Test Macro</name>
|
||||
<name lang="es">Macro de Prueba</name>
|
||||
</display-name>
|
||||
<extension-description>
|
||||
<src lang="en" xlink:href="description/desc_en.txt" />
|
||||
<src lang="es" xlink:href="description/desc_es.txt" />
|
||||
</extension-description>
|
||||
<icon>
|
||||
<default xlink:href="images/testmacro.png" />
|
||||
</icon>
|
||||
<publisher>
|
||||
<name xlink:href="https://elmau.net" lang="en">El Mau</name>
|
||||
<name xlink:href="https://elmau.net" lang="es">El Mau</name>
|
||||
</publisher>
|
||||
<registration>
|
||||
<simple-license accept-by="user" suppress-on-update="true" >
|
||||
<license-text xlink:href="registration/license_en.txt" lang="en" />
|
||||
<license-text xlink:href="registration/license_es.txt" lang="es" />
|
||||
</simple-license>
|
||||
</registration>
|
||||
</description>
|
|
@ -0,0 +1 @@
|
|||
My great extension
|
|
@ -0,0 +1 @@
|
|||
Mi gran extensión
|
Binary file not shown.
After Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,14 @@
|
|||
This file is part of TestMacro.
|
||||
|
||||
TestMacro is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TestMacro is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with TestMacro. If not, see <https://www.gnu.org/licenses/>.
|
|
@ -0,0 +1,14 @@
|
|||
This file is part of TestMacro.
|
||||
|
||||
TestMacro is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TestMacro is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with TestMacro. If not, see <https://www.gnu.org/licenses/>.
|
|
@ -20,6 +20,7 @@
|
|||
import argparse
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from shutil import copyfile
|
||||
from subprocess import call
|
||||
import zipfile
|
||||
|
@ -32,6 +33,7 @@ from conf import (
|
|||
INFO,
|
||||
PATHS,
|
||||
TYPE_EXTENSION,
|
||||
USE_LOCALES,
|
||||
log)
|
||||
|
||||
|
||||
|
@ -74,6 +76,10 @@ def _compress_oxt():
|
|||
z.write(fullpath, file_name, zipfile.ZIP_DEFLATED)
|
||||
z.close()
|
||||
|
||||
if DATA['update']:
|
||||
path_xml = _join(path, FILES['update'])
|
||||
_save(path_xml, DATA['update'])
|
||||
|
||||
log.info('Extension OXT created sucesfully...')
|
||||
return
|
||||
|
||||
|
@ -227,6 +233,13 @@ def _update_files():
|
|||
path = _join(path_source, FILES['addin'])
|
||||
_save(path, DATA['addin'])
|
||||
|
||||
if USE_LOCALES:
|
||||
msg = "Don't forget generate DOMAIN.pot for locales"
|
||||
log.info(msg)
|
||||
for lang in EXTENSION['languages']:
|
||||
path = _join(path_source, DIRS['locales'], lang, 'LC_MESSAGES')
|
||||
Path(path).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
_compile_idl()
|
||||
return
|
||||
|
||||
|
|
Loading…
Reference in New Issue