collective

Browse / github.com/storytold/craft-launcher / patch

Add Korean (한국어) as an interface language

Add Korean (한국어) as an interface language Adds Korean (한국어, `ko`) as the twelfth interface language, following the "Adding a language" steps in `crates/ui-egui/src/i18n/mod.rs`. ## What's in it - **`crates/ui-egui/src/i18n/ko.tsv`**: a complete catalog (306 rows): every `tl!` literal and `t()` call, the `@id` menu rows, the thirteen app taglines, month names, `@plural` and `@msg` rows, and the tray menu. `complete_menus: true`, so the coverage tests enforce it. - **`lang.rs`**: the `ko` registry row (one plural form, like Japanese and Chinese) and `Script::Korean`, since the bundled faces have no Hangul. - **`cjk_font.rs`**: where e

Status
open
Score
0.00
Adopters
0 other operators
Author
kimjinha (imported from pull request #449, open)
Base
0f295d4b9c90d15c2e38e36c322bdbc0fa943a54
Size
+445 −4 in 5 files
Review
pending
Shared
2026-10-28
Id
ec39767f96a261fcbe9513d0

How it went

No other operator has reported using it yet.

Diff

raw · README.md crates/ui-egui/src/cjk_font.rs crates/ui-egui/src/i18n/ko.tsv crates/ui-egui/src/i18n/lang.rs crates/ui-egui/src/i18n/tests.rs

diff --git a/README.md b/README.md--- a/README.md+++ b/README.md@@ -85,12 +85,13 @@ The web version shows the same catalog in the browser, with the latest download ## Interface languages  The interface is in English, Brazilian Portuguese (Português (Brasil)), Czech (Čeština), French-(Français), German (Deutsch), Hungarian (Magyar), Japanese (日本語), Polish (Polski), Russian+(Français), German (Deutsch), Hungarian (Magyar), Japanese (日本語), Korean (한국어), Polish (Polski), Russian (Русский), Simplified Chinese (简体中文) or Spanish (Español). **Auto**, the default, follows the system or browser language; **Settings → Language** picks one and switches at once, and the choice is kept between runs. Czech locales (`cs-CZ`, `cs_CZ.UTF-8`…) select Czech, German ones (`de-DE`, `de-AT`, `de-CH`, `de_DE.UTF-8`…) German, French ones (`fr-FR`, `fr-CA`…) French, Hungarian ones (`hu`, `hu-HU`, `hu_HU.UTF-8`…) Hungarian, Japanese ones (`ja`, `ja-JP`, `ja_JP.UTF-8`…) Japanese,+Korean ones (`ko`, `ko-KR`, `ko_KR.UTF-8`…) Korean, Polish ones (`pl`, `pl-PL`, `pl_PL.UTF-8`) Polish, Spanish ones (`es-ES`, `es-MX`, `es-419`…) Spanish, and Portuguese ones (`pt-BR`, and `pt-PT` too, for now) Brazilian Portuguese. Simplified Chinese locales (`zh-CN`, `zh-SG`, `zh-Hans`, and POSIX forms such as `zh_CN.UTF-8`) selectdiff --git a/crates/ui-egui/src/cjk_font.rs b/crates/ui-egui/src/cjk_font.rs--- a/crates/ui-egui/src/cjk_font.rs+++ b/crates/ui-egui/src/cjk_font.rs@@ -40,6 +40,7 @@ fn script_name(script: Script) -> &'static str {     match script {         Script::Chinese => "Chinese",         Script::Japanese => "Japanese",+        Script::Korean => "Korean",     } } @@ -48,6 +49,7 @@ fn script_families(script: Script) -> &'static str {     match script {         Script::Chinese => "PingFang SC, Hiragino Sans GB, Heiti SC, Microsoft YaHei, SimSun, Noto Sans CJK SC and WenQuanYi",         Script::Japanese => "Hiragino Sans, Yu Gothic, Meiryo, MS Gothic, Noto Sans CJK JP, Noto Sans JP, IPAGothic and TakaoGothic",+        Script::Korean => "Apple SD Gothic Neo, Malgun Gothic, Gulim, Noto Sans CJK KR, Noto Sans KR and NanumGothic",     } } @@ -123,6 +125,7 @@ fn candidates(script: Script) -> Vec<Candidate> {     match script {         Script::Chinese => chinese_candidates(),         Script::Japanese => japanese_candidates(),+        Script::Korean => korean_candidates(),     } } @@ -255,6 +258,62 @@ fn japanese_candidates() -> Vec<Candidate> {     out } +/// Where each system keeps a Korean font, best first.+fn korean_candidates() -> Vec<Candidate> {+    let mut out = Vec::new();+    let mut add = |path: PathBuf, family: &'static str| out.push(Candidate { path, family });+    #[cfg(target_os = "macos")]+    {+        add("/System/Library/Fonts/AppleSDGothicNeo.ttc".into(), "Apple SD Gothic Neo");+        for path in mac_font_assets("AppleSDGothicNeo.ttc") {+            add(path, "Apple SD Gothic Neo");+        }+    }+    #[cfg(target_os = "windows")]+    {+        let root = std::env::var_os("SystemRoot").map_or_else(|| PathBuf::from(r"C:\Windows"), PathBuf::from);+        add(root.join("Fonts").join("malgun.ttf"), "Malgun Gothic");+        add(root.join("Fonts").join("gulim.ttc"), "Gulim");+    }+    #[cfg(all(unix, not(target_os = "macos")))]+    {+        // Debian/Ubuntu, Arch, Fedora (static and variable) and FreeBSD's ports.+        const NOTO_DIRS: [&str; 8] = [+            "/usr/share/fonts/opentype/noto",+            "/usr/share/fonts/noto-cjk",+            "/usr/share/fonts/google-noto-cjk",+            "/usr/share/fonts/google-noto-sans-cjk-fonts",+            "/usr/share/fonts/google-noto-sans-cjk-vf-fonts",+            "/usr/share/fonts/noto",+            "/usr/local/share/fonts/noto",+            "/usr/local/share/fonts/noto-cjk",+        ];+        for file in ["NotoSansCJK-Regular.ttc", "NotoSansCJKkr-Regular.otf", "NotoSansCJK-VF.ttc"] {+            for dir in NOTO_DIRS {+                add(Path::new(dir).join(file), "Noto Sans CJK KR");+            }+        }+        // Standalone Noto Sans KR, and Nanum Gothic (fonts-nanum).+        const KR_DIRS: [&str; 6] = [+            "/usr/share/fonts/opentype/noto",+            "/usr/share/fonts/truetype/noto",+            "/usr/share/fonts/noto",+            "/usr/share/fonts/truetype/nanum",+            "/usr/share/fonts/nanum",+            "/usr/local/share/fonts",+        ];+        for file in ["NotoSansKR-Regular.otf", "NotoSansKR-VF.ttf"] {+            for dir in KR_DIRS {+                add(Path::new(dir).join(file), "Noto Sans KR");+            }+        }+        for dir in KR_DIRS {+            add(Path::new(dir).join("NanumGothic.ttf"), "NanumGothic");+        }+    }+    out+}+ /// `file` in macOS's downloaded font assets: /// `/System/Library/AssetsV2/com_apple_MobileAsset_Font*/*.asset/AssetData/<file>`. #[cfg(target_os = "macos")]diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsvnew file mode 100644--- /dev/null+++ b/crates/ui-egui/src/i18n/ko.tsv@@ -0,0 +1,350 @@+# Korean (ko) catalog for ArtCraft Launcher.+# Format: context<TAB>source<TAB>translation+# Empty context = plain UI string (tl!, t).+# @id = command-id keyed (tr_id).+# @plural = plural forms: one|other in English, one form for Korean.+# @msg = status/error message template (message, msg).+# Other context = disambiguation for tr_ctx.+#+# Clean-room: written from the meaning of ArtCraft Launcher's English labels in neutral Korean,+# using the terms Korean-speaking users of creative software know. The user is addressed in the+# polite 합니다/하세요 register, as in current Korean software. Where a placeholder takes an object+# particle, both forms are given ("{name}을(를)"), the usual convention for software strings.+#+# Coverage: the whole interface — every menu string and tl! literal (complete_menus = true).+# Left in English on purpose: product name "ArtCraft Launcher" (and its "Launcher" tag), suite+# name "Craft App Suite",+# app names (PhotoCraft, LightCraft, FilmCraft, DesignCraft, VectorCraft, PdfCraft, EffectCraft,+# WordCraft, DeckCraft, GridCraft, CADCraft, SoundCraft, FigCraft), "GitHub", "Discord".+# Shortcut keys keep their key-cap names (Shift, Alt, Ctrl, Cmd, Esc).+# Trailing "…" (U+2026) must be preserved. Placeholders {name}, {n}, {version}, {count}, {v},+# {what}, {unit}, {real}, {e} must appear in translation.+# Korean has one plural form. Shown with the system's Korean font (see cjk_font.rs); where the+# system has none, the interface stays in English.++	Launcher	Launcher+	Craft App Suite	Craft App Suite+	Open Source Tools for Creatives, Makers, and Builders	크리에이터, 메이커, 빌더를 위한 오픈 소스 도구+	Settings	설정+	Check for updates	업데이트 확인+	Grid	격자+	Table	표+	Show apps as cards	앱을 카드로 표시+	Show apps as a table	앱을 표로 표시+	All	전체+	Updates	업데이트+	Not installed	설치되지 않음+	Search apps	앱 검색+	Sort	정렬+	Suite order	스위트 순서+	Name	이름+	Inspired by	참고한 앱+	Status	상태+	Installed version	설치된 버전+	Latest version	최신 버전+	Newest release	최신 릴리스+	Discord	Discord+	GitHub	GitHub+	Website	웹사이트+	Classic apps	기본 앱+	New apps	새 앱+	NEW	신규+	Install	설치+	Update to {v}	{v}(으)로 업데이트+	Open	열기+	Download for {os}	{os}용 다운로드+	Download	다운로드+	Coming soon	출시 예정+	Checking…	확인 중…+	Not available	사용할 수 없음+	Offline	오프라인+	Downloading {done} of {total}	다운로드 중 {done} / {total}+	Downloading…	다운로드 중…+	Reconnecting…	다시 연결하는 중…+	Verifying…	검증 중…+	Installing, then restarting…	설치한 뒤 다시 시작합니다…+	Installing…	설치 중…+	Removing…	제거 중…+	Pause download	다운로드 일시 중지+	Cancel download	다운로드 취소+	Resume download	다운로드 계속+	Discard download	다운로드 파일 삭제+	Release notes	릴리스 노트+	Show in Finder	Finder에서 보기+	Show in Explorer	탐색기에서 보기+	Show in Files	파일 관리자에서 보기+	Reinstall	다시 설치+	Uninstall…	제거…+	All releases	모든 릴리스+	ArtCraft Launcher {version} is available.	ArtCraft Launcher {version}을(를) 사용할 수 있습니다.+	Dismiss	닫기+	Update and restart	업데이트 후 다시 시작+	A new version is available. Would you like to relaunch with the updated version?	새 버전이 있습니다. 업데이트된 버전으로 다시 시작할까요?+	Later	나중에+	What's new	새로운 기능+	No notes were published with this release.	이 릴리스에는 공개된 릴리스 노트가 없습니다.+	Released {date}	{date} 출시+	Open on GitHub	GitHub에서 열기+	Close	닫기+	ArtCraft Launcher {version}	ArtCraft Launcher {version}+	Only when I ask	직접 확인할 때만+	Automatically download and install updates	업데이트를 자동으로 다운로드하고 설치+	Notify me when an installed app has an update	설치된 앱에 업데이트가 있으면 알림+	Include pre-releases (betas and release candidates)	사전 릴리스(베타, 릴리스 후보) 포함+	Installing on Linux	Linux에 설치+	Install new apps as	새 앱 설치 형식+	System package (recommended)	시스템 패키지(권장)+	Updates always use the format an app was installed with.	업데이트는 항상 앱을 설치했던 형식으로 진행됩니다.+	Running in the background	백그라운드 실행+	Keep running in the tray when the window is closed	창을 닫아도 트레이에서 계속 실행+	Show the window on the current desktop	현재 데스크톱에 창 표시+	Start ArtCraft Launcher when I log in	로그인할 때 ArtCraft Launcher 시작+	Community	커뮤니티+	Questions, ideas and news from the ArtCraft team	ArtCraft 팀의 질문, 아이디어, 소식+	Appearance	모양+	Quit ArtCraft Launcher	ArtCraft Launcher 종료+	Done	완료+	Uninstall {name}?	{name}을(를) 제거할까요?+	The app will be moved to the Trash. Your documents and settings stay.	앱이 휴지통으로 이동됩니다. 문서와 설정은 그대로 남습니다.+	Windows will remove it like any installed program. Your documents and settings stay.	Windows가 다른 설치된 프로그램과 같은 방식으로 제거합니다. 문서와 설정은 그대로 남습니다.+	Your system's package manager will remove it, and may ask for your password. Your documents and settings stay.	시스템 패키지 관리자가 제거하며, 암호를 물을 수 있습니다. 문서와 설정은 그대로 남습니다.+	The app will be removed. Your documents and settings stay.	앱이 제거됩니다. 문서와 설정은 그대로 남습니다.+	Uninstall	제거+	Cancel	취소+	Checked {ago}	마지막 확인: {ago}+	just now	방금+	yesterday	어제+	{month} {day}, {year}	{year}년 {month} {day}일++	Automatically	자동+	Every Craft app	모든 Craft 앱+	Apps on this computer	이 컴퓨터의 앱+	Installed apps with a newer version	새 버전이 있는 설치된 앱+	Apps you can install	설치할 수 있는 앱+	Hide App	앱 숨기기+	Unhide App	앱 숨기기 해제+	Hidden Apps	숨긴 앱+	Apps you hid	숨긴 앱 목록+	Checked {ago} · using {sources}	마지막 확인: {ago} · 출처: {sources}+	{a} and {b}	{a} 및 {b}+	Join the Discord	Discord 참여+	Learn more	자세히 보기+	Minimize	최소화+	Maximize	최대화+	Restore	이전 크기로+	New	신규+	OK	확인+	Open link	링크 열기+	Update	업데이트+	{name} icon	{name} 아이콘+	Loading ArtCraft Launcher…	ArtCraft Launcher 불러오는 중…+	Cancel update	업데이트 취소+	Stop waiting; the update can be started again later	대기를 중단합니다. 업데이트는 나중에 다시 시작할 수 있습니다+	Download again	다시 다운로드+	Install cancelled	설치를 취소했습니다+	Install cancelled. The download is kept for the next try.	설치를 취소했습니다. 다운로드한 파일은 다음 시도를 위해 보관됩니다.+	Update cancelled	업데이트를 취소했습니다+	Uninstall cancelled	제거를 취소했습니다+	Retry install	설치 다시 시도+	Retry update to {version}	{version}(으)로 업데이트 다시 시도+	The download is still here. It's checked again, then installed.	다운로드한 파일이 남아 있습니다. 다시 검증한 뒤 설치합니다.+	Waiting for another app…	다른 앱을 기다리는 중…+	Waiting for other installs…	다른 설치를 기다리는 중…++# Package formats offered for download (PackageKind::label)+	Installer (.msi)	설치 프로그램 (.msi)+	Portable (.zip)	무설치 버전 (.zip)+	Disk image (.dmg)	디스크 이미지 (.dmg)+	Debian package (.deb)	Debian 패키지 (.deb)+	RPM package (.rpm)	RPM 패키지 (.rpm)+	Flatpak bundle	Flatpak 번들+	Tarball (.tar.gz)	tarball (.tar.gz)++# Contextual: each app's tagline, keyed by app id+photocraft	Image editing	이미지 편집+vectorcraft	Vector illustration	벡터 일러스트+filmcraft	Video editing, color and sound	영상 편집, 색 보정, 사운드+lightcraft	Photo library and raw development	사진 라이브러리와 RAW 현상+pdfcraft	Reading, organizing and protecting PDFs	PDF 읽기, 정리, 보호+effectcraft	Motion graphics and visual effects	모션 그래픽과 시각 효과+designcraft	Page layout and publishing	페이지 레이아웃과 출판+wordcraft	Writing and document design	문서 작성과 디자인+deckcraft	Presentations and slide shows	프레젠테이션과 슬라이드 쇼+gridcraft	Spreadsheets and data	스프레드시트와 데이터+cadcraft	Computer-aided design and drafting	컴퓨터 지원 설계와 제도+soundcraft	Recording, editing and mixing audio	오디오 녹음, 편집, 믹싱+figcraft	Interface design and prototyping	인터페이스 디자인과 프로토타이핑++# Contextual: month abbreviations for date rendering+month	Jan	1월+month	Feb	2월+month	Mar	3월+month	Apr	4월+month	May	5월+month	Jun	6월+month	Jul	7월+month	Aug	8월+month	Sep	9월+month	Oct	10월+month	Nov	11월+month	Dec	12월+	Not checked yet	아직 확인하지 않음+	GitHub's hourly limit was reached; full details return in {min} min	GitHub의 시간당 요청 한도에 도달했습니다. {min}분 뒤에 자세한 정보가 다시 표시됩니다+	GitHub limit hit; back in {min} min	GitHub 한도 도달. {min}분 뒤 복구됩니다+	Installing for {platform}	{platform}용으로 설치+	Downloads for {platform}	{platform}용 다운로드+	No downloads for this system	이 시스템용 다운로드가 없습니다+	Join the ArtCraft community on Discord	Discord에서 ArtCraft 커뮤니티에 참여+	ArtCraft on {name}	{name}의 ArtCraft+	Couldn't open {name}: {e}	{name}을(를) 열 수 없습니다: {e}+	Download cancelled	다운로드를 취소했습니다+	Available to install	설치 가능+	Available	사용 가능+	Installed · up to date	설치됨 · 최신+	Update available	업데이트 있음+	Installed	설치됨+	installed	설치됨+	Not available here	이 플랫폼에서는 사용할 수 없음+	Updating…	업데이트 중…+	Update paused	업데이트 일시 중지됨+	Download paused	다운로드 일시 중지됨+	{version} installed → {latest} released	{version} 설치됨 → {latest} 출시+	Version {version}	버전 {version}+	{installed} installed · latest {latest}	{installed} 설치됨 · 최신 {latest}+	Installed · latest {latest}	설치됨 · 최신 {latest}+	Version {version} installed	버전 {version} 설치됨+	Version {latest}	버전 {latest}+	No release published yet	아직 공개된 릴리스가 없습니다+	ArtCraft Launcher	ArtCraft Launcher+	App	앱+	Latest	최신+	Released	출시일+	Auto	자동+	Language	언어+	Ascending	오름차순+	Descending	내림차순+	Click to reverse the order	클릭하면 순서를 뒤집습니다+	Click to sort by this column	클릭하면 이 열로 정렬합니다+	Like {name}	{name}과(와) 비슷한 앱+	{done} of {total}	{done} / {total}+	Downloading	다운로드 중+	Verifying checksum…	체크섬 검증 중…+	Resume	계속+	{done} of {total} downloaded	{done} / {total} 다운로드됨+	{done} downloaded	{done} 다운로드됨+	Checking for updates…	업데이트 확인 중…+	Downloads the new version, replaces this one and opens it again	새 버전을 다운로드해 현재 버전을 교체한 뒤 다시 엽니다+	Couldn't check for updates: {f}	업데이트를 확인할 수 없습니다: {f}+	Website (coming soon)	웹사이트(준비 중)+	GitHub repository	GitHub 저장소+	ArtCraft	ArtCraft+	Update 1 app	앱 1개 업데이트+	Update all ({count})	모두 업데이트({count})+	⊞  Grid	⊞  격자+	☰  Table	☰  표+	🔍  Search apps	🔍  앱 검색+	{name} {version}	{name} {version}+	Match system	시스템 설정 따름+	Dark	어둡게+	Light	밝게+	Full changelog	전체 변경 내역+	link	링크+	No apps match	일치하는 앱이 없습니다+	Open ArtCraft Launcher to update.	업데이트하려면 ArtCraft Launcher를 여세요.+	{name} {v} is available	{name} {v}을(를) 사용할 수 있습니다+	{count} updates are available	업데이트 {count}개를 사용할 수 있습니다+	These notes weren't fetched (GitHub's request limit was reached). They're on the release page.	릴리스 노트를 가져오지 못했습니다(GitHub 요청 한도 도달). 릴리스 페이지에서 볼 수 있습니다.+	When on, opening the launcher from the menu bar brings its window to the desktop you're on. When off, macOS switches you to the desktop the window was on.	켜면 메뉴 막대에서 런처를 열 때 창이 현재 데스크톱에 표시됩니다. 끄면 macOS가 창이 있던 데스크톱으로 전환합니다.+	Couldn't change the login item: {e}	로그인 항목을 변경할 수 없습니다: {e}++# Contextual: table column headers+column	App	앱+column	Installed	설치된 버전+column	Latest	최신 버전+column	Released	출시일++# Contextual: the filter tab names a group (the status pill says "Installed")+filter	Installed	설치됨+	App details	앱 정보+	Close (Esc)	닫기 (Esc)+	Features	기능+	Latest release	최신 릴리스+	Version	버전+	Platforms	지원 플랫폼+	Releases	릴리스+	Enlarge picture	사진 확대+	Click to enlarge	클릭하면 확대+	Previous picture (←)	이전 사진 (←)+	Next picture (→)	다음 사진 (→)+	Loading pictures…	사진 불러오는 중…+	Pictures couldn't be loaded. Reopen this page to try again.	사진을 불러올 수 없습니다. 이 페이지를 다시 열면 다시 시도합니다.+	{name} details	{name} 정보++# Plural forms for Korean (one form: Korean nouns don't inflect for number)+@plural	{n} app|{n} apps	앱 {n}개+@plural	{n} min ago|{n} min ago	{n}분 전+@plural	{n} h ago|{n} h ago	{n}시간 전+@plural	{n} day ago|{n} days ago	{n}일 전++# Message templates (@msg): toasts from the backend. {placeholders} match any text.+@msg	Couldn't open {name}: {e}	{name}을(를) 열 수 없습니다: {e}+@msg	Download cancelled	다운로드를 취소했습니다+@msg	{name} updated to {version}	{name}을(를) {version}(으)로 업데이트했습니다+@msg	{name} installed: {version}	{name}을(를) 설치했습니다: {version}+@msg	{name} updated to {version} (this release publishes no checksum, so only its size was checked)	{name}을(를) {version}(으)로 업데이트했습니다(이 릴리스는 체크섬을 공개하지 않아 크기만 확인했습니다)+@msg	{name} installed: {version} (this release publishes no checksum, so only its size was checked)	{name}을(를) 설치했습니다: {version}(이 릴리스는 체크섬을 공개하지 않아 크기만 확인했습니다)+@msg	{name} was removed	{name}을(를) 제거했습니다+@msg	{name} is running. Quit it, then try again.	{name}이(가) 실행 중입니다. 종료한 뒤 다시 시도하세요.++# Command IDs for menu items (@id)+# Format: @id<TAB>command_id<TAB>translation+@id	app.install	설치+@id	app.update	{v}(으)로 업데이트+@id	app.open	열기+@id	app.download	{os}용 다운로드+@id	app.reveal	Finder에서 보기+@id	app.reinstall	다시 설치+@id	app.uninstall	제거…+@id	app.notes	릴리스 노트+@id	app.website	웹사이트+@id	app.github	GitHub 저장소+@id	app.releases	모든 릴리스+@id	launcher.update	업데이트 후 다시 시작+@id	launcher.download	다운로드+@id	launcher.notes	새로운 기능+@id	launcher.dismiss	닫기+@id	settings.open	설정+@id	settings.quit	ArtCraft Launcher 종료+@id	view.grid	격자+@id	view.table	표+@id	filter.all	전체+@id	filter.installed	설치됨+@id	filter.updates	업데이트+@id	filter.notinstalled	설치되지 않음+@id	sort.suite	스위트 순서+@id	sort.name	이름+@id	sort.inspired	참고한 앱+@id	sort.status	상태+@id	sort.installed	설치된 버전+@id	sort.latest	최신 버전+@id	sort.released	최신 릴리스+@id	help.discord	Discord+@id	help.github	GitHub+@id	help.website	웹사이트+@id	update.check	업데이트 확인+@id	update.check_auto	자동으로 업데이트 확인+@id	update.notify	설치된 앱에 업데이트가 있으면 알림+@id	update.prereleases	사전 릴리스(베타, 릴리스 후보) 포함+@id	linux.preferred_kind	새 앱 설치 형식+@id	tray.close_to_tray	창을 닫아도 트레이에서 계속 실행+@id	tray.show_on_current_desktop	현재 데스크톱에 창 표시+@id	tray.login_item	로그인할 때 ArtCraft Launcher 시작+@id	appearance.theme	모양++# Tray (menu bar) menu and tooltip+	Show ArtCraft Launcher	ArtCraft Launcher 표시+	Check for Updates	업데이트 확인+	Visit getartcraft.com	getartcraft.com 방문+	ArtCraft on GitHub	GitHub의 ArtCraft+	Join the ArtCraft Discord	ArtCraft Discord 참여+@plural	ArtCraft Launcher · {n} update available|ArtCraft Launcher · {n} updates available	ArtCraft Launcher · 업데이트 {n}개 있음diff --git a/crates/ui-egui/src/i18n/lang.rs b/crates/ui-egui/src/i18n/lang.rs--- a/crates/ui-egui/src/i18n/lang.rs+++ b/crates/ui-egui/src/i18n/lang.rs@@ -13,16 +13,17 @@ use super::detect::system_lang; pub enum Script {     Chinese,     Japanese,+    Korean, }  impl Script {     /// Every script a language can be written in.-    pub const ALL: [Script; 2] = [Script::Chinese, Script::Japanese];+    pub const ALL: [Script; 3] = [Script::Chinese, Script::Japanese, Script::Korean]; }  /// One supported UI language. pub struct LangInfo {-    /// Canonical BCP 47 code (`en`, `ru`, `zh-CN`, `de`, `fr`, `pt-BR`, `es`, `cs`, `pl`, `hu`, `ja`).+    /// Canonical BCP 47 code (`en`, `ru`, `zh-CN`, `de`, `fr`, `pt-BR`, `es`, `cs`, `pl`, `hu`, `ja`, `ko`).     /// Also the `interfaceLanguage` value.     pub code: &'static str,     /// The language's name in itself, shown in the Preferences dropdown.@@ -94,7 +95,7 @@ pub(super) fn plural_polish(n: u64) -> usize { }  /// The registry. English first: it is the fallback and the source language.-pub static LANGUAGES: [LangInfo; 11] = [+pub static LANGUAGES: [LangInfo; 12] = [     LangInfo {         code: "en",         name: "English",@@ -216,6 +217,17 @@ pub static LANGUAGES: [LangInfo; 11] = [         complete_menus: true,         catalog: OnceLock::new(),     },+    LangInfo {+        code: "ko",+        name: "한국어",+        english_name: "Korean",+        script: Some(Script::Korean),+        source: include_str!("ko.tsv"),+        plural: plural_none,+        plural_forms: 1,+        complete_menus: true,+        catalog: OnceLock::new(),+    }, ];  impl LangInfo {@@ -254,6 +266,7 @@ impl Lang {     pub const PL: Lang = Lang(&LANGUAGES[8]);     pub const HU: Lang = Lang(&LANGUAGES[9]);     pub const JA: Lang = Lang(&LANGUAGES[10]);+    pub const KO: Lang = Lang(&LANGUAGES[11]);      pub fn code(self) -> &'static str {         self.0.codediff --git a/crates/ui-egui/src/i18n/tests.rs b/crates/ui-egui/src/i18n/tests.rs--- a/crates/ui-egui/src/i18n/tests.rs+++ b/crates/ui-egui/src/i18n/tests.rs@@ -384,6 +384,24 @@ fn japanese_locales_and_counts_work() {     assert_eq!(message(Lang::JA, "PhotoCraft updated to 0.5.0"), "PhotoCraft を 0.5.0 に更新しました"); } +#[test]+fn korean_locales_and_counts_work() {+    for tag in ["ko", "ko-KR", "ko_KR.UTF-8", "KO_kr"] {+        assert_eq!(lang_from_tag(tag), Some(Lang::KO), "{tag}");+    }+    assert_eq!(super::detect::first_supported(["xx-XX", "ko-KR", "en-US"]), Some(Lang::KO));+    // Korean has one plural form.+    for n in [0, 1, 2, 11, 100] {+        assert_eq!(trn(Lang::KO, n, "{n} app", "{n} apps"), format!("앱 {n}개"));+        assert_eq!(trn(Lang::KO, n, "{n} day ago", "{n} days ago"), format!("{n}일 전"));+    }+    assert_eq!(trn(Lang::KO, 2, "{n} unknown item", "{n} unknown items"), "2 unknown items");+    assert_eq!(tr(Lang::KO, "Untranslated diagnostic"), "Untranslated diagnostic");+    assert_eq!(super::tr_ctx(Lang::KO, "month", "Mar"), "3월");+    assert_eq!(tr(Lang::KO, "{month} {day}, {year}"), "{year}년 {month} {day}일");+    assert_eq!(message(Lang::KO, "PhotoCraft updated to 0.5.0"), "PhotoCraft을(를) 0.5.0(으)로 업데이트했습니다");+}+ /// With the system's Chinese font installed, every UI family can draw the whole Chinese catalog. /// Machines without one (CI, the web) skip this; the UI then stays in English. #[test]