Cleanup make_translation.py (PEP8, Python3, etc.)
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
# coding=utf-8
|
# coding=utf-8
|
||||||
def getFontMap():
|
def get_font_map():
|
||||||
font = {
|
font = {
|
||||||
" ": "0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,",
|
" ": "0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,",
|
||||||
"!": "0x00,0x00,0x00,0x00,0x7C,0xFF,0xFF,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x33,0x00,0x00,0x00,0x00,0x00,",
|
"!": "0x00,0x00,0x00,0x00,0x7C,0xFF,0xFF,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x33,0x00,0x00,0x00,0x00,0x00,",
|
||||||
@@ -414,7 +414,7 @@ def getFontMap():
|
|||||||
return font
|
return font
|
||||||
|
|
||||||
|
|
||||||
def getSmallFontMap():
|
def get_small_font_map():
|
||||||
font = {
|
font = {
|
||||||
" ": "0x00, 0x00, 0x00, 0x00, 0x00, 0x00,",
|
" ": "0x00, 0x00, 0x00, 0x00, 0x00, 0x00,",
|
||||||
"!": "0x00, 0x00, 0x4f, 0x00, 0x00, 0x00,",
|
"!": "0x00, 0x00, 0x4f, 0x00, 0x00, 0x00,",
|
||||||
@@ -1,218 +1,199 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# coding=utf-8
|
|
||||||
from __future__ import print_function
|
|
||||||
import argparse
|
import argparse
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import io
|
|
||||||
import functools
|
import functools
|
||||||
from datetime import datetime
|
import json
|
||||||
import sys
|
import logging
|
||||||
import fontTables
|
import os
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from datetime import datetime
|
||||||
|
from itertools import chain
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Dict, List, TextIO, Tuple, Union
|
||||||
|
|
||||||
HERE = os.path.dirname(__file__)
|
from bdflib import reader as bdfreader
|
||||||
|
from bdflib.model import Font, Glyph
|
||||||
|
|
||||||
try:
|
import font_tables
|
||||||
to_unicode = unicode
|
|
||||||
except NameError:
|
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
|
||||||
to_unicode = str
|
|
||||||
|
HERE = Path(__file__).resolve().parent
|
||||||
|
|
||||||
|
|
||||||
@functools.lru_cache(maxsize=None)
|
@functools.lru_cache(maxsize=None)
|
||||||
def cjkFont():
|
def cjk_font() -> Font:
|
||||||
from bdflib import reader as bdfreader
|
|
||||||
|
|
||||||
with open(os.path.join(HERE, "wqy-bitmapsong/wenquanyi_9pt.bdf"), "rb") as f:
|
with open(os.path.join(HERE, "wqy-bitmapsong/wenquanyi_9pt.bdf"), "rb") as f:
|
||||||
return bdfreader.read_bdf(f)
|
return bdfreader.read_bdf(f)
|
||||||
|
|
||||||
|
|
||||||
def log(message):
|
|
||||||
print(message, file=sys.stdout)
|
|
||||||
|
|
||||||
|
|
||||||
# Loading a single JSON file
|
# Loading a single JSON file
|
||||||
def loadJson(fileName, skipFirstLine):
|
def load_json(filename: str, skip_first_line: bool) -> dict:
|
||||||
with io.open(fileName, mode="r", encoding="utf-8") as f:
|
with open(filename) as f:
|
||||||
if skipFirstLine:
|
if skip_first_line:
|
||||||
f.readline()
|
f.readline()
|
||||||
|
return json.loads(f.read())
|
||||||
obj = json.loads(f.read())
|
|
||||||
|
|
||||||
return obj
|
|
||||||
|
|
||||||
|
|
||||||
def readTranslation(jsonDir, langCode):
|
def read_translation(json_root: Union[str, Path], lang_code: str) -> dict:
|
||||||
fileName = "translation_{}.json".format(langCode)
|
filename = f"translation_{lang_code}.json"
|
||||||
|
|
||||||
fileWithPath = os.path.join(jsonDir, fileName)
|
file_with_path = os.path.join(json_root, filename)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
lang = loadJson(fileWithPath, False)
|
lang = load_json(file_with_path, skip_first_line=False)
|
||||||
except json.decoder.JSONDecodeError as e:
|
except json.decoder.JSONDecodeError as e:
|
||||||
log("Failed to decode " + fileName)
|
logging.error(f"Failed to decode {filename}")
|
||||||
log(str(e))
|
logging.exception(str(e))
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
|
||||||
# Extract lang code from file name
|
validate_langcode_matches_content(filename, lang)
|
||||||
langCode = fileName[12:-5].upper()
|
|
||||||
# ...and the one specified in the JSON file...
|
|
||||||
try:
|
|
||||||
langCodeFromJson = lang["languageCode"]
|
|
||||||
except KeyError:
|
|
||||||
langCodeFromJson = "(missing)"
|
|
||||||
|
|
||||||
# ...cause they should be the same!
|
|
||||||
if langCode != langCodeFromJson:
|
|
||||||
raise ValueError(
|
|
||||||
"Invalid languageCode " + langCodeFromJson + " in file " + fileName
|
|
||||||
)
|
|
||||||
|
|
||||||
return lang
|
return lang
|
||||||
|
|
||||||
|
|
||||||
def writeStart(f):
|
def validate_langcode_matches_content(filename: str, content: dict) -> None:
|
||||||
f.write(
|
# Extract lang code from file name
|
||||||
to_unicode(
|
lang_code = filename[12:-5].upper()
|
||||||
"""// WARNING: THIS FILE WAS AUTO GENERATED BY make_translation.py. PLEASE DO NOT EDIT.
|
# ...and the one specified in the JSON file...
|
||||||
|
try:
|
||||||
|
lang_code_from_json = content["languageCode"]
|
||||||
|
except KeyError:
|
||||||
|
lang_code_from_json = "(missing)"
|
||||||
|
|
||||||
#include "Translation.h"
|
# ...cause they should be the same!
|
||||||
"""
|
if lang_code != lang_code_from_json:
|
||||||
)
|
raise ValueError(f"Invalid languageCode {lang_code_from_json} in file {filename}")
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def escapeC(s):
|
def write_start(f: TextIO):
|
||||||
return s.replace('"', '\\"')
|
f.write("// WARNING: THIS FILE WAS AUTO GENERATED BY make_translation.py. PLEASE DO NOT EDIT.\n")
|
||||||
|
f.write("\n")
|
||||||
|
f.write('#include "Translation.h"\n')
|
||||||
|
|
||||||
|
|
||||||
def getConstants():
|
def get_constants() -> List[str]:
|
||||||
# Extra constants that are used in the firmware that are shared across all languages
|
# Extra constants that are used in the firmware that are shared across all languages
|
||||||
consants = []
|
return [
|
||||||
consants.append(("SymbolPlus", "+"))
|
("SymbolPlus", "+"),
|
||||||
consants.append(("SymbolMinus", "-"))
|
("SymbolMinus", "-"),
|
||||||
consants.append(("SymbolSpace", " "))
|
("SymbolSpace", " "),
|
||||||
consants.append(("SymbolDot", "."))
|
("SymbolDot", "."),
|
||||||
consants.append(("SymbolDegC", "C"))
|
("SymbolDegC", "C"),
|
||||||
consants.append(("SymbolDegF", "F"))
|
("SymbolDegF", "F"),
|
||||||
consants.append(("SymbolMinutes", "M"))
|
("SymbolMinutes", "M"),
|
||||||
consants.append(("SymbolSeconds", "S"))
|
("SymbolSeconds", "S"),
|
||||||
consants.append(("SymbolWatts", "W"))
|
("SymbolWatts", "W"),
|
||||||
consants.append(("SymbolVolts", "V"))
|
("SymbolVolts", "V"),
|
||||||
consants.append(("SymbolDC", "DC"))
|
("SymbolDC", "DC"),
|
||||||
consants.append(("SymbolCellCount", "S"))
|
("SymbolCellCount", "S"),
|
||||||
consants.append(("SymbolVersionNumber", buildVersion))
|
("SymbolVersionNumber", buildVersion)
|
||||||
return consants
|
]
|
||||||
|
|
||||||
|
|
||||||
def getDebugMenu():
|
def get_debug_menu() -> List[str]:
|
||||||
constants = []
|
return [
|
||||||
constants.append(datetime.today().strftime("%d-%m-%y"))
|
datetime.today().strftime("%d-%m-%y"),
|
||||||
constants.append("HW G ") # High Water marker for GUI task
|
"HW G ",
|
||||||
constants.append("HW M ") # High Water marker for MOV task
|
"HW M ",
|
||||||
constants.append("HW P ") # High Water marker for PID task
|
"HW P ",
|
||||||
constants.append("Time ") # Uptime (aka timestamp)
|
"Time ",
|
||||||
constants.append("Move ") # Time of last significant movement
|
"Move ",
|
||||||
constants.append("RTip ") # Tip reading in uV
|
"RTip ",
|
||||||
constants.append("CTip ") # Tip temp in C
|
"CTip ",
|
||||||
constants.append("CHan ") # Handle temp in C
|
"CHan ",
|
||||||
constants.append("Vin ") # Input voltage
|
"Vin ",
|
||||||
constants.append("PCB ") # PCB Version AKA IMU version
|
"PCB ",
|
||||||
constants.append("PWR ") # Power Negotiation State
|
"PWR ",
|
||||||
constants.append("Max ") # Max deg C limit
|
"Max "
|
||||||
|
]
|
||||||
return constants
|
|
||||||
|
|
||||||
|
|
||||||
def getLetterCounts(defs, lang):
|
def get_letter_counts(defs: dict, lang: dict) -> List[str]:
|
||||||
textList = []
|
text_list = []
|
||||||
# iterate over all strings
|
# iterate over all strings
|
||||||
obj = lang["menuOptions"]
|
obj = lang["menuOptions"]
|
||||||
for mod in defs["menuOptions"]:
|
for mod in defs["menuOptions"]:
|
||||||
eid = mod["id"]
|
eid = mod["id"]
|
||||||
textList.append(obj[eid]["desc"])
|
text_list.append(obj[eid]["desc"])
|
||||||
|
|
||||||
obj = lang["messages"]
|
obj = lang["messages"]
|
||||||
for mod in defs["messages"]:
|
for mod in defs["messages"]:
|
||||||
eid = mod["id"]
|
eid = mod["id"]
|
||||||
if eid not in obj:
|
if eid not in obj:
|
||||||
textList.append(mod["default"])
|
text_list.append(mod["default"])
|
||||||
else:
|
else:
|
||||||
textList.append(obj[eid])
|
text_list.append(obj[eid])
|
||||||
|
|
||||||
obj = lang["characters"]
|
obj = lang["characters"]
|
||||||
|
|
||||||
for mod in defs["characters"]:
|
for mod in defs["characters"]:
|
||||||
eid = mod["id"]
|
eid = mod["id"]
|
||||||
textList.append(obj[eid])
|
text_list.append(obj[eid])
|
||||||
|
|
||||||
obj = lang["menuOptions"]
|
obj = lang["menuOptions"]
|
||||||
for mod in defs["menuOptions"]:
|
for mod in defs["menuOptions"]:
|
||||||
eid = mod["id"]
|
eid = mod["id"]
|
||||||
textList.append(obj[eid]["text2"][0])
|
text_list.append(obj[eid]["text2"][0])
|
||||||
textList.append(obj[eid]["text2"][1])
|
text_list.append(obj[eid]["text2"][1])
|
||||||
|
|
||||||
obj = lang["menuGroups"]
|
obj = lang["menuGroups"]
|
||||||
for mod in defs["menuGroups"]:
|
for mod in defs["menuGroups"]:
|
||||||
eid = mod["id"]
|
eid = mod["id"]
|
||||||
textList.append(obj[eid]["text2"][0])
|
text_list.append(obj[eid]["text2"][0])
|
||||||
textList.append(obj[eid]["text2"][1])
|
text_list.append(obj[eid]["text2"][1])
|
||||||
|
|
||||||
obj = lang["menuGroups"]
|
obj = lang["menuGroups"]
|
||||||
for mod in defs["menuGroups"]:
|
for mod in defs["menuGroups"]:
|
||||||
eid = mod["id"]
|
eid = mod["id"]
|
||||||
textList.append(obj[eid]["desc"])
|
text_list.append(obj[eid]["desc"])
|
||||||
constants = getConstants()
|
constants = get_constants()
|
||||||
for x in constants:
|
for x in constants:
|
||||||
textList.append(x[1])
|
text_list.append(x[1])
|
||||||
textList.extend(getDebugMenu())
|
text_list.extend(get_debug_menu())
|
||||||
|
|
||||||
# collapse all strings down into the composite letters and store totals for these
|
# collapse all strings down into the composite letters and store totals for these
|
||||||
|
|
||||||
symbolCounts = {}
|
symbol_counts: dict[str, int] = {}
|
||||||
for line in textList:
|
for line in text_list:
|
||||||
line = line.replace("\n", "").replace("\r", "")
|
line = line.replace("\n", "").replace("\r", "")
|
||||||
line = line.replace("\\n", "").replace("\\r", "")
|
line = line.replace("\\n", "").replace("\\r", "")
|
||||||
if len(line):
|
if line:
|
||||||
# print(line)
|
|
||||||
for letter in line:
|
for letter in line:
|
||||||
symbolCounts[letter] = symbolCounts.get(letter, 0) + 1
|
symbol_counts[letter] = symbol_counts.get(letter, 0) + 1
|
||||||
symbolCounts = sorted(
|
symbols_by_occurrence = sorted(symbol_counts.items(), key=lambda kv: (kv[1], kv[0]))
|
||||||
symbolCounts.items(), key=lambda kv: (kv[1], kv[0])
|
# swap to Big -> little sort order
|
||||||
) # swap to Big -> little sort order
|
symbols_by_occurrence = [x[0] for x in symbols_by_occurrence]
|
||||||
symbolCounts = list(map(lambda x: x[0], symbolCounts))
|
symbols_by_occurrence.reverse()
|
||||||
symbolCounts.reverse()
|
return symbols_by_occurrence
|
||||||
return symbolCounts
|
|
||||||
|
|
||||||
|
|
||||||
def getCJKGlyph(sym):
|
def get_cjk_glyph(sym: str) -> str:
|
||||||
from bdflib.model import Glyph
|
glyph: Glyph = cjk_font()[ord(sym)]
|
||||||
|
|
||||||
try:
|
|
||||||
glyph: Glyph = cjkFont()[ord(sym)]
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
data = glyph.data
|
data = glyph.data
|
||||||
(srcLeft, srcBottom, srcW, srcH) = glyph.get_bounding_box()
|
src_left, src_bottom, src_w, src_h = glyph.get_bounding_box()
|
||||||
dstW = 12
|
dst_w = 12
|
||||||
dstH = 16
|
dst_h = 16
|
||||||
|
|
||||||
# The source data is a per-row list of ints. The first item is the bottom-
|
# The source data is a per-row list of ints. The first item is the bottom-
|
||||||
# most row. For each row, the LSB is the right-most pixel.
|
# most row. For each row, the LSB is the right-most pixel.
|
||||||
# Here, (x, y) is the coordinates with origin at the top-left.
|
# Here, (x, y) is the coordinates with origin at the top-left.
|
||||||
def getCell(x, y):
|
def get_cell(x: int, y: int) -> bool:
|
||||||
# Adjust x coordinates by actual bounding box.
|
# Adjust x coordinates by actual bounding box.
|
||||||
adjX = x - srcLeft
|
adj_x = x - src_left
|
||||||
if adjX < 0 or adjX >= srcW:
|
if adj_x < 0 or adj_x >= src_w:
|
||||||
return False
|
return False
|
||||||
# Adjust y coordinates by actual bounding box, then place the glyph
|
# Adjust y coordinates by actual bounding box, then place the glyph
|
||||||
# baseline 3px above the bottom edge to make it centre-ish.
|
# baseline 3px above the bottom edge to make it centre-ish.
|
||||||
# This metric is optimized for WenQuanYi Bitmap Song 9pt and assumes
|
# This metric is optimized for WenQuanYi Bitmap Song 9pt and assumes
|
||||||
# each glyph is to be placed in a 12x12px box.
|
# each glyph is to be placed in a 12x12px box.
|
||||||
adjY = y - (dstH - srcH - srcBottom - 3)
|
adj_y = y - (dst_h - src_h - src_bottom - 3)
|
||||||
if adjY < 0 or adjY >= srcH:
|
if adj_y < 0 or adj_y >= src_h:
|
||||||
return False
|
return False
|
||||||
if data[srcH - adjY - 1] & (1 << (srcW - adjX - 1)):
|
if data[src_h - adj_y - 1] & (1 << (src_w - adj_x - 1)):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
@@ -224,20 +205,20 @@ def getCJKGlyph(sym):
|
|||||||
# bottom half.
|
# bottom half.
|
||||||
s = ""
|
s = ""
|
||||||
for block in range(2):
|
for block in range(2):
|
||||||
for c in range(dstW):
|
for c in range(dst_w):
|
||||||
b = 0
|
b = 0
|
||||||
for r in range(8):
|
for r in range(8):
|
||||||
if getCell(c, r + 8 * block):
|
if get_cell(c, r + 8 * block):
|
||||||
b |= 0x01 << r
|
b |= 0x01 << r
|
||||||
s += f"0x{b:02X},"
|
s += f"0x{b:02X},"
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
def getCharsFromFontIndex(index: int) -> str:
|
def get_chars_from_font_index(index: int) -> str:
|
||||||
'''
|
"""
|
||||||
Converts the font table index into its corresponding string escape
|
Converts the font table index into its corresponding string escape
|
||||||
sequence(s).
|
sequence(s).
|
||||||
'''
|
"""
|
||||||
|
|
||||||
# We want to be able to use more than 254 symbols (excluding \x00 null
|
# We want to be able to use more than 254 symbols (excluding \x00 null
|
||||||
# terminator and \x01 new-line) in the font table but without making all
|
# terminator and \x01 new-line) in the font table but without making all
|
||||||
@@ -266,159 +247,144 @@ def getCharsFromFontIndex(index: int) -> str:
|
|||||||
# ...
|
# ...
|
||||||
# 0xFF 0xFF => 15 * 0xFF - 15 + 255 = 4065
|
# 0xFF 0xFF => 15 * 0xFF - 15 + 255 = 4065
|
||||||
|
|
||||||
assert index >= 0
|
if index < 0:
|
||||||
page = int((index + 14) / 0xFF)
|
raise ValueError("index must be positive")
|
||||||
assert page <= 0x0F
|
page = (index + 0x0E) // 0xFF
|
||||||
|
if page > 0x0F:
|
||||||
|
raise ValueError("page value out of range")
|
||||||
if page == 0:
|
if page == 0:
|
||||||
return "\\x%0.2X" % index
|
return f"\\x{index:02X}"
|
||||||
else:
|
else:
|
||||||
# Into extended range
|
# Into extended range
|
||||||
# Leader is 0xFz where z is the page number
|
# Leader is 0xFz where z is the page number
|
||||||
# Following char is the remainder
|
# Following char is the remainder
|
||||||
leader = page + 0xF0
|
leader = page + 0xF0
|
||||||
value = ((index + 14) % 0xFF) + 1
|
value = ((index + 0x0E) % 0xFF) + 0x01
|
||||||
assert leader <= 0xFF
|
|
||||||
assert value <= 0xFF
|
if leader > 0xFF or value > 0xFF:
|
||||||
return "\\x%0.2X\\x%0.2X" % (leader, value)
|
raise ValueError("value is out of range")
|
||||||
|
return f"\\x{leader:02X}\\x{value:02X}"
|
||||||
|
|
||||||
|
|
||||||
def getFontMapAndTable(textList):
|
def get_font_map_and_table(text_list: List[str]) -> Tuple[str, Dict[str, str]]:
|
||||||
# the text list is sorted
|
# the text list is sorted
|
||||||
# allocate out these in their order as number codes
|
# allocate out these in their order as number codes
|
||||||
symbolMap = {}
|
symbol_map = {"\n": "\\x01"}
|
||||||
symbolMap["\n"] = "\\x01" # Force insert the newline char
|
|
||||||
index = 2 # start at 2, as 0= null terminator,1 = new line
|
index = 2 # start at 2, as 0= null terminator,1 = new line
|
||||||
forcedFirstSymbols = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
|
forced_first_symbols = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
|
||||||
|
|
||||||
# Get the font table, which does not include CJK chars
|
# Get the font table, which does not include CJK chars
|
||||||
fontTable = fontTables.getFontMap()
|
font_table = font_tables.get_font_map()
|
||||||
fontSmallTable = fontTables.getSmallFontMap()
|
font_small_table = font_tables.get_small_font_map()
|
||||||
|
|
||||||
# We want to put all CJK chars after non-CJK ones so that the CJK chars
|
# We want to put all CJK chars after non-CJK ones so that the CJK chars
|
||||||
# do not need to be in the small font table to save space.
|
# do not need to be in the small font table to save space.
|
||||||
# We assume all symbols not in the font table to be a CJK char.
|
# We assume all symbols not in the font table to be a CJK char.
|
||||||
# We also enforce that numbers are first.
|
# We also enforce that numbers are first.
|
||||||
orderedNormalSymList = forcedFirstSymbols + [x for x in textList if x not in forcedFirstSymbols and x in fontTable]
|
ordered_normal_sym_list: List[str] = forced_first_symbols + [x for x in text_list if x not in forced_first_symbols and x in font_table]
|
||||||
orderedCJKSymList = [x for x in textList if x not in forcedFirstSymbols and x not in fontTable]
|
ordered_cjk_sym_list: List[str] = [x for x in text_list if x not in forced_first_symbols and x not in font_table]
|
||||||
|
|
||||||
totalSymbolCount = len(orderedNormalSymList) + len(orderedCJKSymList)
|
total_symbol_count = len(ordered_normal_sym_list) + len(ordered_cjk_sym_list)
|
||||||
# \x00 is for NULL termination and \x01 is for newline, so the maximum
|
# \x00 is for NULL termination and \x01 is for newline, so the maximum
|
||||||
# number of symbols allowed is as follow (see also the comments in
|
# number of symbols allowed is as follow (see also the comments in
|
||||||
# `getCharsFromFontIndex`):
|
# `get_chars_from_font_index`):
|
||||||
if totalSymbolCount > (0x10 * 0xFF - 15) - 2:
|
if total_symbol_count > (0x10 * 0xFF - 15) - 2: # 4063
|
||||||
log(f"Error, too many used symbols for this version (total {totalSymbolCount})")
|
logging.error(f"Error, too many used symbols for this version (total {total_symbol_count})")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
log("Generating fonts for {} symbols".format(totalSymbolCount))
|
logging.info(f"Generating fonts for {total_symbol_count} symbols")
|
||||||
|
|
||||||
for l in (orderedNormalSymList, orderedCJKSymList):
|
for sym in chain(ordered_normal_sym_list, ordered_cjk_sym_list):
|
||||||
for sym in l:
|
if sym in symbol_map:
|
||||||
assert(sym not in symbolMap)
|
raise ValueError("Symbol not found in symbol map")
|
||||||
symbolMap[sym] = getCharsFromFontIndex(index)
|
symbol_map[sym] = get_chars_from_font_index(index)
|
||||||
index = index + 1
|
index += 1
|
||||||
|
|
||||||
fontTableStrings = []
|
font_table_strings = []
|
||||||
fontSmallTableStrings = []
|
font_small_table_strings = []
|
||||||
for sym in orderedNormalSymList:
|
for sym in ordered_normal_sym_list:
|
||||||
if sym not in fontTable:
|
if sym not in font_table:
|
||||||
log("Missing Large font element for {}".format(sym))
|
logging.error(f"Missing Large font element for {sym}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
fontLine = fontTable[sym]
|
font_line: str = font_table[sym]
|
||||||
fontTableStrings.append(fontLine + "//{} -> {}".format(symbolMap[sym], sym))
|
font_table_strings.append(f"{font_line}//{symbol_map[sym]} -> {sym}")
|
||||||
if sym not in fontSmallTable:
|
if sym not in font_small_table:
|
||||||
log("Missing Small font element for {}".format(sym))
|
logging.error(f"Missing Small font element for {sym}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
fontLine = fontSmallTable[sym]
|
font_line: str = font_small_table[sym]
|
||||||
fontSmallTableStrings.append(
|
font_small_table_strings.append(f"{font_line}//{symbol_map[sym]} -> {sym}")
|
||||||
fontLine + "//{} -> {}".format(symbolMap[sym], sym)
|
|
||||||
)
|
|
||||||
|
|
||||||
for sym in orderedCJKSymList:
|
for sym in ordered_cjk_sym_list:
|
||||||
assert(sym not in fontTable)
|
if sym in font_table:
|
||||||
fontLine = getCJKGlyph(sym)
|
raise ValueError("Symbol already exists in font_table")
|
||||||
if fontLine is None:
|
font_line = get_cjk_glyph(sym)
|
||||||
log("Missing Large font element for {}".format(sym))
|
if font_line is None:
|
||||||
|
logging.error(f"Missing Large font element for {sym}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
fontTableStrings.append(fontLine + "//{} -> {}".format(symbolMap[sym], sym))
|
font_table_strings.append(f"{font_line}//{symbol_map[sym]} -> {sym}")
|
||||||
# No data to add to the small font table
|
# No data to add to the small font table
|
||||||
fontSmallTableStrings.append(
|
font_small_table_strings.append(f"// {symbol_map[sym]} -> {sym}")
|
||||||
"// {} -> {}".format(symbolMap[sym], sym)
|
|
||||||
)
|
|
||||||
|
|
||||||
outputTable = "const uint8_t USER_FONT_12[] = {" + to_unicode("\n")
|
output_table = "const uint8_t USER_FONT_12[] = {\n"
|
||||||
for line in fontTableStrings:
|
for line in font_table_strings:
|
||||||
# join font table int one large string
|
# join font table int one large string
|
||||||
outputTable = outputTable + line + to_unicode("\n")
|
output_table += line + "\n"
|
||||||
outputTable = outputTable + "};" + to_unicode("\n")
|
output_table += "};\n"
|
||||||
outputTable = outputTable + "const uint8_t USER_FONT_6x8[] = {" + to_unicode("\n")
|
output_table += "const uint8_t USER_FONT_6x8[] = {\n"
|
||||||
for line in fontSmallTableStrings:
|
for line in font_small_table_strings:
|
||||||
# join font table int one large string
|
# join font table int one large string
|
||||||
outputTable = outputTable + line + to_unicode("\n")
|
output_table += line + "\n"
|
||||||
outputTable = outputTable + "};" + to_unicode("\n")
|
output_table += "};\n"
|
||||||
return (outputTable, symbolMap)
|
return output_table, symbol_map
|
||||||
|
|
||||||
|
|
||||||
def convStr(symbolConversionTable, text):
|
def convert_string(symbol_conversion_table: Dict[str, str], text: str) -> str:
|
||||||
# convert all of the symbols from the string into escapes for their content
|
# convert all of the symbols from the string into escapes for their content
|
||||||
outputString = ""
|
output_string = ""
|
||||||
for c in text.replace("\\r", "").replace("\\n", "\n"):
|
for c in text.replace("\\r", "").replace("\\n", "\n"):
|
||||||
if c not in symbolConversionTable:
|
if c not in symbol_conversion_table:
|
||||||
log("Missing font definition for {}".format(c))
|
logging.error(f"Missing font definition for {c}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
else:
|
else:
|
||||||
outputString = outputString + symbolConversionTable[c]
|
output_string += symbol_conversion_table[c]
|
||||||
return outputString
|
return output_string
|
||||||
|
|
||||||
|
|
||||||
def writeLanguage(lang, defs, f):
|
def write_language(lang: dict, defs: dict, f: TextIO) -> None:
|
||||||
languageCode = lang["languageCode"]
|
language_code: str = lang["languageCode"]
|
||||||
log("Generating block for " + languageCode)
|
logging.info(f"Generating block for {language_code}")
|
||||||
# Iterate over all of the text to build up the symbols & counts
|
# Iterate over all of the text to build up the symbols & counts
|
||||||
textList = getLetterCounts(defs, lang)
|
text_list = get_letter_counts(defs, lang)
|
||||||
# From the letter counts, need to make a symbol translator & write out the font
|
# From the letter counts, need to make a symbol translator & write out the font
|
||||||
(fontTableText, symbolConversionTable) = getFontMapAndTable(textList)
|
font_table_text, symbol_conversion_table = get_font_map_and_table(text_list)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
langName = lang["languageLocalName"]
|
lang_name = lang["languageLocalName"]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
langName = languageCode
|
lang_name = language_code
|
||||||
|
|
||||||
f.write(to_unicode("\n// ---- " + langName + " ----\n\n"))
|
f.write(f"\n// ---- {lang_name} ----\n\n")
|
||||||
f.write(fontTableText)
|
f.write(font_table_text)
|
||||||
f.write(to_unicode("\n// ---- " + langName + " ----\n\n"))
|
f.write(f"\n// ---- {lang_name} ----\n\n")
|
||||||
|
|
||||||
# ----- Writing SettingsDescriptions
|
# ----- Writing SettingsDescriptions
|
||||||
obj = lang["menuOptions"]
|
obj = lang["menuOptions"]
|
||||||
f.write(to_unicode("const char* SettingsDescriptions[] = {\n"))
|
f.write("const char* SettingsDescriptions[] = {\n")
|
||||||
|
|
||||||
maxLen = 25
|
max_len = 25
|
||||||
index = 0
|
index = 0
|
||||||
for mod in defs["menuOptions"]:
|
for mod in defs["menuOptions"]:
|
||||||
eid = mod["id"]
|
eid = mod["id"]
|
||||||
if "feature" in mod:
|
if "feature" in mod:
|
||||||
f.write(to_unicode("#ifdef " + mod["feature"] + "\n"))
|
f.write(f"#ifdef {mod['feature']}\n")
|
||||||
f.write(
|
f.write(f" /* [{index:02d}] {eid.ljust(max_len)[:max_len]} */ ")
|
||||||
to_unicode(
|
f.write(f"\"{convert_string(symbol_conversion_table, obj[eid]['desc'])}\",//{obj[eid]['desc']} \n")
|
||||||
" /* ["
|
|
||||||
+ "{:02d}".format(index)
|
|
||||||
+ "] "
|
|
||||||
+ eid.ljust(maxLen)[:maxLen]
|
|
||||||
+ " */ "
|
|
||||||
)
|
|
||||||
)
|
|
||||||
f.write(
|
|
||||||
to_unicode(
|
|
||||||
'"'
|
|
||||||
+ convStr(symbolConversionTable, (obj[eid]["desc"]))
|
|
||||||
+ '",'
|
|
||||||
+ "//{} \n".format(obj[eid]["desc"])
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if "feature" in mod:
|
|
||||||
f.write(to_unicode("#endif\n"))
|
|
||||||
index = index + 1
|
|
||||||
|
|
||||||
f.write(to_unicode("};\n\n"))
|
if "feature" in mod:
|
||||||
|
f.write("#endif\n")
|
||||||
|
index += 1
|
||||||
|
|
||||||
|
f.write("};\n\n")
|
||||||
|
|
||||||
# ----- Writing Message strings
|
# ----- Writing Message strings
|
||||||
|
|
||||||
@@ -426,233 +392,134 @@ def writeLanguage(lang, defs, f):
|
|||||||
|
|
||||||
for mod in defs["messages"]:
|
for mod in defs["messages"]:
|
||||||
eid = mod["id"]
|
eid = mod["id"]
|
||||||
sourceText = ""
|
source_text = ""
|
||||||
if "default" in mod:
|
if "default" in mod:
|
||||||
sourceText = mod["default"]
|
source_text = mod["default"]
|
||||||
if eid in obj:
|
if eid in obj:
|
||||||
sourceText = obj[eid]
|
source_text = obj[eid]
|
||||||
translatedText = convStr(symbolConversionTable, sourceText)
|
translated_text = convert_string(symbol_conversion_table, source_text)
|
||||||
f.write(
|
source_text = source_text.replace("\n", "_")
|
||||||
to_unicode(
|
f.write(f'const char* {eid} = "{translated_text}";//{source_text} \n')
|
||||||
"const char* "
|
|
||||||
+ eid
|
|
||||||
+ ' = "'
|
|
||||||
+ translatedText
|
|
||||||
+ '";'
|
|
||||||
+ "//{} \n".format(sourceText.replace("\n", "_"))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
f.write(to_unicode("\n"))
|
f.write("\n")
|
||||||
|
|
||||||
# ----- Writing Characters
|
# ----- Writing Characters
|
||||||
|
|
||||||
obj = lang["characters"]
|
obj = lang["characters"]
|
||||||
|
|
||||||
for mod in defs["characters"]:
|
for mod in defs["characters"]:
|
||||||
eid = mod["id"]
|
eid: str = mod["id"]
|
||||||
f.write(
|
f.write(f'const char* {eid} = "{convert_string(symbol_conversion_table, obj[eid])}";//{obj[eid]} \n')
|
||||||
to_unicode(
|
f.write("\n")
|
||||||
"const char* "
|
|
||||||
+ eid
|
|
||||||
+ ' = "'
|
|
||||||
+ convStr(symbolConversionTable, obj[eid])
|
|
||||||
+ '";'
|
|
||||||
+ "//{} \n".format(obj[eid])
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
f.write(to_unicode("\n"))
|
|
||||||
|
|
||||||
# Write out firmware constant options
|
# Write out firmware constant options
|
||||||
constants = getConstants()
|
constants = get_constants()
|
||||||
for x in constants:
|
for x in constants:
|
||||||
f.write(
|
f.write(f'const char* {x[0]} = "{convert_string(symbol_conversion_table, x[1])}";//{x[1]} \n')
|
||||||
to_unicode(
|
f.write("\n")
|
||||||
"const char* "
|
|
||||||
+ x[0]
|
|
||||||
+ ' = "'
|
|
||||||
+ convStr(symbolConversionTable, x[1])
|
|
||||||
+ '";'
|
|
||||||
+ "//{} \n".format(x[1])
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
f.write(to_unicode("\n"))
|
|
||||||
|
|
||||||
# Debug Menu
|
# Debug Menu
|
||||||
f.write(to_unicode("const char* DebugMenu[] = {\n"))
|
f.write("const char* DebugMenu[] = {\n")
|
||||||
|
|
||||||
for c in getDebugMenu():
|
for c in get_debug_menu():
|
||||||
f.write(
|
f.write(f'\t "{convert_string(symbol_conversion_table, c)}",//{c} \n')
|
||||||
to_unicode(
|
f.write("};\n\n")
|
||||||
'\t "' + convStr(symbolConversionTable, c) + '",' + "//{} \n".format(c)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
f.write(to_unicode("};\n\n"))
|
|
||||||
|
|
||||||
# ----- Writing SettingsDescriptions
|
# ----- Writing SettingsDescriptions
|
||||||
obj = lang["menuOptions"]
|
obj = lang["menuOptions"]
|
||||||
f.write(to_unicode("const char* SettingsShortNames[][2] = {\n"))
|
f.write("const char* SettingsShortNames[][2] = {\n")
|
||||||
|
|
||||||
maxLen = 25
|
max_len = 25
|
||||||
index = 0
|
index = 0
|
||||||
for mod in defs["menuOptions"]:
|
for mod in defs["menuOptions"]:
|
||||||
eid = mod["id"]
|
eid = mod["id"]
|
||||||
if "feature" in mod:
|
if "feature" in mod:
|
||||||
f.write(to_unicode("#ifdef " + mod["feature"] + "\n"))
|
f.write(f"#ifdef {mod['feature']}\n")
|
||||||
f.write(
|
f.write(f" /* [{index:02d}] {eid.ljust(max_len)[:max_len]} */ ")
|
||||||
to_unicode(
|
f.write(f'{{ "{convert_string(symbol_conversion_table, (obj[eid]["text2"][0]))}", "{convert_string(symbol_conversion_table, (obj[eid]["text2"][1]))}" }},//{obj[eid]["text2"]} \n')
|
||||||
" /* ["
|
|
||||||
+ "{:02d}".format(index)
|
|
||||||
+ "] "
|
|
||||||
+ eid.ljust(maxLen)[:maxLen]
|
|
||||||
+ " */ "
|
|
||||||
)
|
|
||||||
)
|
|
||||||
f.write(
|
|
||||||
to_unicode(
|
|
||||||
'{ "'
|
|
||||||
+ convStr(symbolConversionTable, (obj[eid]["text2"][0]))
|
|
||||||
+ '", "'
|
|
||||||
+ convStr(symbolConversionTable, (obj[eid]["text2"][1]))
|
|
||||||
+ '" },'
|
|
||||||
+ "//{} \n".format(obj[eid]["text2"])
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if "feature" in mod:
|
if "feature" in mod:
|
||||||
f.write(to_unicode("#endif\n"))
|
f.write("#endif\n")
|
||||||
index = index + 1
|
index += 1
|
||||||
|
|
||||||
f.write(to_unicode("};\n\n"))
|
f.write("};\n\n")
|
||||||
|
|
||||||
# ----- Writing Menu Groups
|
# ----- Writing Menu Groups
|
||||||
obj = lang["menuGroups"]
|
obj = lang["menuGroups"]
|
||||||
f.write(to_unicode("const char* SettingsMenuEntries[" + str(len(obj)) + "] = {\n"))
|
f.write(f"const char* SettingsMenuEntries[{len(obj)}] = {{\n")
|
||||||
|
|
||||||
maxLen = 25
|
max_len = 25
|
||||||
for mod in defs["menuGroups"]:
|
for mod in defs["menuGroups"]:
|
||||||
eid = mod["id"]
|
eid = mod["id"]
|
||||||
f.write(to_unicode(" /* " + eid.ljust(maxLen)[:maxLen] + " */ "))
|
f.write(f" /* {eid.ljust(max_len)[:max_len]} */ ")
|
||||||
f.write(
|
txt = f'{obj[eid]["text2"][0]}\\n{obj[eid]["text2"][1]}'
|
||||||
to_unicode(
|
f.write(f'"{convert_string(symbol_conversion_table, txt)}",//{obj[eid]["text2"]} \n')
|
||||||
'"'
|
|
||||||
+ convStr(
|
|
||||||
symbolConversionTable,
|
|
||||||
(obj[eid]["text2"][0]) + "\\n" + obj[eid]["text2"][1],
|
|
||||||
)
|
|
||||||
+ '",'
|
|
||||||
+ "//{} \n".format(obj[eid]["text2"])
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
f.write(to_unicode("};\n\n"))
|
f.write("};\n\n")
|
||||||
|
|
||||||
# ----- Writing Menu Groups Descriptions
|
# ----- Writing Menu Groups Descriptions
|
||||||
obj = lang["menuGroups"]
|
obj = lang["menuGroups"]
|
||||||
f.write(
|
f.write(f"const char* SettingsMenuEntriesDescriptions[{(len(obj))}] = {{\n")
|
||||||
to_unicode(
|
|
||||||
"const char* SettingsMenuEntriesDescriptions[" + str(len(obj)) + "] = {\n"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
maxLen = 25
|
max_len = 25
|
||||||
for mod in defs["menuGroups"]:
|
for mod in defs["menuGroups"]:
|
||||||
eid = mod["id"]
|
eid = mod["id"]
|
||||||
f.write(to_unicode(" /* " + eid.ljust(maxLen)[:maxLen] + " */ "))
|
f.write(f" /* {eid.ljust(max_len)[:max_len]} */ ")
|
||||||
f.write(
|
f.write(f"\"{convert_string(symbol_conversion_table, (obj[eid]['desc']))}\",//{obj[eid]['desc']} \n")
|
||||||
to_unicode(
|
|
||||||
'"'
|
|
||||||
+ convStr(symbolConversionTable, (obj[eid]["desc"]))
|
|
||||||
+ '",'
|
|
||||||
+ "//{} \n".format(obj[eid]["desc"])
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
f.write(to_unicode("};\n\n"))
|
f.write("};\n\n")
|
||||||
f.write(
|
f.write(f"const bool HasFahrenheit = {('true' if lang.get('tempUnitFahrenheit', True) else 'false')};\n")
|
||||||
"const bool HasFahrenheit = "
|
|
||||||
+ ("true" if lang.get("tempUnitFahrenheit", True) else "false")
|
|
||||||
+ ";\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
f.write(to_unicode("\n// Verify SettingsItemIndex values:\n"))
|
f.write("\n// Verify SettingsItemIndex values:\n")
|
||||||
for i, mod in enumerate(defs["menuOptions"]):
|
for i, mod in enumerate(defs["menuOptions"]):
|
||||||
eid = mod["id"]
|
eid = mod["id"]
|
||||||
f.write(to_unicode(
|
f.write(f"static_assert(static_cast<uint8_t>(SettingsItemIndex::{eid}) == {i});\n")
|
||||||
f"static_assert(static_cast<uint8_t>(SettingsItemIndex::{eid}) == {i});\n"))
|
|
||||||
|
|
||||||
|
|
||||||
def readVersion(jsonDir):
|
def read_version() -> str:
|
||||||
with open(os.path.relpath(jsonDir + "/../source/version.h"), "r") as version_file:
|
with open(HERE.parent / 'source' / 'version.h') as version_file:
|
||||||
try:
|
for line in version_file:
|
||||||
for line in version_file:
|
if re.findall(r"^.*(?<=(#define)).*(?<=(BUILD_VERSION))", line):
|
||||||
if re.findall(r"^.*(?<=(#define)).*(?<=(BUILD_VERSION))", line):
|
line = re.findall(r"\"(.+?)\"", line)
|
||||||
line = re.findall(r"\"(.+?)\"", line)
|
if line:
|
||||||
if line:
|
version = line[0]
|
||||||
version = line[0]
|
try:
|
||||||
try:
|
version += f".{subprocess.check_output(['git', 'rev-parse', '--short=7', 'HEAD']).strip().decode('ascii').upper()}"
|
||||||
version += (
|
# --short=7: the shorted hash with 7 digits. Increase/decrease if needed!
|
||||||
"."
|
except OSError:
|
||||||
+ subprocess.check_output(
|
version += " git"
|
||||||
["git", "rev-parse", "--short=7", "HEAD"]
|
return version
|
||||||
)
|
|
||||||
.strip()
|
|
||||||
.decode("ascii")
|
|
||||||
.upper()
|
|
||||||
)
|
|
||||||
# --short=7: the shorted hash with 7 digits. Increase/decrease if needed!
|
|
||||||
except OSError:
|
|
||||||
version += " git"
|
|
||||||
finally:
|
|
||||||
if version_file:
|
|
||||||
version_file.close()
|
|
||||||
return version
|
|
||||||
|
|
||||||
|
|
||||||
def orderOutput(langDict):
|
def parse_args() -> argparse.Namespace:
|
||||||
# These languages go first
|
|
||||||
mandatoryOrder = ["EN"]
|
|
||||||
|
|
||||||
# Then add all others in alphabetical order
|
|
||||||
sortedKeys = sorted(langDict.keys())
|
|
||||||
|
|
||||||
# Add the rest as they come
|
|
||||||
for key in sortedKeys:
|
|
||||||
if key not in mandatoryOrder:
|
|
||||||
mandatoryOrder.append(key)
|
|
||||||
|
|
||||||
return mandatoryOrder
|
|
||||||
|
|
||||||
|
|
||||||
def parseArgs():
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument(
|
parser.add_argument("--output", "-o",
|
||||||
"--output", "-o", help="Target file", type=argparse.FileType("w"), required=True
|
help="Target file",
|
||||||
)
|
type=argparse.FileType("w"),
|
||||||
parser.add_argument("languageCode", help="Language to generate")
|
required=True
|
||||||
|
)
|
||||||
|
parser.add_argument("languageCode",
|
||||||
|
help="Language to generate")
|
||||||
return parser.parse_args()
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
jsonDir = HERE
|
json_dir = HERE
|
||||||
|
|
||||||
args = parseArgs()
|
|
||||||
|
|
||||||
|
args = parse_args()
|
||||||
try:
|
try:
|
||||||
buildVersion = readVersion(jsonDir)
|
buildVersion = read_version()
|
||||||
except:
|
except FileNotFoundError:
|
||||||
log("error: could not get/extract build version")
|
logging.error("error: Could not find version info ")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
log("Build version: " + buildVersion)
|
logging.info(f"Build version: {buildVersion}")
|
||||||
log("Making " + args.languageCode + " from " + jsonDir)
|
logging.info(f"Making {args.languageCode} from {json_dir}")
|
||||||
|
|
||||||
lang = readTranslation(jsonDir, args.languageCode)
|
lang_ = read_translation(json_dir, args.languageCode)
|
||||||
defs = loadJson(os.path.join(jsonDir, "translations_def.js"), True)
|
defs_ = load_json(os.path.join(json_dir, "translations_def.js"), True)
|
||||||
out = args.output
|
out_ = args.output
|
||||||
writeStart(out)
|
write_start(out_)
|
||||||
writeLanguage(lang, defs, out)
|
write_language(lang_, defs_, out_)
|
||||||
|
|
||||||
log("Done")
|
logging.info("Done")
|
||||||
|
|||||||
@@ -1,23 +1,22 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# coding=utf-8
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
|
||||||
class TestMakeTranslation(unittest.TestCase):
|
class TestMakeTranslation(unittest.TestCase):
|
||||||
def test_getCharsFromFontIndex(self):
|
def test_get_chars_from_font_index(self):
|
||||||
from make_translation import getCharsFromFontIndex
|
from make_translation import get_chars_from_font_index
|
||||||
|
|
||||||
self.assertEqual(getCharsFromFontIndex(2), "\\x02")
|
self.assertEqual(get_chars_from_font_index(2), "\\x02")
|
||||||
self.assertEqual(getCharsFromFontIndex(239), "\\xEF")
|
self.assertEqual(get_chars_from_font_index(239), "\\xEF")
|
||||||
self.assertEqual(getCharsFromFontIndex(240), "\\xF0")
|
self.assertEqual(get_chars_from_font_index(240), "\\xF0")
|
||||||
self.assertEqual(getCharsFromFontIndex(241), "\\xF1\\x01")
|
self.assertEqual(get_chars_from_font_index(241), "\\xF1\\x01")
|
||||||
self.assertEqual(getCharsFromFontIndex(495), "\\xF1\\xFF")
|
self.assertEqual(get_chars_from_font_index(495), "\\xF1\\xFF")
|
||||||
self.assertEqual(getCharsFromFontIndex(496), "\\xF2\\x01")
|
self.assertEqual(get_chars_from_font_index(496), "\\xF2\\x01")
|
||||||
self.assertEqual(getCharsFromFontIndex(750), "\\xF2\\xFF")
|
self.assertEqual(get_chars_from_font_index(750), "\\xF2\\xFF")
|
||||||
self.assertEqual(getCharsFromFontIndex(751), "\\xF3\\x01")
|
self.assertEqual(get_chars_from_font_index(751), "\\xF3\\x01")
|
||||||
self.assertEqual(getCharsFromFontIndex(0x10 * 0xFF - 15), "\\xFF\\xFF")
|
self.assertEqual(get_chars_from_font_index(0x10 * 0xFF - 15), "\\xFF\\xFF")
|
||||||
with self.assertRaises(AssertionError):
|
with self.assertRaises(ValueError):
|
||||||
getCharsFromFontIndex(0x10 * 0xFF - 14)
|
get_chars_from_font_index(0x10 * 0xFF - 14)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
Reference in New Issue
Block a user