Make language non-optional with english as default

This commit is contained in:
Laurenz 2022-04-13 15:01:19 +02:00
parent 67e9313b91
commit d025854457
9 changed files with 55 additions and 53 deletions

39
src/library/text/lang.rs Normal file
View File

@ -0,0 +1,39 @@
use crate::eval::Value;
use crate::geom::Dir;
/// A natural language.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Lang([u8; 2]);
impl Lang {
/// The code for the english language.
pub const ENGLISH: Self = Self(*b"en");
/// Construct a language from a two-byte ISO 639-1 code.
pub fn from_str(iso: &str) -> Option<Self> {
let mut bytes: [u8; 2] = iso.as_bytes().try_into().ok()?;
bytes.make_ascii_lowercase();
Some(Self(bytes))
}
/// Return the language code as a string slice.
pub fn as_str(&self) -> &str {
std::str::from_utf8(&self.0).unwrap_or_default()
}
/// The default direction for the language.
pub fn dir(&self) -> Dir {
match self.as_str() {
"ar" | "dv" | "fa" | "he" | "ks" | "pa" | "ps" | "sd" | "ug" | "ur"
| "yi" => Dir::RTL,
_ => Dir::LTR,
}
}
}
castable! {
Lang,
Expected: "string",
Value::Str(string) => Self::from_str(&string)
.ok_or("expected two letter language code")?,
}

View File

@ -1,6 +1,7 @@
//! Text handling and paragraph layout.
mod deco;
mod lang;
mod link;
mod par;
mod quotes;
@ -8,6 +9,7 @@ mod raw;
mod shaping;
pub use deco::*;
pub use lang::*;
pub use link::*;
pub use par::*;
pub use quotes::*;
@ -64,8 +66,7 @@ impl TextNode {
pub const BOTTOM_EDGE: TextEdge = TextEdge::Metric(VerticalFontMetric::Baseline);
/// An ISO 639-1 language code.
#[property(referenced)]
pub const LANG: Option<Lang> = None;
pub const LANG: Lang = Lang::ENGLISH;
/// The direction for text and inline objects. When `auto`, the direction is
/// automatically inferred from the language.
#[property(resolve)]
@ -257,32 +258,6 @@ castable! {
}),
}
/// A natural language.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Lang(EcoString);
impl Lang {
/// The default direction for the language.
pub fn dir(&self) -> Dir {
match self.0.as_str() {
"ar" | "dv" | "fa" | "he" | "ks" | "pa" | "ps" | "sd" | "ug" | "ur"
| "yi" => Dir::RTL,
_ => Dir::LTR,
}
}
/// Return the language code as a string slice.
pub fn as_str(&self) -> &str {
&self.0
}
}
castable! {
Lang,
Expected: "string",
Value::Str(string) => Self(string.to_lowercase()),
}
/// The direction of text and inline objects in their line.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct HorizontalDir(pub Dir);
@ -301,10 +276,7 @@ impl Resolve for Smart<HorizontalDir> {
fn resolve(self, styles: StyleChain) -> Self::Output {
match self {
Smart::Auto => match styles.get(TextNode::LANG) {
Some(lang) => lang.dir(),
None => Dir::LTR,
},
Smart::Auto => styles.get(TextNode::LANG).dir(),
Smart::Custom(dir) => dir.0,
}
}

View File

@ -408,11 +408,7 @@ fn collect<'a>(
if styles.get(TextNode::SMART_QUOTES) {
// TODO: Also get region.
let lang = styles.get(TextNode::LANG);
let quotes = lang
.as_ref()
.map(|lang| Quotes::from_lang(lang.as_str(), ""))
.unwrap_or_default();
let quotes = Quotes::from_lang(lang.as_str(), "");
let peeked = iter.peek().and_then(|(child, _)| match child {
ParChild::Text(text) => text.chars().next(),
ParChild::Quote(_) => Some('"'),
@ -750,7 +746,7 @@ fn breakpoints<'a>(p: &'a Preparation) -> Breakpoints<'a> {
end: 0,
mandatory: false,
hyphenate: p.get_shared(TextNode::HYPHENATE),
lang: p.get_shared(TextNode::LANG).map(Option::as_ref),
lang: p.get_shared(TextNode::LANG),
}
}
@ -773,7 +769,7 @@ struct Breakpoints<'a> {
/// Whether to hyphenate if it's the same for all children.
hyphenate: Option<bool>,
/// The text language if it's the same for all children.
lang: Option<Option<&'a Lang>>,
lang: Option<Lang>,
}
impl Iterator for Breakpoints<'_> {
@ -831,9 +827,9 @@ impl Breakpoints<'_> {
/// The text language at the given offset.
fn lang_at(&self, offset: usize) -> Option<hypher::Lang> {
let lang = self.lang.unwrap_or_else(|| {
let lang = self.lang.or_else(|| {
let shaped = self.p.find(offset)?.text()?;
shaped.styles.get(TextNode::LANG).as_ref()
Some(shaped.styles.get(TextNode::LANG))
})?;
let bytes = lang.as_str().as_bytes().try_into().ok()?;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -6,13 +6,13 @@
#set page(width: auto)
#grid(
columns: (70pt, 60pt),
text(lang: "en")[Warm welcomes to Typst.],
[Warm welcomes to Typst.],
text(lang: "el")[διαμερίσματα. \ λατρευτός],
)
---
// Test disabling hyphenation for short passages.
#set text(lang: "en", hyphenate: true)
#set text(hyphenate: true)
Welcome to wonderful experiences. \
Welcome to `wonderful` experiences. \
@ -20,14 +20,14 @@ Welcome to #text(hyphenate: false)[wonderful] experiences. \
Welcome to wonde#text(hyphenate: false)[rf]ul experiences. \
// Test enabling hyphenation for short passages.
#set text(lang: "en", hyphenate: false)
#set text(hyphenate: false)
Welcome to wonderful experiences. \
Welcome to wo#text(hyphenate: true)[nd]erful experiences. \
---
// Hyphenate between shape runs.
#set page(width: 80pt)
#set text(lang: "en", hyphenate: true)
#set text(hyphenate: true)
It's a #emph[Tree]beard.
---
@ -46,5 +46,5 @@ It's a #emph[Tree]beard.
// do that. The test passes if there's just one hyphenation between
// "net" and "works".
#set page(width: 70pt)
#set text(lang: "en", hyphenate: true)
#set text(hyphenate: true)
#h(6pt) networks, the rest.

View File

@ -1,7 +1,6 @@
---
#set page(width: 180pt)
#set text(lang: "en")
#set par(
justify: true,
indent: 14pt,

View File

@ -1,6 +1,6 @@
#set page(width: auto, height: auto)
#set par(leading: 4pt, justify: true)
#set text(lang: "en", family: "Latin Modern Roman")
#set text(family: "Latin Modern Roman")
#let story = [
In olden times when wishing still helped one, there lived a king whose

View File

@ -4,7 +4,7 @@
// Test hanging punctuation.
#set page(width: 130pt, margins: 15pt)
#set par(justify: true, linebreaks: "simple")
#set text(lang: "en", size: 9pt)
#set text(size: 9pt)
#rect(fill: rgb(repr(teal) + "00"), width: 100%)[
This is a little bit of text that builds up to
hang-ing hyphens and dash---es and then, you know,

View File

@ -24,12 +24,10 @@
---
// Test single pair of quotes.
#set text(lang: "en")
""
---
// Test sentences with numbers and apostrophes.
#set text(lang: "en")
The 5'11" 'quick' brown fox jumps over the "lazy" dog's ear.
He said "I'm a big fella."
@ -40,7 +38,6 @@ The 5\'11\" 'quick\' brown fox jumps over the \"lazy" dog\'s ear.
---
// Test turning smart quotes off.
#set text(lang: "en")
He's told some books contain questionable "example text".
#set text(smart-quotes: false)
@ -48,7 +45,6 @@ He's told some books contain questionable "example text".
---
// Test changing properties within text.
#set text(lang: "en")
"She suddenly started speaking french: #text(lang: "fr")['Je suis une banane.']" Roman told me.
Some people's thought on this would be #text(smart-quotes: false)["strange."]