The app is FTStore Admin. Its own AGENTS.md already sets the vocabulary — "the FTStore Admin server" for web/, "the FTStore Admin app" for this one — and then most of the comments in it said "the console" anyway. Three user-visible strings went with it: the lock screen, the menu item that locks it, and the biometric prompt. The storage-notification footer named the console too. Their catalog keys move with them, in every locale the app ships. Not "the app": inside these files that already means FTStore on somebody's phone, so a blind swap produced lines like "Dashboard and app only, never the app". AdminConsoleView is AdminHomeView. The Console/ directory keeps its name: the history of Console/*.swift runs back through manager/FTStore/Admin/ and is documented as doing so, which is worth more than a path nobody reads as a name. Also fills a translation gap this turned up — the status-change footer in the feedback detail was untranslated.
45 lines
1.9 KiB
Swift
45 lines
1.9 KiB
Swift
//
|
|
// AdminLocalization.swift
|
|
// FTStore Admin
|
|
//
|
|
// FTStore Admin speaks English and German, and it never asks which: iOS picks
|
|
// from the device's language list, so the operator's phone decides. There is no
|
|
// language switch in Settings, deliberately — an FTStore Admin build that disagrees with the
|
|
// rest of the phone is a bug, not a feature.
|
|
//
|
|
// Most of FTStore Admin needs none of this. SwiftUI reads a *literal* passed to
|
|
// `Text`, `Button`, `Label`, `Section`, `.navigationTitle`, `.alert`,
|
|
// `TextField`, `Toggle` and friends as a `LocalizedStringKey`, so those look
|
|
// themselves up in `Localizable.xcstrings` with no call site change at all.
|
|
// What this file is for is the other half: a `String` that was built before it
|
|
// reached a view (a descriptor table, an interpolated sentence, an
|
|
// `errorDescription`), which SwiftUI renders verbatim.
|
|
//
|
|
// Inlined rather than imported. `admin/` links no Swift package, so the
|
|
// equivalent helper `ios/` gets from NimbleKit is copied here instead
|
|
// (`ios/NimbleKit/Sources/NimbleExtensions/String/String+localized.swift`).
|
|
//
|
|
|
|
import Foundation
|
|
|
|
extension String {
|
|
/// The English source string is the key, exactly as in `ios/`. A key with no
|
|
/// German entry falls back to the key itself, so an untranslated string
|
|
/// shows up as English rather than as a missing-value placeholder.
|
|
static func localized(_ key: String) -> String {
|
|
NSLocalizedString(key, comment: "")
|
|
}
|
|
|
|
/// For a sentence with values in it. The key carries `%@` / `%lld`
|
|
/// placeholders, which German is free to reorder with `%1$@`, `%2$@`.
|
|
static func localized(_ key: String, _ arguments: CVarArg...) -> String {
|
|
String(format: NSLocalizedString(key, comment: ""), arguments: arguments)
|
|
}
|
|
|
|
/// Localizes the receiver. Reads better where the key is already in hand:
|
|
/// `field.title.localized()`.
|
|
func localized() -> String {
|
|
String.localized(self)
|
|
}
|
|
}
|