3636 regexpMultipleDashes = regexp .MustCompile ("-+" )
3737)
3838
39+ // Slugger configures slug generation
40+ type Slugger struct {
41+ // CustomSub stores custom substitution map
42+ CustomSub map [string ]string
43+ // CustomRuneSub stores custom rune substitution map
44+ CustomRuneSub map [rune ]string
45+
46+ // MaxLength stores maximum slug length.
47+ // It's smart so it will cat slug after full word.
48+ // By default slugs aren't shortened.
49+ // If MaxLength is smaller than length of the first word, then returned
50+ // slug will contain only substring from the first word truncated
51+ // after MaxLength.
52+ MaxLength int
53+
54+ // Lowercase defines if the resulting slug is transformed to lowercase.
55+ // Default is true.
56+ Lowercase bool
57+ }
58+
3959//=============================================================================
4060
4161// Make returns slug generated from provided string. Will use "en" as language
@@ -47,12 +67,28 @@ func Make(s string) (slug string) {
4767// MakeLang returns slug generated from provided string and will use provided
4868// language for chars substitution.
4969func MakeLang (s string , lang string ) (slug string ) {
70+ return New ().MakeLang (s , lang )
71+ }
72+
73+ // New returns a Slugger initialized with the current global defaults
74+ func New () Slugger {
75+ return Slugger {
76+ CustomSub : CustomSub ,
77+ CustomRuneSub : CustomRuneSub ,
78+ MaxLength : MaxLength ,
79+ Lowercase : Lowercase ,
80+ }
81+ }
82+
83+ // MakeLang returns slug generated from provided string and will use provided
84+ // language for chars substitution.
85+ func (sl Slugger ) MakeLang (s string , lang string ) (slug string ) {
5086 slug = strings .TrimSpace (s )
5187
5288 // Custom substitutions
5389 // Always substitute runes first
54- slug = SubstituteRune (slug , CustomRuneSub )
55- slug = Substitute (slug , CustomSub )
90+ slug = SubstituteRune (slug , sl . CustomRuneSub )
91+ slug = Substitute (slug , sl . CustomSub )
5692
5793 // Process string with selected substitution language.
5894 // Catch ISO 3166-1, ISO 639-1:2002 and ISO 639-3:2007.
@@ -84,7 +120,7 @@ func MakeLang(s string, lang string) (slug string) {
84120 // Process all non ASCII symbols
85121 slug = unidecode .Unidecode (slug )
86122
87- if Lowercase {
123+ if sl . Lowercase {
88124 slug = strings .ToLower (slug )
89125 }
90126
@@ -93,8 +129,8 @@ func MakeLang(s string, lang string) (slug string) {
93129 slug = regexpMultipleDashes .ReplaceAllString (slug , "-" )
94130 slug = strings .Trim (slug , "-_" )
95131
96- if MaxLength > 0 {
97- slug = smartTruncate (slug )
132+ if sl . MaxLength > 0 {
133+ slug = smartTruncate (slug , sl . MaxLength )
98134 }
99135
100136 return slug
@@ -131,20 +167,20 @@ func SubstituteRune(s string, sub map[rune]string) string {
131167 return buf .String ()
132168}
133169
134- func smartTruncate (text string ) string {
135- if len (text ) < MaxLength {
170+ func smartTruncate (text string , maxLength int ) string {
171+ if len (text ) < maxLength {
136172 return text
137173 }
138174
139175 var truncated string
140176 words := strings .SplitAfter (text , "-" )
141- // If MaxLength is smaller than length of the first word return word
142- // truncated after MaxLength .
143- if len (words [0 ]) > MaxLength {
144- return words [0 ][:MaxLength ]
177+ // If maxLength is smaller than length of the first word return word
178+ // truncated after maxLength .
179+ if len (words [0 ]) > maxLength {
180+ return words [0 ][:maxLength ]
145181 }
146182 for _ , word := range words {
147- if len (truncated )+ len (word )- 1 <= MaxLength {
183+ if len (truncated )+ len (word )- 1 <= maxLength {
148184 truncated = truncated + word
149185 } else {
150186 break
@@ -159,8 +195,17 @@ func smartTruncate(text string) string {
159195// It should be in range of the MaxLength var if specified.
160196// All output from slug.Make(text) should pass this test.
161197func IsSlug (text string ) bool {
198+ return Slugger {MaxLength : MaxLength }.IsSlug (text )
199+ }
200+
201+ // IsSlug returns True if provided text does not contain white characters,
202+ // punctuation, all letters are lower case and only from ASCII range.
203+ // It could contain `-` and `_` but not at the beginning or end of the text.
204+ // It should be in range of the MaxLength var if specified.
205+ // All output from slug.Make(text) should pass this test.
206+ func (sl Slugger ) IsSlug (text string ) bool {
162207 if text == "" ||
163- (MaxLength > 0 && len (text ) > MaxLength ) ||
208+ (sl . MaxLength > 0 && len (text ) > sl . MaxLength ) ||
164209 text [0 ] == '-' || text [0 ] == '_' ||
165210 text [len (text )- 1 ] == '-' || text [len (text )- 1 ] == '_' {
166211 return false
0 commit comments