Telegram-iOS Localization and String Formatting: A Technical Guide to PresentationStrings

Telegram-iOS utilizes a custom PresentationStrings architecture to manage localization through strongly-typed Swift wrappers around standard .strings files, enabling parameterized formatting with range preservation for entity highlighting and dynamic support for remotely downloaded language packs.

The Telegram-iOS project, available at TelegramMessenger/Telegram-iOS, implements a sophisticated localization framework that extends beyond standard iOS bundle lookups. This system combines compile-time type safety via generated Swift code with runtime flexibility to support dynamic language switching and server-side localization updates.

Core Architecture: The PresentationStrings Wrapper

The foundation of Telegram-iOS localization resides in the PresentationStrings class defined in submodules/TelegramPresentationData/Sources/DefaultPresentationStrings.swift. This component serves as a type-safe container for key-value pairs loaded from .strings files compiled into the app bundle.

At initialization, the defaultPresentationStrings instance (see line 44) loads the Localizable.strings file for the default "en" locale from the main bundle. The architecture uses an internal _PresentationStringsComponent struct to encapsulate language-specific metadata including the ISO language code, localized language name, pluralization rules, and the raw string dictionary. This design provides O(1) dictionary lookups while maintaining strong typing through Swift-generated accessors that map directly to localization keys.

Parameterized Strings and Range-Aware Formatting

Beyond simple key-value lookup, Telegram-iOS handles complex string interpolation through the formatWithArgumentRanges(_:_:_:) function (lines 22-41 of DefaultPresentationStrings.swift). This method processes format strings containing placeholders like %@ or %1$d while preserving range metadata critical for styling message entities.

When formatting text containing clickable URLs or styled mentions, the system must track where substituted values appear in the final string. The function accepts a raw format string, an array of placeholder ranges with indices, and the concrete arguments to inject. It returns a tuple containing the formatted string and updated ranges reflecting the actual positions of inserted values, enabling the UI layer to apply attributes to specific character ranges.

// Raw string from Localizable.strings: "You have %1$d new messages"
let rawString = strings.You_have_new_messages

// Define placeholder ranges: index 0 maps to NSRange(location: 9, length: 3)
let ranges = [(0, NSRange(location: 9, length: 3))]
let arguments = ["5"]

// Format while preserving range data for entity styling
let (formattedString, updatedRanges) = formatWithArgumentRanges(
    rawString, 
    ranges, 
    arguments
)
// Result: "You have 5 new messages" with accurate range mapping for the digit

Date Localization and Entity Formatting

Temporal localization operates through submodules/TelegramStringFormatting/Sources/DateFormat.swift, which provides utilities like stringForEntityFormattedDate. These functions receive a PresentationStrings instance to ensure month names, weekday abbreviations, and relative time strings respect the current locale settings.

This centralized approach ensures consistency across chat bubbles, message headers, and notification previews. The implementation leverages standard Foundation APIs while mapping the results through Telegram's string system for custom formatting requirements.

Remote Language Packs via TelegramEngine.Localization

Supporting Telegram's extensive multi-language capabilities requires dynamic updates beyond static app bundles. The TelegramEngine.Localization class in submodules/TelegramCore/Sources/TelegramEngine/Localization/TelegramEngineLocalization.swift manages the download and application of remote localization packs.

The downloadAndApplyLocalization(accountManager:languageCode:) method (lines 32-34) retrieves language assets from Telegram's servers, updates the local postbox cache, and emits a new PresentationStrings instance to refresh the UI without requiring an app restart.

// Request Spanish language pack from server
engine.localization.downloadAndApplyLocalization(
    accountManager: accountManager,
    languageCode: "es"
).start()

Accessing Localized Language Names

For language selection interfaces, the codebase utilizes standard Foundation methods alongside the custom framework. The Locale.localizedString(forLanguageCode:) method maps ISO language codes to human-readable names in the user's current interface language, with fallback to the raw code when localization is unavailable.

let locale = Locale.current
let isoCode = "fr"
let displayName = locale.localizedString(forLanguageCode: isoCode) ?? isoCode
// Returns "French" in the current UI language

This pattern appears in UI components like TranslateScreen.swift (line 355), ensuring consistent language naming across the application's settings screens.

Summary

  • PresentationStrings in DefaultPresentationStrings.swift provides a type-safe, dictionary-backed wrapper around compiled .strings files with O(1) lookup performance.
  • The formatWithArgumentRanges function preserves insertion ranges during string interpolation, enabling entity-aware text styling for rich message content.
  • TelegramEngine.Localization supports dynamic language acquisition, allowing users to download and apply new translations without App Store updates.
  • DateFormat.swift centralizes temporal localization, ensuring consistent date and time presentation across all UI surfaces.
  • Standard Foundation APIs like Locale.localizedString(forLanguageCode:) complement the custom architecture for language metadata display.

Frequently Asked Questions

How does Telegram-iOS load localization files at app launch?

During initialization, the app creates a defaultPresentationStrings instance that loads the Localizable.strings file for the default "en" locale from the main bundle (line 44 of DefaultPresentationStrings.swift). When users switch languages, the system constructs a new PresentationStrings.Component populated from either bundled resources or downloaded localization packs, ensuring the UI receives updated text immediately through dependency injection.

What is the purpose of formatWithArgumentRanges in Telegram-iOS?

The formatWithArgumentRanges(_:_:_:) function merges format strings containing placeholders like %1$d with concrete arguments while tracking the resulting character ranges. This preserved metadata allows the UI layer to apply attributes—such as bold text or tappable links—to specific portions of the final string, which is essential for rendering formatted message entities in chat views.

How does Telegram-iOS handle date and time localization?

The framework routes all temporal formatting through DateFormat.swift, where functions like stringForEntityFormattedDate accept a PresentationStrings instance to retrieve localized month names and weekday abbreviations. This ensures dates displayed in message headers, notifications, and chat bubbles respect the user's selected language and regional preferences.

Can Telegram-iOS download new languages without an App Store update?

Yes. The TelegramEngine.Localization class implements downloadAndApplyLocalization(accountManager:languageCode:) to fetch language packs from Telegram's servers, store them in the local postbox, and regenerate the active PresentationStrings instance. This architecture enables users to access new translations or updated strings immediately, independent of iOS app binary releases.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →