mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
Allow passing region
to LocalName (#926)
This commit is contained in:
parent
1d42d6674c
commit
a6df909a8d
@ -285,7 +285,7 @@ impl<T: Into<Value>> From<Celled<T>> for Value {
|
||||
}
|
||||
|
||||
impl LocalName for TableElem {
|
||||
fn local_name(&self, lang: Lang) -> &'static str {
|
||||
fn local_name(&self, lang: Lang, _: Option<Region>) -> &'static str {
|
||||
match lang {
|
||||
Lang::ARABIC => "جدول",
|
||||
Lang::BOKMÅL => "Tabell",
|
||||
|
@ -277,7 +277,7 @@ impl Count for EquationElem {
|
||||
}
|
||||
|
||||
impl LocalName for EquationElem {
|
||||
fn local_name(&self, lang: Lang) -> &'static str {
|
||||
fn local_name(&self, lang: Lang, _: Option<Region>) -> &'static str {
|
||||
match lang {
|
||||
Lang::ARABIC => "معادلة",
|
||||
Lang::BOKMÅL => "Ligning",
|
||||
@ -305,10 +305,11 @@ impl Refable for EquationElem {
|
||||
vt: &mut Vt,
|
||||
supplement: Option<Content>,
|
||||
lang: Lang,
|
||||
region: Option<Region>,
|
||||
) -> SourceResult<Content> {
|
||||
// first we create the supplement of the heading
|
||||
let mut supplement =
|
||||
supplement.unwrap_or_else(|| TextElem::packed(self.local_name(lang)));
|
||||
supplement.unwrap_or_else(|| TextElem::packed(self.local_name(lang, region)));
|
||||
|
||||
// we append a space if the supplement is not empty
|
||||
if !supplement.is_empty() {
|
||||
|
@ -152,10 +152,14 @@ impl Show for BibliographyElem {
|
||||
|
||||
let mut seq = vec![];
|
||||
if let Some(title) = self.title(styles) {
|
||||
let title = title.unwrap_or_else(|| {
|
||||
TextElem::packed(self.local_name(TextElem::lang_in(styles)))
|
||||
let title =
|
||||
title.unwrap_or_else(|| {
|
||||
TextElem::packed(self.local_name(
|
||||
TextElem::lang_in(styles),
|
||||
TextElem::region_in(styles),
|
||||
))
|
||||
.spanned(self.span())
|
||||
});
|
||||
});
|
||||
|
||||
seq.push(HeadingElem::new(title).with_level(NonZeroUsize::ONE).pack());
|
||||
}
|
||||
@ -206,7 +210,7 @@ impl Finalize for BibliographyElem {
|
||||
}
|
||||
|
||||
impl LocalName for BibliographyElem {
|
||||
fn local_name(&self, lang: Lang) -> &'static str {
|
||||
fn local_name(&self, lang: Lang, _: Option<Region>) -> &'static str {
|
||||
match lang {
|
||||
Lang::ARABIC => "المراجع",
|
||||
Lang::BOKMÅL => "Bibliografi",
|
||||
|
@ -193,7 +193,10 @@ impl Synthesize for FigureElem {
|
||||
Smart::Auto => match &kind {
|
||||
FigureKind::Elem(func) => {
|
||||
let elem = Content::new(*func).with::<dyn LocalName>().map(|c| {
|
||||
TextElem::packed(c.local_name(TextElem::lang_in(styles)))
|
||||
TextElem::packed(c.local_name(
|
||||
TextElem::lang_in(styles),
|
||||
TextElem::region_in(styles),
|
||||
))
|
||||
});
|
||||
|
||||
if numbering.is_some() {
|
||||
@ -273,6 +276,7 @@ impl Refable for FigureElem {
|
||||
vt: &mut Vt,
|
||||
supplement: Option<Content>,
|
||||
_: Lang,
|
||||
_: Option<Region>,
|
||||
) -> SourceResult<Content> {
|
||||
// If the figure is not numbered, we cannot reference it.
|
||||
// Otherwise we build the supplement and numbering scheme.
|
||||
@ -283,7 +287,12 @@ impl Refable for FigureElem {
|
||||
Ok(desc)
|
||||
}
|
||||
|
||||
fn outline(&self, vt: &mut Vt, _: Lang) -> SourceResult<Option<Content>> {
|
||||
fn outline(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
_: Lang,
|
||||
_: Option<Region>,
|
||||
) -> SourceResult<Option<Content>> {
|
||||
// If the figure is not outlined, it is not referenced.
|
||||
if !self.outlined(StyleChain::default()) {
|
||||
return Ok(None);
|
||||
|
@ -164,13 +164,14 @@ impl Refable for HeadingElem {
|
||||
vt: &mut Vt,
|
||||
supplement: Option<Content>,
|
||||
lang: Lang,
|
||||
region: Option<Region>,
|
||||
) -> SourceResult<Content> {
|
||||
// Create the supplement of the heading.
|
||||
let mut supplement = if let Some(supplement) = supplement {
|
||||
supplement
|
||||
} else {
|
||||
match self.supplement(StyleChain::default()) {
|
||||
Smart::Auto => TextElem::packed(self.local_name(lang)),
|
||||
Smart::Auto => TextElem::packed(self.local_name(lang, region)),
|
||||
Smart::Custom(None) => Content::empty(),
|
||||
Smart::Custom(Some(supplement)) => {
|
||||
supplement.resolve(vt, std::iter::once(Value::from(self.clone())))?
|
||||
@ -208,7 +209,12 @@ impl Refable for HeadingElem {
|
||||
Counter::of(Self::func())
|
||||
}
|
||||
|
||||
fn outline(&self, vt: &mut Vt, _: Lang) -> SourceResult<Option<Content>> {
|
||||
fn outline(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
_: Lang,
|
||||
_: Option<Region>,
|
||||
) -> SourceResult<Option<Content>> {
|
||||
// Check whether the heading is outlined.
|
||||
if !self.outlined(StyleChain::default()) {
|
||||
return Ok(None);
|
||||
@ -228,7 +234,7 @@ impl Refable for HeadingElem {
|
||||
}
|
||||
|
||||
impl LocalName for HeadingElem {
|
||||
fn local_name(&self, lang: Lang) -> &'static str {
|
||||
fn local_name(&self, lang: Lang, _: Option<Region>) -> &'static str {
|
||||
match lang {
|
||||
Lang::ARABIC => "الفصل",
|
||||
Lang::BOKMÅL => "Kapittel",
|
||||
|
@ -27,9 +27,10 @@ pub use self::reference::*;
|
||||
pub use self::state::*;
|
||||
|
||||
use typst::doc::Lang;
|
||||
use typst::doc::Region;
|
||||
|
||||
/// The named with which an element is referenced.
|
||||
pub trait LocalName {
|
||||
/// Get the name in the given language.
|
||||
fn local_name(&self, lang: Lang) -> &'static str;
|
||||
/// Get the name in the given language and (optionally) region.
|
||||
fn local_name(&self, lang: Lang, region: Option<Region>) -> &'static str;
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use typst::util::option_eq;
|
||||
|
||||
use super::{
|
||||
Counter, CounterKey, HeadingElem, LocalName, Numbering, NumberingPattern, Refable,
|
||||
};
|
||||
@ -141,10 +143,14 @@ impl Show for OutlineElem {
|
||||
let mut seq = vec![ParbreakElem::new().pack()];
|
||||
// Build the outline title.
|
||||
if let Some(title) = self.title(styles) {
|
||||
let title = title.unwrap_or_else(|| {
|
||||
TextElem::packed(self.local_name(TextElem::lang_in(styles)))
|
||||
let title =
|
||||
title.unwrap_or_else(|| {
|
||||
TextElem::packed(self.local_name(
|
||||
TextElem::lang_in(styles),
|
||||
TextElem::region_in(styles),
|
||||
))
|
||||
.spanned(self.span())
|
||||
});
|
||||
});
|
||||
|
||||
seq.push(HeadingElem::new(title).with_level(NonZeroUsize::ONE).pack());
|
||||
}
|
||||
@ -152,6 +158,7 @@ impl Show for OutlineElem {
|
||||
let indent = self.indent(styles);
|
||||
let depth = self.depth(styles).map_or(usize::MAX, NonZeroUsize::get);
|
||||
let lang = TextElem::lang_in(styles);
|
||||
let region = TextElem::region_in(styles);
|
||||
|
||||
let mut ancestors: Vec<&Content> = vec![];
|
||||
let elems = vt.introspector.query(&self.target(styles));
|
||||
@ -165,7 +172,7 @@ impl Show for OutlineElem {
|
||||
continue;
|
||||
}
|
||||
|
||||
let Some(outline) = refable.outline(vt, lang)? else {
|
||||
let Some(outline) = refable.outline(vt, lang, region)? else {
|
||||
continue;
|
||||
};
|
||||
|
||||
@ -255,10 +262,11 @@ impl Finalize for OutlineElem {
|
||||
}
|
||||
|
||||
impl LocalName for OutlineElem {
|
||||
fn local_name(&self, lang: Lang) -> &'static str {
|
||||
fn local_name(&self, lang: Lang, region: Option<Region>) -> &'static str {
|
||||
match lang {
|
||||
Lang::ARABIC => "المحتويات",
|
||||
Lang::BOKMÅL => "Innhold",
|
||||
Lang::CHINESE if option_eq(region, "TW") => "目錄",
|
||||
Lang::CHINESE => "目录",
|
||||
Lang::CZECH => "Obsah",
|
||||
Lang::FRENCH => "Table des matières",
|
||||
|
@ -184,10 +184,11 @@ impl Show for RefElem {
|
||||
};
|
||||
|
||||
let lang = TextElem::lang_in(styles);
|
||||
let region = TextElem::region_in(styles);
|
||||
let reference = elem
|
||||
.with::<dyn Refable>()
|
||||
.expect("element should be refable")
|
||||
.reference(vt, supplement, lang)?;
|
||||
.reference(vt, supplement, lang, region)?;
|
||||
|
||||
Ok(reference.linked(Destination::Location(elem.location().unwrap())))
|
||||
}
|
||||
@ -259,21 +260,27 @@ pub trait Refable {
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `vt` - The virtual typesetter.
|
||||
/// - `styles` - The styles of the reference.
|
||||
/// - `location` - The location where the reference is being created.
|
||||
/// - `supplement` - The supplement of the reference.
|
||||
/// - `lang`: The language of the reference.
|
||||
/// - `region`: The region of the reference.
|
||||
fn reference(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
supplement: Option<Content>,
|
||||
lang: Lang,
|
||||
region: Option<Region>,
|
||||
) -> SourceResult<Content>;
|
||||
|
||||
/// Tries to build an outline element for this element.
|
||||
/// If this returns `None`, the outline will not include this element.
|
||||
/// By default this just calls [`Refable::reference`].
|
||||
fn outline(&self, vt: &mut Vt, lang: Lang) -> SourceResult<Option<Content>> {
|
||||
self.reference(vt, None, lang).map(Some)
|
||||
fn outline(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
lang: Lang,
|
||||
region: Option<Region>,
|
||||
) -> SourceResult<Option<Content>> {
|
||||
self.reference(vt, None, lang, region).map(Some)
|
||||
}
|
||||
|
||||
/// Returns the level of this element.
|
||||
|
@ -201,7 +201,7 @@ impl Finalize for RawElem {
|
||||
}
|
||||
|
||||
impl LocalName for RawElem {
|
||||
fn local_name(&self, lang: Lang) -> &'static str {
|
||||
fn local_name(&self, lang: Lang, _: Option<Region>) -> &'static str {
|
||||
match lang {
|
||||
Lang::ARABIC => "قائمة",
|
||||
Lang::BOKMÅL => "Utskrift",
|
||||
|
@ -122,7 +122,7 @@ impl Layout for ImageElem {
|
||||
}
|
||||
|
||||
impl LocalName for ImageElem {
|
||||
fn local_name(&self, lang: Lang) -> &'static str {
|
||||
fn local_name(&self, lang: Lang, _: Option<Region>) -> &'static str {
|
||||
match lang {
|
||||
Lang::ARABIC => "شكل",
|
||||
Lang::BOKMÅL => "Figur",
|
||||
|
26
src/doc.rs
26
src/doc.rs
@ -591,6 +591,12 @@ impl Region {
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&str> for Region {
|
||||
fn eq(&self, other: &&str) -> bool {
|
||||
self.as_str() == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Region {
|
||||
type Err = &'static str;
|
||||
|
||||
@ -688,3 +694,23 @@ cast_to_value! {
|
||||
"y" => Value::Length(v.point.y.into()),
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{doc::Region, util::option_eq};
|
||||
|
||||
#[test]
|
||||
fn test_partialeq_str() {
|
||||
let region = Region([b'U', b'S']);
|
||||
assert_eq!(region, "US");
|
||||
assert_ne!(region, "AB");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_region_option_eq() {
|
||||
let region = Some(Region([b'U', b'S']));
|
||||
|
||||
assert!(option_eq(region, "US"));
|
||||
assert!(!option_eq(region, "AB"));
|
||||
}
|
||||
}
|
||||
|
@ -226,3 +226,13 @@ pub fn pretty_array_like(parts: &[impl AsRef<str>], trailing_comma: bool) -> Str
|
||||
buf.push(')');
|
||||
buf
|
||||
}
|
||||
|
||||
/// Check if the [`Option`]-wrapped L is same to R.
|
||||
///
|
||||
/// This is the stable version of [`Option::contains`].
|
||||
pub fn option_eq<L, R>(left: Option<L>, other: R) -> bool
|
||||
where
|
||||
L: PartialEq<R>,
|
||||
{
|
||||
left.map(|v| v == other).unwrap_or(false)
|
||||
}
|
||||
|
BIN
tests/ref/text/lang-with-region.png
Normal file
BIN
tests/ref/text/lang-with-region.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
16
tests/typ/text/lang-with-region.typ
Normal file
16
tests/typ/text/lang-with-region.typ
Normal file
@ -0,0 +1,16 @@
|
||||
// Test if text with region works
|
||||
|
||||
---
|
||||
// without any region
|
||||
#set text(lang: "zh")
|
||||
#outline()
|
||||
|
||||
---
|
||||
// with unknown region configured
|
||||
#set text(lang: "zh", region: "XX")
|
||||
#outline()
|
||||
|
||||
---
|
||||
// with region configured
|
||||
#set text(lang: "zh", region: "TW")
|
||||
#outline()
|
Loading…
x
Reference in New Issue
Block a user