Fix #4946: a Language setting per text, with Indian languages (#4943)

Character panel > Language sets the selected characters' language;
text.setFormat and text.setRangeStyle take `language` by name or tag
(unknown: an error), and character styles carry it. Document Setup's
language list gains Hindi, Marathi, Gujarati, Bengali, Punjabi, Tamil,
Telugu, Kannada, Malayalam, Odia and Urdu, with catalog rows; the
Digits menu's numeral names move to a digits context, as Hindi is now
also a language name.
This commit is contained in:
bflatastic
2026-11-01 01:39:16 +07:00
parent a85487ad39
commit 2bdaaa8981
36 changed files with 405 additions and 18 deletions
+14 -3
View File
@@ -167,6 +167,17 @@ pub const LANGUAGES: &[(&str, &str, Quotes)] = &[
("Turkish", "tr", Quotes { double: ['“', '”'], single: ['‘', '’'] }),
("Japanese", "ja", Quotes { double: ['「', '」'], single: ['『', '』'] }),
("Chinese", "zh", Quotes { double: ['“', '”'], single: ['‘', '’'] }),
("Hindi", "hi", Quotes::ENGLISH),
("Marathi", "mr", Quotes::ENGLISH),
("Gujarati", "gu", Quotes::ENGLISH),
("Bengali", "bn", Quotes::ENGLISH),
("Punjabi", "pa", Quotes::ENGLISH),
("Tamil", "ta", Quotes::ENGLISH),
("Telugu", "te", Quotes::ENGLISH),
("Kannada", "kn", Quotes::ENGLISH),
("Malayalam", "ml", Quotes::ENGLISH),
("Odia", "or", Quotes::ENGLISH),
("Urdu", "ur", Quotes::ENGLISH),
];
/// The quotes of a [`LANGUAGES`] entry (case-insensitive).
@@ -354,13 +365,13 @@ mod tests {
#[test]
fn char_languages_are_stored_by_tag() {
assert_eq!(char_language("Turkish"), Ok(Some("tr")));
assert_eq!(char_language("TR"), Ok(Some("tr")));
assert_eq!(char_language("MR"), Ok(Some("mr")));
assert_eq!(char_language("english: usa"), Ok(None));
assert_eq!(char_language("en-US"), Ok(None));
assert!(char_language("Klingon").is_err() && char_language("").is_err());
assert_eq!(
(char_language_name(None), char_language_name(Some("de")), char_language_name(Some("x-unknown"))),
(Some("English: USA"), Some("German"), None)
(char_language_name(None), char_language_name(Some("gu")), char_language_name(Some("x-unknown"))),
(Some("English: USA"), Some("Gujarati"), None)
);
// Every entry has a tag of its own, and a name of its own.
for (i, (n, t, _)) in LANGUAGES.iter().enumerate() {
File diff suppressed because one or more lines are too long
+17 -1
View File
@@ -39,7 +39,7 @@ pub fn specs() -> Vec<CommandSpec> {
"Character",
[],
None,
"{id? (default: the one selected type object), start?: byte, end?: byte (default: all text), font?, style?, size?: pt, leading?: pt|\"auto\", tracking?, kerning?: 1/1000 em|\"auto\"|\"optical\", baselineShift?: pt, hScale?: %, vScale?: %, rotation?: deg, fill?: colour|\"none\", stroke?: colour|\"none\", keepModel?: bool (fill and stroke, as paint.setFill), strokeWidth?: pt, strokeOptions?: {weight?, cap?, join?, miterLimit?, align?, dash?, dashOffset?, alignDashes?} (as stroke.set: the character stroke), underline?, strikethrough?, allCaps?: bool, smallCaps?: bool, position?: \"normal\"|\"superscript\"|\"subscript\" (sizes from Document Setup), features?: [\"dlig\", \"-liga\", …], charAlign?: \"romanBaseline\"|\"emBoxTop\"|\"emBoxCenter\"|\"emBoxBottom\"|\"icfTop\"|\"icfBottom\", proportionalMetrics?: bool (full-width glyphs on the font's proportional widths: `palt` in horizontal type, `vpal` in vertical type), tateChuYoko?: bool (Character panel menu › Tate-chu-yoko, with Show East Asian Options: in vertical type those characters stand side by side across one em of the column; kept on the characters and ignored in horizontal type), noBreak?: bool (Character panel menu › No Break: these characters stay on one line, including across a space inside the run), charDirection?: \"default\"|\"leftToRight\"|\"rightToLeft\" (Character panel menu › Character Direction: the characters are set left to right or right to left inside their paragraph, as a Unicode bidi embedding; default: as the bidi algorithm sets them), digits?: \"default\"|\"arabic\"|\"hindi\"|\"farsi\" (Character panel menu › Digits: the numeral system every digit is drawn in, whatever was typed), fontAxes?: {\"wght\": 650, …} (Character panel › Variable Font: the setting of each variation axis named, in the axis's units and clamped to its range; null: back to the style's own setting; other axes keep theirs; tags the font has no axis for are left out; a font or style change clears them; text.fontList {family, style} lists the axes)} style a character range (size/leading/baselineShift are document points and hScale includes the object transform; runs are split at the range ends) → {id, runs, warning?: text (the font or style set isn't available: its type is drawn in the fallback font or the family's closest style)}",
"{id? (default: the one selected type object), start?: byte, end?: byte (default: all text), font?, style?, size?: pt, leading?: pt|\"auto\", tracking?, kerning?: 1/1000 em|\"auto\"|\"optical\", baselineShift?: pt, hScale?: %, vScale?: %, rotation?: deg, fill?: colour|\"none\", stroke?: colour|\"none\", keepModel?: bool (fill and stroke, as paint.setFill), strokeWidth?: pt, strokeOptions?: {weight?, cap?, join?, miterLimit?, align?, dash?, dashOffset?, alignDashes?} (as stroke.set: the character stroke), underline?, strikethrough?, allCaps?: bool, smallCaps?: bool, position?: \"normal\"|\"superscript\"|\"subscript\" (sizes from Document Setup), features?: [\"dlig\", \"-liga\", …], charAlign?: \"romanBaseline\"|\"emBoxTop\"|\"emBoxCenter\"|\"emBoxBottom\"|\"icfTop\"|\"icfBottom\", proportionalMetrics?: bool (full-width glyphs on the font's proportional widths: `palt` in horizontal type, `vpal` in vertical type), tateChuYoko?: bool (Character panel menu › Tate-chu-yoko, with Show East Asian Options: in vertical type those characters stand side by side across one em of the column; kept on the characters and ignored in horizontal type), noBreak?: bool (Character panel menu › No Break: these characters stay on one line, including across a space inside the run), charDirection?: \"default\"|\"leftToRight\"|\"rightToLeft\" (Character panel menu › Character Direction: the characters are set left to right or right to left inside their paragraph, as a Unicode bidi embedding; default: as the bidi algorithm sets them), digits?: \"default\"|\"arabic\"|\"hindi\"|\"farsi\" (Character panel menu › Digits: the numeral system every digit is drawn in, whatever was typed), language?: name|tag (Character panel › Language: one of Document Setup's languages by name or BCP 47 tag, case-insensitive, such as \"Turkish\" or \"tr\"; the characters are shaped in it, so the font uses that language's forms (OpenType `locl`); saved as the tag, English: USA, the default, as none; new type takes the document's language), fontAxes?: {\"wght\": 650, …} (Character panel › Variable Font: the setting of each variation axis named, in the axis's units and clamped to its range; null: back to the style's own setting; other axes keep theirs; tags the font has no axis for are left out; a font or style change clears them; text.fontList {family, style} lists the axes)} style a character range (size/leading/baselineShift are document points and hScale includes the object transform; runs are split at the range ends) → {id, runs, warning?: text (the font or style set isn't available: its type is drawn in the fallback font or the family's closest style)}",
has_doc,
set_range_style
),
@@ -321,6 +321,8 @@ pub(crate) struct CharChange {
tate_chu_yoko: Option<bool>,
no_break: Option<bool>,
digits: Option<vectorcraft_doc::Digits>,
/// The language to set: a tag, or `None` for the default.
language: Option<Option<String>>,
font_axes: Option<AxisChange>,
}
@@ -350,6 +352,15 @@ pub(crate) fn digits_param(p: &Value, cmd: &str) -> Result<Option<vectorcraft_do
}))
}
/// `language: name|tag` (one of Document Setup's languages, case-insensitive) → the language to
/// set ([`vectorcraft_doc::CharStyle::language`]: `None` inside for the default).
pub(crate) fn language_param(p: &Value, cmd: &str) -> Result<Option<Option<String>>> {
let Some(v) = p.get("language").filter(|v| !v.is_null()) else { return Ok(None) };
let l = v.as_str().ok_or_else(|| bad(cmd, "`language` must be a language name or tag, such as \"Turkish\" or \"tr\""))?;
let tag = vectorcraft_doc::setup::char_language(l).map_err(|e| bad(cmd, e))?;
Ok(Some(tag.map(str::to_string)))
}
/// Variable Font settings to change: by axis tag, a value in the axis's units, or `None` to go
/// back to the style's own setting of that axis.
pub(crate) type AxisChange = std::collections::BTreeMap<String, Option<f64>>;
@@ -507,6 +518,7 @@ impl CharChange {
tate_chu_yoko: flag("tateChuYoko"),
no_break: flag("noBreak"),
digits: digits_param(p, cmd)?,
language: language_param(p, cmd)?,
font_axes: font_axes_param(p, cmd)?,
};
if c.size.is_some_and(|v| v <= 0.0) {
@@ -552,6 +564,7 @@ impl CharChange {
&& self.tate_chu_yoko.is_none()
&& self.no_break.is_none()
&& self.digits.is_none()
&& self.language.is_none()
&& self.font_axes.is_none()
}
@@ -655,6 +668,9 @@ impl CharChange {
if let Some(v) = self.digits {
st.digits = v;
}
if let Some(v) = &self.language {
st.language.clone_from(v);
}
}
}
+9 -1
View File
@@ -177,6 +177,7 @@ pub fn char_attrs(v: &CharStyle) -> Map<String, Value> {
("tateChuYoko", json!(v.tate_chu_yoko)),
("noBreak", json!(v.no_break)),
("digits", json!(v.digits)),
("language", json!(v.language)),
] {
m.insert(k.into(), x);
}
@@ -480,7 +481,14 @@ fn attrs_param(p: &Value, kind: Kind, verb: &str) -> Result<Option<Map<String, V
// form (so comparing a style with its text's attributes is exact).
let c = kind.cmd(verb);
let full = match kind {
Kind::Char => char_attrs(&with_attrs(&CharStyle::default(), m, &c)?),
Kind::Char => {
let mut st = with_attrs(&CharStyle::default(), m, &c)?;
// A language of the list, stored as its tag (as text.setFormat takes it).
if let Some(l) = &st.language {
st.language = vectorcraft_doc::setup::char_language(l).map_err(|e| bad(&c, e))?.map(str::to_string);
}
char_attrs(&st)
}
Kind::Para => para_attrs(&with_attrs(&ParaStyle::default(), m, &c)?),
};
Ok(Some(m.keys().filter_map(|k| full.get(k).map(|v| (k.clone(), v.clone()))).collect()))
@@ -1268,6 +1268,55 @@ fn digits_are_a_character_attribute_saved_only_when_set() {
assert_eq!(set, [("صفحة ".to_string(), Digits::Default), ("12".to_string(), Digits::Farsi)]);
}
/// Language (Character panel, #4946): a character attribute set by name or tag, saved as the tag
/// only when set, kept by save and reopen and by character styles; new type takes the document's.
#[test]
fn language_is_a_character_attribute_saved_only_when_set() {
let mut s = Session::new();
s.execute("file.new", &json!({"width": 400, "height": 400})).unwrap();
let id = s.execute("text.create", &json!({"x": 10, "y": 50, "text": "fi i fikir"})).unwrap()["id"].as_u64().unwrap();
let runs = |s: &Session| match &s.doc().unwrap().doc.node(NodeId(id)).unwrap().kind {
NodeKind::Text(t) => t.runs.clone(),
_ => panic!("text"),
};
let set = |s: &Session| runs(s).iter().map(|r| (r.text.clone(), r.style.language.clone())).collect::<Vec<_>>();
assert_eq!(runs(&s)[0].style.language, None);
assert!(serde_json::to_value(&runs(&s)[0].style).unwrap().get("language").is_none());
s.execute("select.set", &json!({"ids": [id]})).unwrap();
s.execute("text.setFormat", &json!({"language": "Turkish"})).unwrap();
assert_eq!(set(&s), [("fi i fikir".to_string(), Some("tr".to_string()))]);
assert_eq!(serde_json::to_value(&runs(&s)[0].style).unwrap()["language"], "tr");
for wrong in [json!("Klingon"), json!(5)] {
let err = s.execute("text.setFormat", &json!({ "language": wrong })).unwrap_err().to_string();
assert!(err.contains("language"), "{err}");
}
// Characters selected with the Type tool: only the range takes it; the default is none.
s.execute("text.setRangeStyle", &json!({"id": id, "start": 0, "end": 2, "language": "en-US"})).unwrap();
assert_eq!(set(&s), [("fi".to_string(), None), (" i fikir".to_string(), Some("tr".to_string()))]);
s.execute("edit.undo", &json!({})).unwrap();
assert_eq!(set(&s), [("fi i fikir".to_string(), Some("tr".to_string()))]);
s.execute("edit.redo", &json!({})).unwrap();
// Saved and reopened as it was.
let back = vectorcraft_format::load(&vectorcraft_format::save(&s.doc().unwrap().doc, false)).unwrap();
let NodeKind::Text(t) = &back.node(NodeId(id)).unwrap().kind else { panic!("text") };
let reopened: Vec<_> = t.runs.iter().map(|r| (r.text.clone(), r.style.language.clone())).collect();
assert_eq!(reopened, set(&s));
// A character style captured from the characters carries it, the default included; one given
// a language by name stores its tag.
assert_eq!(super::super::textstyles::char_attrs(&runs(&s)[1].style)["language"], "tr");
assert_eq!(super::super::textstyles::char_attrs(&runs(&s)[0].style).get("language"), Some(&serde_json::Value::Null));
s.execute("charStyle.new", &json!({"name": "Marathi", "attrs": {"language": "Marathi"}})).unwrap();
let listed = s.execute("charStyle.list", &json!({})).unwrap();
let marathi = listed["styles"].as_array().unwrap().iter().find(|st| st["name"] == "Marathi").unwrap();
assert_eq!(marathi["attrs"]["language"], "mr");
assert!(s.execute("charStyle.new", &json!({"name": "Bad", "attrs": {"language": "Klingon"}})).is_err());
// New type in a Turkish document is in Turkish.
s.execute("document.setup", &json!({"language": "Turkish"})).unwrap();
let id2 = s.execute("text.create", &json!({"x": 10, "y": 150, "text": "fikir"})).unwrap()["id"].as_u64().unwrap();
let NodeKind::Text(t) = &s.doc().unwrap().doc.node(NodeId(id2)).unwrap().kind else { panic!("text") };
assert_eq!(t.runs[0].style.language.as_deref(), Some("tr"));
}
/// Variable Font settings (Character panel › Variable Font): a character attribute, saved only
/// when set, each value clamped to its axis's range, and cleared by another font or style.
#[test]
+10
View File
@@ -5926,4 +5926,14 @@ breakText Glyphs Глифи
Set Size of Each Задаване на размер на всеки
@msg select exactly two objects изберете точно два обекта
@msg give `width` or `height` задайте `width` или `height`
Marathi Маратхи
Gujarati Гуджарати
Bengali Бенгалски
Punjabi Пенджабски
Tamil Тамилски
Telugu Телугу
Kannada Каннада
Malayalam Малаялам
Odia Ория
Urdu Урду
VectorCraft {release} and later (version {n}) VectorCraft {release} и по-нови (версия {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -5960,4 +5960,14 @@ shape Open Otvoren
Set Size of Each Postavi veličinu svakog
@msg select exactly two objects odaberite tačno dva objekta
@msg give `width` or `height` zadajte `width` ili `height`
Marathi Marathi
Gujarati Gudžarati
Bengali Bengalski
Punjabi Pandžapski
Tamil Tamilski
Telugu Telugu
Kannada Kanada
Malayalam Malajalam
Odia Odija
Urdu Urdu
VectorCraft {release} and later (version {n}) VectorCraft {release} i novije (verzija {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -6033,4 +6033,14 @@ breakText Glyphs Glifs
Set Size of Each Defineix la mida de cadascun
@msg select exactly two objects selecciona exactament dos objectes
@msg give `width` or `height` indica `width` o `height`
Marathi Marathi
Gujarati Gujarati
Bengali Bengalí
Punjabi Panjabi
Tamil Tàmil
Telugu Telugu
Kannada Kannada
Malayalam Malaiàlam
Odia Oriya
Urdu Urdú
VectorCraft {release} and later (version {n}) VectorCraft {release} i posteriors (versió {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+12 -1
View File
@@ -1442,7 +1442,8 @@ lighting Light Světlo
Character Direction Směr znaků
Digits Číslice
Arabic Arabské
Hindi Hindské
Hindi Hindština
digits Hindi Hindské
Farsi Perské
Reset Panel Obnovit panel
Roman Baseline Latinková účaří
@@ -6042,4 +6043,14 @@ breakText Glyphs Glyfy
Set Size of Each Nastavit velikost jednotlivě
@msg select exactly two objects vyberte právě dva objekty
@msg give `width` or `height` zadejte `width` nebo `height`
Marathi Maráthština
Gujarati Gudžarátština
Bengali Bengálština
Punjabi Paňdžábština
Tamil Tamilština
Telugu Telugština
Kannada Kannadština
Malayalam Malajálamština
Odia Urijština
Urdu Urdština
VectorCraft {release} and later (version {n}) VectorCraft {release} a novější (verze {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -5940,4 +5940,14 @@ breakText Glyphs Glyffer
Set Size of Each Angiv størrelse for hver
@msg select exactly two objects markér præcis to objekter
@msg give `width` or `height` angiv `width` eller `height`
Marathi Marathi
Gujarati Gujarati
Bengali Bengali
Punjabi Punjabi
Tamil Tamil
Telugu Telugu
Kannada Kannada
Malayalam Malayalam
Odia Oriya
Urdu Urdu
VectorCraft {release} and later (version {n}) VectorCraft {release} og nyere (version {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -5628,4 +5628,14 @@ breakText Glyphs Glyphen
Set Size of Each Größe einzeln festlegen
@msg select exactly two objects wählen Sie genau zwei Objekte aus
@msg give `width` or `height` geben Sie `width` oder `height` an
Marathi Marathi
Gujarati Gujarati
Bengali Bengalisch
Punjabi Punjabi
Tamil Tamil
Telugu Telugu
Kannada Kannada
Malayalam Malayalam
Odia Oriya
Urdu Urdu
VectorCraft {release} and later (version {n}) VectorCraft {release} und neuer (Version {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -5995,4 +5995,14 @@ breakText Glyphs Γλύφοι
Set Size of Each Ορισμός μεγέθους καθενός
@msg select exactly two objects επιλέξτε ακριβώς δύο αντικείμενα
@msg give `width` or `height` δώστε `width` ή `height`
Marathi Μαραθικά
Gujarati Γκουγιαράτι
Bengali Βεγγαλικά
Punjabi Παντζαπικά
Tamil Ταμιλικά
Telugu Τελούγκου
Kannada Κανάντα
Malayalam Μαλαγιάλαμ
Odia Όντια
Urdu Ούρντου
VectorCraft {release} and later (version {n}) VectorCraft {release} και νεότερες (έκδοση {n})
Can't render this file because it contains an unexpected character in line 164 and column 5.
+10
View File
@@ -5985,4 +5985,14 @@ breakText Glyphs Glifos
Set Size of Each Definir el tamaño de cada uno
@msg select exactly two objects selecciona exactamente dos objetos
@msg give `width` or `height` indica `width` o `height`
Marathi Maratí
Gujarati Guyaratí
Bengali Bengalí
Punjabi Punyabí
Tamil Tamil
Telugu Telugu
Kannada Canarés
Malayalam Malayálam
Odia Oriya
Urdu Urdu
VectorCraft {release} and later (version {n}) VectorCraft {release} y posteriores (versión {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -6073,4 +6073,14 @@ breakText Glyphs Merkit
Set Size of Each Aseta kunkin koko
@msg select exactly two objects valitse täsmälleen kaksi objektia
@msg give `width` or `height` anna `width` tai `height`
Marathi Marathi
Gujarati Gudžarati
Bengali Bengali
Punjabi Pandžabi
Tamil Tamili
Telugu Telugu
Kannada Kannada
Malayalam Malajalam
Odia Orija
Urdu Urdu
VectorCraft {release} and later (version {n}) VectorCraft {release} ja uudemmat (versio {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -6040,4 +6040,14 @@ breakText Glyphs Glyphes
Set Size of Each Définir la taille de chaque objet
@msg select exactly two objects sélectionnez exactement deux objets
@msg give `width` or `height` indiquez `width` ou `height`
Marathi Marathi
Gujarati Goudjarati
Bengali Bengali
Punjabi Pendjabi
Tamil Tamoul
Telugu Télougou
Kannada Kannada
Malayalam Malayalam
Odia Odia
Urdu Ourdou
VectorCraft {release} and later (version {n}) VectorCraft {release} et ultérieures (version {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -6029,4 +6029,14 @@ breakText Glyphs Glifák
Set Size of Each Egyenkénti méret beállítása
@msg select exactly two objects jelölj ki pontosan két objektumot
@msg give `width` or `height` add meg a `width` vagy a `height` értéket
Marathi Maráthi
Gujarati Gudzsaráti
Bengali Bengáli
Punjabi Pandzsábi
Tamil Tamil
Telugu Telugu
Kannada Kannada
Malayalam Malajálam
Odia Odia
Urdu Urdu
VectorCraft {release} and later (version {n}) VectorCraft {release} és újabb (verzió: {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -5940,4 +5940,14 @@ breakText Glyphs Glif
Set Size of Each Atur ukuran masing-masing
@msg select exactly two objects pilih tepat dua objek
@msg give `width` or `height` berikan `width` atau `height`
Marathi Marathi
Gujarati Gujarati
Bengali Bengali
Punjabi Punjabi
Tamil Tamil
Telugu Telugu
Kannada Kannada
Malayalam Malayalam
Odia Oriya
Urdu Urdu
VectorCraft {release} and later (version {n}) VectorCraft {release} dan yang lebih baru (versi {n})
Can't render this file because it contains an unexpected character in line 2175 and column 5.
+10
View File
@@ -5662,4 +5662,14 @@ breakText Glyphs Glifi
Set Size of Each Imposta dimensione di ciascuno
@msg select exactly two objects seleziona esattamente due oggetti
@msg give `width` or `height` indica `width` o `height`
Marathi Marathi
Gujarati Gujarati
Bengali Bengalese
Punjabi Punjabi
Tamil Tamil
Telugu Telugu
Kannada Kannada
Malayalam Malayalam
Odia Odia
Urdu Urdu
VectorCraft {release} and later (version {n}) VectorCraft {release} e successive (versione {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+12 -1
View File
@@ -46,7 +46,8 @@ font-technology Variable バリアブル
Character Direction 文字の方向
Digits 数字
Arabic アラビア数字
Hindi ヒンディー数字
Hindi ヒンディー語
digits Hindi ヒンディー数字
Farsi ペルシャ数字
Favorites お気に入り
Flip 反転
@@ -5728,4 +5729,14 @@ breakText Glyphs 字形
Set Size of Each 個別にサイズを設定
@msg select exactly two objects オブジェクトをちょうど 2 つ選択してください
@msg give `width` or `height` `width` または `height` を指定してください
Marathi マラーティー語
Gujarati グジャラート語
Bengali ベンガル語
Punjabi パンジャブ語
Tamil タミル語
Telugu テルグ語
Kannada カンナダ語
Malayalam マラヤーラム語
Odia オディア語
Urdu ウルドゥー語
VectorCraft {release} and later (version {n}) VectorCraft {release} 以降 (バージョン {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -6032,4 +6032,14 @@ breakText Glyphs გლიფები
Set Size of Each თითოეულის ზომის დაყენება
@msg select exactly two objects მონიშნეთ ზუსტად ორი ობიექტი
@msg give `width` or `height` მიუთითეთ `width` ან `height`
Marathi მარათჰი
Gujarati გუჯარათი
Bengali ბენგალური
Punjabi პენჯაბური
Tamil ტამილური
Telugu ტელუგუ
Kannada კანადა
Malayalam მალაიალამური
Odia ორია
Urdu ურდუ
VectorCraft {release} and later (version {n}) VectorCraft {release} და უფრო ახალი (ვერსია {n})
Can't render this file because it is too large.
+10
View File
@@ -5625,4 +5625,14 @@ breakText Glyphs 글리프
Set Size of Each 각각 크기 설정
@msg select exactly two objects 개체를 정확히 두 개 선택하세요
@msg give `width` or `height` `width` 또는 `height`를 지정하세요
Marathi 마라티어
Gujarati 구자라트어
Bengali 벵골어
Punjabi 펀잡어
Tamil 타밀어
Telugu 텔루구어
Kannada 칸나다어
Malayalam 말라얄람어
Odia 오리야어
Urdu 우르두어
VectorCraft {release} and later (version {n}) VectorCraft {release} 이상 (버전 {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -5984,4 +5984,14 @@ breakText Glyphs Glyphs
Set Size of Each Formaat van elk instellen
@msg select exactly two objects selecteer precies twee objecten
@msg give `width` or `height` geef `width` of `height` op
Marathi Marathi
Gujarati Gujarati
Bengali Bengaals
Punjabi Punjabi
Tamil Tamil
Telugu Telugu
Kannada Kannada
Malayalam Malayalam
Odia Odia
Urdu Urdu
VectorCraft {release} and later (version {n}) VectorCraft {release} en nieuwer (versie {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -5898,4 +5898,14 @@ breakText Glyphs Glify
Set Size of Each Ustaw rozmiar każdego
@msg select exactly two objects zaznacz dokładnie dwa obiekty
@msg give `width` or `height` podaj `width` lub `height`
Marathi Marathi
Gujarati Gudżarati
Bengali Bengalski
Punjabi Pendżabski
Tamil Tamilski
Telugu Telugu
Kannada Kannada
Malayalam Malajalam
Odia Orija
Urdu Urdu
VectorCraft {release} and later (version {n}) VectorCraft {release} i nowsze (wersja {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -5962,4 +5962,14 @@ breakText Glyphs Glifos
Set Size of Each Definir Tamanho de Cada Um
@msg select exactly two objects selecione exatamente dois objetos
@msg give `width` or `height` informe `width` ou `height`
Marathi Marati
Gujarati Guzerate
Bengali Bengali
Punjabi Panjabi
Tamil Tâmil
Telugu Télugo
Kannada Canarim
Malayalam Malaiala
Odia Oriá
Urdu Urdu
VectorCraft {release} and later (version {n}) VectorCraft {release} e posteriores (versão {n})
Can't render this file because it contains an unexpected character in line 6 and column 47.
+10
View File
@@ -6020,4 +6020,14 @@ breakText Glyphs Глифы
Set Size of Each Задать размер каждого
@msg select exactly two objects выделите ровно два объекта
@msg give `width` or `height` укажите `width` или `height`
Marathi Маратхи
Gujarati Гуджарати
Bengali Бенгальский
Punjabi Панджаби
Tamil Тамильский
Telugu Телугу
Kannada Каннада
Malayalam Малаялам
Odia Ория
Urdu Урду
VectorCraft {release} and later (version {n}) VectorCraft {release} и новее (версия {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -6095,4 +6095,14 @@ breakText Glyphs Glyfer
Set Size of Each Ange storlek för vart och ett
@msg select exactly two objects markera exakt två objekt
@msg give `width` or `height` ange `width` eller `height`
Marathi Marathi
Gujarati Gujarati
Bengali Bengali
Punjabi Punjabi
Tamil Tamil
Telugu Telugu
Kannada Kannada
Malayalam Malayalam
Odia Oriya
Urdu Urdu
VectorCraft {release} and later (version {n}) VectorCraft {release} och senare (version {n})
Can't render this file because it contains an unexpected character in line 5 and column 25.
+10
View File
@@ -6000,4 +6000,14 @@ breakText Glyphs Glifler
Set Size of Each Her Birinin Boyutunu Ayarla
@msg select exactly two objects tam olarak iki nesne seç
@msg give `width` or `height` `width` veya `height` belirt
Marathi Marathi dili
Gujarati Gücerat dili
Bengali Bengalce
Punjabi Pencapça
Tamil Tamilce
Telugu Telugu dili
Kannada Kannada dili
Malayalam Malayalam dili
Odia Oriya dili
Urdu Urduca
VectorCraft {release} and later (version {n}) VectorCraft {release} ve sonrası (sürüm {n})
Can't render this file because it contains an unexpected character in line 5 and column 25.
+10
View File
@@ -5642,4 +5642,14 @@ breakText Glyphs Гліфи
Set Size of Each Задати розмір кожного
@msg select exactly two objects виділіть рівно два об’єкти
@msg give `width` or `height` укажіть `width` або `height`
Marathi Маратхі
Gujarati Гуджараті
Bengali Бенгальська
Punjabi Панджабі
Tamil Тамільська
Telugu Телугу
Kannada Каннада
Malayalam Малаялам
Odia Одія
Urdu Урду
VectorCraft {release} and later (version {n}) VectorCraft {release} і новіші (версія {n})
Can't render this file because it contains an unexpected character in line 178 and column 5.
+12 -1
View File
@@ -1624,7 +1624,8 @@ file-filter Templates Mẫu
Highlight Substituted Fonts Đánh dấu phông thay thế
Highlight Substituted Glyphs Đánh dấu Glyph bị thay thế
Highlight Variable Đánh dấu biến
Hindi Hindi
Hindi Tiếng Hindi
digits Hindi Hindi
History Lịch sử
History Options… Tùy chọn lịch sử…
Step Backward Lùi một bước
@@ -5644,4 +5645,14 @@ breakText Glyphs Glyph
Set Size of Each Đặt kích thước từng cái
@msg select exactly two objects hãy chọn đúng hai đối tượng
@msg give `width` or `height` hãy cho `width` hoặc `height`
Marathi Tiếng Marathi
Gujarati Tiếng Gujarati
Bengali Tiếng Bengali
Punjabi Tiếng Punjab
Tamil Tiếng Tamil
Telugu Tiếng Telugu
Kannada Tiếng Kannada
Malayalam Tiếng Malayalam
Odia Tiếng Odia
Urdu Tiếng Urdu
VectorCraft {release} and later (version {n}) VectorCraft {release} trở lên (phiên bản {n})
Can't render this file because it contains an unexpected character in line 200 and column 5.
+12 -1
View File
@@ -2358,7 +2358,8 @@ font-script Japanese 汉字
Character Direction 字符方向
Digits 数字
Arabic 阿拉伯数字
Hindi 印地数字
Hindi 印地语
digits Hindi 印地数字
Farsi 波斯数字
Proportional Oldstyle 比例旧式数字
Pucker & Bloat… 缩拢与膨胀…
@@ -5884,4 +5885,14 @@ breakText Glyphs 字形
Set Size of Each 分别设置大小
@msg select exactly two objects 请恰好选择两个对象
@msg give `width` or `height` 请提供 `width` 或 `height`
Marathi 马拉地语
Gujarati 古吉拉特语
Bengali 孟加拉语
Punjabi 旁遮普语
Tamil 泰米尔语
Telugu 泰卢固语
Kannada 卡纳达语
Malayalam 马拉雅拉姆语
Odia 奥里亚语
Urdu 乌尔都语
VectorCraft {release} and later (version {n}) VectorCraft {release} 及更高版本 (版本 {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+12 -1
View File
@@ -3299,7 +3299,8 @@ font-script Japanese 漢字
Character Direction 字元方向
Digits 數字
Arabic 阿拉伯數字
Hindi 印地數字
Hindi 印地文
digits Hindi 印地數字
Farsi 波斯數字
Proportional Oldstyle 比例舊式數字
Pucker & Bloat… 縮攏與膨脹…
@@ -5681,4 +5682,14 @@ breakText Glyphs 字符
Set Size of Each 個別設定大小
@msg select exactly two objects 請選取正好兩個物件
@msg give `width` or `height` 請提供 `width` 或 `height`
Marathi 馬拉地文
Gujarati 古吉拉特文
Bengali 孟加拉文
Punjabi 旁遮普文
Tamil 坦米爾文
Telugu 泰盧固文
Kannada 坎那達文
Malayalam 馬來亞拉姆文
Odia 歐利亞文
Urdu 烏都文
VectorCraft {release} and later (version {n}) VectorCraft {release} 及更新版本 (版本 {n})
Can't render this file because it contains an unexpected character in line 6 and column 47.
+18 -4
View File
@@ -1,11 +1,12 @@
//! Character panel: font family / style, size, leading, kerning, tracking, vertical and horizontal
//! scale, baseline shift, character rotation and the All Caps, Small Caps, Superscript, Subscript,
//! Underline and Strikethrough toggles.
//! Underline and Strikethrough toggles and the Language menu.
use std::sync::{Mutex, OnceLock};
use egui::{Key, Ui, vec2};
use serde_json::{Value, json};
use vectorcraft_doc::setup::{LANGUAGES, char_language_name};
use vectorcraft_doc::{CharStyle, NodeId, NodeKind};
use vectorcraft_tools::{Mods, ToolKey};
@@ -922,6 +923,17 @@ fn attributes(app: &mut VectorcraftApp, ui: &mut Ui) {
}
}
});
// Language: the characters are shaped in it, so that the font uses that language's forms.
ui.add_space(4.0);
let names: Vec<&str> = LANGUAGES.iter().map(|(n, _, _)| *n).collect();
// Mixed: blank; a tag from a file that is not in the list: as it is.
let current = shared(app, |s| s.language.clone())
.map_or_else(String::new, |l| char_language_name(l.as_deref()).map_or_else(|| l.unwrap_or_default(), str::to_string));
widgets::label_row(ui, tl!("Language:"), 64.0, |ui| {
if let Some(name) = widgets::dropdown(ui, "ch-language", &current, &names, w - 72.0).and_then(|i| names.get(i)) {
format(app, json!({"language": name}));
}
});
}
/// The `text.setFormat` params of the Superscript or Subscript toggle `p` for text whose
@@ -1079,11 +1091,13 @@ pub fn menu(app: &mut VectorcraftApp, ui: &mut Ui) {
ui.add_enabled_ui(has, |ui| {
ui.menu_button(format!(" {}", tl!("Digits")), |ui| {
use vectorcraft_doc::Digits;
// The numeral systems, in the digits context: Hindi is also a language.
let digits_label = |s| crate::i18n::tr_ctx(crate::i18n::current(), "digits", s);
for (label, d, key) in [
(tl!("Default"), Digits::Default, "default"),
(tl!("Arabic"), Digits::Arabic, "arabic"),
(tl!("Hindi"), Digits::Hindi, "hindi"),
(tl!("Farsi"), Digits::Farsi, "farsi"),
(digits_label("Arabic"), Digits::Arabic, "arabic"),
(digits_label("Hindi"), Digits::Hindi, "hindi"),
(digits_label("Farsi"), Digits::Farsi, "farsi"),
] {
if menu_item(ui, label, true, digits == Some(d)) {
format(app, json!({"digits": key}));
+15
View File
@@ -5034,6 +5034,21 @@ A digit the font lacks comes from a fallback font. Default and saved only when s
{"name":"run_command","arguments":{"command":"text.setFormat","params":{"digits":"hindi"}}}
```
## Language
`text.setFormat {language}` (the selected type, or `ids`) and `text.setRangeStyle {id, start, end, language}` (a range)
set the language of the characters, as the Character panel's Language menu does: one of Document Setup's languages
(`document.setup {language}`), by name or BCP 47 tag, case-insensitive (`"Turkish"` or `"tr"`, `"Marathi"` or `"mr"`).
An unknown language is an error. The characters are shaped in it, so the font uses that language's forms (OpenType
`locl`): in Turkish, Source Serif 4 keeps `fi` as two letters and the dot on the i, where English makes the fi ligature.
Runs are saved with the tag, and English: USA, the default, as no language, so files without languages load and save
as before. New type takes the document's language. Character styles captured from type carry it, and `charStyle.new` /
`charStyle.setAttrs` take `attrs: {language}` the same way. One undo step.
```json
{"name":"run_command","arguments":{"command":"text.setFormat","params":{"language":"Turkish"}}}
```
## Touch Type
The Touch Type tool (`touchType`, Shift+T) changes one character at a time. A click on a character of a type object
+2 -1
View File
@@ -1,6 +1,6 @@
# Parity with Adobe Illustrator
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-31 · **Change:** minor (New Document: Save Preset in More Settings, #4893; scores unchanged) · **Target:** Adobe Illustrator 2026 (30.x; public release notes through 30.7, August 2026)
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-01 · **Change:** minor (Type core: text shaped in its language, a Language per character, Indian languages, #4940 #4946 #4943; scores unchanged) · **Target:** Adobe Illustrator 2026 (30.x; public release notes through 30.7, August 2026)
## Feature submission evidence
@@ -1403,6 +1403,7 @@ dialogs, Preview and Cancel, Zoom to Selection) and `command_sweep`. Commands: `
| Date | Change | Summary |
|---|---|---|
| 2026-11-01 | minor | Type core: a Language per character (Character panel › Language, `text.setFormat` / `text.setRangeStyle {language}`, character styles), new type in the document's language; text is shaped in its language so fonts use their language forms (OpenType `locl`: Turkish `fi`, #4940, #4946); Hindi, Marathi, Gujarati, Bengali, Punjabi, Tamil, Telugu, Kannada, Malayalam, Odia and Urdu in the language list (#4943); scores unchanged |
| 2026-10-31 | minor | Selection tools: with Alt held at the press, a Direct Selection marquee selects every path it touches whole and keeps the Group Selection pointer (#4890); a press on a selected object's centre point selects the object whole and a drag from it moves it (#4891); regression tests in `direct/tests.rs`; scores and estimates unchanged. |
| 2026-10-31 | minor | Arrange Tools add-on (a VectorCraft addition): evidence added; scores unchanged. |
| 2026-10-31 | minor | Guides and snapping: Snap to Perpendicular and Snap to Tangent apply to an existing line's end dragged with Direct Selection, as the public pages describe for editing existing lines (the end anchor of a straight segment, not mid-line anchors or curved segments); a regression test covers both snaps, both toggles and non-snapping controls (#2530); scores and estimates unchanged. |
+3 -1
View File
@@ -1,6 +1,6 @@
# Type parity
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-31 · **Change:** minor (PDF import finds installed fonts whose PDF names hold hyphens or a composite font's CMap; scores unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-01 · **Change:** minor (Language per character: text is shaped in its language, Character panel › Language, Indian languages; scores unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
Type is Illustrator's largest single area by use (weight 13 of 105 across "Type core" and "Type advanced" in
[target-app-parity.md](target-app-parity.md)). This checklist lists the features one by one. Status is from the
@@ -60,6 +60,7 @@ against Illustrator's public documentation; **estimated** unless noted.
| CJK: Proportional Metrics (`palt` in horizontal type, `vpal` in vertical type) | done | #966 |
| CJK: manual tate-chu-yoko | done | Character panel menu › Tate-chu-yoko (`text.setFormat` / `text.setRangeStyle {tateChuYoko}`), with Show East Asian Options: marked characters stand side by side across one em of a vertical column, squeezed to the em when wider; two or three half-width digits still do so without the mark; horizontal type keeps the mark and does not move them. Up/Down and Left/Right settings remain. Evidence: `tests_vertical::manual_tate_chu_yoko_sets_marked_characters_across_one_em`, `typecmd::tate_chu_yoko_is_a_character_attribute_saved_only_when_on` |
| CJK: ruby, manual tate-chu-yoko | partial | ruby (ふりがな) for live text (`type.ruby`): a reading over a byte range, above (right of the column in vertical type) or below, start/centre/end alignment, size, overhang or squeeze; saved natively, laid out with its line growing, drawn on the canvas, in SVG and PDF (as outlines where ruby is present), in EPS, EMF/WMF and legacy `.ai` (legacy `.ai` writes type with ruby as outlines), and kept by Create Outlines, Expand Appearance and flattening, each glyph where the layout puts it (`typecmd::ruby_tests::create_outlines_keeps_the_ruby_where_it_is_laid_out`); manual tate-chu-yoko missing | #633 |
| Language per character (Character panel › Language, character styles), text shaped in it | done | `text.setFormat` / `text.setRangeStyle {language}` by name or BCP 47 tag, one of Document Setup's languages (Hindi, Marathi, Gujarati, Bengali, Punjabi, Tamil, Telugu, Kannada, Malayalam, Odia and Urdu added, #4943); the shaper gets the tag, so the font's language forms apply (OpenType `locl`: Turkish keeps `fi` apart and the dot on its i, #4940); new type takes the document's language; saved as the tag only when set, carried by character styles (#4946). Not yet: hyphenation and spelling by it, `.ai`/PDF import of a text's language, paragraph styles. Evidence: `features::tests::language_picks_the_fonts_forms`, `typecmd::area_tests::language_is_a_character_attribute_saved_only_when_set` |
| No Break | done | Character panel menu (`text.setFormat` / `text.setRangeStyle {noBreak}`): the marked characters stay on one line, including across a space; a run that does not fit after earlier text moves together, and a run longer than the line stays together. Evidence: `layout::wrapping_tests::no_break_keeps_marked_characters_on_one_line`, `tests::no_break_keeps_marked_words_on_one_line`, `typecmd::no_break_is_a_character_attribute_saved_only_when_on` |
| CJK: ruby | missing | #633 |
| Inline symbols in text | beyond Illustrator | not scored |
@@ -71,6 +72,7 @@ Character Styles menu New/Redefine and footer New capture the first selected cha
| Date | Change | Summary |
|---|---|---|
| 2026-11-01 | minor | Language per character (#4946): Character panel › Language, `text.setFormat` / `text.setRangeStyle {language}`, character styles; text is shaped in its language (`locl`, #4940); new type takes the document's; Indian languages in the list (#4943); scores unchanged |
| 2026-10-31 | minor | PDF import finds an installed font whose PDF name holds hyphens (`Noto-Sans-Bold` is Noto Sans, Bold: the longest part before a hyphen that names an installed family) and a composite font by its CIDFont's name rather than its base name, which ends in the CMap's (`Name-Identity-H`, [ISO 32000-1 §9.7.6.1](https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/PDF32000_2008.pdf)); a missing font is split only before a style part (`Helvetica-BoldOblique`), so it is reported as `MS PGothic`, not `MS`; scores unchanged |
| 2026-10-31 | minor | Highlight Alternate Glyphs: an optional feature (such as `salt`) that changes a lam-alef ligature is highlighted again, only the required ligature staying clear, and a lam-alef with any combining mark (Arabic Extended-A/B/C included) counts as the ligature (#394); scores unchanged |
| 2026-10-30 | minor | Highlight Alternate Glyphs leaves the required lam-alef ligature unhighlighted also in older Arabic fonts (such as legacy Arial) that put it in `liga` rather than `rlig` (#394); scores unchanged |
+2 -1
View File
@@ -1,6 +1,6 @@
# UI and interaction parity
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-01 · **Change:** minor (native Save As Version menu, refused-save alert, fixed Contributors table header, freeform point swatch opens its popover: #4931, #4933, #4944, #4953) · **Target:** Adobe Illustrator 2026 (30.x)
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-01 · **Change:** minor (Character panel › Language, Indian languages in Document Setup › Language, #4946 #4943) · **Target:** Adobe Illustrator 2026 (30.x)
## Feature submission evidence
@@ -381,6 +381,7 @@ separate. Scores and hours unchanged. [Behavior and command details](development
| Date | Change | Summary |
|---|---|---|
| 2026-11-01 | minor | Character panel › Language: the selected characters' language, from Document Setup's list, which gains Hindi, Marathi, Gujarati, Bengali, Punjabi, Tamil, Telugu, Kannada, Malayalam, Odia and Urdu (#4946, #4943); the Digits menu's numeral names keep their own translations; scores unchanged |
| 2026-11-01 | minor | VectorCraft Options' Version is a menu of the versions VectorCraft writes, each named by the releases that read it, and an uncompressible version turns Use Compression off (#4931); a save refused before writing shows the Can't save alert with the reason (#4933); About › Contributors' table keeps its header row above the scrolling rows (#4944); the Gradient panel's freeform point swatch opens the point's popover (#4953); scores unchanged |
| 2026-10-31 | minor | A file opened from the file manager while VectorCraft runs opens as a new tab in that window, which comes to the front, on Windows and Linux (#4892); `--new-instance` opts out; scores unchanged |
| 2026-10-31 | minor | Object › Path › Smooth: Auto-Smooth takes a shaky line to one smooth curve, and direct-selected anchors smooth only their section; scores unchanged |