Merge pull request #70 from mattrose/13-gettext

This commit is contained in:
Markus Frosch 2020-05-18 00:19:46 +02:00 committed by GitHub
commit ec2d50cdfc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 803 additions and 778 deletions

5
.gitignore vendored
View File

@ -19,8 +19,3 @@ remotinatorc
terminatorlib/meliae
/dist
/MANIFEST
## language / intltool related files
.intltool*
data/terminator.appdata.xml
data/terminator.desktop

27
DEVELOPMENT.md Normal file
View File

@ -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`.

7
babel.cfg Normal file
View File

@ -0,0 +1,7 @@
[ignore: build/**]
[python: **.py]
[python: terminator]
[python: remotinator]
[glade: **.glade]
[glade: data/terminator.metainfo.xml]
[desktop: **.desktop]

View File

@ -2,47 +2,47 @@
<!-- Copyright 2013 Stephen Boddy <stephen.j.boddy@gmail.com> -->
<component type="desktop">
<id>terminator.desktop</id>
<metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-2.0 only</project_license>
<_name>Terminator</_name>
<_summary>Multiple terminals in one window</_summary>
<metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-2.0 only</project_license>
<name translatable="yes">Terminator</name>
<summary translatable="yes">Multiple terminals in one window</summary>
<description>
<_p>
<p translatable="yes">
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
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).
</_p>
<_p>
</p>
<p translatable="yes">
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
directions with useful features for sysadmins and other users.
</_p>
<_p>Some highlights:</_p>
</p>
<p translatable="yes">Some highlights:</p>
<ul>
<_li>Arrange terminals in a grid</_li>
<_li>Tabs</_li>
<_li>Drag and drop re-ordering of terminals</_li>
<_li>Lots of keyboard shortcuts</_li>
<_li>Save multiple layouts and profiles via GUI preferences editor</_li>
<_li>Simultaneous typing to arbitrary groups of terminals</_li>
<li translatable="yes">Arrange terminals in a grid</li>
<li translatable="yes">Tabs</li>
<li translatable="yes">Drag and drop re-ordering of terminals</li>
<li translatable="yes">Lots of keyboard shortcuts</li>
<li translatable="yes">Save multiple layouts and profiles via GUI preferences editor</li>
<li translatable="yes">Simultaneous typing to arbitrary groups of terminals</li>
</ul>
<_p>And lots more...</_p>
<p translatable="yes">And lots more...</p>
</description>
<screenshots>
<screenshot type="default">
<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>
<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>
<image>http://2.bp.blogspot.com/-t_8oRyMXUls/VdemmRVnZnI/AAAAAAAAA88/rHIr8L1X7Ho/s1600/terminator_prefs_global.png</image>
<_caption>The preferences window where you can change the defaults</_caption>
<image>http://2.bp.blogspot.com/-t_8oRyMXUls/VdemmRVnZnI/AAAAAAAAA88/rHIr8L1X7Ho/s1600/terminatorprefs_global.png</image>
<caption translatable="yes">The preferences window where you can change the defaults</caption>
</screenshot>
</screenshots>
<url type="homepage">https://github.com/gnome-terminator/terminator</url>

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +0,0 @@
#!/bin/sh
# Update translation files
for po_file in `ls *.po`; do
msgmerge -N -U ${po_file} terminator.pot
done

View File

@ -1,2 +1,7 @@
[aliases]
test=pytest
[extract_messages]
mapping_file = babel.cfg
output_file = po/terminator.pot
input_dirs = .

119
setup.py
View File

@ -16,76 +16,61 @@ import platform
from terminatorlib.version import APP_NAME, APP_VERSION
PO_DIR = 'po'
MO_DIR = os.path.join('build', 'mo')
GETTEXT_SOURCE = 'po'
GETTEXT_DOMAIN = 'terminator'
GETTEXT_TARGET = os.path.join('share', 'locale')
CSS_DIR = os.path.join('terminatorlib', 'themes')
if sys.version_info < (3, 0):
PYTEST_VERSION = '<5'
BABELGLADE_VERSION = '< 0.7'
else:
PYTEST_VERSION = '>0'
BABELGLADE_VERSION = '> 0'
class TerminatorDist(Distribution):
global_options = Distribution.global_options + [
("build-documentation", None, "Build 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")]
def __init__ (self, *args):
self.without_gettext = False
self.without_icon_cache = False
Distribution.__init__(self, *args)
class BuildData(build):
def run (self):
build.run (self)
class CustomBuild(build):
"""
Custom build extensions to build
"""
if not self.distribution.without_gettext:
# Build the translations
for po in glob.glob (os.path.join (PO_DIR, '*.po')):
lang = os.path.basename(po[:-3])
mo = os.path.join(MO_DIR, lang, 'terminator.mo')
def run(self):
build.run(self)
self.build_i18n()
directory = os.path.dirname(mo)
if not os.path.exists(directory):
info('creating %s' % directory)
os.makedirs(directory)
def build_i18n(self):
"""
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]
if newer(po, mo):
info('compiling %s -> %s' % (po, mo))
try:
rc = subprocess.call(['msgfmt', '-o', mo, po])
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)
for po in glob.glob(os.path.join(GETTEXT_SOURCE, '*.po')):
lang = os.path.basename(po[:-3])
mo = os.path.join(self.build_base, GETTEXT_TARGET, lang, 'LC_MESSAGES', 'terminator.mo')
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]
directory = os.path.dirname(mo)
if not os.path.exists(directory):
os.makedirs(directory)
if newer(po, mo):
compiler.input_file = po
compiler.output_file = mo
compiler.run()
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):
description = "Attempt an uninstall from an install --record file"
@ -148,7 +133,7 @@ class Uninstall(Command):
class InstallData(install_data):
def run (self):
self.data_files.extend (self._find_css_files ())
self.data_files.extend (self._find_mo_files ())
self.data_files.extend(self._find_mo_files())
install_data.run (self)
if not self.distribution.without_icon_cache:
self._update_icon_cache ()
@ -161,14 +146,16 @@ class InstallData(install_data):
except Exception as 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 = []
if not self.distribution.without_gettext:
for mo in glob.glob (os.path.join (MO_DIR, '*', 'terminator.mo')):
lang = os.path.basename(os.path.dirname(mo))
dest = os.path.join('share', 'locale', lang, 'LC_MESSAGES')
data_files.append((dest, [mo]))
build_base = self.distribution.command_obj['build'].build_base
for mo in glob.glob(os.path.join(build_base, GETTEXT_TARGET, '*', 'LC_MESSAGES', '*.mo')):
dest = mo.lstrip(build_base + os.sep)
data_files.append((dest, [mo]))
return data_files
@ -183,6 +170,27 @@ class InstallData(install_data):
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']:
man_dir = 'man'
else:
@ -229,6 +237,8 @@ setup(name=APP_NAME,
],
setup_requires=[
'pytest-runner',
'babel',
'BabelGladeExtractor ' + BABELGLADE_VERSION,
],
install_requires=[
'pycairo',
@ -240,6 +250,7 @@ setup(name=APP_NAME,
tests_require=test_deps,
extras_require={'test': test_deps},
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)