i18n: wrap hardcoded UI strings for Chinese localization
- Wrap remaining hardcoded UI labels and buttons with tr()/tl!() calls - Add missing Simplified and Traditional Chinese translations - Add entries to other language catalogs for consistency
This commit is contained in:
parent
d428de6caa
commit
f0349fb2f8
|
|
@ -660,3 +660,6 @@
|
|||
Video Video
|
||||
De-Interlace… Odstranit prokládání…
|
||||
NTSC Colors Barvy NTSC
|
||||
RGB: RGB:
|
||||
CMYK: CMYK:
|
||||
CMYK CMYK
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
|
|
@ -3929,3 +3929,5 @@ axis Both Ambos
|
|||
Duplication Duplicación
|
||||
Interpolation Interpolación
|
||||
@msg Imported library {name} Biblioteca {name} importada
|
||||
RGB: RGB:
|
||||
CMYK: CMYK:
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
|
|
@ -3940,3 +3940,5 @@ axis Both Les deux
|
|||
Duplication Duplication
|
||||
Interpolation Interpolation
|
||||
@msg Imported library {name} Bibliothèque {name} importée
|
||||
RGB: RGB:
|
||||
CMYK: CMYK:
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
|
|
@ -3929,3 +3929,5 @@ axis Both Entrambi
|
|||
Duplication Duplicazione
|
||||
Interpolation Interpolazione
|
||||
@msg Imported library {name} Libreria {name} importata
|
||||
RGB: RGB:
|
||||
CMYK: CMYK:
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
|
|
@ -3921,3 +3921,5 @@ theme Appearance 外観
|
|||
Duplication 複製
|
||||
Interpolation 補間
|
||||
@msg Imported library {name} ライブラリ {name} を読み込みました
|
||||
RGB: RGB:
|
||||
CMYK: CMYK:
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
|
|
@ -254,6 +254,13 @@ pub fn lang_from_tag(tag: &str) -> Option<Lang> {
|
|||
cands.iter().find_map(|c| Lang::from_code(c))
|
||||
}
|
||||
|
||||
/// True when `tag` names the generic `C` / `POSIX` locale (or a variant like `C.UTF-8`), which on
|
||||
/// macOS means "no particular language" rather than English: the system language list decides.
|
||||
fn is_c_locale(tag: &str) -> bool {
|
||||
let base = tag.split(['.', '@']).next().unwrap_or("").to_ascii_lowercase();
|
||||
matches!(base.as_str(), "c" | "posix")
|
||||
}
|
||||
|
||||
/// Work out the system language on a background thread, so the first frame doesn't wait for the
|
||||
/// locale probe (which runs `reg.exe` on Windows and `defaults` on macOS). Call it at startup; a
|
||||
/// frame that needs the language before the probe finishes waits for it. A no-op on wasm.
|
||||
|
|
@ -295,6 +302,11 @@ fn detect_system_lang() -> Lang {
|
|||
// variables. `LANGUAGE` is a colon-separated priority list.
|
||||
for var in ["VECTORCRAFT_LOCALE", "LC_ALL", "LC_MESSAGES", "LANG", "LANGUAGE"] {
|
||||
let Some(v) = std::env::var(var).ok().filter(|v| !v.is_empty()) else { continue };
|
||||
// `C` / `POSIX` (and variants like `C.UTF-8`, `POSIX.UTF-8`) mean "no particular locale":
|
||||
// don't force English, fall through to the OS preferred-languages list below.
|
||||
if v.split(':').all(is_c_locale) {
|
||||
continue;
|
||||
}
|
||||
if let Some(l) = v.split(':').find_map(lang_from_tag) {
|
||||
return l;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2721,3 +2721,5 @@
|
|||
Video Vídeo
|
||||
De-Interlace… Desentrelaçar…
|
||||
NTSC Colors Cores NTSC
|
||||
RGB: RGB:
|
||||
CMYK: CMYK:
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -3927,3 +3927,5 @@ axis Both Оба
|
|||
Duplication Дублированием
|
||||
Interpolation Интерполяцией
|
||||
@msg Imported library {name} Импортирована библиотека {name}
|
||||
RGB: RGB:
|
||||
CMYK: CMYK:
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
|
|
@ -3912,3 +3912,5 @@ axis Both Обидві
|
|||
Duplication Дублюванням
|
||||
Interpolation Інтерполяцією
|
||||
@msg Imported library {name} Імпортовано бібліотеку {name}
|
||||
RGB: RGB:
|
||||
CMYK: CMYK:
|
||||
|
|
|
|||
|
Can't render this file because it has a wrong number of fields in line 13.
|
|
|
@ -3340,3 +3340,5 @@ axis Both 兩者
|
|||
Even Fields 偶數圖場
|
||||
Duplication 複製
|
||||
Interpolation 內插
|
||||
RGB: RGB:
|
||||
CMYK: CMYK:
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -424,7 +424,7 @@ pub(crate) fn label_or_name(s: &str, built_in: bool) -> &str {
|
|||
/// command feeds); returns the one clicked, for the caller to apply.
|
||||
pub(crate) fn recent_colors_row(app: &VectorcraftApp, ui: &mut Ui) -> Option<Color> {
|
||||
let t = Tokens::get(ui.ctx());
|
||||
crate::widgets::subheader(ui, "Recent Colors");
|
||||
crate::widgets::subheader(ui, tl!("Recent Colors"));
|
||||
let (r, _) = ui.allocate_exact_size(vec2(ui.available_width(), 22.0), Sense::hover());
|
||||
ui.painter().rect_stroke(r, 0.0, egui::Stroke::new(1.0, t.input_border), egui::StrokeKind::Inside);
|
||||
let mut chosen = None;
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ fn plates_section(app: &mut VectorcraftApp, ui: &mut Ui) {
|
|||
run(app, "view.separationsPreview", json!({"plates": plates.iter().map(|p| p.name.clone()).collect::<Vec<_>>()}));
|
||||
}
|
||||
});
|
||||
ui.label(egui::RichText::new("CMYK").size(12.0).color(if on { t.text } else { t.text_dim }));
|
||||
ui.label(egui::RichText::new(tl!("CMYK")).size(12.0).color(if on { t.text } else { t.text_dim }));
|
||||
});
|
||||
for p in &plates {
|
||||
ui.horizontal(|ui| {
|
||||
|
|
@ -86,13 +86,13 @@ fn settings_section(app: &mut VectorcraftApp, ui: &mut Ui) {
|
|||
let st = cms::active_settings();
|
||||
widgets::section_header(ui, tl!("Color Settings"));
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("RGB:");
|
||||
ui.label(tl!("RGB:"));
|
||||
if let Some(n) = profile_dropdown(ui, "cms-rgb", &st.rgb, ProfileKind::Rgb, None) {
|
||||
run(app, "edit.colorSettings", json!({"rgb": n}));
|
||||
}
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("CMYK:");
|
||||
ui.label(tl!("CMYK:"));
|
||||
if let Some(n) = profile_dropdown(ui, "cms-cmyk", &st.cmyk, ProfileKind::Cmyk, None) {
|
||||
run(app, "edit.colorSettings", json!({"cmyk": n}));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -255,9 +255,53 @@ pub fn install_fonts(ctx: &egui::Context) {
|
|||
mono.extend(fallback);
|
||||
fonts.families.insert(FontFamily::Name(FONT_MONO.into()), mono);
|
||||
add_craft_fonts(&mut fonts);
|
||||
// System CJK fallback (PingFang / Heiti / Noto…) when craft-fonts are absent.
|
||||
if let Some((name, data)) = system_cjk_font() {
|
||||
fonts.font_data.insert(name.clone(), Arc::new(data));
|
||||
for stack in fonts.families.values_mut() {
|
||||
stack.push(name.clone());
|
||||
}
|
||||
}
|
||||
ctx.set_fonts(fonts);
|
||||
}
|
||||
|
||||
/// A CJK font already installed on the system, as a last-resort fallback.
|
||||
fn system_cjk_font() -> Option<(String, FontData)> {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
let paths: &[&str] = if cfg!(target_os = "macos") {
|
||||
&[
|
||||
"/System/Library/Fonts/PingFang.ttc",
|
||||
"/System/Library/Fonts/STHeiti Medium.ttc",
|
||||
"/System/Library/Fonts/STHeiti Light.ttc",
|
||||
"/System/Library/Fonts/Hiragino Sans GB.ttc",
|
||||
"/System/Library/Fonts/Supplemental/Songti.ttc",
|
||||
"/Library/Fonts/Arial Unicode.ttf",
|
||||
]
|
||||
} else if cfg!(target_os = "windows") {
|
||||
&[r"C:\Windows\Fonts\msyh.ttc", r"C:\Windows\Fonts\simhei.ttf", r"C:\Windows\Fonts\simsun.ttc"]
|
||||
} else {
|
||||
&[
|
||||
"/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",
|
||||
"/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc",
|
||||
"/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc",
|
||||
]
|
||||
};
|
||||
for path in paths {
|
||||
if let Ok(bytes) = std::fs::read(path) {
|
||||
let mut data = FontData::from_owned(bytes);
|
||||
data.index = 0;
|
||||
return Some(("system-cjk".to_string(), data));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// The egui name of a craft-fonts face.
|
||||
pub(crate) fn craft_font_name(f: &vectorcraft_text::CraftFont) -> String {
|
||||
format!("craft-fonts {} {}", f.family, f.style)
|
||||
|
|
|
|||
|
|
@ -598,10 +598,10 @@ pub fn fill_stroke_proxy(ui: &mut Ui, fill: &Paint, stroke: &Paint, mixed: (bool
|
|||
None
|
||||
};
|
||||
ProxyClicks {
|
||||
fill: fill_resp.on_hover_text("Fill (X), double-click for the Color Picker").clicked(),
|
||||
stroke: stroke_resp.on_hover_text("Stroke (X), double-click for the Color Picker").clicked(),
|
||||
swap: swap.on_hover_text("Swap Fill and Stroke (Shift+X)").clicked(),
|
||||
default: def.on_hover_text("Default Fill and Stroke (D)").clicked(),
|
||||
fill: fill_resp.on_hover_text(tl!("Fill (X), double-click for the Color Picker")).clicked(),
|
||||
stroke: stroke_resp.on_hover_text(tl!("Stroke (X), double-click for the Color Picker")).clicked(),
|
||||
swap: swap.on_hover_text(tl!("Swap Fill and Stroke (Shift+X)")).clicked(),
|
||||
default: def.on_hover_text(tl!("Default Fill and Stroke (D)")).clicked(),
|
||||
pick,
|
||||
}
|
||||
}
|
||||
|
|
@ -1668,7 +1668,7 @@ pub fn harmony_wheel(ui: &mut Ui, id: &str, size: f32, colors: &[Color], base: O
|
|||
ui.add_space(6.0);
|
||||
ui.horizontal(|ui| {
|
||||
ui.add_space(((ui.available_width() - size - 76.0) / 2.0).max(0.0));
|
||||
ui.add_sized([70.0, 22.0], egui::Label::new(egui::RichText::new("Brightness").color(t.text_dim)));
|
||||
ui.add_sized([70.0, 22.0], egui::Label::new(egui::RichText::new(tl!("Brightness")).color(t.text_dim)));
|
||||
if let (Some(b), Some([h, s, _])) = (base, base_hsb)
|
||||
&& let (Some(nv), _) = color_slider(ui, (id, "brightness"), v, size, &|x| crate::panels::c32(&Color::from_hsb(h, s, x)))
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue