Skip to content

Commit 9b5d7e8

Browse files
committed
Version 3.34.4
1 parent 091d810 commit 9b5d7e8

File tree

85 files changed

+2271
-1502
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+2271
-1502
lines changed
522 Bytes
Loading

Documentation/Images/Logo.png

-7.75 KB
Binary file not shown.
31.5 KB
Loading

Documentation/Index.md

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,7 @@ Returns `self` with location name set.
394394
Method is mandatory to create [WebimSession](#webim-session) object.
395395

396396
<h3 id ="set-prechat">Instance method set(prechat:)</h3>
397+
Attention: this method can't be used as is. It requires that client server to support this mechanism!
397398
Sets prechat fields for the session.
398399
`prechat` parameter – `String`-typed prechat fields in JSON format.
399400
Returns `self` with location name set.
@@ -483,6 +484,7 @@ Method is not mandatory to create [WebimSession](#webim-session) object.
483484

484485
<h3 id ="set-multivisitor-section">Instance method set(multivisitorSection:)</h3>
485486

487+
Attention: this method can't be used as is. It requires that client server to support this mechanism!
486488
Sets necesarity to receive remote notifications by different visitors on one device. Without multivisitor section only last visitor can receive remote notifications.
487489
`multivisitorSection` parameter – suffix for device ID. Each visitor has device ID. This parameter can split one device to some virtual devices.
488490
Returns `self` with the functionality activation setting.
@@ -573,7 +575,7 @@ Error that is thrown when trying to create session object with invalid remote no
573575

574576
When client provides custom visitor authorization mechanism, it can be realised by providing custom authorization token which is used instead of visitor fields.
575577
When provided authorization token is generated (or passed to session by client app), `update(providedAuthorizationToken:)` method is called. This method call indicates that client app must send provided authorisation token to its server which is responsible to send it to Webim service.
576-
This mechanism can't be used as is. It requires that client server to support this mecahnism.
578+
This mechanism can't be used as is. It requires that client server to support this mechanism.
577579

578580
<h3 id ="update-provided-authorization-token">update(providedAuthorizationToken:) method</h3>
579581

@@ -679,6 +681,7 @@ Can throw errors of [AccessError](#access-error) type.
679681

680682
<h3 id ="rate-operator-with-id-note-by-rating-rating">rateOperatorWith(id:note:byRating:completionHandler:) method</h3>
681683

684+
Attention: this method can't be used as is. It requires that client server to support this mechanism!
682685
Rates an operator.
683686
To get an ID of the current operator call [getCurrentOperator()](#get-current-operator).
684687
`id` parameter – String-typed ID of the operator to be rated. Optional: if `nil` is passed, current chat operator will be rated.
@@ -689,6 +692,7 @@ Can throw errors of [AccessError](#access-error) type.
689692

690693
<h3 id ="respond-sentry-call">respondSentryCall(id:) method</h3>
691694

695+
Attention: this method can't be used as is. It requires that client server to support this mechanism!
692696
Respond sentry call.
693697
`id` parameter – String-typed ID of redirect to sentry message.
694698
Can throw errors of [AccessError](#access-error) type.
@@ -707,6 +711,7 @@ Can throw errors of [AccessError](#access-error) type.
707711

708712
<h3 id ="start-chat-custom-fields">startChat(customFields:) method</h3>
709713

714+
Attention: this method can't be used as is. It requires that client server to support this mechanism!
710715
Changes [ChatState](#chat-state) to [queue](#queue). Starts chat with custom fields.
711716
Method call is not mandatory. Starts chat with custom fields.
712717
`customFields` paramater – String-typed custom fields in JSON format.
@@ -730,13 +735,15 @@ Can throw errors of [AccessError](#access-error) type.
730735

731736
<h3 id ="start-chat-first-question-custom-fields">startChat(firstQuestion:customFields:) method</h3>
732737

738+
Attention: this method can't be used as is. It requires that client server to support this mechanism!
733739
Starts chat with custom fields and sends first message simultaneously.
734740
Changes [ChatState](#chat-state) to [queue](#queue).
735741
If account settings provide automatic complimentary message it won't be sent before any "startChat" method or first sent message.
736742
Can throw errors of [AccessError](#access-error) type.
737743

738744
<h3 id ="start-chat-department-key-custom-fields">startChat(departmentKey:customFields:) method</h3>
739745

746+
Attention: this method can't be used as is. It requires that client server to support this mechanism!
740747
Starts chat with particular department and custom fields. Department is identified by `departmentKey` parameter (see [getKey()](#get-key) of [Department](#department) protocol)
741748
Changes [ChatState](#chat-state) to [queue](#queue).
742749
In most cases method call is not mandatory, send message or send file methods start chat automatically. But it is mandatory when [VisitSessionState](#visit-session-state) is in [departmentSelection state](#department-selection).
@@ -745,6 +752,7 @@ Can throw errors of [AccessError](#access-error) type.
745752

746753
<h3 id ="start-chat-department-key-first-question-custom-fields">startChat(departmentKey:firstQuestion:customFields:) method</h3>
747754

755+
Attention: this method can't be used as is. It requires that client server to support this mechanism!
748756
Starts chat with particular department and customFields and sends first message simultaneously. Department is identified by `departmentKey` parameter (see [getKey()](#get-key) of [Department](#department) protocol)
749757
Changes [ChatState](#chat-state) to [queue](#queue).
750758
In most cases method call is not mandatory, send message or send file methods start chat automatically. But it is mandatory when [VisitSessionState](#visit-session-state) is in [departmentSelection state](#department-selection).
@@ -764,6 +772,7 @@ Can throw errors of [AccessError](#access-error) type.
764772

765773
<h3 id ="send-message-data">send(message:data:completionHandler:) method</h3>
766774

775+
Attention: this method can't be used as is. It requires that client server to support this mechanism!
767776
Sends a text message.
768777
When calling this method, if there is an active [MessageTracker](#message-tracker) object. [added(message newMessage:,after previousMessage:) method](#added-message-new-message-after-previous-message)) with a message [sending case](#sending) in the status is also called.
769778
`message` parameter – `String`-typed message text.
@@ -774,6 +783,7 @@ Can throw errors of [AccessError](#access-error) type.
774783

775784
<h3 id ="send-message-is-hint-question">send(message:isHintQuestion:) method</h3>
776785

786+
Attention: this method can't be used as is. It requires that client server to support this mechanism!
777787
Sends a text message.
778788
When calling this method, if there is an active [MessageTracker](#message-tracker) object. [added(message newMessage:,after previousMessage:) method](#added-message-new-message-after-previous-message)) with a message [sending case](#sending) in the status is also called.
779789
`message` parameter – `String`-typed message text.
@@ -810,7 +820,8 @@ Can throw errors of [AccessError](#access-error) type.
810820

811821
<h3 id ="update-widget-status">updateWidgetStatus(data:) method</h3>
812822

813-
Update widget status. The change is displayed by the operator..
823+
Attention: this method can't be used as is. It requires that client server to support this mechanism!
824+
Update widget status. The change is displayed by the operator.
814825
`data` parameter – JSON string with new widget status.
815826
Can throw errors of [AccessError](#access-error) type.
816827

@@ -834,7 +845,7 @@ When calling this method, if there is an active [MessageTracker](#message-tracke
834845
Returns true if message can be edited.
835846
Can throw errors of [AccessError](#access-error) type.
836847

837-
<h3 id ="delete-message">edit(message:text:completionHandler:) method</h3>
848+
<h3 id ="delete-message">delete(message:completionHandler:) method</h3>
838849

839850
Deletes a text message.
840851
Before calling this method recommended to find out the possibility of editing the message using [canBeEdited() method](#can-be-edited).
@@ -861,6 +872,7 @@ Can throw errors of [AccessError](#access-error) type.
861872

862873
<h3 id ="set-prechat-fields">set(prechatFields:) method</h3>
863874

875+
Attention: this method can't be used as is. It requires that client server to support this mechanism!
864876
Sends prechat fields to server.
865877
Can throw errors of [AccessError](#access-error) type.
866878

@@ -915,6 +927,7 @@ Sets [UnreadByVisitorTimestampChangeListener](#unread-by-visitor-timestamp-chang
915927

916928
<h2 id ="data-message-completion-handler">DataMessageCompletionHandler protocol</h2>
917929

930+
Attention: this mechanism can't be used as is. It requires that client server to support this mechanism!
918931
Protocol which methods are called after [send(message:data:completionHandler:)](#send-message-data) method is finished. Must be adopted.
919932

920933
<h3 id ="on-success-message-id-data-message-completion-handler">onSuccess(messageID:) method</h3>
@@ -1271,6 +1284,7 @@ First status is not recieved yet or status is not supported by this version of t
12711284

12721285
<h2 id ="data-message-error">DataMessageError enum</h2>
12731286

1287+
Attention: this method can't be used as is. It requires that client server to support this mechanism!
12741288
Error types that could be passed in [onFailure(messageID:error:) method](#on-failure-message-id-error-data-message-completion-handler).
12751289

12761290
<h3 id ="unknown-data-message-error">unknown case</h3>
@@ -1954,10 +1968,12 @@ Returns parameters of this remote notification of array of `String` type.
19541968

19551969
<h3 id ="get-location">getLocation() method</h3>
19561970

1971+
Attention: this method can't be used as is. It requires that client server to support this mechanism!
19571972
Returns location of this remote notification of array of type `String` type.
19581973

19591974
<h3 id ="get-unread-by-visitor-messages-count">getUnreadByVisitorMessagesCount() method</h3>
19601975

1976+
Attention: this method can't be used as is. It requires that client server to support this mechanism!
19611977
Returns unread by visitor messages count of this remote notification of array of `Int` type.
19621978

19631979
[Go to table of contents](#table-of-contents)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// additional keys that should be localized, but not present in code or UI files
2+
3+
// MARK: - Remote notifications
4+
// "P.OA".localized
5+
// "P.OF".localized
6+
// "P.OM".localized
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
//
2+
// ProjectParser.swift
3+
// localizer2
4+
//
5+
// Created by EVGENII Loshchenko on 22.03.2021.
6+
//
7+
8+
import Cocoa
9+
typealias Value = String
10+
typealias CodeKey = String
11+
typealias FileName = String
12+
typealias Locale = String
13+
14+
typealias XibFileData = [FileName: [CodeKey: Value]]
15+
typealias Translations = [Locale: [CodeKey: Value]]
16+
typealias XibTranslations = [Locale: [CodeKey: Value]]
17+
18+
// swiftlint:disable force_unwrapping
19+
class ProjectParser: NSObject {
20+
21+
static func run(_ projectFolderPath: String) {
22+
23+
// get all code keys
24+
var codeKeys = [CodeKey: [FileName]]()
25+
getAllCodeKeys(projectFolderPath: projectFolderPath, codeKeys: &codeKeys)
26+
27+
// get all xib keys
28+
var xibKeysMap = XibFileData()
29+
getAllXibKeys(projectFolderPath: projectFolderPath, codeKeys: &codeKeys, xibKeysMap: &xibKeysMap)
30+
31+
let xibTranslations = loadAllXibTranslations(projectFolderPath: projectFolderPath, xibKeysMap: xibKeysMap)
32+
33+
// read and update translations
34+
let translations = updateAllTranslations(projectFolderPath: projectFolderPath, codeKeys: &codeKeys, xibTranslations: xibTranslations)
35+
36+
// update xib localizations
37+
updateXibTranslations(projectFolderPath: projectFolderPath, xibKeysMap: xibKeysMap, translations: translations, xibTranslations: xibTranslations)
38+
39+
}
40+
41+
static func loadAllXibTranslations(projectFolderPath: String, xibKeysMap: XibFileData) -> XibTranslations {
42+
43+
var xibTranslations = XibTranslations()
44+
45+
let stringsFiles = StringsFileParser.filesList(inFolder: projectFolderPath, withSuffix: ".strings")
46+
for file in stringsFiles {
47+
48+
if !file.hasSuffix("Localizable.strings") && !file.hasSuffix("InfoPlist.strings") {
49+
let locale = file.getLocale()
50+
51+
var locationDictionary = xibTranslations[locale] ?? [String: String]()
52+
let fileName = file.lastPathComponent.nameWithoutExtension()
53+
54+
let text = ShellWrapper.readUTF8File(file)
55+
let localizedValues: [String: String] = StringsFileParser.getKeysFromStringsFile(text: text)
56+
57+
let xibKeyDixtionary = xibKeysMap[fileName] ?? [String: String]()
58+
for key in localizedValues.keys {
59+
locationDictionary[key] = localizedValues[key]
60+
61+
if let xibKey = xibKeyDixtionary[key] {
62+
locationDictionary[xibKey] = localizedValues[key]
63+
}
64+
}
65+
66+
xibTranslations[locale] = locationDictionary
67+
}
68+
}
69+
70+
return xibTranslations
71+
}
72+
73+
static func updateXibTranslations(projectFolderPath: String, xibKeysMap: XibFileData, translations: Translations, xibTranslations: XibTranslations ) {
74+
let stringsFiles = StringsFileParser.filesList(inFolder: projectFolderPath, withSuffix: ".strings")
75+
for filePath in stringsFiles {
76+
if !filePath.hasSuffix("Localizable.strings") && !filePath.hasSuffix("InfoPlist.strings"){
77+
78+
let locale = filePath.getLocale()
79+
let filename = filePath.nameWithoutExtension().lastPathComponent
80+
let localeTranslations = translations[locale] ?? [:]
81+
let localeXibTranslations: [CodeKey: Value] = xibTranslations[locale] ?? [CodeKey: Value]()
82+
let xibKeys = xibKeysMap[filename] ?? [:]
83+
84+
var fileString = ""
85+
for key in xibKeys.keys.sorted() {
86+
var translatedValue = localeTranslations[xibKeys[key]!] ?? ""
87+
if translatedValue.isEmpty {
88+
translatedValue = localeXibTranslations[key] ?? ""
89+
}
90+
if translatedValue.isEmpty {
91+
translatedValue = xibKeys[key] ?? ""
92+
}
93+
fileString += "\"\(key)\" = \"\(translatedValue)\";\n"
94+
}
95+
fileString.writeToFile(filePath)
96+
}
97+
98+
}
99+
}
100+
101+
static func updateAllTranslations(projectFolderPath: String, codeKeys: inout [CodeKey: [FileName]], xibTranslations: XibTranslations) -> Translations {
102+
var baseTranslation = [String: String]()
103+
var translations = Translations()
104+
let stringsFiles = StringsFileParser.filesList(inFolder: projectFolderPath, withSuffix: "Localizable.strings")
105+
for filePath in stringsFiles.reversed() {
106+
107+
print(filePath)
108+
let locale = filePath.getLocale()
109+
110+
let text = ShellWrapper.readUTF8File(filePath)
111+
let localizedValues: [String: String] = StringsFileParser.getKeysFromStringsFile(text: text)
112+
translations[locale] = localizedValues
113+
114+
let localeXibTranslations: [CodeKey: Value] = xibTranslations[locale] ?? [CodeKey: Value]()
115+
116+
var fileString = ""
117+
for key in codeKeys.keys.sorted() {
118+
var translation = localizedValues[key] ?? ""
119+
120+
if translation.isEmpty {
121+
translation = localeXibTranslations[key] ?? ""
122+
}
123+
if translation.isEmpty {
124+
translation = key
125+
}
126+
127+
let comment = codeKeys[key]?.sorted().joined(separator: ",") ?? ""
128+
fileString += "//" + comment + "\n"
129+
fileString += "\"\(key)\" = \"\(translation)\";\n"
130+
131+
if locale == "Base.lproj" {
132+
baseTranslation[key] = translation
133+
}
134+
}
135+
fileString.writeToFile(filePath)
136+
}
137+
return translations
138+
}
139+
140+
static func getAllCodeKeys(projectFolderPath: String, codeKeys: inout [CodeKey: [FileName]]) {
141+
142+
let codeFiles = StringsFileParser.filesList(inFolder: projectFolderPath, withSuffix: ".swift")
143+
for filePath in codeFiles {
144+
145+
let fileName = filePath.lastPathComponent
146+
147+
let keys = StringsFileParser.getCodeKeysFromFile(filePath: filePath)
148+
149+
for key in keys {
150+
addKey(key, fromFile: fileName, to: &codeKeys)
151+
}
152+
}
153+
}
154+
155+
static func addKey(_ key: String, fromFile fileName: String, to codeKeys: inout [CodeKey: [FileName]]) {
156+
if codeKeys[key] == nil {
157+
codeKeys[key] = [String]()
158+
}
159+
if !codeKeys[key]!.contains(fileName) {
160+
codeKeys[key]?.append(fileName)
161+
}
162+
}
163+
164+
static func getAllXibKeys(projectFolderPath: String, codeKeys: inout [CodeKey: [FileName]], xibKeysMap: inout XibFileData) {
165+
let xibFiles = StringsFileParser.filesList(inFolder: projectFolderPath, withSuffix: ".xib")
166+
let storyboardFiles = StringsFileParser.filesList(inFolder: projectFolderPath, withSuffix: ".storyboard")
167+
let UIFiles = xibFiles + storyboardFiles
168+
169+
for file in UIFiles {
170+
171+
let xibKeys = StringsFileParser.getXibKeysFromFile(filePath: file)
172+
173+
for key in xibKeys.keys {
174+
175+
addKey(xibKeys[key]!, fromFile: file.lastPathComponent, to: &codeKeys)
176+
177+
}
178+
179+
xibKeysMap[file.lastPathComponent.nameWithoutExtension()] = xibKeys
180+
}
181+
182+
}
183+
184+
}
185+
// swiftlint:enable force_unwrapping
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//
2+
// ShellWrapper.swift
3+
// localizer2
4+
//
5+
// Created by EVGENII Loshchenko on 22.03.2021.
6+
//
7+
8+
import Cocoa
9+
import Foundation
10+
11+
class ShellWrapper: NSObject {
12+
static let tempStringsFileName = "temp_strings_file.strings"
13+
14+
static func shell(_ args: [String]) {
15+
let task = Process()
16+
task.launchPath = "/usr/bin/env"
17+
task.arguments = args
18+
task.launch()
19+
task.waitUntilExit()
20+
}
21+
22+
static func readUTF8File(_ filePath: String) -> String {
23+
var text = ""
24+
do {
25+
text = try String(contentsOfFile: filePath, encoding: .utf8)
26+
} catch { print("readUTF8File error \(filePath)") }
27+
return text
28+
}
29+
30+
static func readUTF16File(_ filePath: String) -> String {
31+
var text = ""
32+
do {
33+
text = try String(contentsOfFile: filePath, encoding: .utf16)
34+
} catch { print("readUTF16File error \(filePath)") }
35+
return text
36+
}
37+
38+
static func generateStringsFileForXib(_ filePath: String) -> String {
39+
40+
var text = ""
41+
shell(["ibtool", filePath, "--generate-strings-file", tempStringsFileName])
42+
text = readUTF16File(tempStringsFileName)
43+
shell(["rm", tempStringsFileName])
44+
45+
return text
46+
}
47+
48+
}

0 commit comments

Comments
 (0)