mirror of
https://github.com/storytold/figcraft.git
synced 2026-10-27 20:06:53 -06:00
Merge main into #1373
This commit is contained in:
Generated
+39
-2
@@ -855,7 +855,20 @@ checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"core-foundation 0.9.4",
|
||||
"core-graphics-types",
|
||||
"core-graphics-types 0.1.3",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-graphics"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97"
|
||||
dependencies = [
|
||||
"bitflags 2.13.2",
|
||||
"core-foundation 0.10.1",
|
||||
"core-graphics-types 0.2.0",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
]
|
||||
@@ -871,6 +884,28 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-graphics-types"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb"
|
||||
dependencies = [
|
||||
"bitflags 2.13.2",
|
||||
"core-foundation 0.10.1",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-text"
|
||||
version = "22.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "333dab512ce710ca2d08574c373d246dbeac8b22769e47da4c0e72730ce442b7"
|
||||
dependencies = [
|
||||
"core-foundation 0.10.1",
|
||||
"core-graphics 0.25.0",
|
||||
"foreign-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core_detect"
|
||||
version = "1.0.0"
|
||||
@@ -1782,10 +1817,12 @@ dependencies = [
|
||||
name = "figcraft-text"
|
||||
version = "0.11.2"
|
||||
dependencies = [
|
||||
"core-text",
|
||||
"figcraft-doc",
|
||||
"figcraft-geom",
|
||||
"harfrust 0.13.3",
|
||||
"log",
|
||||
"objc2 0.6.5",
|
||||
"png",
|
||||
"skrifa 0.47.0",
|
||||
"unicode-bidi",
|
||||
@@ -5982,7 +6019,7 @@ dependencies = [
|
||||
"cfg_aliases",
|
||||
"concurrent-queue",
|
||||
"core-foundation 0.9.4",
|
||||
"core-graphics",
|
||||
"core-graphics 0.23.2",
|
||||
"cursor-icon",
|
||||
"dpi",
|
||||
"js-sys",
|
||||
|
||||
@@ -18,3 +18,13 @@ png = { workspace = true }
|
||||
unicode-bidi = { workspace = true }
|
||||
unicode-segmentation = { workspace = true }
|
||||
log = { workspace = true }
|
||||
|
||||
# Fonts that font managers (RightFont, FontBase, Typeface) activate without copying them into a font
|
||||
# folder are known only to Core Text. Its safe wrappers list every available font's file (Core Text
|
||||
# needs unsafe FFI, which the workspace forbids). 22.0 is the first release whose
|
||||
# `get_descriptors` takes ownership of the array correctly (20.x and 21.x leak it on every scan);
|
||||
# it brings core-foundation 0.10, core-graphics 0.25 and core-graphics-types 0.2 beside the older
|
||||
# versions other crates use. Pinned exactly: review the diff before bumping.
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
core-text = { version = "=22.0.0", default-features = false, features = ["link"] }
|
||||
objc2 = "0.6"
|
||||
|
||||
+64
-32
@@ -817,9 +817,7 @@ impl FontDb {
|
||||
}
|
||||
self.system_scanned = true;
|
||||
let mut found = BTreeMap::new();
|
||||
for dir in system_font_dirs() {
|
||||
scan_dir(&dir, 0, &mut found);
|
||||
}
|
||||
scan_installed_fonts(&mut found);
|
||||
self.merge_scan(found);
|
||||
}
|
||||
|
||||
@@ -924,29 +922,45 @@ fn scan_dir(dir: &std::path::Path, depth: usize, out: &mut BTreeMap<String, (Str
|
||||
scan_dir(&path, depth + 1, out);
|
||||
continue;
|
||||
}
|
||||
// Font-like names can also belong to pipes or devices; opening a pipe can block.
|
||||
// `meta` follows symlinks, so links to regular font files remain supported.
|
||||
if !meta.is_file() {
|
||||
continue;
|
||||
}
|
||||
let ext = path.extension().and_then(std::ffi::OsStr::to_str).map(str::to_ascii_lowercase).unwrap_or_default();
|
||||
if !matches!(ext.as_str(), "ttf" | "otf" | "ttc" | "otc") && !(path.extension().is_none() && starts_like_a_font(&path)) {
|
||||
continue;
|
||||
}
|
||||
// Very large files are indexed all the same (Apple Color Emoji is ~180 MB and is where the
|
||||
// system's colour emoji live): `index_bytes` reads headers and name tables out of a zeroed
|
||||
// buffer, so only those parts are ever touched.
|
||||
if meta.len() > MAX_FONT_FILE {
|
||||
continue;
|
||||
}
|
||||
let Some(bytes) = usize::try_from(meta.len()).ok().and_then(|l| index_bytes(&path, l)) else { continue };
|
||||
for (index, family, style, postscript) in faces_in(&bytes) {
|
||||
out.entry(family.to_lowercase()).or_insert_with(|| (family.clone(), Vec::new())).1.push(Pending {
|
||||
path: path.clone(),
|
||||
index,
|
||||
style,
|
||||
postscript,
|
||||
});
|
||||
index_font_file(&path, &meta, out);
|
||||
}
|
||||
}
|
||||
|
||||
fn index_font_file(path: &std::path::Path, meta: &std::fs::Metadata, out: &mut BTreeMap<String, (String, Vec<Pending>)>) {
|
||||
// Font-like names can also belong to pipes or devices; opening a pipe can block.
|
||||
// `meta` follows symlinks, so links to regular font files remain supported.
|
||||
if !meta.is_file() {
|
||||
return;
|
||||
}
|
||||
let ext = path.extension().and_then(std::ffi::OsStr::to_str).map(str::to_ascii_lowercase).unwrap_or_default();
|
||||
if !matches!(ext.as_str(), "ttf" | "otf" | "ttc" | "otc") && !(path.extension().is_none() && starts_like_a_font(path)) {
|
||||
return;
|
||||
}
|
||||
// Very large files are indexed all the same (Apple Color Emoji is ~180 MB and is where the
|
||||
// system's colour emoji live): `index_bytes` reads headers and name tables out of a zeroed
|
||||
// buffer, so only those parts are ever touched.
|
||||
if meta.len() > MAX_FONT_FILE {
|
||||
return;
|
||||
}
|
||||
let Some(bytes) = usize::try_from(meta.len()).ok().and_then(|l| index_bytes(path, l)) else { return };
|
||||
for (index, family, style, postscript) in faces_in(&bytes) {
|
||||
out.entry(family.to_lowercase()).or_insert_with(|| (family.clone(), Vec::new())).1.push(Pending {
|
||||
path: path.to_path_buf(),
|
||||
index,
|
||||
style,
|
||||
postscript,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn scan_installed_fonts(out: &mut BTreeMap<String, (String, Vec<Pending>)>) {
|
||||
let dirs = system_font_dirs();
|
||||
for dir in &dirs {
|
||||
scan_dir(dir, 0, out);
|
||||
}
|
||||
for path in files_outside_dirs(font_manager_files(), &dirs) {
|
||||
if let Ok(meta) = std::fs::metadata(&path) {
|
||||
index_font_file(&path, &meta, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -959,6 +973,28 @@ fn starts_like_a_font(path: &std::path::Path) -> bool {
|
||||
std::fs::File::open(path).and_then(|mut f| f.read_exact(&mut magic)).is_ok() && matches!(&magic, &[0, 1, 0, 0] | b"OTTO" | b"true" | b"ttcf")
|
||||
}
|
||||
|
||||
fn files_outside_dirs(files: Vec<std::path::PathBuf>, dirs: &[std::path::PathBuf]) -> std::collections::BTreeSet<std::path::PathBuf> {
|
||||
files.into_iter().filter(|file| file.is_absolute() && !dirs.iter().any(|dir| file.starts_with(dir))).collect()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn font_manager_files() -> Vec<std::path::PathBuf> {
|
||||
std::panic::catch_unwind(|| {
|
||||
objc2::rc::autoreleasepool(|_| {
|
||||
core_text::font_collection::create_for_all_families()
|
||||
.get_descriptors()
|
||||
.map(|descriptors| descriptors.iter().filter_map(|descriptor| descriptor.font_path()).collect())
|
||||
.unwrap_or_default()
|
||||
})
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
fn font_manager_files() -> Vec<std::path::PathBuf> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
/// The largest font file read (CJK collections run to ~120 MB, Apple Color Emoji ~180 MB).
|
||||
pub const MAX_FONT_FILE: u64 = 256 * 1024 * 1024;
|
||||
|
||||
@@ -1082,9 +1118,7 @@ pub fn scan_system_fonts() {
|
||||
if !system_fonts_opted_out() {
|
||||
SCANS.fetch_add(1, Ordering::Relaxed);
|
||||
let mut found: BTreeMap<String, (String, Vec<Pending>)> = BTreeMap::new();
|
||||
for dir in system_font_dirs() {
|
||||
scan_dir(&dir, 0, &mut found);
|
||||
}
|
||||
scan_installed_fonts(&mut found);
|
||||
let mut w = raw_db().write().unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||
w.system_scanned = true;
|
||||
w.merge_scan(found);
|
||||
@@ -1108,9 +1142,7 @@ pub fn rescan_system_fonts() -> Rescan {
|
||||
return Rescan { changed: added.clone(), added };
|
||||
}
|
||||
let mut found: BTreeMap<String, (String, Vec<Pending>)> = BTreeMap::new();
|
||||
for dir in system_font_dirs() {
|
||||
scan_dir(&dir, 0, &mut found);
|
||||
}
|
||||
scan_installed_fonts(&mut found);
|
||||
let rescan = raw_db().write().unwrap_or_else(std::sync::PoisonError::into_inner).merge_rescan(found);
|
||||
if !rescan.changed.is_empty() {
|
||||
crate::clear_layout_cache();
|
||||
|
||||
@@ -440,3 +440,54 @@ fn every_platform_has_a_thai_font_in_the_fallbacks() {
|
||||
assert!(at(thai).is_some_and(|i| i > latin), "{thai}");
|
||||
}
|
||||
}
|
||||
|
||||
// The paths are Unix absolute paths (font managers are a macOS thing): on Windows they aren't absolute.
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn font_manager_files_outside_the_font_folders_are_indexed_once() {
|
||||
let folders = [std::path::PathBuf::from("/Library/Fonts"), std::path::PathBuf::from("/Users/a/Library/Fonts")];
|
||||
let library = std::path::PathBuf::from("/Users/a/Fonts.rightfontlibrary/fonts/I/Inter/InterVariable.ttf");
|
||||
let files = vec![
|
||||
std::path::PathBuf::from("/Library/Fonts/Arial.ttf"),
|
||||
std::path::PathBuf::from("/Users/a/Library/Fonts/Sub/Brand.otf"),
|
||||
library.clone(),
|
||||
library.clone(),
|
||||
std::path::PathBuf::from("relative/Font.ttf"),
|
||||
std::path::PathBuf::from("/Library/FontsElsewhere/Mono.ttf"),
|
||||
];
|
||||
let outside: Vec<_> = files_outside_dirs(files, &folders).into_iter().collect();
|
||||
assert_eq!(outside, [std::path::PathBuf::from("/Library/FontsElsewhere/Mono.ttf"), library]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_font_file_outside_the_font_folders_is_indexed_from_its_path() {
|
||||
struct TempDir(std::path::PathBuf);
|
||||
impl Drop for TempDir {
|
||||
fn drop(&mut self) {
|
||||
let _ = std::fs::remove_dir_all(&self.0);
|
||||
}
|
||||
}
|
||||
let installed = system_font_dirs()
|
||||
.into_iter()
|
||||
.find_map(|d| std::fs::read_dir(d).into_iter().flatten().flatten().map(|e| e.path()).find(|p| p.extension().is_some_and(|x| x == "ttf")));
|
||||
let Some(font) = installed else { return };
|
||||
let tmp = TempDir(std::env::temp_dir().join(format!("figcraft-font-manager-{}", std::process::id())));
|
||||
std::fs::create_dir_all(&tmp.0).unwrap();
|
||||
let copy = tmp.0.join("Activated.ttf");
|
||||
std::fs::copy(&font, ©).unwrap();
|
||||
let mut pending = BTreeMap::new();
|
||||
index_font_file(©, &std::fs::metadata(©).unwrap(), &mut pending);
|
||||
let paths: Vec<_> = pending.values().flat_map(|(_, p)| p.iter().map(|p| p.path.clone())).collect();
|
||||
assert!(!paths.is_empty() && paths.iter().all(|p| *p == copy), "{paths:?}");
|
||||
let mut none = BTreeMap::new();
|
||||
index_font_file(&tmp.0, &std::fs::metadata(&tmp.0).unwrap(), &mut none);
|
||||
assert!(none.is_empty());
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[test]
|
||||
fn core_text_lists_the_installed_font_files() {
|
||||
let files = font_manager_files();
|
||||
assert!(files.iter().any(|f| f.starts_with("/System/Library/Fonts")), "{} files", files.len());
|
||||
assert!(files.iter().all(|f| f.is_absolute()));
|
||||
}
|
||||
|
||||
@@ -1719,6 +1719,121 @@ status = "draft — needs native review"
|
||||
"⌘ click" = "⌘ 클릭"
|
||||
"⌘ scroll" = "⌘ 스크롤"
|
||||
"⌥ drag" = "⌥ 드래그"
|
||||
"A responsive product page: hero, features, figures, a quote and a footer" = "대표 영역, 기능, 수치, 인용문, 푸터로 구성된 반응형 제품 페이지"
|
||||
"A title, an agenda, a big figure, a chart and a closing slide" = "제목, 목차, 주요 수치, 차트, 마무리 슬라이드"
|
||||
"A to Z" = "이름 오름차순"
|
||||
"Adding to {name}" = "{name}에 추가 중"
|
||||
"All the fonts this file uses are installed" = "이 파일에 사용된 모든 글꼴이 설치되어 있습니다."
|
||||
"Alphabetical" = "가나다순"
|
||||
"An analytics screen on a grid: figures, charts drawn from vectors and a table" = "수치, 벡터 차트, 표를 격자로 배치한 분석 화면"
|
||||
"Apps" = "앱"
|
||||
"Apr" = "4월"
|
||||
"Aug" = "8월"
|
||||
"Bottom padding" = "아래쪽 안쪽 여백"
|
||||
"Bound to {name}. Click to detach the variable." = "{name}에 연결되어 있습니다. 클릭하면 변수 연결을 해제합니다."
|
||||
"Checking the fonts installed on this computer…" = "이 컴퓨터에 설치된 글꼴 확인 중…"
|
||||
"Colour and text styles, Light and Dark variables, buttons, inputs and cards" = "색상 및 텍스트 스타일, 밝게·어둡게 변수, 버튼, 입력란, 카드"
|
||||
"Convert to frame" = "프레임으로 변환"
|
||||
"Convert to section" = "섹션으로 변환"
|
||||
"Couldn't download the variables" = "변수를 다운로드할 수 없습니다."
|
||||
"Created" = "만든 날짜"
|
||||
"Dashboard" = "대시보드"
|
||||
"Date created" = "만든 날짜"
|
||||
"Dec" = "12월"
|
||||
"Design system starter" = "디자인 시스템 시작 키트"
|
||||
"Draw a frame" = "프레임 그리기"
|
||||
"Drop a .figcraft, .fig, .sketch, .json, .svg or image file." = ".figcraft, .fig, .sketch, .json, .svg 또는 이미지 파일을 놓으세요."
|
||||
"Drop to import" = "놓아서 가져오기"
|
||||
"Drop to open" = "놓아서 열기"
|
||||
"Edited {when}" = "{when} 편집"
|
||||
"Export frames and layers as PNG, JPG, SVG or PDF" = "프레임과 레이어를 PNG, JPG, SVG 또는 PDF로 내보내기"
|
||||
"Feb" = "2월"
|
||||
"File not found" = "파일을 찾을 수 없습니다."
|
||||
"Four screens of a trail app with components and a prototype flow" = "컴포넌트와 프로토타입 흐름이 포함된 트레일 앱 화면 4개"
|
||||
"Getting started" = "시작하기"
|
||||
"Greyscale components and two example screens to sketch a flow with" = "흐름을 구상할 수 있는 회색 음영 컴포넌트와 예시 화면 2개"
|
||||
"Hide these tips (Getting started in the Help menu shows them again)" = "팁 숨기기(도움말 메뉴의 시작하기에서 다시 표시)"
|
||||
"Hide when publishing" = "게시할 때 숨기기"
|
||||
"Icon components on a 24 px grid with keylines and a size preview" = "키라인과 크기 미리 보기가 포함된 24px 격자의 아이콘 컴포넌트"
|
||||
"Icon set starter" = "아이콘 세트 시작 키트"
|
||||
"Individual padding" = "개별 안쪽 여백"
|
||||
"Interface size" = "인터페이스 크기"
|
||||
"Jan" = "1월"
|
||||
"Jul" = "7월"
|
||||
"Jun" = "6월"
|
||||
"Kits" = "키트"
|
||||
"Landing page" = "랜딩 페이지"
|
||||
"Last modified" = "마지막 수정"
|
||||
"Left padding" = "왼쪽 안쪽 여백"
|
||||
"Link frames on the Prototype tab, then present the flow" = "프로토타입 탭에서 프레임을 연결한 다음 흐름을 실행해 보세요."
|
||||
"Make a component" = "컴포넌트 만들기"
|
||||
"Mar" = "3월"
|
||||
"May" = "5월"
|
||||
"Missing fonts" = "없는 글꼴"
|
||||
"Mobile app" = "모바일 앱"
|
||||
"Newest first" = "최신순"
|
||||
"No files or templates match your search" = "검색 조건에 맞는 파일이나 템플릿이 없습니다."
|
||||
"No other pages" = "다른 페이지 없음"
|
||||
"No templates match your search" = "검색 조건에 맞는 템플릿이 없습니다."
|
||||
"Nov" = "11월"
|
||||
"Oct" = "10월"
|
||||
"Oldest first" = "오래된순"
|
||||
"One announcement in five common sizes: square, portrait, story, link and banner" = "하나의 공지를 정사각형, 세로형, 스토리, 링크, 배너의 일반적인 5가지 크기로 구성"
|
||||
"Opening the file…" = "파일 여는 중…"
|
||||
"Opening {n} files as new files" = { other = "파일 {n}개를 새 파일로 여는 중" }
|
||||
"Order" = "순서"
|
||||
"Other" = "기타"
|
||||
"Pick the Frame tool, then drag on the canvas or choose a device size" = "프레임 도구를 선택한 뒤 캔버스에서 드래그하거나 기기 크기를 고르세요."
|
||||
"Plugin" = "플러그인"
|
||||
"Plugins & widgets" = "플러그인 및 위젯"
|
||||
"Presentation slides" = "프레젠테이션 슬라이드"
|
||||
"Playground" = "실험 공간"
|
||||
"Relative to your system's display scaling (100% is the system's own size). Document zoom is separate." = "시스템 디스플레이 배율을 기준으로 합니다(100%는 시스템 기본 크기). 문서 확대/축소는 별도입니다."
|
||||
"Remove from recents" = "최근 목록에서 제거"
|
||||
"Reorder selection" = "선택 항목 순서 변경"
|
||||
"Right padding" = "오른쪽 안쪽 여백"
|
||||
"Search templates" = "템플릿 검색"
|
||||
"See all templates" = "모든 템플릿 보기"
|
||||
"Select layers and they space themselves as their content changes" = "레이어를 선택하면 내용 변경에 맞춰 간격이 자동으로 조정됩니다."
|
||||
"Search files and templates" = "파일 및 템플릿 검색"
|
||||
"Search results" = "검색 결과"
|
||||
"Search pages" = "페이지 검색"
|
||||
"Sep" = "9월"
|
||||
"Share with a code" = "코드로 공유"
|
||||
"Show all templates" = "모든 템플릿 표시"
|
||||
"Show in Explorer" = "탐색기에서 보기"
|
||||
"Show in Finder" = "Finder에서 보기"
|
||||
"Show in folder" = "폴더에서 보기"
|
||||
"Social and slides" = "소셜 및 슬라이드"
|
||||
"Social post sizes" = "소셜 게시물 크기"
|
||||
"Sort by" = "정렬 기준"
|
||||
"Sort by {column}" = "{column} 기준 정렬"
|
||||
"Start from a template" = "템플릿으로 시작"
|
||||
"Start sharing with the Share button, then pass on the code it gives" = "공유 버튼으로 공유를 시작한 뒤 표시되는 코드를 전달하세요."
|
||||
"The destination document is unavailable. Nothing was imported." = "대상 문서를 사용할 수 없습니다. 아무것도 가져오지 않았습니다."
|
||||
"The destination document was closed. Nothing was imported." = "대상 문서가 닫혔습니다. 아무것도 가져오지 않았습니다."
|
||||
"The destination page was removed. Nothing was imported." = "대상 페이지가 삭제되었습니다. 아무것도 가져오지 않았습니다."
|
||||
"The window is too small for {size}%, so the interface is drawn at {drawn}%. Make the window larger to use {size}%." = "창이 너무 작아 {size}% 대신 {drawn}%로 표시합니다. {size}%를 사용하려면 창을 키우세요."
|
||||
"This file is too large to join here (up to {mb} MB)" = "이 파일은 여기에 추가하기에 너무 큽니다(최대 {mb}MB)."
|
||||
"This file uses fonts that aren't installed on this computer. Their text is drawn in a fallback font until you install them." = "이 파일은 이 컴퓨터에 없는 글꼴을 사용합니다. 해당 글꼴을 설치할 때까지 대체 글꼴로 표시합니다."
|
||||
"Top padding" = "위쪽 안쪽 여백"
|
||||
"Try another search, or browse templates." = "다른 검색어를 입력하거나 템플릿을 둘러보세요."
|
||||
"Try another word, or look at every kind." = "다른 단어를 검색하거나 모든 종류를 확인하세요."
|
||||
"Turn a layer into a component, reuse it, and change every copy at once" = "레이어를 컴포넌트로 만들고 재사용하여 모든 사본을 한 번에 변경하세요."
|
||||
"Use your browser's zoom to change the interface size." = "인터페이스 크기는 브라우저의 확대/축소로 변경하세요."
|
||||
"Uses variables: each layer shows them in its own mode" = "변수 사용: 각 레이어의 모드에 따라 표시합니다."
|
||||
"Websites" = "웹사이트"
|
||||
"What you try here changes this preview and the code below, not the file" = "여기서 변경한 내용은 미리 보기와 아래 코드에만 적용되며 파일은 바뀌지 않습니다."
|
||||
"Widget" = "위젯"
|
||||
"Wireframe kit" = "와이어프레임 키트"
|
||||
"Z to A" = "이름 내림차순"
|
||||
"just now" = "방금"
|
||||
"only in a text style or variable" = "텍스트 스타일 또는 변수에서만 사용"
|
||||
"slot layers without a matching slot property were imported as frames" = "일치하는 슬롯 속성이 없는 슬롯 레이어를 프레임으로 가져왔습니다."
|
||||
"yesterday" = "어제"
|
||||
"{month} {day}, {year}" = "{year}년 {month} {day}일"
|
||||
"{n} text layers" = { other = "텍스트 레이어 {n}개" }
|
||||
"{percent}%" = "{percent}%"
|
||||
|
||||
[commands]
|
||||
"align.bottom" = "아래쪽 정렬"
|
||||
@@ -2312,6 +2427,24 @@ status = "draft — needs native review"
|
||||
"widget.setText" = "위젯 필드 편집"
|
||||
"window.focus" = "창을 맨 앞으로 가져오기"
|
||||
"window.new" = "새 창"
|
||||
"arrange.reorder" = "선택 항목 순서 변경"
|
||||
"component.hideWhenPublishing" = "게시할 때 숨기기"
|
||||
"object.convertToGroup" = "그룹으로 변환"
|
||||
"object.convertToFrame" = "프레임으로 변환"
|
||||
"object.convertToSection" = "섹션으로 변환"
|
||||
"text.rescanFonts" = "설치된 글꼴 다시 검색"
|
||||
"text.loadFont" = "글꼴 파일 불러오기"
|
||||
"view.outlinesHiddenLayers" = "윤곽선에 숨겨진 레이어 포함"
|
||||
"view.outlinesObjectBounds" = "윤곽선에 개체 경계 포함"
|
||||
"view.panelWidths" = "패널 너비 초기화"
|
||||
"pref.uiScale" = "인터페이스 크기"
|
||||
"help.gettingStarted" = "시작하기"
|
||||
"style.bind" = "스타일에 변수 연결"
|
||||
"component.playground" = "컴포넌트 실험실"
|
||||
"text.missingFonts" = "누락된 글꼴"
|
||||
"text.refit" = "글꼴에 맞게 텍스트 조정"
|
||||
"template.list" = "템플릿 목록"
|
||||
"file.newFromTemplate" = "템플릿에서 새로 만들기"
|
||||
|
||||
[menu]
|
||||
"bool.exclude" = "제외"
|
||||
@@ -2343,3 +2476,5 @@ status = "draft — needs native review"
|
||||
"view.themeDark" = "다크"
|
||||
"view.themeLight" = "라이트"
|
||||
"view.themeSystem" = "시스템 따르기"
|
||||
"view.outlinesHiddenLayers" = "숨겨진 레이어 포함"
|
||||
"view.outlinesObjectBounds" = "개체 경계 포함"
|
||||
|
||||
@@ -25,6 +25,12 @@ On Linux and other Unix systems except macOS, user fonts are read from
|
||||
`$XDG_DATA_HOME/fonts`, or `$HOME/.local/share/fonts` when `XDG_DATA_HOME` is unset,
|
||||
empty or relative. The legacy `$HOME/.fonts` directory is also scanned.
|
||||
|
||||
On macOS the font folders (`/System/Library/Fonts`, `/Library/Fonts`, `~/Library/Fonts` and the
|
||||
system's downloadable fonts) are read, and so is every other font file Core Text lists as
|
||||
available: fonts a font manager such as RightFont, FontBase or Typeface activates from its own
|
||||
library, without copying them into a font folder. Fonts activated while the app runs are found by
|
||||
`text.rescanFonts`, like newly installed ones.
|
||||
|
||||
On macOS, fonts activated through Adobe Fonts are read where Creative Cloud keeps them
|
||||
(`~/Library/Application Support/Adobe/CoreSync/plugins/livetype`), so they're available while
|
||||
they're active there. Files without an extension are read when they start like a font file.
|
||||
|
||||
Reference in New Issue
Block a user