Merge pull request #70 from mattrose/13-gettext
This commit is contained in:
commit
ec2d50cdfc
|
@ -19,8 +19,3 @@ remotinatorc
|
||||||
terminatorlib/meliae
|
terminatorlib/meliae
|
||||||
/dist
|
/dist
|
||||||
/MANIFEST
|
/MANIFEST
|
||||||
|
|
||||||
## language / intltool related files
|
|
||||||
.intltool*
|
|
||||||
data/terminator.appdata.xml
|
|
||||||
data/terminator.desktop
|
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
Development Notes
|
||||||
|
=================
|
||||||
|
|
||||||
|
Here we connect notes and howtos for development around Terminator. Feel free to extend or submit suggestions.
|
||||||
|
|
||||||
|
## Translation i18n
|
||||||
|
|
||||||
|
Tooling is based on [Babel](https://babel.pocoo.org), the configuration is stored in `babel.cfg`, `setup.cfg` and
|
||||||
|
some code in `setup.py`.
|
||||||
|
|
||||||
|
The POT file [po/terminator.pot](po/terminator.pot) contains the template for all translations and should be updated
|
||||||
|
regularly, especially when messages changed inside the source code.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ python setup.py extract_messages
|
||||||
|
```
|
||||||
|
|
||||||
|
Usually catalogs are updated with external translation tools, e.g. when new translations are merged. But we can update
|
||||||
|
the catalogs here, so translators will have it more easy to pick up their work.
|
||||||
|
This is a custom extension in `setup.py`.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ python setup.py update_catalogs
|
||||||
|
```
|
||||||
|
|
||||||
|
Compilation of catalogs into the binary form, from `*.po` to `*.mo` is done during `setup.py build`, and the files are
|
||||||
|
installed during `setup.py install`.
|
|
@ -0,0 +1,7 @@
|
||||||
|
[ignore: build/**]
|
||||||
|
[python: **.py]
|
||||||
|
[python: terminator]
|
||||||
|
[python: remotinator]
|
||||||
|
[glade: **.glade]
|
||||||
|
[glade: data/terminator.metainfo.xml]
|
||||||
|
[desktop: **.desktop]
|
|
@ -4,45 +4,45 @@
|
||||||
<id>terminator.desktop</id>
|
<id>terminator.desktop</id>
|
||||||
<metadata_license>CC0-1.0</metadata_license>
|
<metadata_license>CC0-1.0</metadata_license>
|
||||||
<project_license>GPL-2.0 only</project_license>
|
<project_license>GPL-2.0 only</project_license>
|
||||||
<_name>Terminator</_name>
|
<name translatable="yes">Terminator</name>
|
||||||
<_summary>Multiple terminals in one window</_summary>
|
<summary translatable="yes">Multiple terminals in one window</summary>
|
||||||
<description>
|
<description>
|
||||||
<_p>
|
<p translatable="yes">
|
||||||
The robot future of terminals
|
The robot future of terminals
|
||||||
</_p>
|
</p>
|
||||||
<_p>
|
<p translatable="yes">
|
||||||
A power-user tool for arranging terminals. It is inspired by programs such as
|
A power-user tool for arranging terminals. It is inspired by programs such as
|
||||||
gnome-multi-term, quadkonsole, etc. in that the main focus is arranging terminals
|
gnome-multi-term, quadkonsole, etc. in that the main focus is arranging terminals
|
||||||
in grids (tabs is the most common default method, which Terminator also supports).
|
in grids (tabs is the most common default method, which Terminator also supports).
|
||||||
</_p>
|
</p>
|
||||||
<_p>
|
<p translatable="yes">
|
||||||
Much of the behavior of Terminator is based on GNOME Terminal, and we are adding
|
Much of the behavior of Terminator is based on GNOME Terminal, and we are adding
|
||||||
more features from that as time goes by, but we also want to extend out in different
|
more features from that as time goes by, but we also want to extend out in different
|
||||||
directions with useful features for sysadmins and other users.
|
directions with useful features for sysadmins and other users.
|
||||||
</_p>
|
</p>
|
||||||
<_p>Some highlights:</_p>
|
<p translatable="yes">Some highlights:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<_li>Arrange terminals in a grid</_li>
|
<li translatable="yes">Arrange terminals in a grid</li>
|
||||||
<_li>Tabs</_li>
|
<li translatable="yes">Tabs</li>
|
||||||
<_li>Drag and drop re-ordering of terminals</_li>
|
<li translatable="yes">Drag and drop re-ordering of terminals</li>
|
||||||
<_li>Lots of keyboard shortcuts</_li>
|
<li translatable="yes">Lots of keyboard shortcuts</li>
|
||||||
<_li>Save multiple layouts and profiles via GUI preferences editor</_li>
|
<li translatable="yes">Save multiple layouts and profiles via GUI preferences editor</li>
|
||||||
<_li>Simultaneous typing to arbitrary groups of terminals</_li>
|
<li translatable="yes">Simultaneous typing to arbitrary groups of terminals</li>
|
||||||
</ul>
|
</ul>
|
||||||
<_p>And lots more...</_p>
|
<p translatable="yes">And lots more...</p>
|
||||||
</description>
|
</description>
|
||||||
<screenshots>
|
<screenshots>
|
||||||
<screenshot type="default">
|
<screenshot type="default">
|
||||||
<image>http://4.bp.blogspot.com/-xt4Tja1TMQ0/Vdemmf8wYSI/AAAAAAAAA9A/uROTre0PMls/s1600/terminator_main_basic.png</image>
|
<image>http://4.bp.blogspot.com/-xt4Tja1TMQ0/Vdemmf8wYSI/AAAAAAAAA9A/uROTre0PMls/s1600/terminator_main_basic.png</image>
|
||||||
<_caption>The main window showing the application in action</_caption>
|
<caption translatable="yes">The main window showing the application in action</caption>
|
||||||
</screenshot>
|
</screenshot>
|
||||||
<screenshot>
|
<screenshot>
|
||||||
<image>http://4.bp.blogspot.com/-rRxALSpEEZw/Vdeu58JgpnI/AAAAAAAAA9o/XewWKJ5HNo4/s1600/terminator_main_complex.png</image>
|
<image>http://4.bp.blogspot.com/-rRxALSpEEZw/Vdeu58JgpnI/AAAAAAAAA9o/XewWKJ5HNo4/s1600/terminator_main_complex.png</image>
|
||||||
<_caption>Getting a little crazy with the terminals</_caption>
|
<caption translatable="yes">Getting a little crazy with the terminals</caption>
|
||||||
</screenshot>
|
</screenshot>
|
||||||
<screenshot>
|
<screenshot>
|
||||||
<image>http://2.bp.blogspot.com/-t_8oRyMXUls/VdemmRVnZnI/AAAAAAAAA88/rHIr8L1X7Ho/s1600/terminator_prefs_global.png</image>
|
<image>http://2.bp.blogspot.com/-t_8oRyMXUls/VdemmRVnZnI/AAAAAAAAA88/rHIr8L1X7Ho/s1600/terminatorprefs_global.png</image>
|
||||||
<_caption>The preferences window where you can change the defaults</_caption>
|
<caption translatable="yes">The preferences window where you can change the defaults</caption>
|
||||||
</screenshot>
|
</screenshot>
|
||||||
</screenshots>
|
</screenshots>
|
||||||
<url type="homepage">https://github.com/gnome-terminator/terminator</url>
|
<url type="homepage">https://github.com/gnome-terminator/terminator</url>
|
11
po/genpot.sh
11
po/genpot.sh
|
@ -1,11 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
# Stupid workaround for intltools not handling extensionless files
|
|
||||||
ln -s terminator ../terminator.py
|
|
||||||
ln -s remotinator ../remotinator.py
|
|
||||||
|
|
||||||
# Make translation files
|
|
||||||
intltool-update -g terminator -o terminator.pot -p
|
|
||||||
|
|
||||||
# Cleanup after stupid workaround
|
|
||||||
rm ../terminator.py
|
|
||||||
rm ../remotinator.py
|
|
1358
po/terminator.pot
1358
po/terminator.pot
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
# Update translation files
|
|
||||||
for po_file in `ls *.po`; do
|
|
||||||
msgmerge -N -U ${po_file} terminator.pot
|
|
||||||
done
|
|
|
@ -1,2 +1,7 @@
|
||||||
[aliases]
|
[aliases]
|
||||||
test=pytest
|
test=pytest
|
||||||
|
|
||||||
|
[extract_messages]
|
||||||
|
mapping_file = babel.cfg
|
||||||
|
output_file = po/terminator.pot
|
||||||
|
input_dirs = .
|
||||||
|
|
101
setup.py
101
setup.py
|
@ -16,76 +16,61 @@ import platform
|
||||||
|
|
||||||
from terminatorlib.version import APP_NAME, APP_VERSION
|
from terminatorlib.version import APP_NAME, APP_VERSION
|
||||||
|
|
||||||
PO_DIR = 'po'
|
GETTEXT_SOURCE = 'po'
|
||||||
MO_DIR = os.path.join('build', 'mo')
|
GETTEXT_DOMAIN = 'terminator'
|
||||||
|
GETTEXT_TARGET = os.path.join('share', 'locale')
|
||||||
CSS_DIR = os.path.join('terminatorlib', 'themes')
|
CSS_DIR = os.path.join('terminatorlib', 'themes')
|
||||||
|
|
||||||
if sys.version_info < (3, 0):
|
if sys.version_info < (3, 0):
|
||||||
PYTEST_VERSION = '<5'
|
PYTEST_VERSION = '<5'
|
||||||
|
BABELGLADE_VERSION = '< 0.7'
|
||||||
else:
|
else:
|
||||||
PYTEST_VERSION = '>0'
|
PYTEST_VERSION = '>0'
|
||||||
|
BABELGLADE_VERSION = '> 0'
|
||||||
|
|
||||||
|
|
||||||
class TerminatorDist(Distribution):
|
class TerminatorDist(Distribution):
|
||||||
global_options = Distribution.global_options + [
|
global_options = Distribution.global_options + [
|
||||||
("build-documentation", None, "Build the documentation"),
|
("build-documentation", None, "Build the documentation"),
|
||||||
("install-documentation", None, "Install the documentation"),
|
("install-documentation", None, "Install the documentation"),
|
||||||
("without-gettext", None, "Don't build/install gettext .mo files"),
|
|
||||||
("without-icon-cache", None, "Don't attempt to run gtk-update-icon-cache")]
|
("without-icon-cache", None, "Don't attempt to run gtk-update-icon-cache")]
|
||||||
|
|
||||||
def __init__ (self, *args):
|
def __init__ (self, *args):
|
||||||
self.without_gettext = False
|
|
||||||
self.without_icon_cache = False
|
self.without_icon_cache = False
|
||||||
Distribution.__init__(self, *args)
|
Distribution.__init__(self, *args)
|
||||||
|
|
||||||
|
|
||||||
class BuildData(build):
|
class CustomBuild(build):
|
||||||
|
"""
|
||||||
|
Custom build extensions to build
|
||||||
|
"""
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
build.run(self)
|
build.run(self)
|
||||||
|
self.build_i18n()
|
||||||
|
|
||||||
if not self.distribution.without_gettext:
|
def build_i18n(self):
|
||||||
# Build the translations
|
"""
|
||||||
for po in glob.glob (os.path.join (PO_DIR, '*.po')):
|
Compiling files for gettext from *.po to *.mo with the proper target path
|
||||||
|
"""
|
||||||
|
info('compiling i18n files')
|
||||||
|
from babel.messages.frontend import compile_catalog
|
||||||
|
compiler = compile_catalog(self.distribution)
|
||||||
|
compiler.domain = [GETTEXT_DOMAIN]
|
||||||
|
|
||||||
|
for po in glob.glob(os.path.join(GETTEXT_SOURCE, '*.po')):
|
||||||
lang = os.path.basename(po[:-3])
|
lang = os.path.basename(po[:-3])
|
||||||
mo = os.path.join(MO_DIR, lang, 'terminator.mo')
|
mo = os.path.join(self.build_base, GETTEXT_TARGET, lang, 'LC_MESSAGES', 'terminator.mo')
|
||||||
|
|
||||||
directory = os.path.dirname(mo)
|
directory = os.path.dirname(mo)
|
||||||
if not os.path.exists(directory):
|
if not os.path.exists(directory):
|
||||||
info('creating %s' % directory)
|
|
||||||
os.makedirs(directory)
|
os.makedirs(directory)
|
||||||
|
|
||||||
if newer(po, mo):
|
if newer(po, mo):
|
||||||
info('compiling %s -> %s' % (po, mo))
|
compiler.input_file = po
|
||||||
try:
|
compiler.output_file = mo
|
||||||
rc = subprocess.call(['msgfmt', '-o', mo, po])
|
compiler.run()
|
||||||
if rc != 0:
|
|
||||||
raise Warning("msgfmt returned %d" % rc)
|
|
||||||
except Exception as e:
|
|
||||||
error("Building gettext files failed. Ensure you have gettext installed. Alternatively, try setup.py --without-gettext [build|install]")
|
|
||||||
error("Error: %s" % str(e))
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
TOP_BUILDDIR='.'
|
|
||||||
INTLTOOL_MERGE='intltool-merge'
|
|
||||||
desktop_in='data/terminator.desktop.in'
|
|
||||||
desktop_data='data/terminator.desktop'
|
|
||||||
rc = os.system ("C_ALL=C " + INTLTOOL_MERGE + " -d -u -c " + TOP_BUILDDIR +
|
|
||||||
"/po/.intltool-merge-cache " + TOP_BUILDDIR + "/po " +
|
|
||||||
desktop_in + " " + desktop_data)
|
|
||||||
if rc != 0:
|
|
||||||
# run the desktop_in through a command to strip the "_" characters
|
|
||||||
with open(desktop_in) as file_in, open(desktop_data, 'w') as file_data:
|
|
||||||
[file_data.write(line.lstrip('_')) for line in file_in]
|
|
||||||
|
|
||||||
appdata_in='data/terminator.appdata.xml.in'
|
|
||||||
appdata_data='data/terminator.metainfo.xml'
|
|
||||||
rc = os.system ("C_ALL=C " + INTLTOOL_MERGE + " -x -u -c " + TOP_BUILDDIR +
|
|
||||||
"/po/.intltool-merge-cache " + TOP_BUILDDIR + "/po " +
|
|
||||||
appdata_in + " " + appdata_data)
|
|
||||||
if rc != 0:
|
|
||||||
# run the appdata_in through a command to strip the "_" characters
|
|
||||||
with open(appdata_in) as file_in, open(appdata_data, 'w') as file_data:
|
|
||||||
[file_data.write(line.replace('<_','<').replace('</_','</')) for line in file_in]
|
|
||||||
|
|
||||||
class Uninstall(Command):
|
class Uninstall(Command):
|
||||||
description = "Attempt an uninstall from an install --record file"
|
description = "Attempt an uninstall from an install --record file"
|
||||||
|
@ -162,12 +147,14 @@ class InstallData(install_data):
|
||||||
warn("updating the GTK icon cache failed: %s" % str(e))
|
warn("updating the GTK icon cache failed: %s" % str(e))
|
||||||
|
|
||||||
def _find_mo_files(self):
|
def _find_mo_files(self):
|
||||||
|
"""
|
||||||
|
search for gettext files built during build step
|
||||||
|
"""
|
||||||
data_files = []
|
data_files = []
|
||||||
|
|
||||||
if not self.distribution.without_gettext:
|
build_base = self.distribution.command_obj['build'].build_base
|
||||||
for mo in glob.glob (os.path.join (MO_DIR, '*', 'terminator.mo')):
|
for mo in glob.glob(os.path.join(build_base, GETTEXT_TARGET, '*', 'LC_MESSAGES', '*.mo')):
|
||||||
lang = os.path.basename(os.path.dirname(mo))
|
dest = mo.lstrip(build_base + os.sep)
|
||||||
dest = os.path.join('share', 'locale', lang, 'LC_MESSAGES')
|
|
||||||
data_files.append((dest, [mo]))
|
data_files.append((dest, [mo]))
|
||||||
|
|
||||||
return data_files
|
return data_files
|
||||||
|
@ -183,6 +170,27 @@ class InstallData(install_data):
|
||||||
return data_files
|
return data_files
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateCatalogs(Command):
|
||||||
|
"""Update all gettext catalogs """
|
||||||
|
description = __doc__
|
||||||
|
user_options = []
|
||||||
|
|
||||||
|
def initialize_options(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def finalize_options(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
from babel.messages.frontend import update_catalog
|
||||||
|
updater = update_catalog(self.distribution)
|
||||||
|
updater.input_file = os.path.join(GETTEXT_SOURCE, 'terminator.pot')
|
||||||
|
|
||||||
|
for po in glob.glob(os.path.join(GETTEXT_SOURCE, '*.po')):
|
||||||
|
updater.output_file = po
|
||||||
|
updater.run()
|
||||||
|
|
||||||
|
|
||||||
if platform.system() in ['FreeBSD', 'OpenBSD']:
|
if platform.system() in ['FreeBSD', 'OpenBSD']:
|
||||||
man_dir = 'man'
|
man_dir = 'man'
|
||||||
else:
|
else:
|
||||||
|
@ -229,6 +237,8 @@ setup(name=APP_NAME,
|
||||||
],
|
],
|
||||||
setup_requires=[
|
setup_requires=[
|
||||||
'pytest-runner',
|
'pytest-runner',
|
||||||
|
'babel',
|
||||||
|
'BabelGladeExtractor ' + BABELGLADE_VERSION,
|
||||||
],
|
],
|
||||||
install_requires=[
|
install_requires=[
|
||||||
'pycairo',
|
'pycairo',
|
||||||
|
@ -240,6 +250,7 @@ setup(name=APP_NAME,
|
||||||
tests_require=test_deps,
|
tests_require=test_deps,
|
||||||
extras_require={'test': test_deps},
|
extras_require={'test': test_deps},
|
||||||
package_data={'terminatorlib': ['preferences.glade', 'layoutlauncher.glade']},
|
package_data={'terminatorlib': ['preferences.glade', 'layoutlauncher.glade']},
|
||||||
cmdclass={'build': BuildData, 'install_data': InstallData, 'uninstall': Uninstall},
|
cmdclass={'build': CustomBuild, 'install_data': InstallData, 'uninstall': Uninstall,
|
||||||
|
'update_catalogs': UpdateCatalogs},
|
||||||
distclass=TerminatorDist)
|
distclass=TerminatorDist)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue