-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
2 changed files
with
54 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,10 @@ | ||
#!/usr/bin/python3 | ||
# -*- coding: utf-8 -*- | ||
# | ||
#--------------------------------------------------------- | ||
# Copyright (c) Marko Manninen <[email protected]>, 2017 | ||
#--------------------------------------------------------- | ||
# | ||
# Usage: | ||
# | ||
# entry_points = """ | ||
# [babel.extractors] | ||
|
@@ -15,72 +18,88 @@ | |
# extensions=hyml.ext.babel_extract | ||
# | ||
# to babel.cfg file | ||
# | ||
#----------------------------------------------------------------------- | ||
# LOCALIZATION ROUTINE | ||
#----------------------------------------------------------------------- | ||
# 1. extract messages: | ||
# pybabel extract -F babel.cfg -o messages.pot . | ||
# 2. initialize language file: | ||
# pybabel init -i messages.pot -d translations -l en | ||
# 3. make changes to the language file (manually or via third party app) | ||
# 4. update translation messages: | ||
# pybabel update -i messages.pot -d translations | ||
# 5. compile translations | ||
# pybabel compile -d translations | ||
#----------------------------------------------------------------------- | ||
|
||
import hy, hy.importer as hyi | ||
import itertools | ||
|
||
# special reader macro symbol for translating string less verbose way. | ||
# instead of (_ "message") in hy you can do i"message" as long as you have | ||
# defined: (defreader i [args] `(_ ~@args)) in your program | ||
readermacro = hy.HySymbol("i") | ||
# defined: (defreader i [args] `(_ ~args)) in your program | ||
readermacro, dispatch_reader_macro = hy.HySymbol("i"), hy.HySymbol("dispatch_reader_macro") | ||
|
||
# accepted gettext / babel keywords | ||
keywords = [hy.HySymbol("_"), | ||
hy.HySymbol("gettext"), | ||
hy.HySymbol("ngettext"), | ||
hy.HySymbol("N_"), | ||
hy.HySymbol("lgettext"), | ||
hy.HySymbol("lngettext")] | ||
|
||
# string and int are accepted as gettext messages | ||
def is_message(e): | ||
return not isinstance(e, hy.HySymbol) and (isinstance(e, hy.HyString) or isinstance(e, hy.HyInteger)) | ||
def is_message(expr): | ||
return not isinstance(expr, hy.HySymbol) and (isinstance(expr, hy.HyString) or isinstance(expr, hy.HyInteger)) | ||
|
||
# create message dictionary | ||
def message(e, f): | ||
singular, plural, context = None, None, None | ||
if f == 0: | ||
singular = str(e) | ||
elif f == 1: | ||
plural = str(e) | ||
def message(expr, count): | ||
singular, plural, num = None, None, None | ||
if count == 0: | ||
singular = str(expr) | ||
elif count == 1: | ||
plural = str(expr) | ||
else: | ||
context = int(e) | ||
return {"context":context, "singular":singular, "plural":plural} | ||
num = int(expr) | ||
return {"num":num, "singular":singular, "plural":plural} | ||
|
||
def extract_from_ast(ast): | ||
d, f = None, 0 | ||
def filter_hy(e): | ||
current, count, prev, dispatch = None, 0, None, False | ||
def filter_hy(expr): | ||
# basicly we are searching for babel keyword expressions here | ||
# and when one is found, it is returned along with: | ||
# linenumber, keyword itself, and message string | ||
global d, f | ||
if isinstance(e, hy.HyExpression) or isinstance(e, list): | ||
if isinstance(e, hy.HyExpression): | ||
d, f = e[0], 0 | ||
global current, count, prev, dispatch | ||
if isinstance(expr, hy.HyExpression) or isinstance(expr, list): | ||
if isinstance(expr, hy.HyExpression): | ||
current, count, prev, dispatch = expr[0], 0, None, False | ||
# recursively filter expression so that only gettext and _ parts are returned | ||
x, f = list(itertools.chain(*filter(None, map(filter_hy, e)))), 0 | ||
messages = list(itertools.chain(*filter(None, map(filter_hy, expr)))) | ||
# reset keyword | ||
d = None | ||
return x | ||
if e == readermacro: | ||
d, f = e, 0 | ||
elif is_message(e): | ||
current, count, prev, dispatch = None, 0, None, False | ||
return messages | ||
if expr == readermacro and prev == dispatch_reader_macro: | ||
current, count, dispatch = expr, 0, True | ||
elif is_message(expr): | ||
# reader macro is regarded as singular form gettext function | ||
if d == readermacro: | ||
if current == readermacro and dispatch: | ||
# we dont accept any more argument for gettext / readermacro | ||
d = None | ||
return e.start_line, "gettext", message(e, 0) | ||
current, prev, dispatch = None, None, False | ||
return expr.start_line, "gettext", message(expr, 0) | ||
# possible keys are: | ||
# ngettext, pgettext, ungettext, dngettext, dgettext, ugettext, gettext, _, N_, npgettext | ||
# but only gettext and _ are supported at the moment | ||
if d in keywords: | ||
if current in keywords: | ||
# there are no comments available in ast, thus only three items are returned | ||
# mark singular and plural forms. later in chunks | ||
# plural and singular forms are combined. this is not particularly genious | ||
# way of doing it. other recursive parsing technique could handle everything | ||
# more efficiently | ||
msg = message(e, f) | ||
f += 1 | ||
return e.start_line, str(d), msg | ||
msg = message(expr, count) | ||
count += 1 | ||
return expr.start_line, str(current), msg | ||
prev = expr | ||
return filter_hy(ast) | ||
|
||
# return list of message items | ||
|
@@ -90,7 +109,7 @@ def items(l, i, n): | |
# detect plural and singular forms of messages | ||
def message_form(t1, t2, t3): | ||
if t2 and "plural" in t2[2] and t2[2]["plural"] != None: | ||
return [t1[2]["singular"], t2[2]["plural"], t3[2]["context"]] | ||
return [t1[2]["singular"], t2[2]["plural"], t3[2]["num"]] | ||
else: | ||
return [t1[2]["singular"]] | ||
|
||
|
@@ -104,7 +123,6 @@ def chunks(l, n): | |
|
||
def babel_extract(fileobj, *args, **kw): | ||
byte = fileobj.read() | ||
# unfortunately line breaks (line numbers) are lost at this point... | ||
text = "".join(map(chr, byte)) | ||
node = hyi.import_buffer_to_hst(text) | ||
tpls = extract_from_ast(node) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,13 +17,13 @@ | |
'hyml': ['*.hy'] | ||
}, | ||
|
||
version = 'v0.2.8', | ||
version = 'v0.2.9', | ||
description = 'HyML - XML / (X)HTML generator for Hy', | ||
author = 'Marko Manninen', | ||
author_email = '[email protected]', | ||
|
||
url = 'https://github.com/markomanninen/hyml', | ||
download_url = 'https://github.com/markomanninen/hyml/archive/v0.2.8.tar.gz', | ||
download_url = 'https://github.com/markomanninen/hyml/archive/v0.2.9.tar.gz', | ||
keywords = ['hylang', 'python', 'lisp', 'macros', 'markup language', 'dsl', 'xml', 'html', 'xhtml'], | ||
platforms = ['any'], | ||
|
||
|