from html.parser import HTMLParser from pathlib import Path from urllib.parse import urljoin import json,html,re b=Path('work/trilium');src=b/'api-source';out=b/'phase9/doc_notes/en/api-ko';out.mkdir(parents=True,exist_ok=True) original=json.loads((src/'script-strings.json').read_text(encoding='utf-8'));translated=(b/'api-script-ko.txt').read_text(encoding='utf-8').splitlines();assert len(original)==len(translated) mapping=dict(zip(original,translated));ui={'Index':'목차','Properties':'속성','Methods':'메서드','Constructors':'생성자','Constructor':'생성자','Parameters':'매개변수','Returns':'반환값','Type declaration':'형식 선언','Type Parameters':'형식 매개변수','Inherited from':'상속한 항목','Overrides':'재정의한 항목','Defined in':'정의 위치','Optional':'선택 사항','Readonly':'읽기 전용','Protected':'보호됨','Private':'비공개','Static':'정적','Permalink':'고유 링크','Interface':'인터페이스','Class':'클래스','Hierarchy':'상속 구조','Implements':'구현','Accessors':'접근자','Default':'기본값'} mapping.update(json.loads((b/'api-script-extra.json').read_text(encoding='utf-8'))) urls={'frontend':'https://triliumnext.github.io/Notes/Script%20API/interfaces/Frontend_Script_API.Api.html','fnote':'https://triliumnext.github.io/Notes/Script%20API/classes/Frontend_Script_API.FNote.html','backend':'https://triliumnext.github.io/Notes/Script%20API/interfaces/Backend_Script_API.Api.html'} titles={'frontend':'프런트엔드 스크립트 API','fnote':'프런트엔드 노트 객체 FNote','backend':'백엔드 스크립트 API'} class Page(HTMLParser): def __init__(self,url):super().__init__(convert_charrefs=False);self.url=url;self.depth=0;self.parts=[];self.tags=[];self.count=0;self.untranslated=[] def handle_starttag(self,t,attrs): a=dict(attrs) if not self.depth: if t=='div' and a.get('class')=='col-content':self.depth=1 else:return else: if t=='div':self.depth+=1 self.tags.append(t) if t not in ['br','hr','wbr','img','input','meta','link','use'] else None if t=='a' and 'href'in a and not a['href'].startswith('#'): absolute=urljoin(self.url,a['href']);a['href']=absolute for n,u in urls.items(): if absolute.split('#')[0]==u:a['href']=n+'.html'+('#'+absolute.split('#',1)[1] if '#'in absolute else '') for k in ['title','aria-label']: if k in a:a[k]=ui.get(a[k],a[k]) self.parts.append('<'+t+''.join(' '+k+'="'+html.escape(v or '',quote=True)+'"' for k,v in a.items())+'>') def handle_startendtag(self,t,a): self.handle_starttag(t,a) if t not in ['br','hr','wbr','img','input','meta','link','use']:self.handle_endtag(t) def handle_endtag(self,t): if not self.depth:return self.parts.append(''+t+'>') if t=='div':self.depth-=1 for i in range(len(self.tags)-1,-1,-1): if self.tags[i]==t:self.tags=self.tags[:i];break def handle_data(self,s): if not self.depth:return k=s.strip();v=s if not any(t in ['pre','code'] for t in self.tags): if k in mapping:v=s.replace(k,mapping[k]);self.count+=1 elif k in ui:v=s.replace(k,ui[k]) elif re.match(r'^(Interface|Class|Defined in|Inherited from|Overrides|Returns)\b',k): for a,c in ui.items():v=v.replace(a,c) elif re.search(r'[a-zA-Z]{2,}\s+[a-zA-Z]{2,}',k):self.untranslated.append(k) self.parts.append(html.escape(v,quote=False)) def handle_entityref(self,n): if self.depth:self.parts.append('&'+n+';') def handle_charref(self,n): if self.depth:self.parts.append(''+n+';') style='body{font:16px/1.7 system-ui,sans-serif;max-width:1050px;margin:24px auto;padding:0 22px;color:#24292f}a{color:#075fbd}pre,.tsd-signature{background:#f3f5f7;padding:12px;overflow:auto}code{font-family:monospace}.tsd-kind-icon{width:18px;height:18px}section{margin:20px 0}h2{border-bottom:1px solid #ddd}h3{margin-top:30px}ul{padding-left:24px}.tsd-anchor-icon{display:none}nav{background:#eef6ff;padding:12px}details{margin:12px 0}svg{display:none}' report={} for n,url in urls.items(): p=Page(url);p.feed((src/(n+'.html')).read_text(encoding='utf-8'));assert p.count>0 page='
연결된 공식 문서의 한국어 사본입니다. 함수 이름과 코드 문법은 원문을 유지했습니다. 외부 문서는 운영 버전과 다를 수 있으므로 지원 여부를 확인하세요. 공식 원문 보기
'+''.join(p.parts)+'' (out/(n+'.html')).write_text(page,encoding='utf-8');report[n]={'translatedTextNodes':p.count,'remainingProse':list(dict.fromkeys(p.untranslated))} (b/'phase9/script-audit.json').write_text(json.dumps(report,ensure_ascii=False,indent=2),encoding='utf-8');print(json.dumps(report,ensure_ascii=False))