120 lines
3.9 KiB
Python
120 lines
3.9 KiB
Python
"""lib 의 tr('…') / trf('…') 열쇠와 한국어 이름 (언어 · 선택 목록 · 모델) 을 모아 JSON 으로 쓴다."""
|
|
import json
|
|
import os
|
|
import re
|
|
import sys
|
|
|
|
sys.path.insert(0, os.path.dirname(__file__))
|
|
from codemod import parse_string, string_start, skip_ws_comments, HANGUL # noqa: E402
|
|
|
|
|
|
def decode(lit_src_parts):
|
|
"""Dart 문자열 본문 (escape 포함) → 실제 글자"""
|
|
out = []
|
|
s = lit_src_parts
|
|
i = 0
|
|
while i < len(s):
|
|
c = s[i]
|
|
if c == '\\':
|
|
n = s[i + 1]
|
|
if n == 'n':
|
|
out.append('\n')
|
|
elif n == 't':
|
|
out.append('\t')
|
|
elif n == 'r':
|
|
out.append('\r')
|
|
elif n == 'u':
|
|
if s[i + 2] == '{':
|
|
j = s.index('}', i)
|
|
out.append(chr(int(s[i + 3:j], 16)))
|
|
i = j + 1
|
|
continue
|
|
out.append(chr(int(s[i + 2:i + 6], 16)))
|
|
i += 6
|
|
continue
|
|
elif n == 'x':
|
|
out.append(chr(int(s[i + 2:i + 4], 16)))
|
|
i += 4
|
|
continue
|
|
else:
|
|
out.append(n)
|
|
i += 2
|
|
continue
|
|
out.append(c)
|
|
i += 1
|
|
return ''.join(out)
|
|
|
|
|
|
def group_text(lits):
|
|
text = []
|
|
k = 0
|
|
for l in lits:
|
|
for p in l.parts:
|
|
if p[0] == 'text':
|
|
text.append(decode(p[1]) if not l.raw else p[1])
|
|
else:
|
|
text.append('{%d}' % k)
|
|
k += 1
|
|
return ''.join(text)
|
|
|
|
|
|
def literal_groups(src):
|
|
"""(시작 위치, 문자열 묶음) 전부"""
|
|
i = 0
|
|
n = len(src)
|
|
while i < n:
|
|
if src.startswith('//', i) or src.startswith('/*', i):
|
|
i = skip_ws_comments(src, i)
|
|
continue
|
|
st = string_start(src, i)
|
|
if st and not (src[i] in 'rR' and i > 0 and (src[i - 1].isalnum() or src[i - 1] in '_$')):
|
|
start = i
|
|
lits = []
|
|
lit, j = parse_string(src, i)
|
|
lits.append(lit)
|
|
while True:
|
|
k = skip_ws_comments(src, j)
|
|
if k < n and string_start(src, k):
|
|
lit, j = parse_string(src, k)
|
|
lits.append(lit)
|
|
else:
|
|
break
|
|
yield start, lits
|
|
i = j
|
|
continue
|
|
i += 1
|
|
|
|
|
|
keys = set()
|
|
NAMED = {'lib/core/languages.dart', 'lib/core/download_detect.dart', 'lib/core/encode_options.dart',
|
|
'lib/core/playlist.dart', 'lib/services/model_store.dart'}
|
|
for root, _, files in os.walk('lib'):
|
|
for f in files:
|
|
if not f.endswith('.dart'):
|
|
continue
|
|
path = os.path.join(root, f).replace('\\', '/')
|
|
src = open(path, encoding='utf-8').read()
|
|
# (그 글이 들어 있는 소스, 위치, 문자열 묶음). 문자열 안의 ${...} 식에 든 문자열도
|
|
# (예: '${n}%${x ? tr(' (보통)') : ''}') 다시 찾는다.
|
|
todo = [(src, st, lits) for st, lits in literal_groups(src)]
|
|
k = 0
|
|
while k < len(todo):
|
|
for l in todo[k][2]:
|
|
for part in l.parts:
|
|
if part[0] == 'expr':
|
|
todo.extend((part[1], st, ls) for st, ls in literal_groups(part[1]))
|
|
k += 1
|
|
for text_src, start, lits in todo:
|
|
before = text_src[max(0, start - 8):start]
|
|
wrapped = re.search(r'\btrf?\(\s*$', before) is not None
|
|
text = group_text(lits)
|
|
if not HANGUL.search(text):
|
|
continue
|
|
if wrapped or (path in NAMED and not any(l.raw for l in lits)):
|
|
keys.add(text)
|
|
# 광고 건너뛰기 표시 (youtube_ads.dart 는 스크립트라 따로)
|
|
keys.add('광고 건너뛰는 중…')
|
|
out = sorted(keys)
|
|
json.dump(out, open(sys.argv[1], 'w', encoding='utf-8'), ensure_ascii=False, indent=1)
|
|
print(len(out), sum(len(k) for k in out))
|