Str holds the string helpers worth carrying over from Laravel: slugs,
masks, limits, excerpts, plural and singular forms, and Markdown.
Str::of wraps a value in a Stringable that chains them. For case
conversions, use the heck crate; for everything else, std::str and
regex. Every count here is in characters, never bytes, so a multibyte
value is never cut inside a character.
use Str;
let slug = slug; // oeuvre-dart-at-home
let card = mask; // ***************1234
let teaser = limit; // The quick brown...
let label = plural; // comments
Slugs
Str::slug(title, separator) spells the title in ASCII, lower-cases it,
writes @ as at, and joins each run of other characters between
letters and digits with the separator:
use Str;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
The ASCII spelling is Laravel's own: the replacement map of
voku/portable-ascii, the package Laravel's Str::ascii uses, so a title
gets the slug it gets in Laravel. That map spells Latin, Greek, Cyrillic,
Arabic, and many other scripts, and drops what it can't spell, such as
Han characters and emoji: Str::slug("北京 city", "-") is city.
You choose the language's spelling with
Str::slug_in(title, separator, language). With German, you get ae for
ä; with Esperanto, you get cx for ĉ. You pass an empty language to
keep Unicode letters instead of transliterating them.
Masks
Str::mask(value, character, index, length) replaces the characters from
index with character: length of them, or all to the end with None.
A negative index counts from the end, and a negative length stops that
many short of the end:
use Str;
assert_eq!;
assert_eq!;
Limits and excerpts
Str::limit(value, limit, end) keeps the first limit characters and
adds end when it cut. Str::limit_words cuts at the last space within
the limit instead, so no word is broken:
use Str;
assert_eq!;
assert_eq!;
You keep the first words space-separated runs with
Str::words(value, words, end) and add end when you cut. You count
markup as part of a word and keep whitespace between words. You pass a
zero word limit to leave the value as it is:
use Str;
assert_eq!;
assert_eq!;
Str::excerpt(text, phrase, radius, omission) frames the first match of
a phrase, ignoring case, with up to radius characters on each side,
in text of any number of lines. It returns None when the phrase is not
there. You trim Laravel's invisible characters, including zero-width
spaces, from the ends you cut:
use Str;
assert_eq!;
Plural and singular
Str::plural(word, count) and Str::singular(word) inflect by the rules
of the current locale's language, the ones Laravel's Pluralizer uses
from doctrine/inflector 2.1.0, the release Laravel 13 installs: English,
Esperanto, French, Italian, Norwegian Bokmål, Portuguese, Spanish, and
Turkish. Any other language uses the English rules. A count of 1 or -1
leaves the word as it is, and the result keeps the word's case:
use Str;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
In a request whose locale is fr, Str::plural("cheval", 2) is
chevaux; in es, Str::plural("ciudad", 2) is ciudades. Without the
localization feature, the rules are English.
You inflect the last word of the value with Str::plural_studly or
Str::plural_pascal. You put the count before the inflected word with
Str::plural_with_count(word, count), using the current locale's integer
format. You keep all digits even for the largest and smallest i64
values. Without localization, you get plain decimal digits.
You vary a page that RenderCache stores by its locale
when you call these inflection helpers: add
.vary(VarianceDimension::Locale) to the route's policy. Without it,
RenderCache declines to store the page.
To choose the form a reader sees in a translated message, use the plural
categories of a Fluent message instead; see
Localization. Str::plural is for words in your own
code, such as a table or a label built from a model's name.
Markdown
Str::markdown(value, &renderer) renders a whole Markdown document to
HTML, and Str::inline_markdown(value, &renderer) renders the inline
syntax only: emphasis, code, links and line breaks, with no paragraph
around it and block markers such as #, > or - kept as text. You
pass the MarkdownRenderer (from suprnova::content) that decides what
raw HTML and links may do:
use Str;
use MarkdownRenderer;
let renderer = default;
let title = inline_markdown?;
assert_eq!;
assert_eq!;
let page = markdown?;
assert!;
# Ok::
The default renderer drops raw HTML and sanitizes its output, so
<script> never reaches the page. You choose otherwise with the
renderer's builder calls, which hold Laravel's CommonMark options:
use Str;
use ;
let renderer = default
.html_input
.allow_unsafe_links
.autolink;
let html = inline_markdown?;
assert_eq!;
# Ok::
html_input(HtmlInput::Sanitize)keeps raw HTML and passes the output through the sanitizer, which keeps safe tags such as<b>and removes scripts, event handlers and unsafe URLs.HtmlInput::Stripremoves raw HTML tags and keeps the text between them.HtmlInput::Escapeshows raw HTML as text.HtmlInput::Allowpasses it through: use it only for Markdown you trust.allow_unsafe_links(true)lets a Markdown link point at ajavascript:,vbscript:,file:ordata:URL. The sanitizer still removes such URLs, so it takes effect withStrip,EscapeorAllow.autolink(true)turns bare URLs and email addresses into links.
A renderer that calls none of them renders as it always has: sanitized,
unless MarkdownOptions::unsafe_html is on.
Fluent strings
Str::of(value) returns a Stringable, whose methods are the Str
helpers, so you chain them as Laravel's Str::of($value)->... chains:
use Str;
let slug = of.limit.slug;
assert_eq!;
let label: String = of.plural.into;
assert_eq!;
A Stringable converts from and into String, compares with &str, and
displays as its value. Next to the Str helpers it has markdown,
inline_markdown, and encryption through Crypt:
encrypt(purpose), encrypt_for(purpose, context), decrypt(purpose)
and decrypt_for(purpose, context). Every encryption names a
CryptPurpose, and a value sealed for one purpose does not open under
another:
use ;
let sealed = of.encrypt?;
let opened = sealed.clone.decrypt?;
assert_eq!;
assert!;
# Ok::
CryptPurpose::Cookie is refused by encrypt and decrypt: a cookie
value is bound to its cookie's name, so you encrypt it with
encrypt_for(CryptPurpose::Cookie, name).
Why Suprnova diverges
- The language follows the locale. Laravel sets the plural language
for the whole process with
Pluralizer::useLanguage; here the current request's locale chooses it, forStr::singularas forStr::plural. - An excerpt can span lines. Laravel's pattern stops at a line break,
so
Str::excerptreturnsnullfor text with a line break inside it; here it finds the phrase on any line. - Counts are characters. Laravel's
limitcounts display width, two for a wide East Asian character, and its word-preserving form also strips HTML tags. - A subset.
Stringablechains the helpersStrkeeps, not every method of Laravel'sStringable; case conversions come fromheck. - Markdown is sanitized by default. Laravel's
Str::markdownlets raw HTML through unless you passhtml_input; here the default renderer drops it and sanitizes the output, and you opt into raw HTML withHtmlInput::Allow. The inline form keeps each line break of the text. - Every encryption names a purpose. Laravel's
Stringable::encrypttakes none; hereencrypttakes aCryptPurpose, so a value encrypted for one use cannot be decrypted as another.
Next
- Localization - percentages, abbreviated numbers, and the rest of the locale-aware formatting
- Dates - reading a date or a time from text
- Validation - rules for the strings your users send
