Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ATTRIBUTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ iconography, images or other Adobe assets; open licences only; every asset attri
| `crates/ui-egui/src/i18n/it.tsv` | FilmCraft contributors | Original work: clean-room Italian interface translations | MIT OR Apache-2.0 |
| `crates/ui-egui/src/i18n/id.tsv` | FilmCraft contributors | Original work: clean-room Indonesian interface translations | MIT OR Apache-2.0 |
| `crates/ui-egui/src/i18n/ko.tsv` | FilmCraft contributors | Original work: clean-room Korean interface translations | MIT OR Apache-2.0 |
| `crates/ui-egui/src/i18n/th.tsv` | FilmCraft contributors | Original work: clean-room Thai interface translations | MIT OR Apache-2.0 |
| `crates/ui-egui/src/i18n/fr.tsv` | FilmCraft contributors | Original work: clean-room French interface translations | MIT OR Apache-2.0 |
| `crates/ui-egui/src/i18n/pt-br.tsv` | FilmCraft contributors | Original work: clean-room Brazilian Portuguese interface translations | MIT OR Apache-2.0 |
| `crates/ui-egui/src/i18n/ru.tsv` | FilmCraft contributors | Original work: clean-room Russian interface translations | MIT OR Apache-2.0 |
Expand Down
2 changes: 1 addition & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ Premiere ships 10 interface languages. Measured from our catalogs (3,498 strings
| German | menus only (native-reviewed) | 10.6% |
| Vietnamese | none | 0% |

Also shipped: Ukrainian (menus only, 10%). Detail: [docs/localization-parity.md](docs/localization-parity.md).
Also shipped: Ukrainian (menus only, 10%), Thai (full interface). Detail: [docs/localization-parity.md](docs/localization-parity.md).

## Upcoming

Expand Down
7 changes: 7 additions & 0 deletions apps/filmcraft/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,13 @@ fn app_creator(launch: Launch, graphics: graphics::GraphicsStart, created: Arc<A
}
let mut app = FilmcraftApp::new(session);
app.graphics_notice = notice;
// winit has no file drag-and-drop on Wayland: say so (Import mode points at
// Browse files… instead) rather than silently swallowing drops. X11
// (`WAYLAND_DISPLAY` unset), Windows and macOS deliver them.
app.os_file_drop_unsupported = filmcraft_ui_egui::os_file_drop_unsupported();
if app.os_file_drop_unsupported {
log::warn!("OS file drag-and-drop is unavailable on Wayland; run with WAYLAND_DISPLAY unset (X11) to drag files in, or use File ▸ Import…");
}
if recover == Some(false) {
app.dialog = None;
}
Expand Down
2 changes: 2 additions & 0 deletions apps/filmcraft/src/native_menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ pub fn install(app: &FilmcraftApp, ctx: egui::Context) -> (Receiver<String>, Men
filmcraft_ui_egui::i18n::Language::It
} else if checked("app.language.korean") {
filmcraft_ui_egui::i18n::Language::Ko
} else if checked("app.language.thai") {
filmcraft_ui_egui::i18n::Language::Th
} else {
filmcraft_ui_egui::i18n::Language::En
};
Expand Down
1 change: 1 addition & 0 deletions crates/engine/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1009,6 +1009,7 @@ static CATEGORIES: &[Category] = &[
("id", "Bahasa Indonesia"),
("it", "Italiano"),
("ko", "한국어"),
("th", "ไทย"),
]),
true,
),
Expand Down
6 changes: 6 additions & 0 deletions crates/engine/src/settings_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ fn interface_language_persists_and_rejects_hostile_values() {
}
set(&mut s, "general.interfaceLanguage", json!("it"));
assert_eq!(Preferences::load(&path).general.interface_language, "it");
// Thai is stored as `th`, not a locale tag
for value in [json!("th-TH"), json!("TH")] {
assert!(s.execute("prefs.set", json!({"key": "general.interfaceLanguage", "value": value})).is_err());
}
set(&mut s, "general.interfaceLanguage", json!("th"));
assert_eq!(Preferences::load(&path).general.interface_language, "th");
// back to following the operating system (#218)
set(&mut s, "general.interfaceLanguage", json!("system"));
assert_eq!(Preferences::load(&path).general.interface_language, "system");
Expand Down
4 changes: 2 additions & 2 deletions crates/ui-egui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ the committed span and undo. Set `FILMCRAFT_UI_SNAPSHOT_DIR` to render screensho
## Localisation

Edit > Language offers English, Japanese, Spanish, Brazilian Portuguese, Ukrainian, Simplified
Chinese, German, Russian, French, Indonesian, Korean and Italian (which cover the whole interface). The language is stored in the engine's `general.interfaceLanguage` preference,
Chinese, German, Russian, French, Indonesian, Korean, Thai and Italian (which cover the whole interface). The language is stored in the engine's `general.interfaceLanguage` preference,
restored on startup, and also available in Settings > General.
Its default, System Language (`system`), follows the operating system: the first of the user's
preferred languages that the interface has (the host supplies them through
`HostHooks::system_languages`: `sys-locale` on the desktop, `navigator.languages` on the web),
otherwise English.
The `app.language.*` UI commands and `prefs.set` reach it through the control channel.
Japanese requires a craft-fonts build or a suitable installed font.
Japanese, Korean and Thai require a craft-fonts build or a suitable installed font.

English source strings are lookup keys in `src/i18n/<code>.tsv`. `tl!` translates literals, `tlf!`
fills translated templates, and `i18n::t` translates names from registries. Placeholder values
Expand Down
56 changes: 56 additions & 0 deletions crates/ui-egui/src/cjk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,26 @@ pub(crate) fn craft_fonts() -> impl Iterator<Item = &'static filmcraft_text::fon
const KOREAN_SAMPLE: &str = "한국어입력테스트";
const KOREAN_PREFERRED: &[&str] = &["Malgun Gothic", "Apple SD Gothic Neo", "Noto Sans CJK KR", "Noto Sans KR", "Source Han Sans K", "NanumGothic"];

// Thai: neither the UI fonts nor CJK fallbacks have it, so typed, pasted and UI Thai needs a fallback.
const THAI_SAMPLE: &str = "ภาษาไทยตัวอย่างการทดสอบ";
const THAI_PREFERRED: &[&str] = &[
"Leelawadee UI",
"Leelawadee",
"Tahoma",
"Thonburi",
"Ayuthaya",
"Sathu",
"Noto Sans Thai",
"Noto Sans Thai Looped",
"Sarabun",
"TH Sarabun New",
"TH SarabunPSK",
"Garuda",
"Loma",
"Kinnari",
"Waree",
];

fn system_font() -> Option<Arc<FontData>> {
static FONT: OnceLock<Option<Arc<FontData>>> = OnceLock::new();
FONT.get_or_init(|| find_system_font(SAMPLE, PREFERRED)).clone()
Expand All @@ -38,6 +58,15 @@ fn korean_font() -> Option<Arc<FontData>> {
FONT.get_or_init(|| find_system_font(KOREAN_SAMPLE, KOREAN_PREFERRED)).clone()
}

fn thai_font() -> Option<Arc<FontData>> {
static FONT: OnceLock<Option<Arc<FontData>>> = OnceLock::new();
FONT.get_or_init(|| find_system_font(THAI_SAMPLE, THAI_PREFERRED)).clone()
}

pub(crate) fn craft_thai_fonts() -> impl Iterator<Item = &'static filmcraft_text::fonts::CraftFont> {
filmcraft_text::fonts::CRAFT_FONTS.iter().filter(|f| f.scripts.contains(&"Thai"))
}

/// A font collection's face index matters: Windows CJK UI fonts commonly live in TTC files.
/// Keep the owned bytes behind an Arc so theme reinstalls do not reread or leak a font file.
fn find_system_font(sample: &str, preferred: &[&str]) -> Option<Arc<FontData>> {
Expand All @@ -59,6 +88,12 @@ pub(crate) fn korean_available() -> bool {
korean_font().is_some()
}

/// Whether [`install`] has a Thai face to add: craft-fonts Thai faces, or an installed system
/// face (scanned once per process). The Thai interface needs one.
pub(crate) fn thai_available() -> bool {
craft_thai_fonts().next().is_some() || thai_font().is_some()
}

/// Whether [`install`] has a Chinese face to add: craft-fonts Hans/Hant faces, or an installed
/// system face (scanned once per process). The Simplified Chinese interface needs one.
pub(crate) fn available() -> bool {
Expand All @@ -76,6 +111,27 @@ pub(crate) fn install(fonts: &mut FontDefinitions) {
stack.push("system-korean".into());
}
}
install_thai(fonts);
}

fn install_thai(fonts: &mut FontDefinitions) {
let thai: Vec<_> = craft_thai_fonts().collect();
if thai.is_empty() {
if let Some(font) = thai_font() {
fonts.font_data.insert("system-thai".into(), font);
for stack in fonts.families.values_mut() {
stack.push("system-thai".into());
}
}
return;
}
let name = |f: &filmcraft_text::fonts::CraftFont| format!("craft:{} {}", f.family, f.style);
for f in &thai {
fonts.font_data.insert(name(f), Arc::new(FontData::from_static(f.bytes)));
}
for stack in fonts.families.values_mut() {
stack.extend(thai.iter().map(|f| name(f)));
}
}

fn install_chinese(fonts: &mut FontDefinitions) {
Expand Down
7 changes: 7 additions & 0 deletions crates/ui-egui/src/i18n/es.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -3443,6 +3443,7 @@
The language changed but could not be saved: {e} El idioma ha cambiado, pero no se ha podido guardar: {e}
no Chinese font is installed on this system; the interface stays in English no hay ninguna fuente china instalada en este sistema; la interfaz sigue en inglés
no Korean font is installed on this system; the interface stays in English No hay ninguna fuente coreana instalada en este sistema; la interfaz sigue en inglés
no Thai font is installed on this system; the interface stays in English No hay ninguna fuente tailandesa instalada en este sistema; la interfaz sigue en inglés
no Japanese font is installed on this system; the interface stays in English no hay ninguna fuente japonesa instalada en este sistema; la interfaz sigue en inglés
Show Mostrar
Sort Ordenar
Expand Down Expand Up @@ -3610,3 +3611,9 @@
Shows the version, community links and credits in a FilmCraft window. Muestra la versión, los enlaces de la comunidad y los créditos en una ventana de FilmCraft.
Couldn't open your web browser No se pudo abrir el navegador web
Open this address in your browser yourself: Abre esta dirección tú mismo en el navegador:
Could not import the dropped files No se pudieron importar los archivos soltados
Imported 1 file 1 archivo importado
Imported {n} files Importados {n} archivos
Drop to import Suelta para importar
Drop on the Timeline to place the clips Suelta en la línea de tiempo para colocar los clips
Add media to your project. Drag-and-drop needs X11 (run with WAYLAND_DISPLAY unset), or choose a source below. Añade medios a tu proyecto. Arrastrar y soltar necesita X11 (ejecuta sin WAYLAND_DISPLAY), o elige una fuente abajo.
7 changes: 7 additions & 0 deletions crates/ui-egui/src/i18n/ja.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -3428,6 +3428,7 @@
The language changed but could not be saved: {e} 表示言語は変更されましたが、保存できませんでした: {e}
no Chinese font is installed on this system; the interface stays in English このシステムには中国語フォントがインストールされていないため、表示は英語のままです
no Korean font is installed on this system; the interface stays in English このシステムには韓国語フォントがインストールされていないため、表示は英語のままです
no Thai font is installed on this system; the interface stays in English このシステムにはタイ語フォントがインストールされていないため、表示は英語のままです
no Japanese font is installed on this system; the interface stays in English このシステムには日本語フォントがインストールされていないため、表示は英語のままです
Show 表示
Sort 並べ替え
Expand Down Expand Up @@ -3609,3 +3610,9 @@
Shows the version, community links and credits in a FilmCraft window. バージョン、コミュニティへのリンク、クレジットを FilmCraft のウィンドウに表示します。
Couldn't open your web browser ウェブブラウザーを開けませんでした
Open this address in your browser yourself: このアドレスをご自身でブラウザーで開いてください:
Could not import the dropped files ドロップされたファイルを読み込めませんでした
Imported 1 file 1 個のファイルを読み込みました
Imported {n} files {n} 個のファイルを読み込みました
Drop to import ドロップして読み込む
Drop on the Timeline to place the clips タイムラインにドロップするとクリップを配置します
Add media to your project. Drag-and-drop needs X11 (run with WAYLAND_DISPLAY unset), or choose a source below. プロジェクトにメディアを追加します。ドラッグ&ドロップには X11 が必要です(WAYLAND_DISPLAY を外して実行)。または下から選んでください。
Loading