Documentation
¶
Overview ¶
Package slug generates URL-friendly slugs from Unicode strings in any language.
A slug is built in three steps: the input is transliterated to ASCII, split into words on every character that is not a letter or a digit, and the words are joined with a separator ("-" by default). Leading, trailing and repeated separators are removed, so the result contains only letters, digits and single separators.
Package-level helpers ¶
The package functions use a default configuration (neutral transliteration, "-" separator, original letter case preserved):
slug.Make("Hello World") // "Hello-World"
slug.Lower("Hello World") // "hello-world"
slug.Upper("Hello World") // "HELLO-WORLD"
Configurable slugs ¶
New builds a Slug from functional options for full control:
s := slug.New(
slug.WithLang(lang.UK), // regional transliteration
slug.WithSeparator("_"), // custom separator
slug.WithMaxLength(60), // cut on a word boundary
slug.WithFallback("post"),// value for an empty result
)
s.Make("Привіт, світ!") // "Pryvit_svit"
A few characters carry meaning and become words: "@" -> "at", "&" -> "and", "#" -> "sharp", "%" -> "pct" (e.g. "r&d" -> "r-and-d"). A true apostrophe between letters is dropped so the letters join ("it's" -> "its").
Concurrency ¶
A Slug is immutable after New, so a single value may be shared and used by multiple goroutines concurrently; the package-level helpers are safe for concurrent use as well.
Index ¶
- Constants
- func IsValid(t string) bool
- func Lower(t string) string
- func Make(t string) string
- func MakeUnique(t string, exists func(string) bool) string
- func TryMakeUnique(t string, exists func(string) bool, maxTries int) (string, bool)
- func Upper(t string) string
- type Option
- type Slug
- func (s *Slug) IsValid(t string) bool
- func (s *Slug) Lower(t string) string
- func (s *Slug) Make(t string) string
- func (s *Slug) MakeUnique(t string, exists func(string) bool) string
- func (s *Slug) TryMakeUnique(t string, exists func(string) bool, maxTries int) (string, bool)
- func (s *Slug) Upper(t string) string
Examples ¶
Constants ¶
const DefaultSeparator = "-"
DefaultSeparator is the word separator used when no other is configured.
Variables ¶
This section is empty.
Functions ¶
func IsValid ¶
IsValid reports whether t is already a canonical slug under the default configuration (see (*Slug).IsValid).
func Lower ¶
Lower is Make with the result lowercased.
Example ¶
package main
import (
"fmt"
"github.com/goloop/slug/v2"
)
func main() {
fmt.Println(slug.Lower("Hello World"))
}
Output: hello-world
func Make ¶
Make returns the slug of t using the default configuration (neutral transliteration, "-" separator, original letter case preserved). It is shorthand for New().Make(t).
Example ¶
package main
import (
"fmt"
"github.com/goloop/slug/v2"
)
func main() {
fmt.Println(slug.Make("Hello World"))
}
Output: Hello-World
Example (Hyphen) ¶
A hyphen in the input is preserved as a separator, not dropped.
package main
import (
"fmt"
"github.com/goloop/slug/v2"
)
func main() {
fmt.Println(slug.Make("co-operate with e-mail"))
}
Output: co-operate-with-e-mail
Example (Symbols) ¶
Meaningful symbols become words and punctuation becomes a separator.
package main
import (
"fmt"
"github.com/goloop/slug/v2"
)
func main() {
fmt.Println(slug.Make("AT&T: 100% ready"))
}
Output: AT-and-T-100-pct-ready
func MakeUnique ¶
MakeUnique returns a slug of t made unique via exists (see (*Slug).MakeUnique), using the default configuration.
func TryMakeUnique ¶ added in v2.1.0
TryMakeUnique returns a unique slug of t and reports success (see (*Slug).TryMakeUnique), using the default configuration.
Types ¶
type Option ¶
type Option func(*config)
An Option configures a Slug in New.
func WithFallback ¶
WithFallback sets the value returned when the input produces an empty slug (e.g. Make("!!!")). Without it such input yields an empty string.
The fallback is itself normalized through the slug pipeline at construction time, so it always obeys the canonical-slug and MaxLength invariants. A fallback that normalizes to nothing (for example "!!!") is treated as no fallback.
Example ¶
package main
import (
"fmt"
"github.com/goloop/slug/v2"
)
func main() {
s := slug.New(slug.WithFallback("post"))
fmt.Println(s.Make("!!!"))
}
Output: post
func WithLang ¶
WithLang sets the transliteration language code. Use the constants of the lang subpackage, e.g. WithLang(lang.UK). An unknown code falls back to language-neutral transliteration (lang.None).
func WithMaxLength ¶
WithMaxLength limits the slug to at most n bytes, cutting on a word boundary so a word is never split. Values <= 0 are ignored (unlimited).
Example ¶
package main
import (
"fmt"
"github.com/goloop/slug/v2"
)
func main() {
s := slug.New(slug.WithMaxLength(11))
fmt.Println(s.Make("hello world foo bar"))
}
Output: hello-world
func WithSeparator ¶
WithSeparator sets the word separator (default "-"). An empty separator concatenates the words without any delimiter.
The separator is not validated. For predictable, URL-safe slugs it should contain only URL-safe, non-alphanumeric characters (for example "-" or "_"). A separator that contains letters or digits merges into the slug body and breaks IsValid; unsafe characters (spaces, ".", "/", "%", ...) produce slugs that are not URL-safe.
Example ¶
package main
import (
"fmt"
"github.com/goloop/slug/v2"
)
func main() {
s := slug.New(slug.WithSeparator("_"))
fmt.Println(s.Make("Hello World"))
}
Output: Hello_World
type Slug ¶
type Slug struct {
// contains filtered or unexported fields
}
Slug generates URL-friendly slugs according to its configuration.
A Slug is created with New and is immutable afterwards: all settings are resolved from the options at construction time. Because nothing is mutated during Make/Lower/Upper/IsValid/MakeUnique, a single *Slug is safe for concurrent use by multiple goroutines.
func New ¶
New returns a Slug configured by the given options. With no options it uses language-neutral transliteration, "-" as the separator, no length limit and an empty fallback.
s := slug.New(
slug.WithLang(lang.UK),
slug.WithMaxLength(60),
slug.WithFallback("post"),
)
s.Make("Привіт, світ!") // "Pryvit-svit"
Example ¶
package main
import (
"fmt"
"github.com/goloop/slug/v2"
"github.com/goloop/slug/v2/lang"
)
func main() {
s := slug.New(slug.WithLang(lang.UK))
fmt.Println(s.Make("Привіт, світ!"))
}
Output: Pryvit-svit
func (*Slug) IsValid ¶
IsValid reports whether t is already a canonical slug for this configuration: non-empty and left unchanged by Make. This means it contains only letters, digits and single separators, without leading or trailing separators, and (if a limit is set) is within MaxLength.
IsValid checks that t is itself canonical, not that t would produce a valid slug. In particular, with WithFallback an input that maps to the fallback is not canonical: IsValid("!!!") is false even though Make("!!!") returns the (valid) fallback.
func (*Slug) Make ¶
Make returns the slug of t. The letter case of the input is preserved; use Lower or Upper to force a case.
The input is transliterated to ASCII and then split into words on any character that is not a letter or a digit; the words are joined with the configured separator. Leading, trailing and repeated separators are removed. If the result is empty the configured fallback is returned (empty by default).
func (*Slug) MakeUnique ¶
MakeUnique returns a slug of t that is unique according to exists: if the base slug is already taken it appends the separator and an incrementing number ("-2", "-3", ...) until exists reports the candidate as free. When MaxLength is set the base is shortened on a word boundary to keep every candidate within the limit. A nil exists function disables the check.
MakeUnique is best-effort: it gives up after a bounded number of attempts (so a predicate that always reports "taken" cannot hang) and returns the base slug, which may then collide. Use TryMakeUnique when you need to detect that no unique slug could be produced.
Example ¶
package main
import (
"fmt"
"github.com/goloop/slug/v2"
)
func main() {
taken := map[string]bool{"hello-world": true, "hello-world-2": true}
s := slug.New()
fmt.Println(s.MakeUnique("hello world", func(x string) bool {
return taken[x]
}))
}
Output: hello-world-3
func (*Slug) TryMakeUnique ¶ added in v2.1.0
TryMakeUnique returns a unique slug of t and reports whether it succeeded. It tests the base slug, then base+separator+2, base+separator+3, ... with exists (which must report whether a slug is already taken), trying at most maxTries candidates. Every candidate satisfies MaxLength; if the limit is so small that no numbered candidate fits, the search stops early. A non-positive maxTries uses a default bound; a nil exists succeeds with the base slug.
It returns (slug, true) on the first free candidate, or ("", false) if none is free within the attempts or no length-valid candidate can be formed.
Example ¶
package main
import (
"fmt"
"github.com/goloop/slug/v2"
)
func main() {
taken := map[string]bool{"post": true, "post-2": true}
s := slug.New()
if got, ok := s.TryMakeUnique("post", func(x string) bool { return taken[x] }, 100); ok {
fmt.Println(got)
}
}
Output: post-3