1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
|
# This file is part of MyPaint.
# Copyright (C) 2007-2013 by Martin Renold <martinxyz@gmx.ch>
# Copyright (C) 2013-2019 by the MyPaint Development Team.
#
# This program 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 2 of the License, or
# (at your option) any later version.
from __future__ import absolute_import
import os
import sys
import logging
# This imports the global gettext package, not lib/gettext
import gettext
import lib.config as config
logger = logging.getLogger(__file__)
def init_gettext(localepath):
"""Initialize locales and gettext.
This must be done before importing any translated python modules
(to get global strings translated, especially brushsettings.py).
"""
import locale
import lib.i18n
# Required in Windows for the "Region and Language" settings
# to take effect.
lib.i18n.set_i18n_envvars()
lib.i18n.fixup_i18n_envvars()
# Internationalization
# Source of many a problem down the line, so lotsa debugging here.
logger.debug("localepath: %r", localepath)
logger.debug("getdefaultlocale(): %r", lib.i18n.getdefaultlocale())
# Set the user's preferred locale.
# https://docs.python.org/2/library/locale.html
# Required in Windows for the "Region and Language" settings
# to take effect.
try:
setlocale_result = locale.setlocale(locale.LC_ALL, '')
except locale.Error:
logger.exception("setlocale(LC_ALL, '') failed")
else:
logger.debug("setlocale(LC_ALL, ''): %r", setlocale_result)
# More debugging: show the state after setlocale().
logger.debug(
"getpreferredencoding(): %r",
locale.getpreferredencoding(do_setlocale=False),
)
locale_categories = [
s for s in dir(locale)
if s.startswith("LC_") and s != "LC_ALL"
]
for category in sorted(locale_categories):
logger.debug(
"getlocale(%s): %r",
category,
locale.getlocale(getattr(locale, category)),
)
# Low-level bindtextdomain with paths.
# This is still required to hook GtkBuilder up with translated
# strings; the gettext() way doesn't cut it for external stuff
# yanked in over GI.
# https://bugzilla.gnome.org/show_bug.cgi?id=574520#c26
bindtextdomain = None
textdomain = None
# Try the POSIX/Linux way first.
try:
bindtextdomain = locale.bindtextdomain
textdomain = locale.textdomain
except AttributeError:
logger.warning(
"No bindtextdomain builtins found in module 'locale'."
)
logger.info(
"Trying platform-specific fallback hacks to find "
"bindtextdomain funcs.",
)
# Windows Python binaries tend not to expose bindtextdomain and
# its buddies anywhere they can be called.
if sys.platform == 'win32':
libintl = None
import ctypes
libnames = [
'libintl-8.dll', # native for MSYS2's MINGW32
'libintl.dll', # no known cases, but a potential fallback
'intl.dll', # some old recipes off the internet
]
for libname in libnames:
try:
libintl = ctypes.cdll.LoadLibrary(libname)
bindtextdomain = libintl.bindtextdomain
bindtextdomain.argtypes = (
ctypes.c_char_p,
ctypes.c_char_p,
)
bindtextdomain.restype = ctypes.c_char_p
textdomain = libintl.textdomain
textdomain.argtypes = (
ctypes.c_char_p,
)
textdomain.restype = ctypes.c_char_p
except Exception:
logger.exception(
"Windows: attempt to load bindtextdomain funcs "
"from %r failed (ctypes)",
libname,
)
else:
logger.info(
"Windows: found working bindtextdomain funcs "
"in %r (ctypes)",
libname,
)
break
else:
logger.error(
"No platform-specific fallback for locating bindtextdomain "
"is known for %r",
sys.platform,
)
# libmypaint's domain/path must be bound if its messages are not installed
# in a location gettext is configured to look in (system-dependent and
# set at compile time), which don't always include e.g:
# /usr/local/share/locale/ or $HOME/.local/share/locale
# It must also be set here for the appimage, where the path will always
# be the same for libmypaint's and mypaint's message catalogs.
localepath_libmypaint = config.libmypaint_locale_dir
if not localepath_libmypaint:
localepath_libmypaint = localepath
# Bind text domains, i.e. tell libintl+GtkBuilder and Python's where
# to find message catalogs containing translations.
textdomains = [
("mypaint", localepath),
(config.libmypaint_version, localepath_libmypaint),
]
defaultdom = "mypaint"
codeset = "UTF-8"
for dom, path in textdomains:
# Some people choose not to install any translation files.
if not os.path.isdir(path):
logger.warning(
"No translations for %s. Missing locale dir %r.",
dom, path,
)
continue
# Only call the C library gettext setup funcs if there's a
# complete set from the same source.
# Required for translatable strings in GtkBuilder XML
# to be translated.
if bindtextdomain and textdomain:
assert os.path.exists(path)
assert os.path.isdir(path)
if sys.platform == 'win32':
p = bindtextdomain(dom.encode('utf-8'), path.encode('utf-8'))
else:
p = bindtextdomain(dom, path)
logger.debug("C bindtextdomain(%r, %r): %r", dom, path, p)
# Call the implementations in Python's standard gettext module
# too. This has proper cross-platform support, but it only
# initializes the native Python "gettext" module.
# Required for marked strings in Python source to be translated.
# See http://docs.python.org/release/2.7/library/locale.html
p = gettext.bindtextdomain(dom, path)
logger.debug("Python bindtextdomain(%r, %r): %r", dom, path, p)
if bindtextdomain and textdomain:
if sys.platform == 'win32':
d = textdomain(defaultdom.encode('utf-8'))
else:
d = textdomain(defaultdom)
logger.debug("C textdomain(%r): %r", defaultdom, d)
d = gettext.textdomain(defaultdom)
logger.debug("Python textdomain(%r): %r", defaultdom, d)
|