Skip to content

UI Localization and Settings Storage

Deepratna Awale edited this page Oct 10, 2026 · 6 revisions

UI, localization and settings storage

How the app shell is built: the Liquid Glass look, localization in 16 languages, and where settings are stored.

Liquid Glass

On macOS 26 the app uses Liquid Glass: a native split view, a unified toolbar with the tabs in its centre, inspector columns and glass controls. Earlier macOS versions keep the familiar look.

Guidelines, from the code (UI/Components/GlassCompat.swift):

  • Every glass-only API goes through GlassCompat, so views don't repeat availability checks: glassButtonStyle(.prominent / .standard) (glass on 26, bordered/borderedProminent before), borderlessOnGlassButtonStyle() (no glass on glass), glassBackground(in:fallback:), and GlassGroup to group nearby glass so it samples the backdrop once.
  • Chrome is glass, content is opaque. Wallpaper previews, grid tiles, thumbnails, the Metal/AV/Web views, JSON editors and texture previews never get glass.
  • Frosted backgrounds (FrostedBackground, an NSVisualEffectView behind the window) sit under the main window, Settings, Scene Edit / Export and About, so the live wallpaper shows through blurred. They follow the window's active state and Reduce Transparency.
  • Settings pages use grouped Forms with .scrollContentBackground(.hidden); sheets use .regularMaterial.
  • Icon-only buttons always have help text and accessibility labels.

The app icon is an Icon Composer bundle (Resources/AppIcon.icon) rendered with glass on macOS 26, with an asset-catalog fallback for macOS 14/15; the menu bar icon is a template image. Sources are in Design/logo (Klaus Zhu's original, redesigned by Deepratna Awale).

Localization

  • All UI text lives in OpenWallpaperEngine/Localizable.xcstrings (source language English), with translations for de, fr, es, pt-BR, it, ja, ko, zh-Hans, zh-Hant, ru, pl, tr, uk, ar, hi.
  • Pass literals to localizing APIs (Text, Button, Label, .help…). Where text travels as a value (AppKit, errors, view models) use String(localized:) or LocalizedStringResource. A String handed to Text shows in English in every language.
  • Counts use the catalog's plural variations; numbers, sizes, durations and lists use Foundation formatters.
  • Stored or sent values (tags, types, ratings) stay English; show them through LocalizedLabels.
  • WE's own labels come from WE's locale/ui_*.json in the assets (WallpaperEngineLabels), in the user's language over English.
  • A new string needs a translation in every language, using the terms in docs/localization-glossary.md. LocalizationCatalogTests and LocalizationLintTests fail otherwise.
  • The glossary's precedence: Apple's macOS wording, then Steam's, then Microsoft Terminology, then Wallpaper Engine's UI for wallpaper terms. It also fixes each language's style (formal/informal address, quotes, casing). Example: "Questionable" is WE's middle age rating, translated with each country's usual teen-content label; the stored value stays Questionable.
  • The language picker writes AppleLanguages in the app's defaults (GSLocalization.apply), which takes effect at the next launch.
  • The README is translated under resources/readme/.

Settings storage

What Where API
App-wide settings (GlobalSettings) JSON under the key GlobalSettings in the app's defaults GlobalSettingsViewModel (Core/Settings/GlobalSettingsService.swift)
Other defaults (sorting, filters, per-display wallpapers, playlists, properties) The app's defaults UserDefaults.app, @AppStorage(…, store: .app)
Files Application Support and Caches AppStorageLocation.current.supportDirectory / .cachesDirectory
Secrets Keychain Core/Keychain (KeychainStore, KeychainSecret)
  • Never use UserDefaults.standard or hard-coded paths. UserDefaults.app is AppStorageLocation.current.defaults, which is the isolated suite in tests and OWE_ISOLATED_STATE copies (see Building and running).
  • GlobalSettings decodes each field on its own with a default, so an old or partial saved value still loads; some keys keep legacy names (e.g. msaa, postProcessingQuality, reflection).
  • Typed keys only: don't add new "_owe_…" string keys; add a case to the typed settings or property identifiers.
  • Per-frame render settings apply without rebuilding the scene's content.

User guide: Settings overview and Languages

Clone this wiki locally