Support CJK text alignment (#2012)
* Add functions for unicode string alignment * use unicode alignment function to show menu * Allow table content to support unicode text alignment
This commit is contained in:
parent
c9e2027725
commit
47ed711743
|
|
@ -1,32 +1,15 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import unicodedata
|
|
||||||
|
|
||||||
from typing import Callable, Any, List, Iterator, Tuple, Optional, Dict, TYPE_CHECKING
|
from typing import Callable, Any, List, Iterator, Tuple, Optional, Dict, TYPE_CHECKING
|
||||||
|
|
||||||
from .menu import Menu, MenuSelectionType
|
from .menu import Menu, MenuSelectionType
|
||||||
from ..output import error
|
from ..output import error
|
||||||
|
from ..output import unicode_ljust
|
||||||
from ..translationhandler import TranslationHandler, Language
|
from ..translationhandler import TranslationHandler, Language
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
_: Any
|
_: Any
|
||||||
|
|
||||||
def count_cjk_chars(string):
|
|
||||||
"Count the total number of CJK characters contained in a string"
|
|
||||||
return sum(unicodedata.east_asian_width(c) in 'FW' for c in string)
|
|
||||||
|
|
||||||
def cjkljust(string, width, fillbyte=' '):
|
|
||||||
"""Support left alignment of Chinese, Japanese, Korean text
|
|
||||||
>>> cjkljust('Hello', 15, '*')
|
|
||||||
'Hello**********'
|
|
||||||
>>> cjkljust('你好', 15, '*')
|
|
||||||
'你好***********'
|
|
||||||
>>> cjkljust('안녕하세요', 15, '*')
|
|
||||||
'안녕하세요*****'
|
|
||||||
>>> cjkljust('こんにちは', 15, '*')
|
|
||||||
'こんにちは*****'
|
|
||||||
"""
|
|
||||||
return string.ljust(width - count_cjk_chars(string), fillbyte)
|
|
||||||
|
|
||||||
class Selector:
|
class Selector:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
|
@ -145,7 +128,7 @@ class Selector:
|
||||||
|
|
||||||
if current:
|
if current:
|
||||||
padding += 5
|
padding += 5
|
||||||
description = cjkljust(str(self._description), padding, ' ')
|
description = unicode_ljust(str(self._description), padding, ' ')
|
||||||
current = current
|
current = current
|
||||||
else:
|
else:
|
||||||
description = self._description
|
description = self._description
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import unicodedata
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
@ -83,7 +84,7 @@ class FormattedOutput:
|
||||||
if capitalize:
|
if capitalize:
|
||||||
key = key.capitalize()
|
key = key.capitalize()
|
||||||
|
|
||||||
key_list.append(key.ljust(width))
|
key_list.append(unicode_ljust(key, width))
|
||||||
|
|
||||||
output += ' | '.join(key_list) + '\n'
|
output += ' | '.join(key_list) + '\n'
|
||||||
output += '-' * len(output) + '\n'
|
output += '-' * len(output) + '\n'
|
||||||
|
|
@ -99,9 +100,9 @@ class FormattedOutput:
|
||||||
value = '*' * width
|
value = '*' * width
|
||||||
|
|
||||||
if isinstance(value, (int, float)) or (isinstance(value, str) and value.isnumeric()):
|
if isinstance(value, (int, float)) or (isinstance(value, str) and value.isnumeric()):
|
||||||
obj_data.append(str(value).rjust(width))
|
obj_data.append(unicode_rjust(str(value), width))
|
||||||
else:
|
else:
|
||||||
obj_data.append(str(value).ljust(width))
|
obj_data.append(unicode_ljust(str(value), width))
|
||||||
|
|
||||||
output += ' | '.join(obj_data) + '\n'
|
output += ' | '.join(obj_data) + '\n'
|
||||||
|
|
||||||
|
|
@ -326,3 +327,33 @@ def log(
|
||||||
if level != logging.DEBUG or storage.get('arguments', {}).get('verbose', False):
|
if level != logging.DEBUG or storage.get('arguments', {}).get('verbose', False):
|
||||||
sys.stdout.write(f"{text}\n")
|
sys.stdout.write(f"{text}\n")
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
def _count_wchars(string: str) -> int:
|
||||||
|
"Count the total number of wide characters contained in a string"
|
||||||
|
return sum(unicodedata.east_asian_width(c) in 'FW' for c in string)
|
||||||
|
|
||||||
|
def unicode_ljust(string: str, width: int, fillbyte: str = ' ') -> str:
|
||||||
|
"""Return a left-justified unicode string of length width.
|
||||||
|
>>> unicode_ljust('Hello', 15, '*')
|
||||||
|
'Hello**********'
|
||||||
|
>>> unicode_ljust('你好', 15, '*')
|
||||||
|
'你好***********'
|
||||||
|
>>> unicode_ljust('안녕하세요', 15, '*')
|
||||||
|
'안녕하세요*****'
|
||||||
|
>>> unicode_ljust('こんにちは', 15, '*')
|
||||||
|
'こんにちは*****'
|
||||||
|
"""
|
||||||
|
return string.ljust(width - _count_wchars(string), fillbyte)
|
||||||
|
|
||||||
|
def unicode_rjust(string: str, width: int, fillbyte: str = ' ') -> str:
|
||||||
|
"""Return a right-justified unicode string of length width.
|
||||||
|
>>> unicode_rjust('Hello', 15, '*')
|
||||||
|
'**********Hello'
|
||||||
|
>>> unicode_rjust('你好', 15, '*')
|
||||||
|
'***********你好'
|
||||||
|
>>> unicode_rjust('안녕하세요', 15, '*')
|
||||||
|
'*****안녕하세요'
|
||||||
|
>>> unicode_rjust('こんにちは', 15, '*')
|
||||||
|
'*****こんにちは'
|
||||||
|
"""
|
||||||
|
return string.rjust(width - _count_wchars(string), fillbyte)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue