G9: expand Ukrainian UI coverage (#333)
Translate the 396 current panel catalog rows and route Ukrainian Reveal labels for Finder, Explorer and File Manager. Enforce catalog parity, placeholder preservation and platform label coverage; update language docs. Use a fixed-size OCIO row iterator to satisfy the current Clippy gate. Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
parent
30aaddf7c2
commit
4823c08d9c
|
|
@ -1,5 +1,6 @@
|
|||
# Roadmap
|
||||
|
||||
- 2026-10-09: Ukrainian now covers all 396 current panel-catalog strings, including dialogs, buttons and tooltips, alongside its menu translation. The catalog keeps the same source keys and placeholder counts as the Chinese catalogs; missing or engine-generated text still falls back to English.
|
||||
- 2026-10-09: Settings ▸ General ▸ Language now translates the interface below the menu bar as well: panels, dialogs, buttons and tooltips read their text through `crates/ui-egui/src/i18n/ui.rs`, keyed by the English source string. Simplified and Traditional Chinese are complete (384 strings); Japanese rows can follow in the same file. A test fails when a converted panel gains a hard-coded string, and another keeps the catalog free of unused rows.
|
||||
- 2026-10-08: `effectcraft-cli render --out` resolves a relative path against the working directory, like `--project` (it used the project's folder, which doubled a path that already named it). Render Queue outputs set in a project are unchanged.
|
||||
- 2026-10-08: Long-press a grouped toolbar button to choose its tools, including Horizontal/Vertical Type; releasing the hold keeps the menu open. Existing point/paragraph text creation is unchanged.
|
||||
|
|
|
|||
|
|
@ -372,7 +372,7 @@ pub fn parse_spimtx(text: &str) -> Option<FileXform> {
|
|||
}
|
||||
let mut m = [0.0; 16];
|
||||
let mut offset = [0.0; 4];
|
||||
for (r, row) in v.chunks_exact(4).enumerate() {
|
||||
for (r, row) in v.as_chunks::<4>().0.iter().enumerate() {
|
||||
m[r * 4..r * 4 + 3].copy_from_slice(&row[..3]);
|
||||
offset[r] = row[3] / 65535.0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,7 +80,17 @@ fn supported(locale: Option<&str>) -> &'static str {
|
|||
}
|
||||
|
||||
pub(crate) fn label<'a>(app: &EffectcraftApp, command: &str, source: &'a str) -> &'a str {
|
||||
match language(app) {
|
||||
let language = language(app);
|
||||
// The engine names the platform's file manager before the catalog sees the label. These
|
||||
// two commands keep their ids, but on Windows/Linux their source is no longer "Finder".
|
||||
if language == "uk" && matches!(command, "file.revealInFinder" | "layer.revealInFinder") {
|
||||
match source {
|
||||
"Reveal in Explorer" => return "Показати у Провіднику",
|
||||
"Reveal in File Manager" => return "Показати у файловому менеджері",
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
match language {
|
||||
"ja" => lookup(JAPANESE, command, source),
|
||||
"zh-hans" => lookup(SIMPLIFIED_CHINESE, command, source),
|
||||
"zh-hant" => lookup(TRADITIONAL_CHINESE, command, source),
|
||||
|
|
@ -2727,6 +2737,30 @@ mod tests {
|
|||
assert_eq!(japanese_keys, ukrainian_keys, "the languages must translate the same entries");
|
||||
}
|
||||
|
||||
/// Exercise each engine spelling on every host: a macOS-only run must still catch a
|
||||
/// Windows/Linux catalog miss, while filenames and unrelated commands stay untouched.
|
||||
#[test]
|
||||
fn ukrainian_reveal_labels_follow_the_platform_file_manager() {
|
||||
let mut app = EffectcraftApp::new(effectcraft_engine::Session::default());
|
||||
app.session.execute("prefs.set", json!({"key": "general.language", "value": "uk"})).unwrap();
|
||||
for command in ["file.revealInFinder", "layer.revealInFinder"] {
|
||||
for (source, translated) in [
|
||||
("Reveal in Finder", "Показати у Finder"),
|
||||
("Reveal in Explorer", "Показати у Провіднику"),
|
||||
("Reveal in File Manager", "Показати у файловому менеджері"),
|
||||
] {
|
||||
let e = MenuEntry { label: source.into(), command: command.into(), params: json!({"item": "My file.mp4"}), shortcut: None };
|
||||
assert_eq!(label(&app, command, source), translated);
|
||||
assert_eq!(entry(&app, &e, source.into()), translated);
|
||||
assert_eq!(label(&app, "file.openRecent", source), source);
|
||||
}
|
||||
assert_eq!(label(&app, command, "My file.mp4"), "My file.mp4");
|
||||
}
|
||||
app.session.execute("prefs.set", json!({"key": "general.language", "value": "en"})).unwrap();
|
||||
assert_eq!(label(&app, "file.revealInFinder", "Reveal in Explorer"), "Reveal in Explorer");
|
||||
assert_eq!(label(&app, "layer.revealInFinder", "Reveal in File Manager"), "Reveal in File Manager");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn language_changes_native_labels_without_changing_commands_or_parameters() {
|
||||
let mut app = EffectcraftApp::new(effectcraft_engine::Session::default());
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use std::fmt::Display;
|
|||
use std::sync::OnceLock;
|
||||
|
||||
thread_local! {
|
||||
/// The resolved interface language ("en", "ja", "zh-hans", "zh-hant"); "en" until the first
|
||||
/// The resolved interface language ("en", "ja", "zh-hans", "zh-hant", "uk"); "en" until the first
|
||||
/// frame sets it.
|
||||
static CURRENT: Cell<&'static str> = const { Cell::new("en") };
|
||||
}
|
||||
|
|
@ -42,9 +42,11 @@ type Index = HashMap<&'static str, &'static str>;
|
|||
fn catalog(language: &str) -> Option<&'static Index> {
|
||||
static HANS: OnceLock<Index> = OnceLock::new();
|
||||
static HANT: OnceLock<Index> = OnceLock::new();
|
||||
static UK: OnceLock<Index> = OnceLock::new();
|
||||
let (index, rows) = match language {
|
||||
"zh-hans" => (&HANS, SIMPLIFIED_CHINESE),
|
||||
"zh-hant" => (&HANT, TRADITIONAL_CHINESE),
|
||||
"uk" => (&UK, UKRAINIAN),
|
||||
_ => return None,
|
||||
};
|
||||
Some(index.get_or_init(|| rows.iter().copied().collect()))
|
||||
|
|
@ -909,6 +911,437 @@ const TRADITIONAL_CHINESE: &[(&str, &str)] = &[
|
|||
("⚠ {} is used by:", "⚠ {} 已被以下專案使用:"),
|
||||
];
|
||||
|
||||
/// Ukrainian (uk): original translations of the same interface rows as the Chinese catalogs.
|
||||
/// Technical names, key names and substituted project content keep their original spelling.
|
||||
const UKRAINIAN: &[(&str, &str)] = &[
|
||||
(" OK ", " Гаразд "),
|
||||
(" Delete ", " Видалити "),
|
||||
(" Open Auto-Save ", " Відкрити автозбереження "),
|
||||
("(missing)", "(відсутній)"),
|
||||
("360 View Orientation", "Орієнтація огляду 360°"),
|
||||
("3:2 Pulldown: {}", "Перетворення кадрів 3:2: {}"),
|
||||
(
|
||||
"A clean-room, open-source compositor for motion graphics and visual effects: native on macOS, Windows and Linux, and in the browser. Part of the ArtCraft family of creative apps.",
|
||||
"Незалежно розроблена програма з відкритим кодом для компонування анімованої графіки та візуальних ефектів: працює на macOS, Windows і Linux, а також у браузері. Належить до родини творчих програм ArtCraft.",
|
||||
),
|
||||
("About EffectCraft", "Про EffectCraft"),
|
||||
("About...", "Про програму..."),
|
||||
("Active Camera", "Активна камера"),
|
||||
("Adapt Feature On Every Frame", "Адаптувати ознаку в кожному кадрі"),
|
||||
("Adaptive Sample Limit:", "Межа адаптивних вибірок:"),
|
||||
("Add Animator", "Додати аніматор"),
|
||||
("Add Comment", "Додати коментар"),
|
||||
("Add Formatting", "Додати форматування"),
|
||||
("Add Group", "Додати групу"),
|
||||
("Add Mirror", "Додати дзеркало"),
|
||||
("Add Selected As", "Додати виділене як"),
|
||||
("Add a comment", "Додати коментар"),
|
||||
("Add a shape, fill, stroke or path operation", "Додати фігуру, заливку, обведення або операцію з контуром"),
|
||||
("Add to Composition", "Додати до композиції"),
|
||||
("Add to Favorites", "Додати до обраного"),
|
||||
("Add:", "Додати:"),
|
||||
("Adjust Exposure (stops)", "Налаштувати експозицію (ступені)"),
|
||||
("Adjust composition duration to the time span of the selected layers", "Припасувати тривалість композиції до часового діапазону виділених шарів"),
|
||||
("Advanced 3D", "Розширений 3D"),
|
||||
("Align Layers to:", "Вирівняти шари відносно:"),
|
||||
("All six face cameras turn together; the scene is not changed.", "Усі шість камер граней повертаються разом; сцена залишається без змін."),
|
||||
("Anchor:", "Опорна точка:"),
|
||||
("Aperture", "Діафрагма"),
|
||||
("Apply Dimensions:", "Застосувати виміри:"),
|
||||
("Apply Motion To:", "Застосувати рух до:"),
|
||||
("Arrange", "Упорядкувати"),
|
||||
("Assign", "Призначити"),
|
||||
("Auto", "Автоматично"),
|
||||
("Auto-saves", "Автозбереження"),
|
||||
("Back", "Ззаду"),
|
||||
("Background Color:", "Колір тла:"),
|
||||
("Blend Mode:", "Режим змішування:"),
|
||||
("Blending Mode", "Режим змішування"),
|
||||
("Blur", "Розмиття"),
|
||||
("Blur Level", "Рівень розмиття"),
|
||||
("Browser Storage", "Сховище браузера"),
|
||||
("Browse…", "Огляд…"),
|
||||
("Brush Dynamics", "Динаміка пензля"),
|
||||
("Caching frames…", "Кешування кадрів…"),
|
||||
("Cancel", "Скасувати"),
|
||||
("Casts Shadows", "Відкидає тіні"),
|
||||
("Change Renderer…", "Змінити рушій рендерингу…"),
|
||||
(
|
||||
"Changing a shortcut creates a custom preset; the default stays as it is.",
|
||||
"Зміна клавіатурного скорочення створює власний набір; стандартний залишається без змін.",
|
||||
),
|
||||
("Channel", "Канал"),
|
||||
("Channel:", "Канал:"),
|
||||
("Chapter:", "Розділ:"),
|
||||
("Choose...", "Вибрати..."),
|
||||
("Classic 3D", "Класичний 3D"),
|
||||
("Clear", "Очистити"),
|
||||
("Clear list", "Очистити список"),
|
||||
("Click a key to see its commands.", "Клацніть клавішу, щоб переглянути її команди."),
|
||||
("Click adds a point (½ height = no change)", "Клацніть, щоб додати точку (½ висоти = без змін)"),
|
||||
("Click adds a point; drag one off to remove", "Клацніть, щоб додати точку; перетягніть її за межі, щоб вилучити"),
|
||||
("Click to make this viewer active", "Клацніть, щоб зробити цю область перегляду активною"),
|
||||
("Click to reveal the expression in the timeline", "Клацніть, щоб показати вираз на шкалі часу"),
|
||||
("Click to show the active composition here", "Клацніть, щоб показати тут активну композицію"),
|
||||
("Click, then click in the Composition panel", "Клацніть тут, а потім на панелі «Композиція»"),
|
||||
("Clone Options", "Параметри клонування"),
|
||||
("Clone Source Overlay:", "Накладання джерела клонування:"),
|
||||
("Close", "Закрити"),
|
||||
("Close Panel", "Закрити панель"),
|
||||
("Close tutorial", "Закрити урок"),
|
||||
("Color", "Колір"),
|
||||
("Color Depth: {}", "Глибина кольору: {}"),
|
||||
("Color:", "Колір:"),
|
||||
("Colour map", "Карта кольорів"),
|
||||
("Columns", "Стовпці"),
|
||||
("Comment:", "Коментар:"),
|
||||
("Community", "Спільнота"),
|
||||
("Composition", "Композиція"),
|
||||
("Composition Mini-Flowchart", "Мініблок-схема композиції"),
|
||||
("Composition Name:", "Назва композиції:"),
|
||||
("Composition Settings ▸ 3D Renderer", "Налаштування композиції ▸ Рушій 3D-рендерингу"),
|
||||
("Composition Settings…", "Налаштування композиції…"),
|
||||
("Composition marker bin: drag a marker to the time ruler", "Список маркерів композиції: перетягніть маркер на часову лінійку"),
|
||||
("Cone Angle", "Кут конуса"),
|
||||
("Cone Feather", "Розтушовування конуса"),
|
||||
("Constrain Proportions", "Зберігати пропорції"),
|
||||
("Continuous (Lock Outgoing to Incoming)", "Безперервна (прирівняти вихідну швидкість до вхідної)"),
|
||||
("Cue Point", "Сигнальна точка"),
|
||||
("Current Render", "Поточний рендеринг"),
|
||||
("Darker", "Темніше"),
|
||||
("Default Output:", "Стандартний вихід:"),
|
||||
("Default: {}", "Стандартне: {}"),
|
||||
("Defaults", "Стандартні значення"),
|
||||
("Delete", "Видалити"),
|
||||
("Delete Selected Points", "Видалити виділені точки"),
|
||||
("Delete selected project items", "Видалити виділені елементи проєкту"),
|
||||
("Delete this template", "Видалити цей шаблон"),
|
||||
("Depth of Field", "Глибина різкості"),
|
||||
("Discord", "Discord"),
|
||||
("Distribute Layers:", "Розподілити шари:"),
|
||||
("Don't Recover", "Не відновлювати"),
|
||||
("Don't Save", "Не зберігати"),
|
||||
("Double-click a layer to open it in the Layer panel", "Двічі клацніть шар, щоб відкрити його на панелі «Шар»"),
|
||||
("Double-click footage in the Project panel to open it here", "Двічі клацніть матеріал на панелі «Проєкт», щоб відкрити його тут"),
|
||||
("Double-click to edit the comment", "Двічі клацніть, щоб змінити коментар"),
|
||||
("Download", "Завантажити"),
|
||||
(
|
||||
"Drag properties here from the timeline,\nor use Animation > Add Property to Essential Graphics.",
|
||||
"Перетягніть сюди властивості зі шкали часу,\nабо скористайтеся командою «Анімація > Додати властивість до основної графіки».",
|
||||
),
|
||||
("Drag to change", "Перетягніть, щоб змінити"),
|
||||
("Drag to create a guide", "Перетягніть, щоб створити напрямну"),
|
||||
("Drag to slip the source", "Перетягніть, щоб зсунути матеріал у межах шару"),
|
||||
("Drop Frame", "Пропуск номерів"),
|
||||
("Duplicate", "Дублювати"),
|
||||
("Duration:", "Тривалість:"),
|
||||
("Edit Gradient…", "Редагувати градієнт…"),
|
||||
("Edit Target: {}", "Ціль редагування: {}"),
|
||||
("Edit in the Timeline", "Редагувати на шкалі часу"),
|
||||
("EffectCraft didn't quit normally last time.", "Минулого разу EffectCraft завершив роботу некоректно."),
|
||||
("Effects & Presets options", "Параметри ефектів і наборів"),
|
||||
("Effects: {}", "Ефекти: {}"),
|
||||
("Empty folder", "Порожня тека"),
|
||||
("Enable Depth of Field", "Увімкнути глибину різкості"),
|
||||
("Enable Expression", "Увімкнути вираз"),
|
||||
("Enhance", "Покращити"),
|
||||
("Essential Properties — {}", "Основні властивості — {}"),
|
||||
("Event", "Подія"),
|
||||
("Export Template…", "Експортувати шаблон…"),
|
||||
("Export...", "Експорт..."),
|
||||
("Expression Language Menu", "Меню мови виразів"),
|
||||
("Expression pick whip: drag onto a property", "Зв’язування виразу: перетягніть на властивість"),
|
||||
("Expression:", "Вираз:"),
|
||||
("Eyedropper: click, then click in the Composition panel", "Піпетка: клацніть тут, а потім на панелі «Композиція»"),
|
||||
("Falloff", "Згасання"),
|
||||
("Falloff Distance", "Відстань згасання"),
|
||||
("Favorites", "Обране"),
|
||||
("Field Render: {}", "Рендеринг полів: {}"),
|
||||
("Figures", "Цифри"),
|
||||
("Fill Target", "Ціль заливки"),
|
||||
("Finished", "Завершено"),
|
||||
("Flowchart: {}", "Блок-схема: {}"),
|
||||
("Focus Distance", "Відстань фокусування"),
|
||||
("Follow Feature Rotation and Scale", "Враховувати обертання та масштаб ознаки"),
|
||||
("Footage: {}", "Матеріал: {}"),
|
||||
("Format: {}", "Формат: {}"),
|
||||
("Frame Aspect Ratio: {}", "Пропорції кадру: {}"),
|
||||
("Frame Blending: {}", "Змішування кадрів: {}"),
|
||||
("Frame Rate:", "Частота кадрів:"),
|
||||
("Frame Render Time {}ms", "Час рендерингу кадру {} мс"),
|
||||
("Frame Target:", "Цільовий фрейм:"),
|
||||
("Grab bag", "Список"),
|
||||
("Grid", "Сітка"),
|
||||
("Guide Layers: {}", "Допоміжні шари: {}"),
|
||||
("Guides", "Напрямні"),
|
||||
("Height:", "Висота:"),
|
||||
("Hide This", "Приховати це"),
|
||||
("Histogram", "Гістограма"),
|
||||
("Hold In Place", "Утримувати на місці"),
|
||||
("Home", "Головна"),
|
||||
("If Confidence is Below", "Якщо достовірність нижча за"),
|
||||
("Import", "Імпортувати"),
|
||||
("Import and Add to Composition", "Імпортувати та додати до композиції"),
|
||||
("Import...", "Імпорт..."),
|
||||
("Imported media", "Імпортовані матеріали"),
|
||||
("Influence:", "Вплив:"),
|
||||
("Install from File…", "Встановити з файлу…"),
|
||||
("Intensity", "Інтенсивність"),
|
||||
("Inverted", "Інвертовано"),
|
||||
("Join the ArtCraft community on Discord", "Приєднайтеся до спільноти ArtCraft у Discord"),
|
||||
("Key: {}", "Клавіша: {}"),
|
||||
("LEARN", "НАВЧАННЯ"),
|
||||
("Label", "Мітка"),
|
||||
("Label Colors and Names:", "Кольори та назви міток:"),
|
||||
("Label:", "Мітка:"),
|
||||
("Latest auto-save: {}", "Останнє автозбереження: {}"),
|
||||
("Layer", "Шар"),
|
||||
("Layer controls", "Керування шарами"),
|
||||
("Layer {}", "Шар {}"),
|
||||
("Layer:", "Шар:"),
|
||||
("Layer: {}", "Шар: {}"),
|
||||
("Learn", "Навчання"),
|
||||
("Leave all attributes in \"{}\"", "Залишити всі атрибути в «{}»"),
|
||||
("Licence: {}", "Ліцензія: {}"),
|
||||
("Ligatures", "Лігатури"),
|
||||
("Light Type", "Тип світла"),
|
||||
("Lighter", "Світліше"),
|
||||
("Link Selected Property", "Зв’язати виділену властивість"),
|
||||
("Lock Aspect Ratio to {}", "Зафіксувати співвідношення сторін на {}"),
|
||||
("Lock to Zoom", "Прив’язати до масштабу"),
|
||||
("Locked: {} — {}", "Заблоковано: {} — {}"),
|
||||
("Log:", "Журнал:"),
|
||||
("Loop (Trace Path)", "Цикл (уздовж контуру)"),
|
||||
("MIT OR Apache-2.0 • Fonts: Inter, JetBrains Mono (OFL)", "MIT OR Apache-2.0 • Шрифти: Inter, JetBrains Mono (OFL)"),
|
||||
("Magnification ratio popup", "Меню коефіцієнта збільшення"),
|
||||
("Make Comp Size", "За розміром композиції"),
|
||||
("Masks", "Маски"),
|
||||
("Maximize Panel", "Розгорнути панель"),
|
||||
("Media Replacement", "Заміна матеріалу"),
|
||||
("Mesh:", "Сітка:"),
|
||||
("Method Used: {} Average Error: {} pixels", "Використаний метод: {} Середня похибка: {} пікселів"),
|
||||
("Models folder: {}", "Тека моделей: {}"),
|
||||
("Modifiers:", "Модифікатори:"),
|
||||
("More", "Більше"),
|
||||
("More ArtCraft apps", "Інші програми ArtCraft"),
|
||||
("More tutorials", "Інші уроки"),
|
||||
("Motion Blur", "Розмиття руху"),
|
||||
("Motion Blur: {}", "Розмиття руху: {}"),
|
||||
("Motion Sketch: drag to record", "Ескіз руху: перетягніть, щоб записати"),
|
||||
("Move Down", "Перемістити вниз"),
|
||||
("Move Up", "Перемістити вгору"),
|
||||
("Move to Project Root", "Перемістити до кореня проєкту"),
|
||||
("Name", "Назва"),
|
||||
("Name:", "Назва:"),
|
||||
("Navigation", "Навігація"),
|
||||
("New", "Створити"),
|
||||
("New Comp from Selection", "Нова композиція з виділеного"),
|
||||
("New Duration:", "Нова тривалість:"),
|
||||
("New composition name:", "Назва нової композиції:"),
|
||||
("New from Render Queue item:", "Створити з елемента черги рендерингу:"),
|
||||
("New from Template", "Створити із шаблону"),
|
||||
("Next", "Далі"),
|
||||
("Nice work. Pick another tutorial on the Home screen's Learn tab.", "Гарна робота. Виберіть інший урок на вкладці «Навчання» головного екрана."),
|
||||
(
|
||||
"No VR environments yet. Create one with Composition ▸ VR ▸ Create VR Environment…",
|
||||
"Середовищ VR ще немає. Створіть одне через «Композиція ▸ VR ▸ Створити середовище VR…».",
|
||||
),
|
||||
("No audio layer selected", "Аудіошар не виділено"),
|
||||
("No background jobs running", "Немає активних фонових завдань"),
|
||||
("No composition markers", "Немає маркерів композиції"),
|
||||
("No contributor data was built into this copy.", "Ця копія не містить даних про учасників."),
|
||||
(
|
||||
"No device list from this host; the system default output is used.",
|
||||
"Цей пристрій не надає списку пристроїв; використовується стандартний вихід системи.",
|
||||
),
|
||||
("No layer selected", "Шар не виділено"),
|
||||
("No matching effects or presets", "Не знайдено відповідних ефектів або наборів"),
|
||||
("No model credits were built into this copy.", "Ця копія не містить відомостей про моделі."),
|
||||
("No nested compositions", "Немає вкладених композицій"),
|
||||
("No shortcut", "Немає клавіатурного скорочення"),
|
||||
("No unlocked layer selected", "Не виділено жодного розблокованого шару"),
|
||||
("No video", "Немає відео"),
|
||||
("None", "Немає"),
|
||||
("Not applied: tick it in the list to add it.", "Не застосовано: позначте в списку, щоб додати."),
|
||||
("Not assigned", "Не призначено"),
|
||||
("Note: Shadows are only cast from layers with Cast Shadows enabled.", "Примітка: тіні відкидають лише шари з увімкненим параметром «Відкидати тіні»."),
|
||||
("Notify", "Сповістити"),
|
||||
("OK", "Гаразд"),
|
||||
("Offset:", "Зсув:"),
|
||||
("On ({}) stop:", "Після зупинки ({}):"),
|
||||
("One-Node Camera", "Одновузлова камера"),
|
||||
("Opacity:", "Непрозорість:"),
|
||||
("Open Composition", "Відкрити композицію"),
|
||||
("Open Last Saved Project", "Відкрити останній збережений проєкт"),
|
||||
("Open New Composition", "Відкрити нову композицію"),
|
||||
("Open Output", "Відкрити результат"),
|
||||
("Open a composition to build Essential Graphics", "Відкрийте композицію, щоб створити основну графіку"),
|
||||
("Open a composition to see its scopes", "Відкрийте композицію, щоб переглянути колірні діаграми"),
|
||||
("Open a composition to track motion.", "Відкрийте композицію, щоб відстежувати рух."),
|
||||
("Opus Tuning: {}", "Налаштування Opus: {}"),
|
||||
("Original Duration:", "Початкова тривалість:"),
|
||||
("Output Cycle: {}", "Цикл виводу: {}"),
|
||||
("Output To:", "Вивести до:"),
|
||||
("Parameter Name:", "Назва параметра:"),
|
||||
("Parent pick whip: drag onto a layer", "Зв’язування батьківського шару: перетягніть на шар"),
|
||||
("Pixel Aspect Ratio:", "Пропорції пікселя:"),
|
||||
("Playing on Video Preview", "Відтворення на відеоперегляді"),
|
||||
("Post-Render Action: {}", "Дія після рендерингу: {}"),
|
||||
("Preserve frame rate when nested or in render queue", "Зберігати частоту кадрів у вкладених композиціях або черзі рендерингу"),
|
||||
("Preserve resolution when nested", "Зберігати роздільність у вкладених композиціях"),
|
||||
("Preset", "Набір"),
|
||||
("Preset:", "Набір:"),
|
||||
("Presets", "Набори"),
|
||||
("Previous", "Назад"),
|
||||
("Primary:", "Основний:"),
|
||||
("Process Before Match", "Обробити перед зіставленням"),
|
||||
("Profile: {}", "Профіль: {}"),
|
||||
(
|
||||
"Project color depth: click to cycle 8/16/32 bpc, Alt-click for Project Settings",
|
||||
"Глибина кольору проєкту: клацніть, щоб перемикати 8/16/32 bpc, або клацніть з Alt, щоб відкрити налаштування проєкту",
|
||||
),
|
||||
("Project: {}", "Проєкт: {}"),
|
||||
("Projects", "Проєкти"),
|
||||
("Property pick whip: drag onto a property", "Зв’язування властивості: перетягніть на властивість"),
|
||||
("Protected Region", "Захищена область"),
|
||||
("Proxy Use: {}", "Використання проксі: {}"),
|
||||
("Push All to Comp", "Застосувати все до композиції"),
|
||||
("Radius", "Радіус"),
|
||||
("Rate Control: {}", "Керування бітовою швидкістю: {}"),
|
||||
("Recent", "Нещодавні"),
|
||||
("Recording", "Запис"),
|
||||
("Remove", "Вилучити"),
|
||||
("Rename", "Перейменувати"),
|
||||
("Render: {} ms • UI {} fps{}", "Рендеринг: {} мс • Інтерфейс {} кадр/с{}"),
|
||||
("Renderer:", "Рушій рендерингу:"),
|
||||
("Request Persistent Storage", "Запросити постійне сховище"),
|
||||
("Reset", "Скинути"),
|
||||
("Reset Labels", "Скинути мітки"),
|
||||
("Reset Preset", "Скинути набір"),
|
||||
("Reset to Default", "Відновити стандартні значення"),
|
||||
("Reset to Saved Layout", "Відновити збережене компонування"),
|
||||
("Resolution/Down Sample Factor Popup", "Меню роздільності та коефіцієнта зменшення"),
|
||||
("Restore Panel Size", "Відновити розмір панелі"),
|
||||
("Reverse the order", "Обернути порядок"),
|
||||
("Revert All", "Відновити все"),
|
||||
("Roman Hanging Punctuation", "Висячі латинські розділові знаки"),
|
||||
("Roving:", "Автоматичний час:"),
|
||||
("Ruler zero point (drag to move, double-click to reset)", "Початок лінійки (перетягніть, щоб перемістити; двічі клацніть, щоб скинути)"),
|
||||
("Rulers", "Лінійки"),
|
||||
("Run", "Виконати"),
|
||||
("Sample Format: {}", "Формат вибірок: {}"),
|
||||
("Samples Per Frame:", "Вибірок на кадр:"),
|
||||
("Save from #{}", "Зберегти з #{}"),
|
||||
("Saved {}", "Збережено {}"),
|
||||
("Script… (⌘/Ctrl+Enter runs)", "Скрипт… (⌘/Ctrl+Enter запускає)"),
|
||||
("Search commands or shortcuts", "Пошук команд або клавіатурних скорочень"),
|
||||
("Select", "Виділити"),
|
||||
("Select a command to change its shortcut.", "Виберіть команду, щоб змінити її клавіатурне скорочення."),
|
||||
("Select a layer to see its effects", "Виділіть шар, щоб переглянути його ефекти"),
|
||||
("Select a layer to see its properties", "Виділіть шар, щоб переглянути його властивості"),
|
||||
(
|
||||
"Select a layer with a mask or shape path (or the path property), or Puppet pins.",
|
||||
"Виділіть шар із маскою або контуром фігури (або властивість контуру) чи опорні точки деформації.",
|
||||
),
|
||||
("Select a text layer", "Виділіть текстовий шар"),
|
||||
("Select an item in the Project panel", "Виділіть елемент на панелі «Проєкт»"),
|
||||
("Select animated properties to show them in the Graph Editor", "Виділіть анімовані властивості, щоб показати їх у редакторі графіків"),
|
||||
(
|
||||
"Select the leader pin, then Shift-click the pins that should trail it (hair, cloth, tails)",
|
||||
"Виділіть провідну опорну точку, а потім клацніть із Shift точки, які мають рухатися за нею (волосся, тканина, хвости)",
|
||||
),
|
||||
("Set Ground Plane and Origin", "Задати площину землі та початок координат"),
|
||||
("Set Paint Colors to Black and White (D)", "Задати чорний і білий кольори малювання (D)"),
|
||||
("Settings", "Налаштування"),
|
||||
("Settings Name:", "Назва налаштувань:"),
|
||||
("Shadow Darkness", "Темнота тіні"),
|
||||
("Shadow Diffusion", "Розсіювання тіні"),
|
||||
("Shadows", "Тіні"),
|
||||
("Shape…", "Фігура…"),
|
||||
("Show", "Показати"),
|
||||
("Show Layer Name", "Показати назву шару"),
|
||||
("Show Source Name", "Показати назву матеріалу"),
|
||||
("Show me", "Показати мені"),
|
||||
("Show:", "Показати:"),
|
||||
("Shutter Angle:", "Кут затвора:"),
|
||||
("Shutter Phase:", "Фаза затвора:"),
|
||||
("Size", "Розмір"),
|
||||
("Skip", "Пропустити"),
|
||||
("Snapping", "Прив’язування"),
|
||||
("Snapping options", "Параметри прив’язування"),
|
||||
("Snapshot", "Знімок"),
|
||||
("Solo Supported Properties", "Лише підтримувані властивості"),
|
||||
("Solo Switches: {}", "Перемикачі соло: {}"),
|
||||
("Sort", "Сортувати"),
|
||||
("Spacing:", "Інтервал:"),
|
||||
("Spatial Interpolation:", "Просторова інтерполяція:"),
|
||||
("Speed:", "Швидкість:"),
|
||||
("Start Timecode:", "Початковий часовий код:"),
|
||||
("Start: {} Duration: {}", "Початок: {} Тривалість: {}"),
|
||||
("Step {} of {}: {}", "Крок {} з {}: {}"),
|
||||
("Stop {} at {}°", "Колірна точка {} на {}°"),
|
||||
("Stored in: {}", "Збережено в: {}"),
|
||||
("Stretch", "Розтягнення"),
|
||||
("Stretch Factor:", "Коефіцієнт розтягнення:"),
|
||||
("Stylistic Sets", "Стилістичні набори"),
|
||||
("Subpixel Positioning", "Субпіксельне позиціювання"),
|
||||
("Swap Paint Colors (X)", "Поміняти місцями кольори малювання (X)"),
|
||||
("System Default", "Стандартне системне"),
|
||||
("Table", "Таблиця"),
|
||||
("Template name", "Назва шаблону"),
|
||||
("Template: {}\n{}", "Шаблон: {}\n{}"),
|
||||
("Temporal Interpolation:", "Часова інтерполяція:"),
|
||||
("The Media Browser is not available here (use File ▸ Import)", "Браузер матеріалів тут недоступний (скористайтеся меню «Файл ▸ Імпорт»)"),
|
||||
("The OpenEXR layer shown in red, green, blue and alpha", "Шар OpenEXR, показаний у червоному, зеленому, синьому та альфа-каналі"),
|
||||
("The render queue is empty.", "Черга рендерингу порожня."),
|
||||
("This ScriptUI panel has closed", "Цю панель ScriptUI закрито"),
|
||||
("This change will create a new solid for this layer.", "Ця зміна створить новий матеріал суцільного кольору для цього шару."),
|
||||
("Time", "Час"),
|
||||
("Time Stretch…", "Розтягнення часу…"),
|
||||
("Time:", "Час:"),
|
||||
("Time: {}", "Час: {}"),
|
||||
("Title/action safe", "Безпечні області титрів і дії"),
|
||||
("Toggle Switches / Modes", "Перемкнути перемикачі / режими"),
|
||||
("Track Name:", "Назва відстеження:"),
|
||||
(
|
||||
"Trained models are available in the desktop app; the browser uses the classic engine.",
|
||||
"Навчені моделі доступні в настільній програмі; браузер використовує класичний рушій.",
|
||||
),
|
||||
("Transform", "Перетворення"),
|
||||
("Transparency grid", "Сітка прозорості"),
|
||||
("Tutorial complete", "Урок завершено"),
|
||||
("Two-Node Camera", "Двовузлова камера"),
|
||||
("Type", "Тип"),
|
||||
("Type a command or effect…", "Введіть команду або ефект…"),
|
||||
("URL:", "URL:"),
|
||||
("Undock Panel", "Від’єднати панель"),
|
||||
("Unlink {}", "Від’єднати {}"),
|
||||
(
|
||||
"Use this option to place the currently selected layers together into a new intermediate composition.",
|
||||
"Скористайтеся цим параметром, щоб розмістити виділені шари разом у новій проміжній композиції.",
|
||||
),
|
||||
("VR Environments", "Середовища VR"),
|
||||
("Value:", "Значення:"),
|
||||
("Variable Font Axes", "Осі змінного шрифту"),
|
||||
("Video Codec: {}", "Відеокодек: {}"),
|
||||
("View:", "Вигляд:"),
|
||||
("Welcome to EffectCraft", "Ласкаво просимо до EffectCraft"),
|
||||
("Width:", "Ширина:"),
|
||||
("You can undo this.", "Це можна скасувати."),
|
||||
("Your changes will be lost if you don't save them.", "Якщо не зберегти зміни, їх буде втрачено."),
|
||||
("Zoom", "Масштаб"),
|
||||
("built-in", "вбудований"),
|
||||
("frames per second", "кадрів за секунду"),
|
||||
("template name", "назва шаблону"),
|
||||
("{} contributors · {} commits", "Учасники: {} · Фіксації змін: {}"),
|
||||
("{} x {}, {}MB per 8bpc frame", "{} x {}, {} МБ на кадр 8bpc"),
|
||||
("{} — coming soon", "{} — незабаром"),
|
||||
("{} — double-click to open, {}-click to reveal", "{} — двічі клацніть, щоб відкрити; клацніть із {}, щоб показати розташування"),
|
||||
("⌘/Ctrl-drag a pin to record its motion", "Перетягніть опорну точку з ⌘/Ctrl, щоб записати її рух"),
|
||||
("▣ {}", "▣ {}"),
|
||||
("⚠ {} is used by:", "⚠ {} використовується в:"),
|
||||
];
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
@ -991,7 +1424,7 @@ mod tests {
|
|||
const UNITS: &[&str] = &[" px", "%", "·", "s", "ms", "°", "fps", " bpc", " mm", " s", " %", " pixels"];
|
||||
|
||||
fn catalogs() -> Vec<(&'static str, &'static str)> {
|
||||
SIMPLIFIED_CHINESE.iter().copied().chain(TRADITIONAL_CHINESE.iter().copied()).collect()
|
||||
SIMPLIFIED_CHINESE.iter().copied().chain(TRADITIONAL_CHINESE.iter().copied()).chain(UKRAINIAN.iter().copied()).collect()
|
||||
}
|
||||
|
||||
/// A row that translates nothing, repeats a source string, or changes the number of values the
|
||||
|
|
@ -1001,6 +1434,8 @@ mod tests {
|
|||
let hans: Vec<&str> = SIMPLIFIED_CHINESE.iter().map(|(en, _)| *en).collect();
|
||||
let hant: Vec<&str> = TRADITIONAL_CHINESE.iter().map(|(en, _)| *en).collect();
|
||||
assert_eq!(hans, hant, "the two Chinese catalogs list different source strings");
|
||||
let uk: Vec<&str> = UKRAINIAN.iter().map(|(en, _)| *en).collect();
|
||||
assert_eq!(hans, uk, "the Ukrainian catalog lists different source strings");
|
||||
let mut sorted = hans.clone();
|
||||
sorted.sort_unstable();
|
||||
let listed = sorted.len();
|
||||
|
|
@ -1027,6 +1462,21 @@ mod tests {
|
|||
set_current("en");
|
||||
}
|
||||
|
||||
/// The same language preference used for the menus reaches panels immediately, and formatted
|
||||
/// text keeps the caller's values intact even when they contain non-Ukrainian words.
|
||||
#[test]
|
||||
fn ukrainian_panels_translate_and_keep_project_content() {
|
||||
set_current("uk");
|
||||
assert_eq!(tr("Composition Name:"), "Назва композиції:");
|
||||
assert_eq!(tr("Cancel"), "Скасувати");
|
||||
assert_eq!(tr("my layer.mp4"), "my layer.mp4");
|
||||
assert_eq!(tr_args("Proxy Use: {}", &[&"Best"]), "Використання проксі: Best");
|
||||
assert_eq!(tr_args("Step {} of {}: {}", &[&1, &3, &"Colour"]), "Крок 1 з 3: Colour");
|
||||
assert_eq!(tr_args("Template: {}\n{}", &[&"Title", &"My description"]), "Шаблон: Title\nMy description");
|
||||
set_current("en");
|
||||
assert_eq!(tr("Composition Name:"), "Composition Name:");
|
||||
}
|
||||
|
||||
/// Values fill the placeholders in order, and a missing value is dropped instead of panicking.
|
||||
#[test]
|
||||
fn tr_args_fills_values_in_order() {
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -29,7 +29,7 @@ Commands (CLI, MCP, control channel):
|
|||
|
||||
### Settings that change behaviour
|
||||
|
||||
- `general.language`: interface language (`system` / `en` / `ja` / `zh-hans` / `zh-hant` / `uk`), Settings ▸ General ▸ Language; menu labels change immediately. `system` (Match System, the default) follows the operating system's interface language where EffectCraft has a translation and is English otherwise: a Simplified Chinese locale (`zh`, `zh-CN`, `zh_CN.UTF-8`, `zh-Hans-CN`, `zh-SG`) selects `zh-hans`, a Traditional one (`zh-TW`, `zh-HK`, `zh-Hant`, `zh_MO`) selects `zh-hant`, a Ukrainian one (`uk`, `uk-UA`, `uk_UA.UTF-8`) selects `uk`; the browser build stays in English with it. Choose **Українська** for Ukrainian menus; Ukrainian dialog and panel contents stay in English for now, and Ukrainian uses the bundled UI fonts. Native Japanese, Simplified and Traditional Chinese UI uses installed system fonts; the web host must supply a Japanese font. The same setting picks the CJK fallback for the interface *and* the Han preference of the text engine, so the composition's own text is drawn with the same language's glyph forms (the text engine's preference is process-global); swapping the language reinstalls the fonts, so it applies without a restart. Two catalogs back the text: the menus are keyed by `(command, English label)` (`crates/ui-egui/src/i18n.rs`), and the rest of the interface - panels, dialogs, buttons, tooltips - is keyed by its English source string (`crates/ui-egui/src/i18n/ui.rs`), where a panel writes `tr("Rename")`, or `tr_args("Proxy Use: {}", &[&quality])` when the row carries a value. A row that is missing falls back to English, so a new string shows up untranslated rather than empty; the tests in that module fail on an unused row and on a hard-coded string in a converted panel.
|
||||
- `general.language`: interface language (`system` / `en` / `ja` / `zh-hans` / `zh-hant` / `uk`), Settings ▸ General ▸ Language; menu labels change immediately. `system` (Match System, the default) follows the operating system's interface language where EffectCraft has a translation and is English otherwise: a Simplified Chinese locale (`zh`, `zh-CN`, `zh_CN.UTF-8`, `zh-Hans-CN`, `zh-SG`) selects `zh-hans`, a Traditional one (`zh-TW`, `zh-HK`, `zh-Hant`, `zh_MO`) selects `zh-hant`, a Ukrainian one (`uk`, `uk-UA`, `uk_UA.UTF-8`) selects `uk`; the browser build stays in English with it. Choose **Українська** for Ukrainian menus and cataloged panel, dialog, button and tooltip text; Ukrainian uses the bundled UI fonts. Native Japanese, Simplified and Traditional Chinese UI uses installed system fonts; the web host must supply a Japanese font. The same setting picks the CJK fallback for the interface *and* the Han preference of the text engine, so the composition's own text is drawn with the same language's glyph forms (the text engine's preference is process-global); swapping the language reinstalls the fonts, so it applies without a restart. Two catalogs back the text: the menus are keyed by `(command, English label)` (`crates/ui-egui/src/i18n.rs`), and the rest of the interface - panels, dialogs, buttons, tooltips - is keyed by its English source string (`crates/ui-egui/src/i18n/ui.rs`), where a panel writes `tr("Rename")`, or `tr_args("Proxy Use: {}", &[&quality])` when the row carries a value. A row that is missing falls back to English, so a new string shows up untranslated rather than empty; the tests in that module fail on an unused row and on a hard-coded string in a converted panel.
|
||||
- `general.undoLevels`: Levels of Undo
|
||||
- `general.pathPointSize`: Path Point and Handle Size
|
||||
- `general.recentItems`: Recent Projects Shown
|
||||
|
|
|
|||
Loading…
Reference in New Issue