Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.prism.byescaleira.com/llms.txt

Use this file to discover all available pages before exploring further.

PrismUI’s internationalization module builds on top of Apple’s standard localization infrastructure — xcstrings catalogs, LocalizedStringKey, and Foundation formatters — while adding higher-level helpers for RTL layouts, CLDR-compliant pluralization, and multi-locale previews. Everything in this module integrates naturally with SwiftUI’s \.locale and \.layoutDirection environment values.

Registering localized strings

PrismLocalizedKey pairs a localization key with a developer comment, which tooling uses to generate Xcode’s .xcstrings catalog. Register keys at the call site using .prismLocalized(_:comment:table:):
Text("welcome.title")
    .prismLocalized(
        "welcome.title",
        comment: "Title displayed on the welcome screen",
        table: "Onboarding"
    )
Under the hood, the modifier calls PrismStringExporter.shared.register(_:) on view appearance. You can query the exporter to audit which keys are in use:
// Export all keys registered by the Onboarding module
let keys = PrismStringExporter.shared.exportKeys(from: "welcome")
for key in keys {
    print("\(key.key)\(key.comment)")
}
PrismLocalizedKey exposes a .localizedStringKey property that returns a SwiftUI LocalizedStringKey, so you can use it directly in Text initializers:
let key = PrismLocalizedKey(
    key: "error.network.title",
    comment: "Title for network error alert"
)
Text(key.localizedStringKey)
Keep all keys registered in one place (for example, a static enum) so the exporter captures them reliably during UI tests or catalog-generation runs.

RTL layout support

Apply .prismLayoutDirection(_:) to a view to set an explicit or automatic layout direction:
// Always right-to-left
SomeView()
    .prismLayoutDirection(.rightToLeft)

// Always left-to-right
SomeView()
    .prismLayoutDirection(.leftToRight)

// Follow the current locale automatically
SomeView()
    .prismLayoutDirection(.auto)
PrismLayoutDirection has three cases:
CaseBehavior
.leftToRightForces \.layoutDirection to .leftToRight.
.rightToLeftForces \.layoutDirection to .rightToLeft.
.autoDerives direction from \.locale — RTL for Arabic, Hebrew, Farsi, Urdu, Pashto, Sindhi, Yiddish, and Kurdish.

Bidirectional stacks

Use PrismBidirectionalStack when you need an HStack that automatically mirrors child order in RTL layouts:
PrismBidirectionalStack(spacing: 8) {
    Image(systemName: "chevron.left")
    Text("Back")
}
In LTR locales the chevron appears to the left of the text; in RTL locales it appears to the right — no conditional logic required.

Resolving directional edges

PrismDirectionalEdge maps logical leading/trailing edges to physical screen edges for a given layout direction:
let edge = PrismDirectionalEdge.leading
let physical = edge.resolved(for: layoutDirection)
// Returns .leading in LTR, .trailing in RTL

Pluralization

PrismPluralRule implements CLDR plural categories for English, Arabic, Russian, and CJK/South-East Asian languages. Use it together with PrismPluralizedText to render pluralized strings declaratively:
PrismPluralizedText(
    count: itemCount,
    forms: [
        .one:   "1 item",
        .other: "\(itemCount) items",
    ]
)
For Arabic, which has six plural categories, you can specify all forms:
PrismPluralizedText(
    count: n,
    forms: [
        .zero:  "لا عناصر",
        .one:   "عنصر واحد",
        .two:   "عنصران",
        .few:   "\(n) عناصر",
        .many:  "\(n) عنصرًا",
        .other: "\(n) عنصر",
    ]
)
The PrismPluralCategory cases map directly to CLDR plural rule operands:
CaseTypical usage
.zeroArabic zero form.
.oneSingular — English 1 item.
.twoArabic dual form.
.fewRussian 2–4, Arabic 3–10.
.manyRussian 5–20, Arabic 11–99.
.otherGeneral/default — English n items.
You can also call PrismPluralRule.shared.category(for:locale:) directly to resolve the category programmatically:
let rule = PrismPluralRule.shared
let category = rule.category(for: 2, locale: Locale(identifier: "ar"))
// Returns .two
Japanese, Chinese, Korean, Vietnamese, and Thai always return .other because those languages do not distinguish plural forms.

Locale-aware formatters

PrismUI ships three locale-aware formatters that wrap Foundation’s format styles.

Numbers

PrismNumberFormatter formats Double values with four styles:
let formatter = PrismNumberFormatter.shared
let locale = Locale(identifier: "de_DE")

formatter.format(1_234.5,     style: .decimal,            locale: locale)
// "1.234,5"

formatter.format(1_234.5,     style: .currency(code: "EUR"), locale: locale)
// "1.234,50 €"

formatter.format(0.75,        style: .percent,            locale: locale)
// "75 %"

formatter.format(6.022e23,    style: .scientific,         locale: locale)
// "6,022E23"

Dates

PrismDateFormatter formats Date values with five styles:
let formatter = PrismDateFormatter.shared
let date = Date.now
let locale = Locale(identifier: "en_US")

formatter.format(date, style: .short,    locale: locale)   // "4/28/26"
formatter.format(date, style: .medium,   locale: locale)   // "Apr 28, 2026"
formatter.format(date, style: .long,     locale: locale)   // "April 28, 2026"
formatter.format(date, style: .full,     locale: locale)   // "Tuesday, April 28, 2026"
formatter.format(date, style: .relative, locale: locale)   // "yesterday"

Relative time

PrismRelativeTimeFormatter computes the difference between two dates and returns a human-readable string:
let formatter = PrismRelativeTimeFormatter.shared
let past = Date.now.addingTimeInterval(-7200)   // 2 hours ago

formatter.format(past, relativeTo: .now, locale: Locale(identifier: "en"))
// "2 hours ago"

formatter.format(past, relativeTo: .now, locale: Locale(identifier: "de"))
// "vor 2 Stunden"

Multi-locale preview

PrismMultiLocalePreview renders your view side by side in up to six locales, including correct RTL direction. Use it inside Xcode previews to catch layout issues before shipping.
#Preview {
    PrismMultiLocalePreview {
        MyCardView()
    }
}
The default locales are English, Arabic, Japanese, German, Spanish, and Simplified Chinese. Supply a custom list to override:
#Preview {
    PrismMultiLocalePreview(locales: [
        Locale(identifier: "en"),
        Locale(identifier: "ar"),
        Locale(identifier: "he"),
    ]) {
        MyCardView()
    }
}
The view modifier form lets you chain the preview directly on any view:
#Preview {
    MyCardView()
        .prismPreviewLocales([
            Locale(identifier: "fr"),
            Locale(identifier: "ja"),
        ])
}
Each locale panel is rendered with its correct \.locale and \.layoutDirection environment values, so Arabic and Hebrew panels automatically mirror the layout.
PrismMultiLocalePreview.defaultLocales is a static property you can read to build custom locale lists on top of the defaults without duplicating the list.