TinyString is a lightweight Go library that provides comprehensive string manipulation, type conversion, formatting, and multilingual error handling with a fluid API, specifically designed for small devices and web applications using TinyGo as the target compiler.
- 🚀 Fluid and chainable API - Easy to use and readable operations
- 📝 Complete string toolkit - Transformations, conversions, formatting, and error handling
- 🌍 Multilingual error messages - Built-in dictionary system with 9 languages
- 🧵 Concurrency safe - Thread-safe operations for concurrent environments
- 📦 Zero dependencies - No
fmt
,strings
,strconv
, orerrors
imports - 🎯 TinyGo optimized - Manual implementations for minimal binary size
- 🌐 WebAssembly-first - Designed for modern web deployment
- 🔄 Universal type support - Works with strings, numbers, booleans, and slices
- ⚡ Performance focused - Predictable allocations and custom optimizations
go get github.com/cdvelop/tinystring
import . "github.com/cdvelop/tinystring"
// Quick start - Basic conversion and transformation
text := Convert("Hóla Múndo").Tilde().ToLower().String() // out: "hola mundo"
// Working with different data types
numText := Convert(42).String() // out: "42"
boolText := Convert(true).String() // out: "true"
// Memory-efficient approach using string pointers
original := "Él Múrcielago Rápido"
Convert(&original).Tilde().CamelLow().Apply()
// original is now: "elMurcielagoRapido"
// Efficient, Unified builder and chaining example usage in loops and reuse, with accent normalization (Tilde)
items := []string{" ÁPPLE ", " banána ", " piñata "," ÑANDÚ "}
builder := Convert() // without params reused buffer = optimal performance
for i, item := range items {
processed := Convert(item).
TrimSpace(). // TrimSpace whitespace
Tilde(). // Normalize accents
ToLower(). // Convert to lowercase
Capitalize(). // Capitalize first letter
String() // Finalize the string
builder.Write(processed)
if i < len(items)-1 {
builder.Write(" - ")
}
}
out := builder.String() // Finalize the string hiding the error
out, err := builder.StringErr() // OR finalize with error handling
// out: "Apple - Banana - Piñata - Ñandu", err: nil
Replace common strings
package functions with TinyString equivalents:
Go Standard | TinyString Equivalent |
---|---|
strings.Builder |
c:= Convert() c.Write(a) c.Write(b) c.String() |
strings.Contains() |
Contains(s, substr) |
strings.Index() |
Index(s, substr) |
strings.LastIndex() |
LastIndex(s, substr) |
strings.Join() |
Convert(slice).Join(sep).String() |
strings.Repeat() |
Convert(s).Repeat(n).String() |
strings.Replace() |
Convert(s).Replace(old, new).String() |
strings.Split() |
Convert(s).Split(sep).String() |
strings.ToLower() |
Convert(s).ToLower().String() |
strings.ToUpper() |
Convert(s).ToUpper().String() |
strings.TrimSpace() |
Convert(s).TrimSpace().String() |
strings.TrimPrefix() |
Convert(s).TrimPrefix(prefix).String() |
strings.TrimSuffix() |
Convert(s).TrimSuffix(suffix).String() |
strings.HasPrefix() |
HasPrefix(s, prefix) |
strings.HasSuffix() |
HasSuffix(s, suffix) |
filepath.Base() |
PathBase(path) |
Convert("hello world").CamelLow().String() // out: "helloWorld"
Convert("hello world").CamelUp().String() // out: "HelloWorld"
Convert("hello world").SnakeLow().String() // out: "hello_world"
Convert("hello world").SnakeUp().String() // out: "HELLO_WORLD"
// Search and count
pos := Index("hello world", "world") // out: 6 (first occurrence)
found := Contains("hello world", "world") // out: true
count := Count("abracadabra", "abra") // out: 2
// Prefix / Suffix checks
isPref := HasPrefix("hello", "he") // out: true
isSuf := HasSuffix("file.txt", ".txt") // out: true
// Note: this library follows the standard library semantics for prefixes/suffixes:
// an empty prefix or suffix is considered a match (HasPrefix(s, "") == true,
// HasSuffix(s, "") == true).
// Find last occurrence (useful for file extensions)
pos := LastIndex("image.backup.jpg", ".") // out: 12
if pos >= 0 {
extension := "image.backup.jpg"[pos+1:] // out: "jpg"
}
// ⚠️ Note: Index, Contains and LastIndex are global functions, not methods.
// Do NOT use: Convert(s).Contains(substr) // ❌ Incorrect, will not compile
// Use: Index(s, substr) // ✅ Correct
// Contains(s, substr) // ✅ Correct
// LastIndex(s, substr) // ✅ Correct
// PathBase
PathBase("/a/b/c.txt") // -> "c.txt"
PathBase("folder/file.txt") // -> "file.txt"
PathBase("") // -> "."
PathBase("c:\file program\app.exe") // -> "app.exe"
// Replace operations
Convert("hello world").Replace("world", "Go").String() // out: "hello Go"
Convert("test 123 test").Replace(123, 456).String() // out: "test 456 test"
// Split strings (always use Convert(...).Split(...))
parts := Convert("apple,banana,cherry").Split(",")
// out: []string{"apple", "banana", "cherry"}
parts := Convert("hello world new").Split() // Handles whitespace
// out: []string{"hello", "world", "new"}
// Join slices
Convert([]string{"Hello", "World"}).Join().String() // out: "Hello World"
Convert([]string{"a", "b", "c"}).Join("-").String() // out: "a-b-c"
// TrimSpace operations
Convert(" hello ").TrimSpace().String() // out: "hello"
Convert("prefix-data").TrimPrefix("prefix-").String() // out: "data"
Convert("file.txt").TrimSuffix(".txt").String() // out: "file"
// Repeat strings
Convert("Go").Repeat(3).String() // out: "GoGoGo"
Replace strconv
package functions for type conversions:
Go Standard | TinyString Equivalent |
---|---|
strconv.Itoa() |
Convert(i).String() |
strconv.Atoi() |
Convert(s).Int() |
strconv.ParseFloat() |
Convert(s).Float64() |
strconv.ParseBool() |
Convert(s).Bool() |
strconv.FormatFloat() |
Convert(f).Round(n).String() |
strconv.Quote() |
Convert(s).Quote().String() |
// String to numbers => Int,Int32,Int64,Uint,Uint32,Uint64,Float32,Float64 eg:
result, err := Convert("123").Int() // out: 123, nil
result, err := Convert("456").Uint() // out: 456, nil
result, err := Convert("3.14").Float64() // out: 3.14, nil
// Numbers to string
Convert(42).String() // out: "42"
Convert(3.14159).String() // out: "3.14159"
// Boolean conversions
result, err := Convert("true").Bool() // out: true, nil
result, err := Convert(42).Bool() // out: true, nil (non-zero = true)
result, err := Convert(0).Bool() // out: false, nil
// String quoting
Convert("hello").Quote().String() // out: "\"hello\""
Convert("say \"hello\"").Quote().String() // out: "\"say \\\"hello\\\"\""
// Decimal rounding: keep N decimals, round or truncate
// By default, rounds using "round half to even" (bankers rounding)
// Pass true as the second argument to truncate (no rounding), e.g.:
Convert("3.14159").Round(2).String() // "3.14" (rounded)
Convert("3.155").Round(2).String() // "3.16" (rounded)
Convert("3.14159").Round(2, true).String() // "3.14" (truncated, NOT rounded)
Convert("3.159").Round(2, true).String() // "3.15" (truncated, NOT rounded)
// Formatting with thousands separator (EU default)
Convert(2189009.00).Thousands().String() // out: "2.189.009"
// Anglo/US style (comma, dot)
Convert(2189009.00).Thousands(true).String() // out: "2,189,009"
Replace fmt
package functions for formatting:
Go Standard | TinyString Equivalent |
---|---|
fmt.Sprintf() |
Fmt(format, args...) |
fmt.Sprint() |
Convert(v).String() |
fmt.Fprintf() |
Fprintf(w, format, args...) |
fmt.Sscanf() |
Sscanf(src, format, args...) |
// Printf-style formatting
result := Fmt("Hello %s, you have %d messages", "John", 5)
// out: "Hello John, you have 5 messages"
// Multiple format specifiers
result := Fmt("Number: %d, Float: %.2f, Bool: %v", 42, 3.14159, true)
// out: "Number: 42, Float: 3.14, Bool: true"
// Advanced formatting (hex, binary, octal)
result := Fmt("Hex: %x, Binary: %b, Octal: %o", 255, 10, 8)
// out: "Hex: ff, Binary: 1010, Octal: 10"
// Write formatted output to io.Writer
var buf bytes.Buffer
Fprintf(&buf, "Hello %s, count: %d\n", "world", 42)
// Write to file
file, _ := os.Create("output.txt")
Fprintf(file, "Data: %v\n", someData)
// Parse formatted text from string (like fmt.Sscanf)
var pos int
var name string
n, err := Sscanf("!3F question", "!%x %s", &pos, &name)
// n = 2, pos = 63, name = "question", err = nil
// Parse complex formats
var code, unicode int
var word string
n, err := Sscanf("!3F U+003F question", "!%x U+%x %s", &code, &unicode, &word)
// n = 3, code = 63, unicode = 63, word = "question", err = nil
Replace errors
package functions for error handling with multilingual support:
Go Standard | TinyString Equivalent |
---|---|
errors.New() |
Err(message) |
fmt.Errorf() |
Errf(format, args...) |
// Multiple error messages and types
err := Err("invalid format", "expected number", 404)
// out: "invalid format expected number 404"
// Formatted errors (like fmt.Errorf)
err := Errf("invalid value: %s at position %d", "abc", 5)
// out: "invalid value: abc at position 5"
TinyString enables multilingual error messages using reusable dictionary terms. It supports 9 languages and allows global or inline language selection.
// Set and get current language code
code := OutLang(ES) // returns "ES"
code = OutLang() // auto-detects and returns code (e.g. "EN")
err := Err(D.Format, D.Invalid)
// → "formato inválido"
// return strings
msg := Translate(FR, D.Format, D.Invalid).String()
// → "format invalide"
// Force French
err = Err(FR, D.Empty, D.String)
// → "vide chaîne"
See dictionary.go
for built-in words.
Combine D.
(default terms) and custom dictionaries for flexible messaging.
📘 Full documentation available in docs/TRANSLATE.md
TinyString provides automatic message type classification to help identify the nature of text content. The system detects common message types like errors, warnings, success messages, and information using zero-allocation buffer-based pattern matching.
// Before: messagetype library usage
message := Translate(msgs...).String()
msgType := messagetype.DetectMessageType(message)
// After: tinystring Single operation with StringType() (zero allocations)
message, msgType := Translate(msgs...).StringType()
// Real example - Progress callback with message classification
progressCallback := func(msgs ...any) {
message, msgType := Translate(msgs...).StringType()
if msgType.IsError() {
handleError(message)
} else {
logMessage(message, msgType)
}
}
// Message type constants available via Msg struct
if msgType.IsError() {
// Handle error case
}
// Available message types:
// Msg.Normal - Default type for general content
// Msg.Info - Information messages
// Msg.Error - Error messages and failures
// Msg.Warning - Warning and caution messages
// Msg.Success - Success and completion messages
// Zero allocations - reuses existing conversion buffers
// Perfect for logging, UI status messages, and error handling
// Basic truncation with ellipsis
Convert("Hello, World!").Truncate(10).String()
// out: "Hello, ..."
// Name truncation for UI display
Convert("Jeronimo Dominguez").TruncateName(3, 15).String()
// out: "Jer. Dominguez"
// Advanced name handling
Convert("Juan Carlos Rodriguez").TruncateName(3, 20).String()
// out: "Jua. Car. Rodriguez"
// Key-value parsing with the new API:
value, err := Convert("user:admin").KV() // out: "admin", nil
value, err := Convert("count=42").KV("=") // out: "42", nil
// Struct tag value extraction (TagValue):
value, found := Convert(`json:"name" Label:"Nombre"`).TagValue("Label") // out: "Nombre", true
value, found := Convert(`json:"name" Label:"Nombre"`).TagValue("xml") // out: "", false