Skip to content

Commit ef46385

Browse files
authored
Merge pull request igorkulman#2 from scriptease/master
Support for string tables
2 parents d2c6863 + f235bd1 commit ef46385

File tree

8 files changed

+149
-31
lines changed

8 files changed

+149
-31
lines changed

LocalizationEditor.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
172274D420D933970036EA4E /* LocalizationGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 172274D320D933970036EA4E /* LocalizationGroup.swift */; };
1011
F3D9C94620BEC7460081830A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3D9C94520BEC7460081830A /* AppDelegate.swift */; };
1112
F3D9C94820BEC7460081830A /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3D9C94720BEC7460081830A /* ViewController.swift */; };
1213
F3D9C94A20BEC7460081830A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F3D9C94920BEC7460081830A /* Assets.xcassets */; };
@@ -41,6 +42,7 @@
4142
/* End PBXCopyFilesBuildPhase section */
4243

4344
/* Begin PBXFileReference section */
45+
172274D320D933970036EA4E /* LocalizationGroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalizationGroup.swift; sourceTree = "<group>"; };
4446
F3D9C94220BEC7460081830A /* LocalizationEditor.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LocalizationEditor.app; sourceTree = BUILT_PRODUCTS_DIR; };
4547
F3D9C94520BEC7460081830A /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
4648
F3D9C94720BEC7460081830A /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
@@ -110,6 +112,7 @@
110112
F3D9C95520BEC9E30081830A /* Models */ = {
111113
isa = PBXGroup;
112114
children = (
115+
172274D320D933970036EA4E /* LocalizationGroup.swift */,
113116
F3D9C95620BEC9F10081830A /* LocalizationString.swift */,
114117
F3D9C95820BECA270081830A /* Localization.swift */,
115118
);
@@ -231,6 +234,7 @@
231234
F3D9C94820BEC7460081830A /* ViewController.swift in Sources */,
232235
F3D9C96720BEDF640081830A /* KeyCell.swift in Sources */,
233236
F3D9C95720BEC9F10081830A /* LocalizationString.swift in Sources */,
237+
172274D420D933970036EA4E /* LocalizationGroup.swift in Sources */,
234238
F3D9C95C20BECDBF0081830A /* LocalizationProvider.swift in Sources */,
235239
F3D9C96E20BEEAA10081830A /* LocalizationsDataSource.swift in Sources */,
236240
F3D9C95920BECA270081830A /* Localization.swift in Sources */,
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>IDEDidComputeMac32BitWarning</key>
6+
<true/>
7+
</dict>
8+
</plist>

LocalizationEditor/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
<key>CFBundleShortVersionString</key>
2020
<string>1.0</string>
2121
<key>CFBundleVersion</key>
22-
<string>1</string>
22+
<string>2</string>
2323
<key>LSMinimumSystemVersion</key>
2424
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
2525
<key>NSHumanReadableCopyright</key>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//
2+
// LocalizationGroup.swift
3+
// LocalizationEditor
4+
//
5+
// Created by Florian Agsteiner on 19.06.18.
6+
// Copyright © 2018 Igor Kulman. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
class LocalizationGroup {
12+
let name: String
13+
let path: String
14+
let localizations : [Localization]
15+
16+
init(name: String, localizations: [Localization], path: String) {
17+
self.name = name
18+
self.localizations = localizations
19+
self.path = path
20+
}
21+
}
22+
23+
extension LocalizationGroup: CustomStringConvertible {
24+
var description: String {
25+
return name
26+
}
27+
}

LocalizationEditor/Providers/LocalizationProvider.swift

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,27 @@ import Foundation
1313
class LocalizationProvider {
1414
private let ignoredDirectories = ["Carthage", "build", ".framework"]
1515

16-
func getLocalizations(url: URL) -> [Localization] {
16+
func getLocalizations(url: URL) -> [LocalizationGroup] {
1717
Log.debug?.message("Searching \(url) for Localizable.strings")
1818

1919
guard let folder = try? Folder(path: url.path) else {
2020
return []
2121
}
2222

23-
let localizationFiles = folder.makeFileSequence(recursive: true).filter { file in
24-
return file.name == "Localizable.strings" && ignoredDirectories.map({file.path.contains("\($0)/")}).filter({$0}).count == 0
25-
}
26-
23+
let localizationFiles = Dictionary(grouping: folder.makeFileSequence(recursive: true).filter { file in
24+
return file.name.hasSuffix(".strings") && ignoredDirectories.map({file.path.contains("\($0)/")}).filter({$0}).count == 0
25+
}, by: {$0.path.components(separatedBy:"/").filter({!$0.hasSuffix(".lproj")}).joined(separator:"/")})
26+
2727
Log.debug?.message("Found \(localizationFiles) localization files")
28-
29-
return localizationFiles.map({ file in
30-
let parts = file.path.split(separator: "/")
31-
let lang = String(parts[parts.count - 2]).replacingOccurrences(of: ".lproj", with: "")
32-
return Localization(language: lang, translations: getLocalizationStrings(path: file.path), path: file.path)
33-
})
28+
29+
return localizationFiles.map({ (path, files) in
30+
let name = URL(fileURLWithPath: path).lastPathComponent
31+
return LocalizationGroup(name: name, localizations: files.map({ file in
32+
let parts = file.path.split(separator: "/")
33+
let lang = String(parts[parts.count - 2]).replacingOccurrences(of: ".lproj", with: "")
34+
return Localization(language: lang, translations: getLocalizationStrings(path: file.path), path: file.path)
35+
}), path: path)
36+
}).sorted(by: {$0.name < $1.name})
3437
}
3538

3639
private func getLocalizationStrings(path: String) -> [LocalizationString] {

LocalizationEditor/Providers/LocalizationsDataSource.swift

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,27 +13,45 @@ class LocalizationsDataSource: NSObject, NSTableViewDataSource {
1313

1414
// MARK: - Properties
1515

16+
private var localizationGroups: [LocalizationGroup] = []
17+
private var selectedLocalizationGroup: LocalizationGroup? = nil
1618
private var localizations: [Localization] = []
1719
private var masterLocalization: Localization?
1820
private let localizationProvider = LocalizationProvider()
1921
private var numberOfKeys = 0
2022

2123
// MARK: - Action
2224

23-
func load(folder: URL, onCompletion: @escaping ([String]) -> Void) {
25+
func load(folder: URL, onCompletion: @escaping ([String], String?, [LocalizationGroup]) -> Void) {
2426
DispatchQueue.global(qos: .background).async {
25-
self.localizations = self.localizationProvider.getLocalizations(url: folder)
26-
self.numberOfKeys = self.localizations.map({ $0.translations.count }).max() ?? 0
27-
self.masterLocalization = self.localizations.first(where: { $0.translations.count == self.numberOfKeys })
28-
29-
DispatchQueue.main.async {
30-
onCompletion(self.localizations.map({ $0.language }))
27+
28+
self.localizationGroups = self.localizationProvider.getLocalizations(url: folder)
29+
if let group = self.localizationGroups.filter({$0.name == "Localizable.strings" }).first ?? self.localizationGroups.first {
30+
let languages = self.select(group: group)
31+
32+
DispatchQueue.main.async {
33+
onCompletion(languages, self.selectedLocalizationGroup?.name, self.localizationGroups)
34+
}
3135
}
3236
}
3337
}
38+
39+
func select(name: String) -> [String]{
40+
let group = self.localizationGroups.filter({$0.name == name}).first!
41+
return select(group: group)
42+
}
43+
44+
func select(group: LocalizationGroup) -> [String]{
45+
self.selectedLocalizationGroup = group
46+
self.localizations = self.selectedLocalizationGroup?.localizations ?? []
47+
self.numberOfKeys = self.localizations.map({ $0.translations.count }).max() ?? 0
48+
self.masterLocalization = self.localizations.first(where: { $0.translations.count == self.numberOfKeys })
49+
50+
return self.localizations.map({ $0.language })
51+
}
3452

3553
func getKey(row: Int) -> String? {
36-
return masterLocalization?.translations[row].key
54+
return (row < masterLocalization?.translations.count ?? 0) ? masterLocalization?.translations[row].key : nil
3755
}
3856

3957
func getLocalization(language: String, row: Int) -> LocalizationString {

LocalizationEditor/UI/Base.lproj/Main.storyboard

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
2+
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="14113" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
33
<dependencies>
4-
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="13771"/>
4+
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14113"/>
55
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
66
</dependencies>
77
<scenes>
@@ -62,6 +62,9 @@
6262
</items>
6363
</menu>
6464
</menuItem>
65+
<menuItem title="Select" id="3lY-JD-VuH">
66+
<modifierMask key="keyEquivalentModifierMask"/>
67+
</menuItem>
6568
</items>
6669
</menu>
6770
<connections>
@@ -108,13 +111,13 @@
108111
<autoresizingMask key="autoresizingMask"/>
109112
<subviews>
110113
<scrollView autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4ba-Nv-4Q4">
111-
<rect key="frame" x="0.0" y="0.0" width="658" height="416"/>
114+
<rect key="frame" x="0.0" y="0.0" width="658" height="392"/>
112115
<clipView key="contentView" id="xNj-vz-MO7">
113-
<rect key="frame" x="1" y="0.0" width="656" height="415"/>
116+
<rect key="frame" x="1" y="0.0" width="656" height="391"/>
114117
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
115118
<subviews>
116119
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" alternatingRowBackgroundColors="YES" columnReordering="NO" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" typeSelect="NO" usesAutomaticRowHeights="YES" headerView="Bry-MY-OIY" id="ByO-mI-RPv">
117-
<rect key="frame" x="0.0" y="0.0" width="656" height="392"/>
120+
<rect key="frame" x="0.0" y="0.0" width="656" height="368"/>
118121
<autoresizingMask key="autoresizingMask"/>
119122
<size key="intercellSpacing" width="3" height="2"/>
120123
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
@@ -138,18 +141,46 @@
138141
<progressIndicator wantsLayer="YES" horizontalHuggingPriority="750" verticalHuggingPriority="750" maxValue="100" displayedWhenStopped="NO" bezeled="NO" indeterminate="YES" controlSize="small" style="spinning" translatesAutoresizingMaskIntoConstraints="NO" id="orS-Om-jEF">
139142
<rect key="frame" x="321" y="200" width="16" height="16"/>
140143
</progressIndicator>
144+
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ZFg-5m-6pC">
145+
<rect key="frame" x="84" y="390" width="577" height="26"/>
146+
<popUpButtonCell key="cell" type="push" title="Open folder first" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="border" inset="2" selectedItem="NVn-GV-ID4" id="4aK-eh-T5Y">
147+
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
148+
<font key="font" metaFont="menu"/>
149+
<menu key="menu" id="5W8-5b-o7R">
150+
<items>
151+
<menuItem title="Open folder first" state="on" id="NVn-GV-ID4"/>
152+
</items>
153+
</menu>
154+
</popUpButtonCell>
155+
</popUpButton>
156+
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="16j-oD-cAE">
157+
<rect key="frame" x="3" y="395" width="75" height="17"/>
158+
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="String table" id="z8U-Ny-4JF">
159+
<font key="font" metaFont="system"/>
160+
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
161+
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
162+
</textFieldCell>
163+
</textField>
141164
</subviews>
142165
<constraints>
143-
<constraint firstItem="4ba-Nv-4Q4" firstAttribute="top" secondItem="m2S-Jp-Qdl" secondAttribute="top" id="Fcq-O0-4L6"/>
166+
<constraint firstItem="ZFg-5m-6pC" firstAttribute="leading" secondItem="16j-oD-cAE" secondAttribute="trailing" constant="10" id="D6G-Vj-vzc"/>
167+
<constraint firstItem="4ba-Nv-4Q4" firstAttribute="top" secondItem="m2S-Jp-Qdl" secondAttribute="top" constant="24" id="Fcq-O0-4L6"/>
168+
<constraint firstAttribute="trailing" secondItem="ZFg-5m-6pC" secondAttribute="trailing" id="I29-aq-1Lr"/>
169+
<constraint firstItem="ZFg-5m-6pC" firstAttribute="top" secondItem="m2S-Jp-Qdl" secondAttribute="top" constant="2" id="PJB-vg-X9o"/>
144170
<constraint firstAttribute="trailing" secondItem="4ba-Nv-4Q4" secondAttribute="trailing" id="U2K-bp-ktM"/>
145171
<constraint firstItem="4ba-Nv-4Q4" firstAttribute="leading" secondItem="m2S-Jp-Qdl" secondAttribute="leading" id="aFu-bj-BOT"/>
146172
<constraint firstItem="orS-Om-jEF" firstAttribute="centerY" secondItem="m2S-Jp-Qdl" secondAttribute="centerY" id="cdU-Z2-VjR"/>
173+
<constraint firstItem="4ba-Nv-4Q4" firstAttribute="top" secondItem="ZFg-5m-6pC" secondAttribute="bottom" constant="1" id="fUC-6L-ChH"/>
147174
<constraint firstAttribute="bottom" secondItem="4ba-Nv-4Q4" secondAttribute="bottom" id="m5c-j8-Z7f"/>
175+
<constraint firstItem="16j-oD-cAE" firstAttribute="leading" secondItem="m2S-Jp-Qdl" secondAttribute="leading" constant="5" id="osA-pP-jh6"/>
148176
<constraint firstItem="orS-Om-jEF" firstAttribute="centerX" secondItem="m2S-Jp-Qdl" secondAttribute="centerX" id="p93-Be-Z2I"/>
177+
<constraint firstItem="16j-oD-cAE" firstAttribute="centerY" secondItem="ZFg-5m-6pC" secondAttribute="centerY" id="rs9-h5-XO3"/>
149178
</constraints>
150179
</view>
151180
<connections>
181+
<outlet property="defaultSelectItem" destination="NVn-GV-ID4" id="Ibj-ZN-bm2"/>
152182
<outlet property="progressIndicator" destination="orS-Om-jEF" id="W9q-Ft-3Pn"/>
183+
<outlet property="selectButton" destination="ZFg-5m-6pC" id="uUm-fN-AZO"/>
153184
<outlet property="tableView" destination="ByO-mI-RPv" id="HZj-sq-2j6"/>
154185
</connections>
155186
</viewController>

LocalizationEditor/UI/ViewController.swift

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ class ViewController: NSViewController {
1313
// MARK: - Outlets
1414

1515
@IBOutlet private weak var tableView: NSTableView!
16+
@IBOutlet private weak var selectButton: NSPopUpButton!
1617
@IBOutlet private weak var progressIndicator: NSProgressIndicator!
18+
@IBOutlet private var defaultSelectItem: NSMenuItem!
1719

1820
// MARK: - Properties
1921

@@ -31,6 +33,8 @@ class ViewController: NSViewController {
3133
private func setupMenu() {
3234
let appDelegate = NSApplication.shared.delegate as! AppDelegate
3335
appDelegate.openFolderMenuItem.action = #selector(ViewController.openAction(sender:))
36+
selectButton.menu?.removeAllItems();
37+
selectButton.menu?.addItem(defaultSelectItem)
3438
}
3539

3640
private func setupData() {
@@ -43,8 +47,16 @@ class ViewController: NSViewController {
4347
tableView.delegate = self
4448
tableView.dataSource = dataSource
4549
}
50+
51+
private func setupSetupLocalizationSelectionMenu(files: [LocalizationGroup]){
52+
selectButton.menu?.removeAllItems()
53+
files.map({NSMenuItem(title: $0.name, action: #selector(ViewController.selectAction(sender:)), keyEquivalent: "")}).forEach({selectButton.menu?.addItem($0)})
54+
}
55+
56+
private func reloadData(with languages: [String], title: String?) {
57+
let prefix = "LocalizationEditor"
58+
self.view.window?.title = title.flatMap({"\(prefix) [\($0)]"}) ?? prefix // TODO
4659

47-
private func reloadData(with languages: [String]) {
4860
let columns = tableView.tableColumns
4961
columns.forEach {
5062
self.tableView.removeTableColumn($0)
@@ -73,8 +85,15 @@ class ViewController: NSViewController {
7385
}
7486
return string
7587
}
88+
89+
@IBAction @objc func selectAction(sender: NSMenuItem) {
90+
let title = sender.title
91+
let languages = self.dataSource.select(name: title)
7692

77-
@objc func openAction(sender _: NSMenuItem) {
93+
self.reloadData(with: languages, title:title)
94+
}
95+
96+
@IBAction @objc func openAction(sender _: NSMenuItem) {
7897
let openPanel = NSOpenPanel()
7998
openPanel.allowsMultipleSelection = false
8099
openPanel.canChooseDirectories = true
@@ -84,9 +103,17 @@ class ViewController: NSViewController {
84103
if result.rawValue == NSApplication.ModalResponse.OK.rawValue {
85104
if let url = openPanel.url {
86105
self.progressIndicator.startAnimation(self)
87-
self.dataSource.load(folder: url) { [unowned self] languages in
88-
self.reloadData(with: languages)
106+
self.dataSource.load(folder: url) { [unowned self] languages, title, localizationFiles in
107+
self.reloadData(with: languages, title:title)
89108
self.progressIndicator.stopAnimation(self)
109+
110+
if let title = title{
111+
self.setupSetupLocalizationSelectionMenu(files: localizationFiles)
112+
self.selectButton.selectItem(at: self.selectButton.indexOfItem(withTitle: title))
113+
}
114+
else {
115+
self.setupMenu()
116+
}
90117
}
91118
}
92119
}
@@ -112,7 +139,7 @@ extension ViewController: NSTableViewDelegate {
112139
let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: LocalizationCell.identifier), owner: self)! as! LocalizationCell
113140
cell.delegate = self
114141
cell.language = language
115-
cell.value = dataSource.getLocalization(language: language, row: row)
142+
cell.value = row < dataSource.numberOfRows(in: tableView) ? dataSource.getLocalization(language: language, row: row) : nil
116143
return cell
117144
}
118145
}

0 commit comments

Comments
 (0)