From ada84bbe3147115d6c1b68535c09ac2cb847d5d2 Mon Sep 17 00:00:00 2001 From: Selim Mustafaev Date: Mon, 7 Dec 2020 00:27:00 +0300 Subject: [PATCH] More localization --- AutoCat.xcodeproj/project.pbxproj | 30 ++- .../xcschemes/xcschememanagement.plist | 24 +- .../Base.lproj/Localizable.stringsdict | 22 ++ AutoCat/Controllers/FiltersController.swift | 32 +-- .../Controllers/Osago/OsagoController.swift | 28 ++- AutoCat/Controllers/OwnersController.swift | 47 ++-- AutoCat/Controllers/RecordsController.swift | 36 +-- AutoCat/Controllers/RegionsController.swift | 2 +- AutoCat/Controllers/ReportController.swift | 68 +++--- AutoCat/Controllers/SearchController.swift | 10 +- AutoCat/Models/Vehicle.swift | 9 +- AutoCat/Utils/Constants.swift | 4 +- AutoCat/Views/eureka/MultilineLabelRow.swift | 55 +++++ AutoCat/ru.lproj/Localizable.strings | 222 ++++++++++++++++++ 14 files changed, 461 insertions(+), 128 deletions(-) create mode 100644 AutoCat/AutoCat/Base.lproj/Localizable.stringsdict create mode 100644 AutoCat/Views/eureka/MultilineLabelRow.swift diff --git a/AutoCat.xcodeproj/project.pbxproj b/AutoCat.xcodeproj/project.pbxproj index 4a47d83..a5f0e5f 100644 --- a/AutoCat.xcodeproj/project.pbxproj +++ b/AutoCat.xcodeproj/project.pbxproj @@ -15,6 +15,7 @@ 7A0420BA25693D2C00034941 /* dkbm.js in Resources */ = {isa = PBXBuildFile; fileRef = 7A0420B925693D2C00034941 /* dkbm.js */; }; 7A051611241412CA00FC55AC /* SwiftDate in Frameworks */ = {isa = PBXBuildFile; productRef = 7A051610241412CA00FC55AC /* SwiftDate */; }; 7A05161A2414FF0900FC55AC /* DateSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A0516192414FF0900FC55AC /* DateSection.swift */; }; + 7A0B96A0257D6D4B000B39AD /* MultilineLabelRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A0B969F257D6D4B000B39AD /* MultilineLabelRow.swift */; }; 7A1090E824A394F100B4F0B2 /* AudioRecordCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1090E724A394F100B4F0B2 /* AudioRecordCell.swift */; }; 7A1090EA24A3A26300B4F0B2 /* AudioPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1090E924A3A26300B4F0B2 /* AudioPlayer.swift */; }; 7A1090EC24A4E3E100B4F0B2 /* CellProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1090EB24A4E3E100B4F0B2 /* CellProgressView.swift */; }; @@ -55,6 +56,7 @@ 7A530B8B240181F500CBFE6E /* RxRealm in Frameworks */ = {isa = PBXBuildFile; productRef = 7A530B8A240181F500CBFE6E /* RxRealm */; }; 7A61FF8B2575A2CD00D905D5 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7A61FF892575A2CD00D905D5 /* Localizable.strings */; }; 7A61FF912575A5B300D905D5 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7A61FF8F2575A5B300D905D5 /* InfoPlist.strings */; }; + 7A61FFA0257D3CFC00D905D5 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 7A61FFA2257D3CFC00D905D5 /* Localizable.stringsdict */; }; 7A64AE732469DFB600ABE48E /* DismissAnimationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A64AE6F2469DFB600ABE48E /* DismissAnimationController.swift */; }; 7A64AE742469DFB600ABE48E /* MediaContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A64AE702469DFB600ABE48E /* MediaContentView.swift */; }; 7A64AE752469DFB600ABE48E /* MediaBrowserViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A64AE712469DFB600ABE48E /* MediaBrowserViewController.swift */; }; @@ -112,6 +114,7 @@ 7A0420B52568650C00034941 /* DkbmController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DkbmController.swift; sourceTree = ""; }; 7A0420B925693D2C00034941 /* dkbm.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = dkbm.js; sourceTree = ""; }; 7A0516192414FF0900FC55AC /* DateSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateSection.swift; sourceTree = ""; }; + 7A0B969F257D6D4B000B39AD /* MultilineLabelRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultilineLabelRow.swift; sourceTree = ""; }; 7A1090E724A394F100B4F0B2 /* AudioRecordCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRecordCell.swift; sourceTree = ""; }; 7A1090E924A3A26300B4F0B2 /* AudioPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioPlayer.swift; sourceTree = ""; }; 7A1090EB24A4E3E100B4F0B2 /* CellProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CellProgressView.swift; sourceTree = ""; }; @@ -152,6 +155,8 @@ 7A61FF902575A5B300D905D5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/InfoPlist.strings; sourceTree = ""; }; 7A61FF932575A5B600D905D5 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/InfoPlist.strings; sourceTree = ""; }; 7A61FF962576C16400D905D5 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Main.strings; sourceTree = ""; }; + 7A61FFA1257D3CFC00D905D5 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = ""; }; + 7A61FFA4257D3D0200D905D5 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ru; path = ru.lproj/Localizable.stringsdict; sourceTree = ""; }; 7A64AE6B2469DC6900ABE48E /* AutoCat.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = AutoCat.entitlements; sourceTree = ""; }; 7A64AE6F2469DFB600ABE48E /* DismissAnimationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DismissAnimationController.swift; sourceTree = ""; }; 7A64AE702469DFB600ABE48E /* MediaContentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaContentView.swift; sourceTree = ""; }; @@ -242,6 +247,14 @@ path = JS; sourceTree = ""; }; + 7A0B969D257D6CB3000B39AD /* eureka */ = { + isa = PBXGroup; + children = ( + 7A0B969F257D6D4B000B39AD /* MultilineLabelRow.swift */, + ); + path = eureka; + sourceTree = ""; + }; 7A1146F423FDE7E500B424AF = { isa = PBXGroup; children = ( @@ -279,6 +292,7 @@ 7A11470B23FDE7E600B424AF /* LaunchScreen.storyboard */, 7A11470E23FDE7E600B424AF /* Info.plist */, 7A61FF892575A2CD00D905D5 /* Localizable.strings */, + 7A61FFA2257D3CFC00D905D5 /* Localizable.stringsdict */, 7A61FF8F2575A5B300D905D5 /* InfoPlist.strings */, ); path = AutoCat; @@ -404,6 +418,7 @@ 7A6DD901242BF48D009DE740 /* Views */ = { isa = PBXGroup; children = ( + 7A0B969D257D6CB3000B39AD /* eureka */, 7A6DD902242BF4A5009DE740 /* PlateView.swift */, 7A6DD90B24335A6D009DE740 /* FlagLayer.swift */, 7AB67E8B2435C38700258F61 /* CustomTextField.swift */, @@ -524,6 +539,7 @@ files = ( 7A0420BA25693D2C00034941 /* dkbm.js in Resources */, 7A61FF912575A5B300D905D5 /* InfoPlist.strings in Resources */, + 7A61FFA0257D3CFC00D905D5 /* Localizable.stringsdict in Resources */, 7ADF6C99250F872C00F237B2 /* RoadNumbers.otf in Resources */, 7A11470D23FDE7E600B424AF /* LaunchScreen.storyboard in Resources */, 7A61FF8B2575A2CD00D905D5 /* Localizable.strings in Resources */, @@ -553,6 +569,7 @@ 7A3F07AD2436350B00E59687 /* SearchController.swift in Sources */, 7AABDE26253350C30041AFC6 /* RxSectionedDataSource.swift in Sources */, 7AB562BA249C9E9B00473D53 /* Region.swift in Sources */, + 7A0B96A0257D6D4B000B39AD /* MultilineLabelRow.swift in Sources */, 7A659B5924A2B1BA0043A0F2 /* AudioRecord.swift in Sources */, 7A6DD90C24335A6D009DE740 /* FlagLayer.swift in Sources */, 7AE26A3524F31B0700625033 /* EventsController.swift in Sources */, @@ -654,6 +671,15 @@ name = InfoPlist.strings; sourceTree = ""; }; + 7A61FFA2257D3CFC00D905D5 /* Localizable.stringsdict */ = { + isa = PBXVariantGroup; + children = ( + 7A61FFA1257D3CFC00D905D5 /* en */, + 7A61FFA4257D3D0200D905D5 /* ru */, + ); + name = Localizable.stringsdict; + sourceTree = ""; + }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ @@ -779,7 +805,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = AutoCat/AutoCat.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 57; + CURRENT_PROJECT_VERSION = 58; DEVELOPMENT_TEAM = 46DTTB8X4S; INFOPLIST_FILE = AutoCat/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.0; @@ -802,7 +828,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = AutoCat/AutoCat.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 57; + CURRENT_PROJECT_VERSION = 58; DEVELOPMENT_TEAM = 46DTTB8X4S; INFOPLIST_FILE = AutoCat/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.0; diff --git a/AutoCat.xcodeproj/xcuserdata/selim.xcuserdatad/xcschemes/xcschememanagement.plist b/AutoCat.xcodeproj/xcuserdata/selim.xcuserdatad/xcschemes/xcschememanagement.plist index 50bdf8c..5b28f1c 100644 --- a/AutoCat.xcodeproj/xcuserdata/selim.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/AutoCat.xcodeproj/xcuserdata/selim.xcuserdatad/xcschemes/xcschememanagement.plist @@ -14,14 +14,14 @@ isShown orderHint - 5 + 2 DifferenceKit (Playground) 2.xcscheme isShown orderHint - 6 + 3 DifferenceKit (Playground).xcscheme @@ -35,14 +35,14 @@ isShown orderHint - 8 + 5 Eureka (Playground) 2.xcscheme isShown orderHint - 9 + 6 Eureka (Playground) 3.xcscheme @@ -70,7 +70,7 @@ isShown orderHint - 7 + 4 GettingStarted (Playground) 1.xcscheme @@ -112,42 +112,42 @@ isShown orderHint - 10 + 13 Rx (Playground) 1.xcscheme isShown orderHint - 3 + 8 Rx (Playground) 2.xcscheme isShown orderHint - 4 + 9 Rx (Playground).xcscheme isShown orderHint - 2 + 7 SwiftDate (Playground) 1.xcscheme isShown orderHint - 12 + 11 SwiftDate (Playground) 2.xcscheme isShown orderHint - 13 + 12 SwiftDate (Playground) 3.xcscheme @@ -175,7 +175,7 @@ isShown orderHint - 11 + 10 SuppressBuildableAutocreation diff --git a/AutoCat/AutoCat/Base.lproj/Localizable.stringsdict b/AutoCat/AutoCat/Base.lproj/Localizable.stringsdict new file mode 100644 index 0000000..26876ea --- /dev/null +++ b/AutoCat/AutoCat/Base.lproj/Localizable.stringsdict @@ -0,0 +1,22 @@ + + + + + owners count + + NSStringLocalizedFormatKey + %#@VARIABLE@ + VARIABLE + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + u + one + %u owner + other + %u owners + + + + diff --git a/AutoCat/Controllers/FiltersController.swift b/AutoCat/Controllers/FiltersController.swift index 898b5ce..7d353a3 100644 --- a/AutoCat/Controllers/FiltersController.swift +++ b/AutoCat/Controllers/FiltersController.swift @@ -9,9 +9,9 @@ enum AddedBy: String, CustomStringConvertible, CaseIterable { var description: String { switch self { - case .anyone: return "Anyone" - case .me: return "Me" - case .anyoneButMe: return "Anyone but me" + case .anyone: return NSLocalizedString("Anyone", comment: "Added by") + case .me: return NSLocalizedString("Me", comment: "Added by") + case .anyoneButMe: return NSLocalizedString("Anyone but me", comment: "Added by") } } } @@ -28,11 +28,11 @@ class FiltersController: FormViewController { override func viewDidLoad() { super.viewDidLoad() - form +++ Section("Main filters") { $0.tag = "MainFilters" } + form +++ Section(NSLocalizedString("Main filters", comment: "")) { $0.tag = "MainFilters" } <<< PushRow("Brand") { row in - row.title = "Brand" + row.title = NSLocalizedString("Brand", comment: "") row.value = self.filter.brand ?? "Any" - row.selectorTitle = "Brands" + row.selectorTitle = NSLocalizedString("Brands", comment: "") row.optionsProvider = .lazy({ form, completion in Api.getBrands().observeOn(MainScheduler.instance).subscribe(onSuccess: { brands in completion(["Any"] + brands) @@ -45,7 +45,7 @@ class FiltersController: FormViewController { .cellUpdate { $1.value = self.filter.brand ?? "Any" } <<< PushRow("Model") { row in - row.title = "Model" + row.title = NSLocalizedString("Model", comment: "") row.value = self.filter.model ?? "Any" row.disabled = "$Brand == 'Any'" row.optionsProvider = .lazy({ form, completion in @@ -64,7 +64,7 @@ class FiltersController: FormViewController { .cellUpdate { $1.value = self.filter.model ?? "Any" } <<< PushRow("Color") { row in - row.title = "Color" + row.title = NSLocalizedString("Color", comment: "") row.value = self.filter.color ?? "Any" row.optionsProvider = .lazy({ form, completion in Api.getColors().observeOn(MainScheduler.instance).subscribe(onSuccess: { colors in @@ -79,7 +79,7 @@ class FiltersController: FormViewController { form +++ Section() { $0.tag = "Regions" } <<< LabelRow("RegionsRow") { row in - row.title = "Regions" + row.title = NSLocalizedString("Regions", comment: "") row.value = self.filter.regions?.map(String.init).joined(separator: ",") ?? "Any" row.cellUpdate { cell, _ in cell.accessoryType = .disclosureIndicator @@ -99,8 +99,8 @@ class FiltersController: FormViewController { form +++ Section() { $0.tag = "AddedByMe" } <<< ActionSheetRow("AddedByMeRow") { row in - row.title = "Added by" - row.selectorTitle = "Added by" + row.title = NSLocalizedString("Added by", comment: "") + row.selectorTitle = NSLocalizedString("Added by", comment: "") row.options = AddedBy.allCases.map { $0.description } row.value = self.filter.addedBy?.description ?? AddedBy.anyone.description } @@ -117,22 +117,22 @@ class FiltersController: FormViewController { form +++ Section("Time range") <<< DateInlineRow("FromDate") { row in - row.title = "From" - row.noValueDisplayText = "Beginning" + row.title = NSLocalizedString("From", comment: "") + row.noValueDisplayText = NSLocalizedString("Beginning", comment: "") row.value = self.filter.fromDate } .onChange { self.filter.fromDate = $0.value } .cellUpdate(self.update(cell:row:)) <<< DateInlineRow("ToDate") { row in - row.title = "To" - row.noValueDisplayText = "Now" + row.title = NSLocalizedString("To", comment: "") + row.noValueDisplayText = NSLocalizedString("Now", comment: "") row.value = self.filter.toDate } .onChange { self.filter.toDate = $0.value } .cellUpdate(self.update(cell:row:)) form +++ Section() - <<< ButtonRow("ClearAll") { $0.title = "Clear all filters" }.onCellSelection { cell, row in + <<< ButtonRow("ClearAll") { $0.title = NSLocalizedString("Clear all filters", comment: "") }.onCellSelection { cell, row in self.filter.clear() for section in self.form.allSections { // For some reason certain cells do not redraw after first reload diff --git a/AutoCat/Controllers/Osago/OsagoController.swift b/AutoCat/Controllers/Osago/OsagoController.swift index 6d6ca44..6885154 100644 --- a/AutoCat/Controllers/Osago/OsagoController.swift +++ b/AutoCat/Controllers/Osago/OsagoController.swift @@ -47,19 +47,19 @@ class OsagoController: FormViewController { self.form.removeAll() for osago in vehicle.osagoContracts.sorted(by: { $0.date < $1.date }) { self.form +++ Section(formatter.string(from: Date(timeIntervalSince1970: osago.date))) - <<< self.row("Contract #", value: osago.number) - <<< self.row("Name", value: osago.name) - <<< self.row("Status", value: osago.status) - <<< self.row("Insurant", value: osago.insurant) - <<< self.row("Owner", value: osago.owner) - <<< self.row("Region", value: osago.usageRegion) - <<< self.row("Restrictions", value: osago.restrictions, height: 100) - <<< self.row("Plate number", value: osago.plateNumber) - <<< self.row("VIN", value: osago.vin) + <<< self.multilineRow(NSLocalizedString("Contract series and number", comment: ""), value: osago.number) + <<< self.multilineRow(NSLocalizedString("Insurance organization name", comment: ""), value: osago.name) + <<< self.multilineRow(NSLocalizedString("OSAGO contract status", comment: ""), value: osago.status) + <<< self.multilineRow(NSLocalizedString("Insurant", comment: ""), value: osago.insurant) + <<< self.multilineRow(NSLocalizedString("Owner", comment: ""), value: osago.owner) + <<< self.multilineRow(NSLocalizedString("Vehicle usage region", comment: ""), value: osago.usageRegion) + <<< self.multilineRow(NSLocalizedString("Contract restrictions", comment: ""), value: osago.restrictions) + <<< self.row(NSLocalizedString("Plate number", comment: ""), value: osago.plateNumber) + <<< self.row(NSLocalizedString("VIN", comment: ""), value: osago.vin) } } - func row(_ title: String, value: String?, height: CGFloat = 44) -> LabelRow { + func row(_ title: String, value: String?) -> LabelRow { LabelRow() { row in if let cell = row.cell, let label = cell.detailTextLabel, let titleLabel = cell.textLabel { titleLabel.translatesAutoresizingMaskIntoConstraints = false @@ -75,7 +75,13 @@ class OsagoController: FormViewController { label.font = UIFont.preferredFont(forTextStyle: .subheadline) } - //row.cell.height = { height } + row.title = title + row.value = value + } + } + + func multilineRow(_ title: String, value: String?) -> MultilineLabelRow { + MultilineLabelRow() { row in row.title = title row.value = value } diff --git a/AutoCat/Controllers/OwnersController.swift b/AutoCat/Controllers/OwnersController.swift index ff4b628..7249f1b 100644 --- a/AutoCat/Controllers/OwnersController.swift +++ b/AutoCat/Controllers/OwnersController.swift @@ -10,37 +10,33 @@ class OwnersController: FormViewController { override func viewDidLoad() { super.viewDidLoad() + self.tableView.rowHeight = UITableView.automaticDimension + self.formatter.dateStyle = .long self.formatter.timeStyle = .none - self.title = "\(self.owners.count) owner(s)" + self.title = String.localizedStringWithFormat(NSLocalizedString("owners count", comment: ""), self.owners.count) for (index, owner) in self.owners.enumerated() { - let section = Section(header: "", footer: owner.lastOperation) + + let fromDate = Date(timeIntervalSince1970: TimeInterval(owner.from/1000)) + let from = self.formatter.string(from: fromDate) + var to = NSLocalizedString("now", comment: "") + if owner.to > 0 { + let toDate = Date(timeIntervalSince1970: TimeInterval(owner.to/1000)) + to = self.formatter.string(from: toDate) + } + + let section = Section(header: from + " - " + to, footer: owner.lastOperation) form +++ section <<< LabelRow("Owner\(index)") { row in - row.title = "Owner type" - row.value = owner.ownerType - } - <<< LabelRow("From\(index)") { row in - row.title = "From" - let date = Date(timeIntervalSince1970: TimeInterval(owner.from/1000)) - row.value = self.formatter.string(from: date) - } - <<< LabelRow("To\(index)") { row in - row.title = "To" - if owner.to == 0 { - row.value = "now" - } else { - let date = Date(timeIntervalSince1970: TimeInterval(owner.to/1000)) - row.value = self.formatter.string(from: date) - } + row.title = NSLocalizedString("Owner type", comment: "") + row.value = NSLocalizedString(owner.ownerType, comment: "") } if let vehicleRegistrationRegion = owner.region { - section <<< LabelRow("VehicleRegion\(index)") { row in - row.cell.detailTextLabel?.numberOfLines = 0 - row.title = "Vehicle region" + section <<< MultilineLabelRow("VehicleRegion\(index)") { row in + row.title = NSLocalizedString("Vehicle region", comment: "") row.value = vehicleRegistrationRegion } } @@ -51,16 +47,15 @@ class OwnersController: FormViewController { if let driverRegion = owner.registrationRegion { dRegion += " (\(driverRegion))" } - section <<< LabelRow("DriverRegion\(index)") { row in - row.cell.detailTextLabel?.numberOfLines = 0 - row.title = "Driver region" + section <<< MultilineLabelRow("DriverRegion\(index)") { row in + row.title = NSLocalizedString("Driver region", comment: "") row.value = dRegion } } if let code = owner.code { - section <<< LabelRow("Code\(index)") { row in - row.title = "ZIP (or OKTMO) code" + section <<< MultilineLabelRow("Code\(index)") { row in + row.title = NSLocalizedString("ZIP (or OKTMO) code", comment: "") row.value = code } } diff --git a/AutoCat/Controllers/RecordsController.swift b/AutoCat/Controllers/RecordsController.swift index a8c9fe2..d461fe6 100644 --- a/AutoCat/Controllers/RecordsController.swift +++ b/AutoCat/Controllers/RecordsController.swift @@ -65,12 +65,12 @@ class RecordsController: UIViewController, UITableViewDelegate { activity.persistentIdentifier = activityId activity.isEligibleForSearch = true activity.isEligibleForPrediction = true - activity.title = "Add new audio record" + activity.title = NSLocalizedString("Add new audio record", comment: "") activity.suggestedInvocationPhrase = "Запиши номер" let attributes = CSSearchableItemAttributeSet() attributes.contentType = kUTTypeItem as String - attributes.contentDescription = "Add new plate number via audio recording" + attributes.contentDescription = NSLocalizedString("Add new plate number via audio recording", comment: "") activity.contentAttributeSet = attributes self.userActivity = activity @@ -153,9 +153,9 @@ class RecordsController: UIViewController, UITableViewDelegate { } func showRecordingAlert() -> UIAlertController { - let alert = UIAlertController(title: "Recording...", message: nil, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { _ in self.recordDisposable?.dispose() })) - alert.addAction(UIAlertAction(title: "Done", style: .default, handler: { _ in self.recorder?.stopRecording() })) + let alert = UIAlertController(title: NSLocalizedString("Recording...", comment: ""), message: nil, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel, handler: { _ in self.recordDisposable?.dispose() })) + alert.addAction(UIAlertAction(title: NSLocalizedString("Done", comment: ""), style: .default, handler: { _ in self.recorder?.stopRecording() })) self.present(alert, animated: true) return alert } @@ -230,7 +230,7 @@ class RecordsController: UIViewController, UITableViewDelegate { let record = self.recordsDataSource.item(at: indexPath) - let check = UIContextualAction(style: .normal, title: "Check") { action, view, completion in + let check = UIContextualAction(style: .normal, title: NSLocalizedString("Check", comment: "")) { action, view, completion in if let number = record.number { self.check(number: number, event: record.event) } @@ -239,14 +239,14 @@ class RecordsController: UIViewController, UITableViewDelegate { check.backgroundColor = .systemGray2 check.image = UIImage(systemName: "eye") - let action = UIContextualAction(style: .normal, title: "Action") { action, view, completion in + let action = UIContextualAction(style: .normal, title: NSLocalizedString("Action", comment: "")) { action, view, completion in self.moreActions(for: record, cell: cell) completion(true) } action.backgroundColor = .systemGray2 action.image = UIImage(systemName: "ellipsis" /*"square.and.arrow.up"*/) - let delete = UIContextualAction(style: .destructive, title: "Delete") { action, view, completion in + let delete = UIContextualAction(style: .destructive, title: NSLocalizedString("Delete", comment: "")) { action, view, completion in do { if let realm = record.realm { try realm.write { @@ -267,9 +267,9 @@ class RecordsController: UIViewController, UITableViewDelegate { } func moreActions(for record: AudioRecord, cell: UITableViewCell) { - let sheet = UIAlertController(title: "More actions", message: nil, preferredStyle: .actionSheet) - let cancel = UIAlertAction(title: "Cancel", style: .cancel) { _ in sheet.dismiss(animated: true, completion: nil) } - let share = UIAlertAction(title: "Share", style: .default) { _ in + let sheet = UIAlertController(title: NSLocalizedString("More actions", comment: ""), message: nil, preferredStyle: .actionSheet) + let cancel = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel) { _ in sheet.dismiss(animated: true, completion: nil) } + let share = UIAlertAction(title: NSLocalizedString("Share", comment: ""), style: .default) { _ in do { let url = try FileManager.default.url(for: record.path, in: "recordings") let controller = UIActivityViewController(activityItems: [url], applicationActivities: nil) @@ -279,13 +279,13 @@ class RecordsController: UIViewController, UITableViewDelegate { HUD.show(error: error) } } - let showText = UIAlertAction(title: "Show recognized text", style: .default) { action in - self.showAlert(title: "Recognized text", message: record.rawText) + let showText = UIAlertAction(title: NSLocalizedString("Show recognized text", comment: ""), style: .default) { action in + self.showAlert(title: NSLocalizedString("Recognized text", comment: ""), message: record.rawText) } - let editNumber = UIAlertAction(title: "Edit plate number", style: .default) { action in + let editNumber = UIAlertAction(title: NSLocalizedString("Edit plate number", comment: ""), style: .default) { action in self.edit(record: record) } - let showOnMap = UIAlertAction(title: "Show on map", style: .default) { action in + let showOnMap = UIAlertAction(title: NSLocalizedString("Show on map", comment: ""), style: .default) { action in let controller = ShowEventController() controller.event = record.event controller.hidesBottomBarWhenPushed = true @@ -311,8 +311,8 @@ class RecordsController: UIViewController, UITableViewDelegate { } func edit(record: AudioRecord) { - let alert = UIAlertController(title: "Edit plate number", message: nil, preferredStyle: .alert) - let done = UIAlertAction(title: "Done", style: .default) { action in + let alert = UIAlertController(title: NSLocalizedString("Edit plate number", comment: ""), message: nil, preferredStyle: .alert) + let done = UIAlertAction(title: NSLocalizedString("Done", comment: ""), style: .default) { action in guard let tf = alert.textFields?.first else { return } if let realm = try? Realm() { try? realm.write { @@ -321,7 +321,7 @@ class RecordsController: UIViewController, UITableViewDelegate { } } alert.addAction(done) - alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { action in + alert.addAction(UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel, handler: { action in alert.dismiss(animated: true) })) alert.addTextField { tf in diff --git a/AutoCat/Controllers/RegionsController.swift b/AutoCat/Controllers/RegionsController.swift index 83c9ad2..32db8de 100644 --- a/AutoCat/Controllers/RegionsController.swift +++ b/AutoCat/Controllers/RegionsController.swift @@ -26,7 +26,7 @@ class RegionsController: UIViewController, UISearchResultsUpdating, UITableViewD searchController.searchResultsUpdater = self searchController.obscuresBackgroundDuringPresentation = false - searchController.searchBar.placeholder = "Search regions" + searchController.searchBar.placeholder = NSLocalizedString("Search regions", comment: "Search field placeholder") navigationItem.searchController = searchController navigationItem.hidesSearchBarWhenScrolling = false definesPresentationContext = true diff --git a/AutoCat/Controllers/ReportController.swift b/AutoCat/Controllers/ReportController.swift index 3d50db4..27510e1 100644 --- a/AutoCat/Controllers/ReportController.swift +++ b/AutoCat/Controllers/ReportController.swift @@ -46,30 +46,30 @@ class ReportController: FormViewController, MediaBrowserViewControllerDataSource } form +++ Section() - <<< LabelRow("Model").cellUpdate { cell, _ in cell.imageView?.kf.setImage(with: URL(string: self.vehicle?.brand?.logo ?? ""), placeholder: self.logoPlaceholder) } + <<< LabelRow(NSLocalizedString("Model", comment: "")).cellUpdate { cell, _ in cell.imageView?.kf.setImage(with: URL(string: self.vehicle?.brand?.logo ?? ""), placeholder: self.logoPlaceholder) } - form +++ Section("General") - <<< LabelRow("Year") { $0.title = "Year" } - <<< LabelRow("Color") { $0.title = "Color" } - <<< LabelRow("Category") { $0.title = "Category" } - <<< LabelRow("STP") { $0.title = "Steering wheel position" } - <<< LabelRow("Japanese") { $0.title = "Japanese" } + form +++ Section(NSLocalizedString("General", comment: "")) + <<< LabelRow("Year") { $0.title = NSLocalizedString("Year", comment: "") } + <<< LabelRow("Color") { $0.title = NSLocalizedString("Color", comment: "") } + <<< LabelRow("Category") { $0.title = NSLocalizedString("Category", comment: "") } + <<< LabelRow("STP") { $0.title = NSLocalizedString("Steering wheel position", comment: "") } + <<< LabelRow("Japanese") { $0.title = NSLocalizedString("Japanese", comment: "") } - form +++ Section("Identifiers") - <<< LabelRow("PlateNumber") { $0.title = "Number" } - <<< LabelRow("VIN") { $0.title = "VIN" } - <<< LabelRow("STS") { $0.title = "STS" } - <<< LabelRow("PTS") { $0.title = "PTS" } + form +++ Section(NSLocalizedString("Identifiers", comment: "")) + <<< LabelRow("PlateNumber") { $0.title = NSLocalizedString("Plate number", comment: "") } + <<< LabelRow("VIN") { $0.title = NSLocalizedString("VIN", comment: "") } + <<< LabelRow("STS") { $0.title = NSLocalizedString("STS", comment: "") } + <<< LabelRow("PTS") { $0.title = NSLocalizedString("PTS", comment: "") } - form +++ Section("Engine") - <<< LabelRow("EngineNumber") { $0.title = "Number" } - <<< LabelRow("FuelType") { $0.title = "Fuel type" } - <<< LabelRow("Volume") { $0.title = "Volume (cm³)" } - <<< LabelRow("PowerHP") { $0.title = "Power (HP)" } - <<< LabelRow("PowerKw") { $0.title = "Power (kw)" } + form +++ Section(NSLocalizedString("Engine", comment: "")) + <<< LabelRow("EngineNumber") { $0.title = NSLocalizedString("Number", comment: "") } + <<< LabelRow("FuelType") { $0.title = NSLocalizedString("Fuel type", comment: "") } + <<< LabelRow("Volume") { $0.title = NSLocalizedString("Volume (cm³)", comment: "") } + <<< LabelRow("PowerHP") { $0.title = NSLocalizedString("Power (HP)", comment: "") } + <<< LabelRow("PowerKw") { $0.title = NSLocalizedString("Power (kw)", comment: "") } - form +++ Section("History") - <<< LabelRow("Events") { $0.title = "Events" } + form +++ Section(NSLocalizedString("History", comment: "")) + <<< LabelRow("Events") { $0.title = NSLocalizedString("Events", comment: "") } .cellUpdate { cell, _ in cell.accessoryType = .disclosureIndicator } .onCellSelection { _, _ in let sb = UIStoryboard(name: "Main", bundle: nil) @@ -78,7 +78,7 @@ class ReportController: FormViewController, MediaBrowserViewControllerDataSource self.navigationController?.pushViewController(controller, animated: true) } - <<< LabelRow("OSAGO") { $0.title = "OSAGO" } + <<< LabelRow("OSAGO") { $0.title = NSLocalizedString("OSAGO", comment: "") } .cellUpdate { cell, _ in cell.accessoryType = .disclosureIndicator } .onCellSelection { _, _ in let sb = UIStoryboard(name: "Main", bundle: nil) @@ -88,7 +88,7 @@ class ReportController: FormViewController, MediaBrowserViewControllerDataSource } <<< LabelRow("Owners") { row in - row.title = "Owners" + row.title = NSLocalizedString("Owners", comment: "") row.disabled = "$Owners == '0'" } .cellUpdate { cell, _ in cell.accessoryType = .disclosureIndicator } @@ -102,7 +102,7 @@ class ReportController: FormViewController, MediaBrowserViewControllerDataSource } <<< LabelRow("Photos") { row in - row.title = "Photos" + row.title = NSLocalizedString("Photos", comment: "") row.disabled = "$Photos == '0'" } .cellUpdate { cell, _ in cell.accessoryType = .disclosureIndicator } @@ -125,8 +125,8 @@ class ReportController: FormViewController, MediaBrowserViewControllerDataSource self.row("Year")?.value = String(self.vehicle?.year ?? 0) self.row("Color")?.value = self.vehicle?.color ?? "" self.row("Category")?.value = self.vehicle?.category ?? "" - self.row("STP")?.value = self.stringFromBool(self.vehicle?.isRightWheel.value, yes: "Right", no: "Left") - self.row("Japanese")?.value = self.stringFromBool(self.vehicle?.isJapanese.value, yes: "Yes", no: "No") + self.row("STP")?.value = self.stringFromBool(self.vehicle?.isRightWheel.value, yes: NSLocalizedString("Right", comment: ""), no: NSLocalizedString("Left", comment: "")) + self.row("Japanese")?.value = self.stringFromBool(self.vehicle?.isJapanese.value, yes: NSLocalizedString("Yes", comment: ""), no: NSLocalizedString("No", comment: "")) var num = self.vehicle?.getNumber() ?? "" if self.vehicle?.outdated ?? false, let current = self.vehicle?.currentNumber { @@ -204,11 +204,11 @@ class ReportController: FormViewController, MediaBrowserViewControllerDataSource @IBAction func onShare(_ sender: UIBarButtonItem) { guard let vehicle = self.vehicle else { return } - let sheet = UIAlertController(title: "Share report", message: nil, preferredStyle: .actionSheet) + let sheet = UIAlertController(title: NSLocalizedString("Share report", comment: ""), message: nil, preferredStyle: .actionSheet) sheet.popoverPresentationController?.barButtonItem = self.actionBarItem - let cancel = UIAlertAction(title: "Cancel", style: .cancel) { _ in sheet.dismiss(animated: true, completion: nil) } - let shareImage = UIAlertAction(title: "As one image", style: .default) { _ in + let cancel = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel) { _ in sheet.dismiss(animated: true, completion: nil) } + let shareImage = UIAlertAction(title: NSLocalizedString("As one image", comment: ""), style: .default) { _ in let image = vehicle.reportImage(width: self.tableView.contentSize.width) do { @@ -228,7 +228,7 @@ class ReportController: FormViewController, MediaBrowserViewControllerDataSource } } - let shareTextAndImage = UIAlertAction(title: "As text and photos", style: .default) { _ in + let shareTextAndImage = UIAlertAction(title: NSLocalizedString("As text and photos", comment: ""), style: .default) { _ in guard let vehicle = self.vehicle else { return } var items: [Any] = [vehicle.reportText()] for photo in vehicle.photos { @@ -245,7 +245,7 @@ class ReportController: FormViewController, MediaBrowserViewControllerDataSource self.present(controller, animated: true) } - let shareLink = UIAlertAction(title: "As link", style: .default) { _ in + let shareLink = UIAlertAction(title: NSLocalizedString("As link", comment: ""), style: .default) { _ in guard let vehicle = self.vehicle else { return } if let jwt = try? JWT.generate(for: vehicle.getNumber()), let url = URL(string: Constants.reportLinkBaseURL + "?token=" + jwt) { @@ -285,11 +285,11 @@ class ReportController: FormViewController, MediaBrowserViewControllerDataSource // MARK: - Copy @IBAction func onCopy(_ sender: UIBarButtonItem) { - let sheet = UIAlertController(title: "Copy to pasteboard", message: nil, preferredStyle: .actionSheet) + let sheet = UIAlertController(title: NSLocalizedString("Copy to pasteboard", comment: ""), message: nil, preferredStyle: .actionSheet) sheet.popoverPresentationController?.barButtonItem = self.copyBarItem - let cancel = UIAlertAction(title: "Cancel", style: .cancel) { _ in sheet.dismiss(animated: true, completion: nil) } - let copyPlateNumber = UIAlertAction(title: "Plate number", style: .default) { _ in UIPasteboard.general.string = self.vehicle?.getNumber() } - let copyVin = UIAlertAction(title: "VIN", style: .default) { _ in UIPasteboard.general.string = self.vehicle?.vin1 } + let cancel = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel) { _ in sheet.dismiss(animated: true, completion: nil) } + let copyPlateNumber = UIAlertAction(title: NSLocalizedString("Plate number", comment: ""), style: .default) { _ in UIPasteboard.general.string = self.vehicle?.getNumber() } + let copyVin = UIAlertAction(title: NSLocalizedString("VIN", comment: ""), style: .default) { _ in UIPasteboard.general.string = self.vehicle?.vin1 } sheet.addAction(copyPlateNumber) sheet.addAction(copyVin) sheet.addAction(cancel) diff --git a/AutoCat/Controllers/SearchController.swift b/AutoCat/Controllers/SearchController.swift index 33c77be..9a5abc5 100644 --- a/AutoCat/Controllers/SearchController.swift +++ b/AutoCat/Controllers/SearchController.swift @@ -24,7 +24,7 @@ class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDe searchController.searchResultsUpdater = self searchController.obscuresBackgroundDuringPresentation = false - searchController.searchBar.placeholder = "Search plate numbers" + searchController.searchBar.placeholder = NSLocalizedString("Search plate numbers", comment: "") navigationItem.searchController = searchController definesPresentationContext = true @@ -42,7 +42,7 @@ class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDe .flatMap { Api.getVehicles(with: $0).catchErrorJustReturn([]) } .observeOn(MainScheduler.instance) .do(onNext: { - self.navigationItem.title = "\($0.count) vehicles found" + self.navigationItem.title = String.localizedStringWithFormat(NSLocalizedString("vehicles found", comment: ""), $0.count) self.showMapButton.isEnabled = $0.count > 0 self.refreshControl.endRefreshing() }) @@ -117,7 +117,7 @@ class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDe func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { let vehicle = self.datasource.item(at: indexPath) - let updateAction = UIContextualAction(style: .normal, title: "Update") { action, view, completion in + let updateAction = UIContextualAction(style: .normal, title: NSLocalizedString("Update", comment: "")) { action, view, completion in self.update(vehicle: vehicle, at: indexPath) completion(true) } @@ -133,11 +133,11 @@ class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDe let vehicle = self.datasource.item(at: indexPath) return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { _ in - let update = UIAction(title: "Update", image: UIImage(systemName: "arrow.2.circlepath")) { action in + let update = UIAction(title: NSLocalizedString("Update", comment: ""), image: UIImage(systemName: "arrow.2.circlepath")) { action in self.update(vehicle: vehicle, at: indexPath) } - return UIMenu(title: "Actions", children: [update]) + return UIMenu(title: NSLocalizedString("Actions", comment: ""), children: [update]) } } diff --git a/AutoCat/Models/Vehicle.swift b/AutoCat/Models/Vehicle.swift index 46aaf29..d8c38a3 100644 --- a/AutoCat/Models/Vehicle.swift +++ b/AutoCat/Models/Vehicle.swift @@ -58,9 +58,16 @@ class VehiclePhoto: Object, Decodable { } } -enum OwnerType: String { +enum OwnerType: String, CustomStringConvertible { case legal case individual + + var description: String { + switch self { + case .legal: return NSLocalizedString("legal", comment: "Owner type") + case .individual: return NSLocalizedString("individual", comment: "Owner type") + } + } } enum SteeringWheelPosition: CustomStringConvertible { diff --git a/AutoCat/Utils/Constants.swift b/AutoCat/Utils/Constants.swift index 34e7169..fd8bd02 100644 --- a/AutoCat/Utils/Constants.swift +++ b/AutoCat/Utils/Constants.swift @@ -3,9 +3,9 @@ import Foundation enum Constants { static var baseUrl: String { #if DEBUG - return "http://127.0.0.1:3000/" + //return "http://127.0.0.1:3000/" //return "http://192.168.1.67:3000/" - //return "https://vps.aliencat.pro:8443/" + return "https://vps.aliencat.pro:8443/" #else return "https://vps.aliencat.pro:8443/" #endif diff --git a/AutoCat/Views/eureka/MultilineLabelRow.swift b/AutoCat/Views/eureka/MultilineLabelRow.swift new file mode 100644 index 0000000..b6bdfd3 --- /dev/null +++ b/AutoCat/Views/eureka/MultilineLabelRow.swift @@ -0,0 +1,55 @@ +import UIKit +import Eureka + +final class MultilineLabelCell: Cell, CellType { + private var title: UILabel! + private var value: UILabel! + + required init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + override func setup() { + super.setup() + + self.title = UILabel() + self.contentView.addSubview(self.title) + self.title.translatesAutoresizingMaskIntoConstraints = false + self.title.font = UIFont.preferredFont(forTextStyle: .caption1) + self.title.leadingAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.leadingAnchor).isActive = true + self.title.trailingAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.trailingAnchor).isActive = true + self.title.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: 8).isActive = true + + self.value = UILabel() + self.contentView.addSubview(self.value) + self.value.translatesAutoresizingMaskIntoConstraints = false + self.value.textColor = .secondaryLabel + self.value.numberOfLines = 0 + self.value.textAlignment = .right + self.value.leadingAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.leadingAnchor).isActive = true + self.value.trailingAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.trailingAnchor).isActive = true + self.value.topAnchor.constraint(equalTo: self.title.bottomAnchor, constant: 8).isActive = true + self.value.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: -8).isActive = true + } + + override func update() { + super.update() + + self.textLabel?.text = nil + self.detailTextLabel?.text = nil + + self.title.text = row.title + self.value.text = row.value + } +} + +final class MultilineLabelRow: Row, RowType { + required init(tag: String?) { + super.init(tag: tag) + cellProvider = CellProvider() + } +} diff --git a/AutoCat/ru.lproj/Localizable.strings b/AutoCat/ru.lproj/Localizable.strings index d3549ea..1f99a17 100644 --- a/AutoCat/ru.lproj/Localizable.strings +++ b/AutoCat/ru.lproj/Localizable.strings @@ -1,60 +1,282 @@ +/* No comment provided by engineer. */ +"Action" = "Действие"; + /* No comment provided by engineer. */ "Actions" = "Действия"; +/* No comment provided by engineer. */ +"Add new audio record" = "Добавить новую голосовую запись"; + +/* No comment provided by engineer. */ +"Add new plate number via audio recording" = "Добавить новый гос. номер с помощью голосовой записи"; + +/* No comment provided by engineer. */ +"Added by" = "Добавлено"; + /* No comment provided by engineer. */ "Alternative order" = "Альтернативный порядок"; +/* Added by */ +"Anyone" = "Кем угодно"; + +/* Added by */ +"Anyone but me" = "Кем угодно кроме меня"; + +/* No comment provided by engineer. */ +"As link" = "Как ссылку"; + +/* No comment provided by engineer. */ +"As one image" = "Как одну картинку"; + +/* No comment provided by engineer. */ +"As text and photos" = "Как текст и фотографии"; + /* No comment provided by engineer. */ "AutoCat Account" = "Аккаунт в АвтоКот"; /* No comment provided by engineer. */ "Beep before record" = "Звуковой сигнал перед записью"; +/* No comment provided by engineer. */ +"Beginning" = "Начала"; + +/* No comment provided by engineer. */ +"Brand" = "Марка"; + +/* No comment provided by engineer. */ +"Brands" = "Марки"; + /* No comment provided by engineer. */ "Cancel" = "Отмена"; +/* No comment provided by engineer. */ +"Category" = "Категория"; + +/* No comment provided by engineer. */ +"Check" = "Проверить"; + +/* No comment provided by engineer. */ +"Clear all filters" = "Очистить все фильтры"; + +/* No comment provided by engineer. */ +"Color" = "Цвет"; + +/* No comment provided by engineer. */ +"Contract restrictions" = "Ограничения лиц, допущенных к управлению"; + +/* No comment provided by engineer. */ +"Contract series and number" = "Серия и номер договора"; + +/* No comment provided by engineer. */ +"Copy to pasteboard" = "Копировать в буфер обмена"; + /* No comment provided by engineer. */ "Default region" = "Регион по умолчанию"; +/* No comment provided by engineer. */ +"Delete" = "Удалить"; + +/* No comment provided by engineer. */ +"Done" = "Готово"; + +/* No comment provided by engineer. */ +"Driver region" = "Регион прописки владельца ТС"; + +/* No comment provided by engineer. */ +"Edit plate number" = "Редактировать гос. номер"; + +/* No comment provided by engineer. */ +"Engine" = "Двигатель"; + +/* No comment provided by engineer. */ +"Events" = "События"; + +/* No comment provided by engineer. */ +"From" = "С"; + +/* No comment provided by engineer. */ +"Fuel type" = "Вид топлива"; + +/* No comment provided by engineer. */ +"General" = "Общее"; + /* No comment provided by engineer. */ "Google" = "Аккаунт Google"; +/* No comment provided by engineer. */ +"History" = "История"; + +/* No comment provided by engineer. */ +"Identifiers" = "Идентификаторы"; + /* No comment provided by engineer. */ "If enabled, app will try to recognize shortened plate numbers (without region) and add default region" = "Если опция включена, приложение попытается распознавать укороченные номера (без региона) и добавлять регион по умолчанию"; +/* Owner type */ +"individual" = "Физ. лицо"; + +/* No comment provided by engineer. */ +"Insurance organization name" = "Наименование страховой организации"; + +/* No comment provided by engineer. */ +"Insurant" = "Страхователь"; + +/* No comment provided by engineer. */ +"Japanese" = "Японское ТС"; + +/* No comment provided by engineer. */ +"Left" = "Левый"; + +/* Owner type */ +"legal" = "Юр. лицо"; + /* No comment provided by engineer. */ "Log In" = "Войти"; +/* No comment provided by engineer. */ +"Main filters" = "Основные фильтры"; + +/* Added by */ +"Me" = "Мной"; + +/* No comment provided by engineer. */ +"Model" = "Модель"; + +/* No comment provided by engineer. */ +"More actions" = "Больше действий"; + +/* No comment provided by engineer. */ +"No" = "Нет"; + +/* No comment provided by engineer. */ +"now" = "Настоящий момент"; + +/* No comment provided by engineer. */ +"Now" = "Настоящий момент"; + +/* No comment provided by engineer. */ +"Number" = "Номер"; + +/* No comment provided by engineer. */ +"OSAGO" = "ОСАГО"; + +/* No comment provided by engineer. */ +"OSAGO contract status" = "Статус договора ОСАГО"; + +/* No comment provided by engineer. */ +"Owner" = "Владелец"; + +/* No comment provided by engineer. */ +"Owner type" = "Тип владельца"; + +/* No comment provided by engineer. */ +"Owners" = "Владельцы"; + +/* No comment provided by engineer. */ +"Photos" = "Фотографии"; + +/* No comment provided by engineer. */ +"Plate number" = "Гос. номер"; + /* No comment provided by engineer. */ "Plate number recognition" = "Распознавание гос. номера"; +/* No comment provided by engineer. */ +"Power (HP)" = "Мощность (л.с.)"; + +/* No comment provided by engineer. */ +"Power (kw)" = "Мощность (кВт)"; + /* No comment provided by engineer. */ "Profile" = "Профиль"; +/* No comment provided by engineer. */ +"PTS" = "ПТС"; + /* No comment provided by engineer. */ "Recognize plate numbers in alternative form. For example 'ЕВА 123 777' instead of 'Е123ВА 777'" = "Распознавать гос. номер в альтернативной форме. Например 'ЕВА 123 777' вместо 'Е123ВА 777'"; +/* No comment provided by engineer. */ +"Recognized text" = "Распознанный текст"; + +/* No comment provided by engineer. */ +"Recording..." = "Запись..."; + +/* No comment provided by engineer. */ +"Regions" = "Регионы"; + /* No comment provided by engineer. */ "Remove" = "Удалить"; +/* No comment provided by engineer. */ +"Right" = "Правый"; + +/* No comment provided by engineer. */ +"Search plate numbers" = "Поиск по гос. номеру"; + +/* Search field placeholder */ +"Search regions" = "Поиск по региону"; + +/* No comment provided by engineer. */ +"Share" = "Поделиться"; + +/* No comment provided by engineer. */ +"Share report" = "Поделиться отчетом"; + /* No comment provided by engineer. */ "Shortened numbers" = "Укороченные номера"; +/* No comment provided by engineer. */ +"Show on map" = "Показать на карте"; + +/* No comment provided by engineer. */ +"Show recognized text" = "Показать распознанный текст"; + /* No comment provided by engineer. */ "Sign Out" = "Выйти"; +/* No comment provided by engineer. */ +"Steering wheel position" = "Положение руля"; + +/* No comment provided by engineer. */ +"STS" = "СТС"; + +/* No comment provided by engineer. */ +"To" = "По"; + /* No comment provided by engineer. */ "Today" = "Сегодня"; /* No comment provided by engineer. */ "Update" = "Обновить"; +/* No comment provided by engineer. */ +"Vehicle region" = "Регион регистрации ТС"; + +/* No comment provided by engineer. */ +"Vehicle usage region" = "Транспортное средство используется в регионе"; + +/* No comment provided by engineer. */ +"VIN" = "VIN"; + +/* No comment provided by engineer. */ +"Volume (cm³)" = "Объем (см³)"; + /* No comment provided by engineer. */ "When enabled, you will hear short sound before starting audio recording. This will only work when audio record is started via Siri" = "Если включено, вы услышите короткий звуковой сигнал перед началом записи аудио."; +/* No comment provided by engineer. */ +"Year" = "Год"; + +/* No comment provided by engineer. */ +"Yes" = "Да"; + /* No comment provided by engineer. */ "Yesterday" = "Вчера"; /* No comment provided by engineer. */ "You are currently signed in with email %@. It will help to gather more data about vehicles." = "Сейчас вы залогинены с почтой %@. Это поможет собирать больше данных для отчета"; +/* No comment provided by engineer. */ +"ZIP (or OKTMO) code" = "Индекс (или ОКТМО)"; +