diff --git a/Ilion/Ilion.swift b/Ilion/Ilion.swift index 630cdfd..37f6f75 100644 --- a/Ilion/Ilion.swift +++ b/Ilion/Ilion.swift @@ -109,6 +109,13 @@ extension Ilion: BrowserWindowControllerDelegate { toolsPanelController = ToolsPanelController() toolsPanelController?.shouldInsertStartEndMarkers = StringsManager.defaultManager.insertsStartEndMarkers toolsPanelController?.shouldTransformCharacters = StringsManager.defaultManager.transformsCharacters + if let factor = StringsManager.defaultManager.expansionFactor { + toolsPanelController?.shouldSimulateExpansion = true + toolsPanelController?.expansionFactor = factor + } + else { + toolsPanelController?.shouldSimulateExpansion = false + } toolsPanelController?.delegate = self browserWindowController?.window?.beginSheet(toolsPanelController!.window!) @@ -156,12 +163,15 @@ extension Ilion: ToolsPanelControllerDelegate { func toolsPanelControllerDidClose(_ sender: ToolsPanelController) { let markersFlag = toolsPanelController!.shouldInsertStartEndMarkers let transformFlag = toolsPanelController!.shouldTransformCharacters + let expansionFlag = toolsPanelController!.shouldSimulateExpansion + let factor = toolsPanelController!.expansionFactor browserWindowController?.window?.endSheet(sender.window!) toolsPanelController = nil StringsManager.defaultManager.insertsStartEndMarkers = markersFlag StringsManager.defaultManager.transformsCharacters = transformFlag + StringsManager.defaultManager.expansionFactor = expansionFlag ? factor : nil } } diff --git a/Ilion/StringsManager.swift b/Ilion/StringsManager.swift index a4a818e..f3c0a0a 100644 --- a/Ilion/StringsManager.swift +++ b/Ilion/StringsManager.swift @@ -34,7 +34,8 @@ typealias StringsDB = [BundleURI: [ResourceURI: [LocKey: StringsEntry]]] private let storedOverridesKey = "Ilion.TranslationOverrides" private let markersKey = "Ilion.InsertsStartEndMarkers" private let transformKey = "Ilion.TransformsCharacters" - + private let expansionFactorKey = "Ilion.SimulatedExpansionFactor" + private let userDefaults: UserDefaults private let stringsFileParser: StringsFileParser @@ -54,6 +55,17 @@ typealias StringsDB = [BundleURI: [ResourceURI: [LocKey: StringsEntry]]] } } + var expansionFactor: Double? = nil { + didSet { + if let factor = expansionFactor { + userDefaults.setValue(factor, forKey: expansionFactorKey) + } + else { + userDefaults.removeObject(forKey: expansionFactorKey) + } + } + } + @objc static let defaultManager = StringsManager(userDefaults: .standard, stringsFileParser: StringsFileParser()) private init(userDefaults: UserDefaults, stringsFileParser: StringsFileParser) { @@ -65,7 +77,10 @@ typealias StringsDB = [BundleURI: [ResourceURI: [LocKey: StringsEntry]]] overriddenKeyPaths = [] insertsStartEndMarkers = userDefaults.value(forKey: markersKey) as? Bool ?? false transformsCharacters = userDefaults.value(forKey: transformKey) as? Bool ?? false - + if let factor = userDefaults.value(forKey: expansionFactorKey) as? Double { + expansionFactor = min(max(factor, 1), 2) + } + super.init() loadStringsFilesInBundle(Bundle.main) @@ -145,6 +160,7 @@ typealias StringsDB = [BundleURI: [ResourceURI: [LocKey: StringsEntry]]] let baseCopy = (value?.isEmpty ?? true) ? key : value! return [Translation.static(baseCopy)] .map { transformsCharacters ? $0.applyingPseudoLocalization() : $0 } + .map { expansionFactor != nil ? $0.simulatingExpansion(by: expansionFactor!) : $0 } .map { insertsStartEndMarkers ? $0.addingStartEndMarkers() : $0 } .first! .toString() @@ -152,6 +168,7 @@ typealias StringsDB = [BundleURI: [ResourceURI: [LocKey: StringsEntry]]] return [entry.override ?? entry.translation] .map { transformsCharacters ? $0.applyingPseudoLocalization() : $0 } + .map { expansionFactor != nil ? $0.simulatingExpansion(by: expansionFactor!) : $0 } .map { insertsStartEndMarkers ? $0.addingStartEndMarkers() : $0 } .first! .toString() diff --git a/Ilion/ToolsPanel.xib b/Ilion/ToolsPanel.xib index 305326b..ad212c0 100644 --- a/Ilion/ToolsPanel.xib +++ b/Ilion/ToolsPanel.xib @@ -8,6 +8,8 @@ + + @@ -18,14 +20,14 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/Ilion/ToolsPanelController.swift b/Ilion/ToolsPanelController.swift index 9ab2604..dd6e0b8 100644 --- a/Ilion/ToolsPanelController.swift +++ b/Ilion/ToolsPanelController.swift @@ -15,20 +15,32 @@ protocol ToolsPanelControllerDelegate: class { final class ToolsPanelController: NSWindowController { @IBOutlet private weak var markersCheckbox: NSButton! @IBOutlet private weak var transformCheckbox: NSButton! - + @IBOutlet private weak var expansionCheckbox: NSButton! + @IBOutlet private weak var expansionFactorSlider: NSSlider! + weak var delegate: ToolsPanelControllerDelegate? var shouldInsertStartEndMarkers: Bool = false { didSet { - guard isWindowLoaded else { return } - markersCheckbox?.state = shouldInsertStartEndMarkers ? .on : .off + updateUI() } } var shouldTransformCharacters: Bool = false { didSet { - guard isWindowLoaded else { return } - transformCheckbox?.state = shouldTransformCharacters ? .on : .off + updateUI() + } + } + + var shouldSimulateExpansion: Bool = false { + didSet { + updateUI() + } + } + + var expansionFactor: Double = 1.0 { + didSet { + updateUI() } } @@ -38,15 +50,35 @@ final class ToolsPanelController: NSWindowController { override func windowDidLoad() { super.windowDidLoad() + updateUI() + } + + private func updateUI() { + guard isWindowLoaded else { return } + markersCheckbox.state = shouldInsertStartEndMarkers ? .on : .off transformCheckbox.state = shouldTransformCharacters ? .on : .off + expansionCheckbox.state = shouldSimulateExpansion ? .on : .off + expansionFactorSlider.doubleValue = expansionFactor } - @IBAction private func checkboxToggled(_ sender: Any) { - shouldInsertStartEndMarkers = markersCheckbox.state == .on - shouldTransformCharacters = transformCheckbox.state == .on + @IBAction private func checkboxToggled(_ sender: NSButton) { + switch sender { + case markersCheckbox: + shouldInsertStartEndMarkers = markersCheckbox.state == .on + case transformCheckbox: + shouldTransformCharacters = transformCheckbox.state == .on + case expansionCheckbox: + shouldSimulateExpansion = expansionCheckbox.state == .on + default: + return + } } - + + @IBAction private func sliderScrubbed(_ sender: Any) { + expansionFactor = expansionFactorSlider.doubleValue + } + @IBAction private func doneClicked(_ sender: Any) { delegate?.toolsPanelControllerDidClose(self) } diff --git a/Ilion/Translation.swift b/Ilion/Translation.swift index 9e68b87..6466b20 100644 --- a/Ilion/Translation.swift +++ b/Ilion/Translation.swift @@ -45,4 +45,31 @@ extension Translation { return .dynamic(transformedFormat) } } + + func simulatingExpansion(by factor: Double) -> Translation { + func paddingText(forLength length: Int) -> String { + let growth = Int(floor(Double(length) * factor)) - length + let pattern = "lorem ipsum dolor sit amet consectetur adipiscing elit " + let paddingSource = String(repeating: pattern, count: (growth / pattern.count) + 1) + let padding = paddingSource[paddingSource.startIndex ..< paddingSource.index(paddingSource.startIndex, offsetBy: growth)] + return "{\(padding)}" + } + + switch self { + case .static(let text): + let padding = paddingText(forLength: text.count) + return .static(text.appending(padding)) + + case .dynamic(let format): + let transformedFormat = format.applyingTransform { slices in + let charCount = slices.map { $0.count }.reduce(0, +) + let padding = paddingText(forLength: charCount) + + var slices = slices + slices[slices.count - 1] = slices.last!.appending(padding) + return slices + } + return .dynamic(transformedFormat) + } + } } diff --git a/doc/GettingStarted.md b/doc/GettingStarted.md index 05e66df..7aedf5c 100644 --- a/doc/GettingStarted.md +++ b/doc/GettingStarted.md @@ -72,6 +72,12 @@ If the _Fuzzy transform Latin characters_ checkbox is checked, any original or o The result is a somewhat noisy but more or less legible copy (e.g. `localization` --> ![localization](pseudo_localization.png). This tool can come handy to detect hardcoded/unlocalized strings in the host application (they will stick out from the accented mass), but you can also use it to verify that your labels are high enough to accomodate letters that extend farther above or below the baseline that the ones in your development language (glyph clipping); and, finally, to see if the chosen font can cope with the shadier parts of the Unicode plane. +#### Simulating expansion + +Check the _Simulate translation expansion_ checkbox to apply an artificial padding to each copy, and use the slider to set the amount by which the strings should grow in length. Padding will appear at the end of each string, enclosed in `{}` curly braces. + +This feature is useful for quickly checking whether UI elements respond well to text size changes. + --- ### Exporting changes diff --git a/doc/tools_button.png b/doc/tools_button.png index 1f28797..7ab171e 100644 Binary files a/doc/tools_button.png and b/doc/tools_button.png differ