mercurial/i18n.py
author Alexander Plavin <me@aplavin.ru>
Thu, 04 Jul 2013 14:18:44 +0400
changeset 19387 f2e4fdb3dd27
parent 14975 b64538363dbe
child 21746 2d47d81c79fb
permissions -rw-r--r--
hgweb: code selection without line numbers in file source view All the source lines are put in a <pre> tag, which gives correct display and copy&paste in both Chromium (WebKit) and FireFox: line numbers are not copied, all the tabs and spaces are kept. This doesn't change the visual appearance of the view compared to current hgweb version and doesn't use any JS code. Also, stripes in this view are now generated clientside with CSS. This implementation is chosen because other variants have important issues: Strategy FF Chrome current D,LT,E,T,L D,L pre S,NW S,NW pre/div/nbsp LT,E,T,TS,NW TS,NW pre/div/br LT,E,T,NW NW ol/li/nbsp LT,E,T,TS,AJ TS,AJ ol/li/br LT,E,T,AJ AJ pre/span LV LV Legend Strategies: - current: implemented in hgweb before this patch, i.e. divs for each line, and line numbers links in the div too - pre: the whole code in one pre tag with newlines, all line numbers in another one with 'float: left' - pre/div/{nbsp,br}: same as just 'pre', but separate divs for each line and &nbsp; or <br> instead of empty lines (otherwise they are not copied at all) - ol/li/{nbsp,br}: a single ol with li's and divs for each line, &nbsp; or <br> same as in previous strategy - pre/span: this patch Problems: D = (very minor) display problems, like wrong width of leading tabs LT = loses leading/trailing whitespace E = loses embedded whitespace B = loses blank lines T = loses tabs L = selects line numbers LV = (only) visually selects line numbers LVE = (only) visually selects line numbers at empty lines S = no stripes (and no ability to easily highlight lines-which-are-linked-at in the future) TS = space copied instead of empty line AJ = get anchor links only with JS (they work even without) NW = no linewrap easily possible (in future) As for browser versions compatibility, the CSS tricks used are supported in (according to caniuse.com): a) line numbers generation with 'content:' property and CSS counters: IE 8+, all other popular browsers (in pre-WebKit Opera numbers are being copied) b) stripes ('nth-child' selector): IE 8+, FF 3.5+, Safari 3.2+, Opera 9.5+, all other popular browsers c) line numbers are not visually selected ('user-select:' property): IE 10+, Opera 15.0+, all other popular browsers This patch is based on a demo implementation by Martin Geisler <martin@geisler.net>.

# i18n.py - internationalization support for mercurial
#
# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.

import encoding
import gettext, sys, os

# modelled after templater.templatepath:
if getattr(sys, 'frozen', None) is not None:
    module = sys.executable
else:
    module = __file__

base = os.path.dirname(module)
for dir in ('.', '..'):
    localedir = os.path.join(base, dir, 'locale')
    if os.path.isdir(localedir):
        break

t = gettext.translation('hg', localedir, fallback=True)

def gettext(message):
    """Translate message.

    The message is looked up in the catalog to get a Unicode string,
    which is encoded in the local encoding before being returned.

    Important: message is restricted to characters in the encoding
    given by sys.getdefaultencoding() which is most likely 'ascii'.
    """
    # If message is None, t.ugettext will return u'None' as the
    # translation whereas our callers expect us to return None.
    if message is None:
        return message

    paragraphs = message.split('\n\n')
    # Be careful not to translate the empty string -- it holds the
    # meta data of the .po file.
    u = u'\n\n'.join([p and t.ugettext(p) or '' for p in paragraphs])
    try:
        # encoding.tolocal cannot be used since it will first try to
        # decode the Unicode string. Calling u.decode(enc) really
        # means u.encode(sys.getdefaultencoding()).decode(enc). Since
        # the Python encoding defaults to 'ascii', this fails if the
        # translated string use non-ASCII characters.
        return u.encode(encoding.encoding, "replace")
    except LookupError:
        # An unknown encoding results in a LookupError.
        return message

def _plain():
    if 'HGPLAIN' not in os.environ and 'HGPLAINEXCEPT' not in os.environ:
        return False
    exceptions = os.environ.get('HGPLAINEXCEPT', '').strip().split(',')
    return 'i18n' not in exceptions

if _plain():
    _ = lambda message: message
else:
    _ = gettext