From 143147cb8e5322bae99a52f7b77b8f2b079c0d87 Mon Sep 17 00:00:00 2001 From: Andrew Senetar Date: Mon, 28 Mar 2022 00:47:46 -0500 Subject: [PATCH] Remove Cocoa specific and other unused code --- build.py | 7 +- hscommon/build.py | 231 ------------------------------------------- hscommon/debug.py | 23 ----- hscommon/desktop.py | 97 +++++++----------- hscommon/geometry.py | 216 ---------------------------------------- hscommon/loc.py | 118 ---------------------- hscommon/trans.py | 12 --- 7 files changed, 38 insertions(+), 666 deletions(-) delete mode 100644 hscommon/debug.py delete mode 100644 hscommon/geometry.py diff --git a/build.py b/build.py index 9aa9e106..01165deb 100644 --- a/build.py +++ b/build.py @@ -109,10 +109,7 @@ def build_updatepot(): print("Building columns.pot") loc.generate_pot(["core"], Path("locale", "columns.pot"), ["coltr"]) print("Building ui.pot") - # When we're not under OS X, we don't want to overwrite ui.pot because it contains Cocoa locs - # We want to merge the generated pot with the old pot in the most preserving way possible. - ui_packages = ["qt", Path("cocoa", "inter")] - loc.generate_pot(ui_packages, Path("locale", "ui.pot"), ["tr"], merge=True) + loc.generate_pot(["qt"], Path("locale", "ui.pot"), ["tr"], merge=True) print("Building qtlib.pot") loc.generate_pot(["qtlib"], Path("qtlib", "locale", "qtlib.pot"), ["tr"]) @@ -121,13 +118,11 @@ def build_mergepot(): print("Updating .po files using .pot files") loc.merge_pots_into_pos("locale") loc.merge_pots_into_pos(Path("qtlib", "locale")) - # loc.merge_pots_into_pos(Path("cocoalib", "locale")) def build_normpo(): loc.normalize_all_pos("locale") loc.normalize_all_pos(Path("qtlib", "locale")) - # loc.normalize_all_pos(Path("cocoalib", "locale")) def build_pe_modules(): diff --git a/hscommon/build.py b/hscommon/build.py index d4562440..fdb34fea 100644 --- a/hscommon/build.py +++ b/hscommon/build.py @@ -20,13 +20,8 @@ import re import importlib from datetime import datetime import glob -import sysconfig -import modulefinder - -from setuptools import setup, Extension from .plat import ISWINDOWS -from .util import ensure_folder, delete_files_with_pattern def print_and_do(cmd): @@ -181,23 +176,6 @@ def build_dmg(app_path, destfolder): print("Build Complete") -def copy_sysconfig_files_for_embed(destpath): - # This normally shouldn't be needed for Python 3.3+. - makefile = sysconfig.get_makefile_filename() - configh = sysconfig.get_config_h_filename() - shutil.copy(makefile, destpath) - shutil.copy(configh, destpath) - with open(op.join(destpath, "site.py"), "w") as fp: - fp.write( - """ -import os.path as op -from distutils import sysconfig -sysconfig.get_makefile_filename = lambda: op.join(op.dirname(__file__), 'Makefile') -sysconfig.get_config_h_filename = lambda: op.join(op.dirname(__file__), 'pyconfig.h') -""" - ) - - def add_to_pythonpath(path): """Adds ``path`` to both ``PYTHONPATH`` env and ``sys.path``.""" abspath = op.abspath(path) @@ -248,20 +226,6 @@ def copy_packages(packages_names, dest, create_links=False, extra_ignores=None): shutil.copy(source_path, dest_path) -def copy_qt_plugins(folder_names, dest): # This is only for Windows - from PyQt5.QtCore import QLibraryInfo - - qt_plugin_dir = QLibraryInfo.location(QLibraryInfo.PluginsPath) - - def ignore(path, names): - if path == qt_plugin_dir: - return [n for n in names if n not in folder_names] - else: - return [n for n in names if not n.endswith(".dll")] - - shutil.copytree(qt_plugin_dir, dest, ignore=ignore) - - def build_debian_changelog( changelogpath, destfile, @@ -349,183 +313,6 @@ def read_changelog_file(filename): return result -class OSXAppStructure: - def __init__(self, dest): - self.dest = dest - self.contents = op.join(dest, "Contents") - self.macos = op.join(self.contents, "MacOS") - self.resources = op.join(self.contents, "Resources") - self.frameworks = op.join(self.contents, "Frameworks") - self.infoplist = op.join(self.contents, "Info.plist") - - def create(self, infoplist): - ensure_empty_folder(self.dest) - os.makedirs(self.macos) - os.mkdir(self.resources) - os.mkdir(self.frameworks) - copy(infoplist, self.infoplist) - open(op.join(self.contents, "PkgInfo"), "wt").write("APPLxxxx") - - def copy_executable(self, executable): - info = plistlib.readPlist(self.infoplist) - self.executablename = info["CFBundleExecutable"] - self.executablepath = op.join(self.macos, self.executablename) - copy(executable, self.executablepath) - - def copy_resources(self, *resources, use_symlinks=False): - for path in resources: - resource_dest = op.join(self.resources, op.basename(path)) - action = symlink if use_symlinks else copy - action(op.abspath(path), resource_dest) - - def copy_frameworks(self, *frameworks): - for path in frameworks: - framework_dest = op.join(self.frameworks, op.basename(path)) - copy(path, framework_dest) - - -def create_osx_app_structure( - dest, - executable, - infoplist, - resources=None, - frameworks=None, - symlink_resources=False, -): - # `dest`: A path to the destination .app folder - # `executable`: the path of the executable file that goes in "MacOS" - # `infoplist`: The path to your Info.plist file. - # `resources`: A list of paths of files or folders going in the "Resources" folder. - # `frameworks`: Same as above for "Frameworks". - # `symlink_resources`: If True, will symlink resources into the structure instead of copying them. - app = OSXAppStructure(dest) - app.create(infoplist) - app.copy_executable(executable) - app.copy_resources(*resources, use_symlinks=symlink_resources) - app.copy_frameworks(*frameworks) - - -class OSXFrameworkStructure: - def __init__(self, dest): - self.dest = dest - self.contents = op.join(dest, "Versions", "A") - self.resources = op.join(self.contents, "Resources") - self.headers = op.join(self.contents, "Headers") - self.infoplist = op.join(self.resources, "Info.plist") - self._update_executable_path() - - def _update_executable_path(self): - if not op.exists(self.infoplist): - self.executablename = self.executablepath = None - return - info = plistlib.readPlist(self.infoplist) - self.executablename = info["CFBundleExecutable"] - self.executablepath = op.join(self.contents, self.executablename) - - def create(self, infoplist): - ensure_empty_folder(self.dest) - os.makedirs(self.contents) - os.mkdir(self.resources) - os.mkdir(self.headers) - copy(infoplist, self.infoplist) - self._update_executable_path() - - def create_symlinks(self): - # Only call this after create() and copy_executable() - os.symlink("A", op.join(self.dest, "Versions", "Current")) - os.symlink(op.relpath(self.executablepath, self.dest), op.join(self.dest, self.executablename)) - os.symlink(op.relpath(self.headers, self.dest), op.join(self.dest, "Headers")) - os.symlink(op.relpath(self.resources, self.dest), op.join(self.dest, "Resources")) - - def copy_executable(self, executable): - copy(executable, self.executablepath) - - def copy_resources(self, *resources, use_symlinks=False): - for path in resources: - resource_dest = op.join(self.resources, op.basename(path)) - action = symlink if use_symlinks else copy - action(op.abspath(path), resource_dest) - - def copy_headers(self, *headers, use_symlinks=False): - for path in headers: - header_dest = op.join(self.headers, op.basename(path)) - action = symlink if use_symlinks else copy - action(op.abspath(path), header_dest) - - -def copy_embeddable_python_dylib(dst): - runtime = op.join( - sysconfig.get_config_var("PYTHONFRAMEWORKPREFIX"), - sysconfig.get_config_var("LDLIBRARY"), - ) - filedest = op.join(dst, "Python") - shutil.copy(runtime, filedest) - os.chmod(filedest, 0o774) # We need write permission to use install_name_tool - cmd = "install_name_tool -id @rpath/Python %s" % filedest - print_and_do(cmd) - - -def collect_stdlib_dependencies(script, dest_folder, extra_deps=None): - sysprefix = sys.prefix # could be a virtualenv - basesysprefix = sys.base_prefix # seems to be path to non-virtual sys - real_lib_prefix = sysconfig.get_config_var("LIBDEST") # leaving this in case it is neede - - def is_stdlib_path(path): - # A module path is only a stdlib path if it's in either sys.prefix or - # sysconfig.get_config_var('prefix') (the 2 are different if we are in a virtualenv) and if - # there's no "site-package in the path. - if not path: - return False - if "site-package" in path: - return False - if not (path.startswith(sysprefix) or path.startswith(basesysprefix) or path.startswith(real_lib_prefix)): - return False - return True - - ensure_folder(dest_folder) - mf = modulefinder.ModuleFinder() - mf.run_script(script) - modpaths = [mod.__file__ for mod in mf.modules.values()] - modpaths = filter(is_stdlib_path, modpaths) - for p in modpaths: - if p.startswith(real_lib_prefix): - relpath = op.relpath(p, real_lib_prefix) - elif p.startswith(sysprefix): - relpath = op.relpath(p, sysprefix) - assert relpath.startswith("lib/python3.") # we want to get rid of that lib/python3.x part - relpath = relpath[len("lib/python3.X/") :] - elif p.startswith(basesysprefix): - relpath = op.relpath(p, basesysprefix) - assert relpath.startswith("lib/python3.") - relpath = relpath[len("lib/python3.X/") :] - else: - raise AssertionError() - if relpath.startswith("lib-dynload"): # We copy .so files in lib-dynload directly in our dest - relpath = relpath[len("lib-dynload/") :] - if relpath.startswith("encodings") or relpath.startswith("distutils"): - # We force their inclusion later. - continue - dest_path = op.join(dest_folder, relpath) - ensure_folder(op.dirname(dest_path)) - copy(p, dest_path) - # stringprep is used by encodings. - # We use real_lib_prefix with distutils because virtualenv messes with it and we need to refer - # to the original distutils folder. - FORCED_INCLUSION = [ - "encodings", - "stringprep", - op.join(real_lib_prefix, "distutils"), - ] - if extra_deps: - FORCED_INCLUSION += extra_deps - copy_packages(FORCED_INCLUSION, dest_folder) - # There's a couple of rather big exe files in the distutils folder that we absolutely don't - # need. Remove them. - delete_files_with_pattern(op.join(dest_folder, "distutils"), "*.exe") - # And, finally, create an empty "site.py" that Python needs around on startup. - open(op.join(dest_folder, "site.py"), "w").close() - - def fix_qt_resource_file(path): # pyrcc5 under Windows, if the locale is non-english, can produce a source file with a date # containing accented characters. If it does, the encoding is wrong and it prevents the file @@ -537,21 +324,3 @@ def fix_qt_resource_file(path): lines = [line for line in lines if not line.startswith(b"#")] with open(path, "wb") as fp: fp.write(b"\n".join(lines)) - - -def build_cocoa_ext(extname, dest, source_files, extra_frameworks=(), extra_includes=()): - extra_link_args = ["-framework", "CoreFoundation", "-framework", "Foundation"] - for extra in extra_frameworks: - extra_link_args += ["-framework", extra] - ext = Extension( - extname, - source_files, - extra_link_args=extra_link_args, - include_dirs=extra_includes, - ) - setup(script_args=["build_ext", "--inplace"], ext_modules=[ext]) - # Our problem here is to get the fully qualified filename of the resulting .so but I couldn't - # find a documented way to do so. The only thing I could find is this below :( - fn = ext._file_name - assert op.exists(fn) - move(fn, op.join(dest, fn)) diff --git a/hscommon/debug.py b/hscommon/debug.py deleted file mode 100644 index 0046dfe4..00000000 --- a/hscommon/debug.py +++ /dev/null @@ -1,23 +0,0 @@ -# Created By: Virgil Dupras -# Created On: 2011-04-19 -# Copyright 2015 Hardcoded Software (http://www.hardcoded.net) -# -# This software is licensed under the "GPLv3" License as described in the "LICENSE" file, -# which should be included with this package. The terms are also available at -# http://www.gnu.org/licenses/gpl-3.0.html - -import sys -import traceback - - -# Taken from http://bzimmer.ziclix.com/2008/12/17/python-thread-dumps/ -def stacktraces(): - code = [] - for thread_id, stack in sys._current_frames().items(): - code.append("\n# ThreadID: %s" % thread_id) - for filename, lineno, name, line in traceback.extract_stack(stack): - code.append('File: "%s", line %d, in %s' % (filename, lineno, name)) - if line: - code.append(" %s" % (line.strip())) - - return "\n".join(code) diff --git a/hscommon/desktop.py b/hscommon/desktop.py index 945a5fed..c468ccaa 100644 --- a/hscommon/desktop.py +++ b/hscommon/desktop.py @@ -42,73 +42,50 @@ def special_folder_path(special_folder, appname=None, portable=False): try: - # Normally, we would simply do "from cocoa import proxy", but due to a bug in pytest (currently - # at v2.4.2), our test suite is broken when we do that. This below is a workaround until that - # bug is fixed. - import cocoa + from PyQt5.QtCore import QUrl, QStandardPaths + from PyQt5.QtGui import QDesktopServices + from qtlib.util import get_appdata + from core.util import executable_folder + from hscommon.plat import ISWINDOWS, ISOSX + import subprocess - if not hasattr(cocoa, "proxy"): - raise ImportError() - proxy = cocoa.proxy - _open_url = proxy.openURL_ - _open_path = proxy.openPath_ - _reveal_path = proxy.revealPath_ + def _open_url(url): + QDesktopServices.openUrl(QUrl(url)) + + def _open_path(path): + url = QUrl.fromLocalFile(str(path)) + QDesktopServices.openUrl(url) + + def _reveal_path(path): + if ISWINDOWS: + subprocess.run(["explorer", "/select,", op.abspath(path)]) + elif ISOSX: + subprocess.run(["open", "-R", op.abspath(path)]) + else: + _open_path(op.dirname(str(path))) def _special_folder_path(special_folder, appname=None, portable=False): if special_folder == SpecialFolder.CACHE: - base = proxy.getCachePath() + if ISWINDOWS and portable: + folder = op.join(executable_folder(), "cache") + else: + folder = QStandardPaths.standardLocations(QStandardPaths.CacheLocation)[0] else: - base = proxy.getAppdataPath() - if not appname: - appname = proxy.bundleInfo_("CFBundleName") - return op.join(base, appname) + folder = get_appdata(portable) + return folder except ImportError: - try: - from PyQt5.QtCore import QUrl, QStandardPaths - from PyQt5.QtGui import QDesktopServices - from qtlib.util import get_appdata - from core.util import executable_folder - from hscommon.plat import ISWINDOWS, ISOSX - import subprocess + # We're either running tests, and these functions don't matter much or we're in a really + # weird situation. Let's just have dummy fallbacks. + logging.warning("Can't setup desktop functions!") - def _open_url(url): - QDesktopServices.openUrl(QUrl(url)) + def _open_path(path): + # Dummy for tests + pass - def _open_path(path): - url = QUrl.fromLocalFile(str(path)) - QDesktopServices.openUrl(url) + def _reveal_path(path): + # Dummy for tests + pass - def _reveal_path(path): - if ISWINDOWS: - subprocess.run(["explorer", "/select,", op.abspath(path)]) - elif ISOSX: - subprocess.run(["open", "-R", op.abspath(path)]) - else: - _open_path(op.dirname(str(path))) - - def _special_folder_path(special_folder, appname=None, portable=False): - if special_folder == SpecialFolder.CACHE: - if ISWINDOWS and portable: - folder = op.join(executable_folder(), "cache") - else: - folder = QStandardPaths.standardLocations(QStandardPaths.CacheLocation)[0] - else: - folder = get_appdata(portable) - return folder - - except ImportError: - # We're either running tests, and these functions don't matter much or we're in a really - # weird situation. Let's just have dummy fallbacks. - logging.warning("Can't setup desktop functions!") - - def _open_path(path): - # Dummy for tests - pass - - def _reveal_path(path): - # Dummy for tests - pass - - def _special_folder_path(special_folder, appname=None, portable=False): - return "/tmp" + def _special_folder_path(special_folder, appname=None, portable=False): + return "/tmp" diff --git a/hscommon/geometry.py b/hscommon/geometry.py deleted file mode 100644 index adcb98e8..00000000 --- a/hscommon/geometry.py +++ /dev/null @@ -1,216 +0,0 @@ -# Created By: Virgil Dupras -# Created On: 2011-08-05 -# Copyright 2015 Hardcoded Software (http://www.hardcoded.net) -# -# This software is licensed under the "GPLv3" License as described in the "LICENSE" file, -# which should be included with this package. The terms are also available at -# http://www.gnu.org/licenses/gpl-3.0.html - -from sys import maxsize as INF -from math import sqrt - -VERY_SMALL = 0.0000001 - - -class Point: - def __init__(self, x, y): - self.x = x - self.y = y - - def __repr__(self): - return "".format(*self) - - def __iter__(self): - yield self.x - yield self.y - - def distance_to(self, other): - return Line(self, other).length() - - -class Line: - def __init__(self, p1, p2): - self.p1 = p1 - self.p2 = p2 - - def __repr__(self): - return "".format(*self) - - def __iter__(self): - yield self.p1 - yield self.p2 - - def dx(self): - return self.p2.x - self.p1.x - - def dy(self): - return self.p2.y - self.p1.y - - def length(self): - return sqrt(self.dx() ** 2 + self.dy() ** 2) - - def slope(self): - if self.dx() == 0: - return INF if self.dy() > 0 else -INF - else: - return self.dy() / self.dx() - - def intersection_point(self, other): - # with help from http://paulbourke.net/geometry/lineline2d/ - if abs(self.slope() - other.slope()) < VERY_SMALL: - # parallel. Even if coincident, we return nothing - return None - - A, B = self - C, D = other - - denom = (D.y - C.y) * (B.x - A.x) - (D.x - C.x) * (B.y - A.y) - if denom == 0: - return None - numera = (D.x - C.x) * (A.y - C.y) - (D.y - C.y) * (A.x - C.x) - numerb = (B.x - A.x) * (A.y - C.y) - (B.y - A.y) * (A.x - C.x) - - mua = numera / denom - mub = numerb / denom - if (0 <= mua <= 1) and (0 <= mub <= 1): - x = A.x + mua * (B.x - A.x) - y = A.y + mua * (B.y - A.y) - return Point(x, y) - else: - return None - - -class Rect: - def __init__(self, x, y, w, h): - self.x = x - self.y = y - self.w = w - self.h = h - - def __iter__(self): - yield self.x - yield self.y - yield self.w - yield self.h - - def __repr__(self): - return "".format(*self) - - @classmethod - def from_center(cls, center, width, height): - x = center.x - width / 2 - y = center.y - height / 2 - return cls(x, y, width, height) - - @classmethod - def from_corners(cls, pt1, pt2): - x1, y1 = pt1 - x2, y2 = pt2 - return cls(min(x1, x2), min(y1, y2), abs(x1 - x2), abs(y1 - y2)) - - def center(self): - return Point(self.x + self.w / 2, self.y + self.h / 2) - - def contains_point(self, point): - x, y = point - (x1, y1), (x2, y2) = self.corners() - return (x1 <= x <= x2) and (y1 <= y <= y2) - - def contains_rect(self, rect): - pt1, pt2 = rect.corners() - return self.contains_point(pt1) and self.contains_point(pt2) - - def corners(self): - return Point(self.x, self.y), Point(self.x + self.w, self.y + self.h) - - def intersects(self, other): - r1pt1, r1pt2 = self.corners() - r2pt1, r2pt2 = other.corners() - if r1pt1.x < r2pt1.x: - xinter = r1pt2.x >= r2pt1.x - else: - xinter = r2pt2.x >= r1pt1.x - if not xinter: - return False - if r1pt1.y < r2pt1.y: - yinter = r1pt2.y >= r2pt1.y - else: - yinter = r2pt2.y >= r1pt1.y - return yinter - - def lines(self): - pt1, pt4 = self.corners() - pt2 = Point(pt4.x, pt1.y) - pt3 = Point(pt1.x, pt4.y) - l1 = Line(pt1, pt2) - l2 = Line(pt2, pt4) - l3 = Line(pt3, pt4) - l4 = Line(pt1, pt3) - return l1, l2, l3, l4 - - def scaled_rect(self, dx, dy): - """Returns a rect that has the same borders at self, but grown/shrunk by dx/dy on each side.""" - x, y, w, h = self - x -= dx - y -= dy - w += dx * 2 - h += dy * 2 - return Rect(x, y, w, h) - - def united(self, other): - """Returns the bounding rectangle of this rectangle and `other`.""" - # ul=upper left lr=lower right - ulcorner1, lrcorner1 = self.corners() - ulcorner2, lrcorner2 = other.corners() - corner1 = Point(min(ulcorner1.x, ulcorner2.x), min(ulcorner1.y, ulcorner2.y)) - corner2 = Point(max(lrcorner1.x, lrcorner2.x), max(lrcorner1.y, lrcorner2.y)) - return Rect.from_corners(corner1, corner2) - - # --- Properties - @property - def top(self): - return self.y - - @top.setter - def top(self, value): - self.y = value - - @property - def bottom(self): - return self.y + self.h - - @bottom.setter - def bottom(self, value): - self.y = value - self.h - - @property - def left(self): - return self.x - - @left.setter - def left(self, value): - self.x = value - - @property - def right(self): - return self.x + self.w - - @right.setter - def right(self, value): - self.x = value - self.w - - @property - def width(self): - return self.w - - @width.setter - def width(self, value): - self.w = value - - @property - def height(self): - return self.h - - @height.setter - def height(self, value): - self.h = value diff --git a/hscommon/loc.py b/hscommon/loc.py index 7287918b..35d0d765 100644 --- a/hscommon/loc.py +++ b/hscommon/loc.py @@ -1,14 +1,11 @@ import os import os.path as op import shutil -import re import tempfile import polib from . import pygettext -from .util import modified_after, dedupe, ensure_folder -from .build import print_and_do, ensure_empty_folder LC_MESSAGES = "LC_MESSAGES" @@ -116,118 +113,3 @@ def normalize_all_pos(base_folder): for pofile in pofiles: p = polib.pofile(pofile) p.save() - - -# --- Cocoa -def all_lproj_paths(folder): - return files_with_ext(folder, ".lproj") - - -def escape_cocoa_strings(s): - return s.replace("\\", "\\\\").replace('"', '\\"').replace("\n", "\\n") - - -def unescape_cocoa_strings(s): - return s.replace("\\\\", "\\").replace('\\"', '"').replace("\\n", "\n") - - -def strings2pot(target, dest): - with open(target, "rt", encoding="utf-8") as fp: - contents = fp.read() - # We're reading an en.lproj file. We only care about the righthand part of the translation. - re_trans = re.compile(r'".*" = "(.*)";') - strings = re_trans.findall(contents) - if op.exists(dest): - po = polib.pofile(dest) - else: - po = polib.POFile() - for s in dedupe(strings): - s = unescape_cocoa_strings(s) - entry = po.find(s) - if entry is None: - entry = polib.POEntry(msgid=s) - po.append(entry) - # we don't know or care about a line number so we put 0 - entry.occurrences.append((target, "0")) - entry.occurrences = dedupe(entry.occurrences) - po.save(dest) - - -def allstrings2pot(lprojpath, dest, excludes=None): - allstrings = files_with_ext(lprojpath, STRING_EXT) - if excludes: - allstrings = [p for p in allstrings if op.splitext(op.basename(p))[0] not in excludes] - for strings_path in allstrings: - strings2pot(strings_path, dest) - - -def po2strings(pofile, en_strings, dest): - # Takes en_strings and replace all righthand parts of "foo" = "bar"; entries with translations - # in pofile, then puts the result in dest. - po = polib.pofile(pofile) - if not modified_after(pofile, dest): - return - ensure_folder(op.dirname(dest)) - print("Creating {} from {}".format(dest, pofile)) - with open(en_strings, "rt", encoding="utf-8") as fp: - contents = fp.read() - re_trans = re.compile(r'(?<= = ").*(?=";\n)') - - def repl(match): - s = match.group(0) - unescaped = unescape_cocoa_strings(s) - entry = po.find(unescaped) - if entry is None: - print("WARNING: Could not find entry '{}' in .po file".format(s)) - return s - trans = entry.msgstr - return escape_cocoa_strings(trans) if trans else s - - contents = re_trans.sub(repl, contents) - with open(dest, "wt", encoding="utf-8") as fp: - fp.write(contents) - - -def generate_cocoa_strings_from_code(code_folder, dest_folder): - # Uses the "genstrings" command to generate strings file from all .m files in "code_folder". - # The strings file (their name depends on the localization table used in the source) will be - # placed in "dest_folder". - # genstrings produces utf-16 files with comments. After having generated the files, we convert - # them to utf-8 and remove the comments. - ensure_empty_folder(dest_folder) - print_and_do('genstrings -o "{}" `find "{}" -name *.m | xargs`'.format(dest_folder, code_folder)) - for stringsfile in os.listdir(dest_folder): - stringspath = op.join(dest_folder, stringsfile) - with open(stringspath, "rt", encoding="utf-16") as fp: - content = fp.read() - content = re.sub(r"/\*.*?\*/", "", content) - content = re.sub(r"\n{2,}", "\n", content) - # I have no idea why, but genstrings seems to have problems with "%" character in strings - # and inserts (number)$ after it. Find these bogus inserts and remove them. - content = re.sub(r"%\d\$", "%", content) - with open(stringspath, "wt", encoding="utf-8") as fp: - fp.write(content) - - -def generate_cocoa_strings_from_xib(xib_folder): - xibs = [op.join(xib_folder, fn) for fn in os.listdir(xib_folder) if fn.endswith(".xib")] - for xib in xibs: - dest = xib.replace(".xib", STRING_EXT) - print_and_do("ibtool {} --generate-strings-file {}".format(xib, dest)) - print_and_do("iconv -f utf-16 -t utf-8 {0} | tee {0}".format(dest)) - - -def localize_stringsfile(stringsfile, dest_root_folder): - stringsfile_name = op.basename(stringsfile) - for lang in get_langs("locale"): - pofile = op.join("locale", lang, "LC_MESSAGES", "ui.po") - cocoa_lang = PO2COCOA.get(lang, lang) - dest_lproj = op.join(dest_root_folder, cocoa_lang + ".lproj") - ensure_folder(dest_lproj) - po2strings(pofile, stringsfile, op.join(dest_lproj, stringsfile_name)) - - -def localize_all_stringsfiles(src_folder, dest_root_folder): - stringsfiles = [op.join(src_folder, fn) for fn in os.listdir(src_folder) if fn.endswith(STRING_EXT)] - for path in stringsfiles: - localize_stringsfile(path, dest_root_folder) diff --git a/hscommon/trans.py b/hscommon/trans.py index 69bff565..7767f7be 100644 --- a/hscommon/trans.py +++ b/hscommon/trans.py @@ -129,18 +129,6 @@ def install_gettext_trans(base_folder, lang): installed_lang = lang -def install_gettext_trans_under_cocoa(): - from cocoa import proxy - - res_folder = proxy.getResourcePath() - base_folder = op.join(res_folder, "locale") - current_lang = proxy.systemLang() - install_gettext_trans(base_folder, current_lang) - localename = get_locale_name(current_lang) - if localename is not None: - locale.setlocale(locale.LC_ALL, localename) - - def install_gettext_trans_under_qt(base_folder, lang=None): # So, we install the gettext locale, great, but we also should try to install qt_*.qm if # available so that strings that are inside Qt itself over which I have no control are in the