mirror of
https://github.com/storytold/designcraft.git
synced 2026-10-24 10:16:59 -06:00
Merge #565: fix(compose): enable Norwegian hyphenation patterns
Conflict: docs/typography-parity.md: kept next's Justification row (#531 note), took the PR's Hyphenation row (Portuguese and Norwegian)
This commit is contained in:
@@ -52,6 +52,12 @@ list (author, source, license) is in ASSETS.md.
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
- Norwegian hyphenation patterns, embedded through the hypher crate (feature "norwegian"):
|
||||
hyph-no.tex from hyph-utf8, https://github.com/hyphenation/tex-hyphen.
|
||||
Copyright (C) Rune Kleveland and Ole Michael Selberg. Copying and distribution of this file,
|
||||
with or without modification, is permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved (additionally distributed under the LaTeX Project Public
|
||||
License in CTAN distributions).
|
||||
- Japanese fonts (craft-fonts): builds made with craft-fonts (CRAFT_FONTS_DIR; all official
|
||||
releases) embed the fonts listed in
|
||||
https://github.com/storytold/craft-fonts/blob/main/ATTRIBUTION.md (BIZ UDPGothic, BIZ UDMincho,
|
||||
|
||||
@@ -21,7 +21,7 @@ log = { workspace = true }
|
||||
regex = { workspace = true }
|
||||
fancy-regex = { workspace = true }
|
||||
miniz_oxide = "0.8"
|
||||
hypher = { version = "0.1.8", default-features = false, features = ["alloc", "portuguese", "spanish"] }
|
||||
hypher = { version = "0.1.8", default-features = false, features = ["alloc", "portuguese", "spanish", "norwegian"] }
|
||||
|
||||
[dev-dependencies]
|
||||
designcraft-fonts = { workspace = true, features = ["testing"] }
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
//! Hyphenation. English uses the bundled dictionary and patterns below. Other languages use the
|
||||
//! Liang patterns compiled into `hypher`, one cargo feature per language: Spanish is Javier Bezos's
|
||||
//! `hyph-es.tex` 5.0 from hyph-utf8, MIT; Portuguese is `hyph-pt.tex` 1.4 from hyph-utf8 (Pedro J.
|
||||
//! de Rezende, J. Joao Dias Almeida, Leonardo Araujo, Aline Benevides), BSD-3-Clause (see NOTICE).
|
||||
//! de Rezende, J. Joao Dias Almeida, Leonardo Araujo, Aline Benevides), BSD-3-Clause; Norwegian is
|
||||
//! `hyph-no.tex` from hyph-utf8 (Rune Kleveland, Ole Michael Selberg), permissive (see NOTICE).
|
||||
//!
|
||||
//! English lookup order for each word:
|
||||
//! 1. the **dictionary** ([`Dictionary::en_us`]) — the public-domain Moby Hyphenator II word list
|
||||
@@ -411,6 +412,26 @@ mod tests {
|
||||
assert_eq!(h("pós-graduação"), "pós-gra-du-a-ção", "each part of a compound");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn norwegian_uses_the_hyph_no_patterns() {
|
||||
let nb = Lang::for_language("Norwegian: Bokmål").unwrap();
|
||||
assert_eq!(nb, Lang::for_language("Norwegian").unwrap());
|
||||
assert_eq!(nb, Lang::for_language("Norwegian: Nynorsk").unwrap());
|
||||
assert_eq!(nb, Lang::for_language("nb").unwrap());
|
||||
assert_eq!(nb, Lang::for_language("nn").unwrap());
|
||||
assert_eq!(nb, Lang::for_language("no").unwrap());
|
||||
assert_ne!(nb, Lang::for_language("Spanish").unwrap());
|
||||
let h = |w: &str| {
|
||||
let pts = hyphen_points_in(w, &Limits::default(), nb);
|
||||
w.chars().enumerate().map(|(i, c)| if pts.contains(&i) { format!("-{c}") } else { c.to_string() }).collect::<String>()
|
||||
};
|
||||
assert_eq!(h("kaller"), "kal-ler");
|
||||
assert_eq!(h("bilde"), "bil-de");
|
||||
assert_eq!(h("sjøfugl"), "sjø-fugl");
|
||||
assert_eq!(h("sirkulasjonen"), "sir-ku-la-sjo-nen");
|
||||
assert_eq!(h("beveger"), "be-ve-ger");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn heuristic_fallback() {
|
||||
let c: Vec<char> = "happen".chars().collect();
|
||||
|
||||
@@ -3335,6 +3335,25 @@ fn portuguese_text_gets_portuguese_hyphenation() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn norwegian_text_gets_norwegian_hyphenation() {
|
||||
let text = "sirkulasjonen beveger nedsynkningen kaller overflaten bilde";
|
||||
let (mut d, sid, _) = doc_with(text, Rect::new(36.0, 36.0, 76.0, 700.0), ParaAttrs::default());
|
||||
let st = d.story_mut(sid).unwrap();
|
||||
let n = st.len();
|
||||
st.format_chars(0..n, |f| f.over.language = Some("Norwegian: Bokmål".into()));
|
||||
let cs = compose_story(&d, sid, &ComposeOptions::default());
|
||||
let breaks: Vec<&str> = all_lines(&cs).into_iter().filter(|l| l.hyphenated).map(|l| text[l.range.clone()].trim_end()).collect();
|
||||
assert!(!breaks.is_empty(), "Norwegian text is hyphenated");
|
||||
for b in breaks {
|
||||
let tail = b.rsplit(' ').next().unwrap_or(b);
|
||||
let whole = text[text.find(b).unwrap() + b.len() - tail.len()..].split(|c: char| !c.is_alphabetic()).next().unwrap_or("");
|
||||
let nb = hyphen::Lang::for_language("Norwegian: Bokmål").unwrap();
|
||||
let pts = hyphen::hyphen_points_in(whole, &hyphen::Limits::default(), nb);
|
||||
assert!(pts.contains(&tail.chars().count()), "break {tail}- in {whole} is a hyph-no point");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cjk_aki_adds_space_without_scaling_outlines() {
|
||||
let (mut d, sid, _) = doc_with("AB", Rect::new(0.0, 0.0, 300.0, 100.0), ParaAttrs::default());
|
||||
|
||||
+1
-1
@@ -136,7 +136,7 @@ Kind: **F** feature · **U** UI/UX · **T** typography · **FF** file format ·
|
||||
- **Estimate:** 25–40 h.
|
||||
|
||||
### 13. Hyphenation and spelling languages (T, L)
|
||||
- **Missing:** hyphenation patterns for every language but English and Spanish; spelling for
|
||||
- **Missing:** hyphenation patterns for every language but English, Spanish, Portuguese and Norwegian; spelling for
|
||||
every language but English. InDesign ships dictionaries for ~40 languages.
|
||||
- **Estimate:** 30–60 h (permissively licensed patterns exist for most; spelling word lists need
|
||||
licence review). **Doc:** [typography-parity.md](typography-parity.md)
|
||||
|
||||
@@ -33,7 +33,7 @@ come as Middle East editions with an English or French interface and right-to-le
|
||||
| Hindi | hi | ✗ | 0 (0%) | none | Devanagari shaped by harfrust in documents but untested; no Hindi hyphenation or spelling | no | none | 20–30 |
|
||||
| Arabic | ar | Middle East edition (English/French UI) | 1,459 (85%) | menus, panels, most dialogs; no help | RTL UI text (`rtl.rs`: bidi + shaping); Arabic composition, kashida, digits, RTL stories and tables ✓ (arabic-typography.md); list bullets and multi-column RTL open (#100) | no | partial | 15–25 |
|
||||
| French | fr | ✓ | 1,438 (83%) | menus, panels, most dialogs; no help | Latin ✓; no French hyphenation | no | partial | 6–10 |
|
||||
| Portuguese (Brazil) | pt-br | ✓ (pt) | 1,057 (61%) | menus, panels, some dialogs; no help | Latin ✓; no Portuguese hyphenation | no | partial | 8–12 |
|
||||
| Portuguese (Brazil) | pt-br | ✓ (pt) | 1,057 (61%) | menus, panels, some dialogs; no help | Latin ✓; Portuguese hyphenation ✓ | no | partial | 8–12 |
|
||||
| Indonesian | id | ✗ | 0 (0%) | none | Latin ✓ | no | none | 12–18 |
|
||||
| Japanese | ja | ✓ | 1,644 (95%) | whole interface (#272), vertical-type commands; no help | vertical text, kinsoku, aki, ruby, warichu ✓ (partial depth, cjk.md); **no canvas IME** (#322); Japanese UI and Mincho fonts from craft-fonts | no | partial | 6–10 (+ IME, shared with zh) |
|
||||
| German | de | ✓ | 1,438 (83%) | menus, panels, most dialogs; no help | Latin ✓; no German hyphenation (InDesign ships 2006 reform patterns) | no | partial | 6–10 |
|
||||
@@ -62,7 +62,7 @@ eight of the twelve (cs, da, el, en_GB, fi, hu, it, nb, nl, pl, ro, ru, sq, sv,
|
||||
## Document languages
|
||||
|
||||
InDesign 2026 hyphenates and spell-checks ~40 languages (Hunspell and Duden dictionaries).
|
||||
DesignCraft hyphenates **English and Spanish** and spell-checks **English** only. Text language
|
||||
DesignCraft hyphenates **English, Spanish, Portuguese and Norwegian** and spell-checks **English** only. Text language
|
||||
can be set per paragraph and character (Properties, Character panel) and drives quotes and
|
||||
locale shaping. See [typography-parity.md](typography-parity.md).
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ they receive, setting type exactly, and basic editing that never fails.
|
||||
| Dimension | Weight | Ready | Remaining (Opus 5.5 h) | Evidence | Doc |
|
||||
|---|---|---|---|---|---|
|
||||
| Features (depth of each area) | 25% | 55% | 250–400 | 275 catalogue rows exist; many lack options (e.g. Books is 258 lines of engine code, Liquid Layout 329); see the area table | this file |
|
||||
| Typography and composition fidelity | 15% | 45% | 120–200 | Knuth–Plass composer, keeps, grids, CJK, Arabic all exist; no comparison with InDesign's line breaks; optical kerning falls back to metrics (#181); overset rule differs (#180); hyphenation patterns for English and Spanish only | [typography-parity.md](typography-parity.md) |
|
||||
| Typography and composition fidelity | 15% | 45% | 120–200 | Knuth–Plass composer, keeps, grids, CJK, Arabic all exist; no comparison with InDesign's line breaks; optical kerning falls back to metrics (#181); overset rule differs (#180); hyphenation patterns for English, Spanish, Portuguese and Norwegian only | [typography-parity.md](typography-parity.md) |
|
||||
| File formats | 20% | 40% | 150–250 (+20–60 for INDD integration) | INDD cannot be opened (#21); IDML both ways and verified in InDesign 2026, but real-file bugs open (#193, #338, #339, #340); PDF export strong; PDF/X-4 only | [file-format-parity.md](file-format-parity.md) |
|
||||
| UI/UX fidelity | 15% | 45% | 120–180 | Measured InDesign 2026 look; but users report object copy/paste (#351, #348, #185, #164), right-click menus (#238, #187, #160), out-port threading (#352, #194, #165), canvas IME (#322) failing | [ui-parity.md](ui-parity.md) |
|
||||
| Stability | 10% | 45% | 60–100 | Never-crash rules and last-resort guards; startup failures on some GPUs and machines (#334, #273, #220, #192, #167, #166); no CI runs the tests on pull requests | [gaps.md](gaps.md) |
|
||||
@@ -349,7 +349,7 @@ It is evidence of breadth: each item exists. It is not a claim of InDesign-level
|
||||
- Edit ▸ Menus (`window.hideMenuItem`): hide menu items; menus with hidden items end in Show All Menu Items.
|
||||
- View ▸ Separations Preview (`view.separations`): one process plate as ink density, or areas over an ink limit in red (a GCR preview of the rendered view; spot plates and the flattener preview aren't there).
|
||||
- Separations Preview plates now come from each object's own colour (CMYK as authored; RGB and images through the colour settings, images via a cached 17³ table), so pure black shows only on the black plate.
|
||||
- Language (Character panel ▸ Language, Properties ▸ Character, `type.char {language}`): text in other languages isn't hyphenated or spell-checked with the English dictionaries, typographer's quotes follow the language (German „…“, French and Russian «…», Swiss, Spanish, Dutch, Nordic, Japanese and Traditional Chinese 「…」, Simplified Chinese “…”), the font's localized forms (OpenType `locl`: Turkish i, Bulgarian Cyrillic, Japanese / Chinese / Korean glyph variants) follow it too, and so does the fallback for CJK characters the font lacks (with Draw Missing Glyphs from Fallback Fonts on): Japanese, Simplified Chinese, Traditional Chinese and Korean each try their own installed system fonts (Japanese starts with the craft-fonts Japanese faces, Mincho first, when built with them; Hangul, kana and Bopomofo pick their language's fonts whatever the language). Language names from IDML keep their spelling; locale codes as InDesign writes them for some languages (`de_DE_2006`, `nl_NL_2005`; any `ll`, `ll_CC`, `ll-CC`) are their language and region for all of the above, and Chinese is also recognised in its common spellings ("Simplified Chinese", "Chinese (Traditional)", `zh_CN`, `zh-Hant`). Spanish is hyphenated with Javier Bezos's Liang patterns (`hyph-es.tex` 5.0, MIT) and Portuguese with hyph-utf8's `hyph-pt.tex` 1.4 (BSD-3-Clause), both through the `hypher` crate; hyphenation for other languages isn't bundled yet.
|
||||
- Language (Character panel ▸ Language, Properties ▸ Character, `type.char {language}`): text in other languages isn't hyphenated or spell-checked with the English dictionaries, typographer's quotes follow the language (German „…“, French and Russian «…», Swiss, Spanish, Dutch, Nordic, Japanese and Traditional Chinese 「…」, Simplified Chinese “…”), the font's localized forms (OpenType `locl`: Turkish i, Bulgarian Cyrillic, Japanese / Chinese / Korean glyph variants) follow it too, and so does the fallback for CJK characters the font lacks (with Draw Missing Glyphs from Fallback Fonts on): Japanese, Simplified Chinese, Traditional Chinese and Korean each try their own installed system fonts (Japanese starts with the craft-fonts Japanese faces, Mincho first, when built with them; Hangul, kana and Bopomofo pick their language's fonts whatever the language). Language names from IDML keep their spelling; locale codes as InDesign writes them for some languages (`de_DE_2006`, `nl_NL_2005`; any `ll`, `ll_CC`, `ll-CC`) are their language and region for all of the above, and Chinese is also recognised in its common spellings ("Simplified Chinese", "Chinese (Traditional)", `zh_CN`, `zh-Hant`). Spanish is hyphenated with Javier Bezos's Liang patterns (`hyph-es.tex` 5.0, MIT), Portuguese with hyph-utf8's `hyph-pt.tex` 1.4 (BSD-3-Clause) and Norwegian with hyph-utf8's `hyph-no.tex` (permissive), all through the `hypher` crate; hyphenation for other languages isn't bundled yet.
|
||||
- Books (`book.new/open/add/remove/list/styleSource/paginate/syncStyles/exportPdf`, Book panel): `.dcbook` files, continuous page numbering, style sync from a style source, one merged PDF.
|
||||
- Track Changes (`changes.track/list/acceptAll/rejectAll`, Type ▸ Track Changes): typing is marked added (highlighted on screen), deletions are kept but hidden from layout and exports until accepted or rejected. Per-change accept/reject and authors aren't there yet.
|
||||
- Track Changes: per-change Accept / Reject (`changes.accept`, `changes.reject`) and a Track Changes panel listing every change.
|
||||
|
||||
@@ -36,7 +36,7 @@ Fidelity: **unmeasured** unless stated.
|
||||
| Single-line Composer | greedy | greedy with the same ranges | ✓ | |
|
||||
| World-Ready composers | Paragraph / Single-line World-Ready | RTL, Arabic and bidi in the main composer | ~ | Indic scripts (Devanagari etc.) shape through harfrust but are untested |
|
||||
| Justification | word/letter spacing, glyph scaling min/desired/max, single-word, last line | all of these | ✓ | a justified line with a tab justifies after the tab (#284); set per paragraph in Type › Justification… and the Paragraph panel menu (#531) |
|
||||
| Hyphenation | per-language dictionaries (~40), zone, limits, capitalized, last word, across columns | Liang patterns: English (trained from the public-domain Moby list) and Spanish (Bezos); zone, limits, exceptions in the user dictionary | ~ | other languages don't hyphenate (#87 reported "doesn't work") |
|
||||
| Hyphenation | per-language dictionaries (~40), zone, limits, capitalized, last word, across columns | Liang patterns: English (trained from the public-domain Moby list), Spanish (Bezos), Portuguese (hyph-pt) and Norwegian (hyph-no); zone, limits, exceptions in the user dictionary | ~ | other languages don't hyphenate (#87 reported "doesn't work") |
|
||||
| Spelling | per-language dictionaries | English (Moby) + document/user dictionary | ~ | |
|
||||
| Kerning | Metrics, Optical, manual, none | Metrics, Optical (outline-based: pairs pulled towards the font's stem gap, `crates/compose/src/optical.rs`), manual, none | ~ | Optical is an approximation of Adobe's algorithm (#181), not a match: imported display text can still break differently |
|
||||
| Tracking, scale, skew, baseline shift | ✓ | ✓ | ✓ | |
|
||||
|
||||
Reference in New Issue
Block a user