Compare commits

...

3 Commits

Author SHA1 Message Date
d946dbe50d WIP Fix mentions when writing notes 2023-03-25 22:52:20 -06:00
9590166367 Modify a string 2023-03-25 08:15:24 -06:00
efdecaf118 WIP translations CI 2023-03-25 08:15:23 -06:00
7 changed files with 123 additions and 20 deletions

View File

@@ -0,0 +1,49 @@
name: Export Source Translations
on:
push:
branches:
- master
jobs:
export-source-translations:
name: Update translations branch
runs-on: macos-12
strategy:
matrix:
include:
- xcode: "14.2"
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Run export script
run: |
sh devtools/export-source-translation.sh
- name: Push source translations to Transifex
uses: transifex/cli-action@v2
with:
token: ${{ secrets.TX_TOKEN }}
args: push --branch ''
- name: Remove extraneous /tmp/tx file from running transifex cli that breaks the next pull step
run: |
rm -rf /tmp/tx
- name: Pull translations from Transifex
uses: transifex/cli-action@v2
with:
token: ${{ secrets.TX_TOKEN }}
args: pull --branch ''
- name: Commit translation changes
uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: Update Translations 🤖
branch: translations
create_branch: true
push_options: '--force'
- name: Create Pull Request
uses: repo-sync/pull-request@v2
with:
source_branch: "translations"
destination_branch: "master"
pr_title: "Update Translations 🤖"
if: steps.auto-commit-action.outputs.changes_detected == 'true'

24
.tx/config Executable file
View File

@@ -0,0 +1,24 @@
[main]
host = https://www.transifex.com
lang_map = aa_DJ: aa-DJ, af_ZA: af-ZA, am_ET: am-ET, ar_AA: ar-AA, ar_AE: ar-AE, ar_DZ: ar-DZ, ar_EG: ar-EG, ar_IQ: ar-IQ, ar_JO: ar-JO, ar_LB: ar-LB, ar_SA: ar-SA, ar_SD: ar-SD, ar_SY: ar-SY, as_IN: as-IN, ast_ES: ast-ES, az_AZ: az-AZ, az_IR: az-IR, be_BY: be-BY, bem_ZM: bem-ZM, bg_BG: bg-BG, bg_US: bg-US, bn_BD: bn-BD, bn_IN: bn-IN, bo_CN: bo-CN, bqi_IR: bqi-IR, br_FR: br-FR, bs_BA: bs-BA, bs_BA-SRP: bs-BA-SRP, ca_ES: ca-ES, cs_CZ: cs-CZ, cy_GB: cy-GB, da_DK: da-DK, de_AT: de-AT, de_CH: de-CH, de_DE: de-DE, dz_BT: dz-BT, el_CY: el-CY, el_DE: el-DE, el_GR: el-GR, en_AE: en-AE, en_AL: en-AL, en_AT: en-AT, en_AU: en-AU, en_BA: en-BA, en_BA-SRP: en-BA-SRP, en_BD: en-BD, en_BE: en-BE, en_BG: en-BG, en_BH: en-BH, en_BR: en-BR, en_CA: en-CA, en_CH: en-CH, en_CL: en-CL, en_CO: en-CO, en_CY: en-CY, en_CZ: en-CZ, en_DE: en-DE, en_DK: en-DK, en_EC: en-EC, en_EG: en-EG, en_ES: en-ES, en_FI: en-FI, en_FJ: en-FJ, en_FR: en-FR, en_GB: en-GB, en_GH: en-GH, en_GR: en-GR, en_HK: en-HK, en_HR: en-HR, en_HU: en-HU, en_IE: en-IE, en_IN: en-IN, en_IT: en-IT, en_JP: en-JP, en_KR: en-KR, en_KW: en-KW, en_LK: en-LK, en_MX: en-MX, en_MY: en-MY, en_NG: en-NG, en_NL: en-NL, en_NO: en-NO, en_NZ: en-NZ, en_PE: en-PE, en_PG: en-PG, en_PH: en-PH, en_PK: en-PK, en_PL: en-PL, en_PR: en-PR, en_PT: en-PT, en_QA: en-QA, en_RO: en-RO, en_RS: en-RS, en_SA: en-SA, en_SE: en-SE, en_SG: en-SG, en_SI: en-SI, en_SK: en-SK, en_TT: en-TT, en_UG: en-UG, en_ZA: en-ZA, en_ZM: en-ZM, en_ee: en-ee, en_lt: en-lt, en_lv: en-lv, es_419: es-419, es_AR: es-AR, es_BO: es-BO, es_CL: es-CL, es_CO: es-CO, es_CR: es-CR, es_CU: es-CU, es_DO: es-DO, es_EC: es-EC, es_ES: es-ES, es_GT: es-GT, es_HN: es-HN, es_MX: es-MX, es_NI: es-NI, es_PA: es-PA, es_PE: es-PE, es_PR: es-PR, es_PY: es-PY, es_SA: es-SA, es_SV: es-SV, es_US: es-US, es_UY: es-UY, es_VE: es-VE, et_EE: et-EE, eu_ES: eu-ES, fa_AF: fa-AF, fa_IR: fa-IR, ff_SN: ff-SN, fi_FI: fi-FI, fil_PH: fil-PH, fo_FO: fo-FO, fr_BE: fr-BE, fr_CA: fr-CA, fr_CH: fr-CH, fr_CI: fr-CI, fr_CM: fr-CM, fr_FR: fr-FR, fr_GA: fr-GA, fr_LU: fr-LU, fy_NL: fy-NL, ga_IE: ga-IE, gl_ES: gl-ES, gu_IN: gu-IN, gug_PY: gug-PY, he_IL: he-IL, hi_IN: hi-IN, hr_BA: hr-BA, hr_BA-SRP: hr-BA-SRP, hr_HR: hr-HR, ht_HT: ht-HT, hu_HU: hu-HU, hu_RO: hu-RO, hu_SK: hu-SK, hy_AM: hy-AM, hy_RU: hy-RU, hye_RU: hye-RU, id_ID: id-ID, is_IS: is-IS, it_CH: it-CH, it_IT: it-IT, ja_JP: ja-JP, ka_GE: ka-GE, kk_KZ: kk-KZ, km_KH: km-KH, kn_IN: kn-IN, ko_KR: ko-KR, ks_IN: ks-IN, ku_IQ: ku-IQ, lg_UG: lg-UG, lo_LA: lo-LA, loz_ZM: loz-ZM, lt_LT: lt-LT, lv_LV: lv-LV, mhr_RU: mhr-RU, mk_MK: mk-MK, ml_IN: ml-IN, mn_MN: mn-MN, mr_IN: mr-IN, ms_BN: ms-BN, ms_MY: ms-MY, mt_MT: mt-MT, my_MM: my-MM, nb_NO: nb-NO, ne_NP: ne-NP, nl_BE: nl-BE, nl_NL: nl-NL, nn_NO: nn-NO, no_NO: no-NO, or_IN: or-IN, pa_IN: pa-IN, pa_PK: pa-PK, pl_PL: pl-PL, ps_AF: ps-AF, pt_AO: pt-AO, pt_BR: pt-BR, pt_MZ: pt-MZ, pt_PT: pt-PT, qu_EC: qu-EC, ro_MD: ro-MD, ro_RO: ro-RO, ru_RU: ru-RU, ru_UA: ru-UA, ru_ee: ru-ee, ru_lt: ru-lt, ru_lv: ru-lv, si_LK: si-LK, sk_SK: sk-SK, sl_SI: sl-SI, sq_AL: sq-AL, sr_BA-SRP: sr-BA-SRP, sr_ME: sr-ME, sr_RS: sr-RS, st_ZA: st-ZA, sv_FI: sv-FI, sv_SE: sv-SE, sw_CD: sw-CD, sw_KE: sw-KE, sw_TZ: sw-TZ, sw_UG: sw-UG, ta_IN: ta-IN, ta_LK: ta-LK, te_IN: te-IN, tg_TJ: tg-TJ, th_TH: th-TH, tk_TM: tk-TM, tl_PH: tl-PH, tr_CY: tr-CY, tr_DE: tr-DE, tr_TR: tr-TR, uk_UA: uk-UA, ur_PK: ur-PK, uz_UZ: uz-UZ, vi_VN: vi-VN, wo_SN: wo-SN, yue_CN: yue-CN, zh_CN: zh-CN, zh_HK: zh-HK, zh_SG: zh-SG, zh_TW: zh-TW, zu_ZA: zu-ZA
[o:damus:p:damus-ios-staging:r:infopliststrings]
file_filter = damus/<lang>.lproj/InfoPlist.strings
source_file = damus/en-US.xcloc/Source Contents/damus/en-US.lproj/InfoPlist.strings
type = STRINGS_UTF8
minimum_perc = 0
resource_name = damus..en-US.lproj/InfoPlist.strings (translations)
[o:damus:p:damus-ios-staging:r:localizablestrings]
file_filter = damus/<lang>.lproj/Localizable.strings
source_file = damus/en-US.xcloc/Source Contents/damus/en-US.lproj/Localizable.strings
type = STRINGS_UTF8
minimum_perc = 0
resource_name = damus..en-US.lproj/Localizable.strings (translations)
[o:damus:p:damus-ios-staging:r:localizablestringsdict]
file_filter = damus/<lang>.lproj/Localizable.stringsdict
source_file = damus/en-US.xcloc/Source Contents/damus/en-US.lproj/Localizable.stringsdict
type = STRINGSDICT
minimum_perc = 0
resource_name = damus..en-US.lproj/Localizable.stringsdict (translations)

View File

@@ -20,7 +20,7 @@ struct TranslateView: View {
@State var translated_artifacts: NoteArtifacts? = nil
var TranslateButton: some View {
Button(NSLocalizedString("Translate Note", comment: "Button to translate note from different language.")) {
Button(NSLocalizedString("Translate Note into your language", comment: "Button to translate note from different language.")) {
show_translated_note = true
}
.translate_button_style()

View File

@@ -40,7 +40,7 @@ struct ShareAction: View {
HStack(alignment: .top, spacing: 25) {
ShareActionButton(img: "link", text: NSLocalizedString("Copy Link", comment: "Button to copy link to note"), col: col) {
ShareActionButton(img: "link", text: NSLocalizedString("Copy Link TempChange", comment: "Button to copy link to note"), col: col) {
show_share_action = false
UIPasteboard.general.string = "https://damus.io/" + (bech32_note_id(event.id) ?? event.id)
}

View File

@@ -16,6 +16,7 @@ let POST_PLACEHOLDER = NSLocalizedString("Type your post here...", comment: "Tex
struct PostView: View {
@State var post: NSMutableAttributedString = NSMutableAttributedString()
@State var cursor: Int = 0
@FocusState var focus: Bool
@State var showPrivateKeyWarning: Bool = false
@State var attach_media: Bool = false
@@ -104,7 +105,7 @@ struct PostView: View {
var TextEntry: some View {
ZStack(alignment: .topLeading) {
TextViewWrapper(attributedText: $post)
TextViewWrapper(attributedText: $post, cursor: $cursor)
.focused($focus)
.textInputAutocapitalization(.sentences)
.onChange(of: post) { _ in
@@ -191,7 +192,7 @@ struct PostView: View {
var body: some View {
VStack(alignment: .leading, spacing: 0) {
let searching = get_searching_string(post.string)
let searching = get_searching_string(post.string, cursor: cursor)
TopBar
@@ -204,7 +205,7 @@ struct PostView: View {
// This if-block observes @ for tagging
if let searching {
UserSearch(damus_state: damus_state, search: searching, post: $post)
UserSearch(damus_state: damus_state, search: searching, post: $post, cursor: $cursor)
.frame(maxHeight: .infinity)
} else {
Divider()
@@ -253,8 +254,12 @@ struct PostView: View {
}
}
func get_searching_string(_ post: String) -> String? {
guard let last_word = post.components(separatedBy: .whitespacesAndNewlines).last else {
func get_searching_string(_ post: String, cursor: Int) -> String? {
guard cursor > 0 else {
return nil
}
guard let last_word = post[...post.index(post.startIndex, offsetBy: cursor - 1)].components(separatedBy: .whitespacesAndNewlines).last else {
return nil
}

View File

@@ -22,6 +22,7 @@ struct UserSearch: View {
let search: String
@Binding var post: NSMutableAttributedString
@Binding var cursor: Int
var users: [SearchedUser] {
guard let contacts = damus_state.contacts.event else {
@@ -36,38 +37,57 @@ struct UserSearch: View {
return
}
// Remove all characters after the last '@'
removeCharactersAfterLastAtSymbol()
// Remove all characters after the '@' and before the cursor
let newCursor = removeCharactersAfterAtSymbol()
// Create and append the user tag
let tagAttributedString = createUserTag(for: user, with: pk)
appendUserTag(tagAttributedString)
insertUserTag(tagAttributedString, cursor: newCursor)
cursor = newCursor
}
private func removeCharactersAfterLastAtSymbol() {
while post.string.last != "@" {
post.deleteCharacters(in: NSRange(location: post.length - 1, length: 1))
private func removeCharactersAfterAtSymbol() -> Int {
let newCursor = cursor
guard newCursor > 0 else {
return 0
}
post.deleteCharacters(in: NSRange(location: post.length - 1, length: 1))
var atSymbolOffset = newCursor
while atSymbolOffset > 0 && post.string[post.string.index(post.string.startIndex, offsetBy: atSymbolOffset - 1)] != "@" {
atSymbolOffset -= 1
}
var endOfWordOffset = newCursor
while endOfWordOffset < post.string.count && !post.string[post.string.index(post.string.startIndex, offsetBy: endOfWordOffset)].isWhitespace {
endOfWordOffset += 1
}
post.deleteCharacters(in: NSRange(location: atSymbolOffset - 1, length: endOfWordOffset - atSymbolOffset + 1))
return atSymbolOffset - 1
}
private func createUserTag(for user: SearchedUser, with pk: String) -> NSMutableAttributedString {
let name = Profile.displayName(profile: user.profile, pubkey: pk).username
let tagString = "@\(name)\u{200B} "
let tagString = "\u{200B}@\(name)\u{200B} "
let tagAttributedString = NSMutableAttributedString(string: tagString,
attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 18.0),
NSAttributedString.Key.link: "@\(pk)"])
tagAttributedString.removeAttribute(.link, range: NSRange(location: 0, length: 1))
tagAttributedString.removeAttribute(.link, range: NSRange(location: tagAttributedString.length - 2, length: 2))
tagAttributedString.addAttributes([NSAttributedString.Key.foregroundColor: UIColor.label], range: NSRange(location: 0, length: 1))
tagAttributedString.addAttributes([NSAttributedString.Key.foregroundColor: UIColor.label], range: NSRange(location: tagAttributedString.length - 2, length: 2))
return tagAttributedString
}
private func appendUserTag(_ tagAttributedString: NSMutableAttributedString) {
private func insertUserTag(_ tagAttributedString: NSMutableAttributedString, cursor: Int) {
let mutableString = NSMutableAttributedString()
mutableString.append(post)
mutableString.append(tagAttributedString)
mutableString.insert(tagAttributedString, at: cursor)
post = mutableString
}
@@ -88,9 +108,10 @@ struct UserSearch: View {
struct UserSearch_Previews: PreviewProvider {
static let search: String = "jb55"
@State static var post: NSMutableAttributedString = NSMutableAttributedString(string: "some @jb55")
@State static var cursor: Int = 0
static var previews: some View {
UserSearch(damus_state: test_damus_state(), search: search, post: $post)
UserSearch(damus_state: test_damus_state(), search: search, post: $post, cursor: $cursor)
}
}

View File

@@ -9,6 +9,7 @@ import SwiftUI
struct TextViewWrapper: UIViewRepresentable {
@Binding var attributedText: NSMutableAttributedString
@Binding var cursor: Int
func makeUIView(context: Context) -> UITextView {
let textView = UITextView()
@@ -31,18 +32,21 @@ struct TextViewWrapper: UIViewRepresentable {
}
func makeCoordinator() -> Coordinator {
Coordinator(attributedText: $attributedText)
Coordinator(attributedText: $attributedText, cursor: $cursor)
}
class Coordinator: NSObject, UITextViewDelegate {
@Binding var attributedText: NSMutableAttributedString
@Binding var cursor: Int
init(attributedText: Binding<NSMutableAttributedString>) {
init(attributedText: Binding<NSMutableAttributedString>, cursor: Binding<Int>) {
_attributedText = attributedText
_cursor = cursor
}
func textViewDidChange(_ textView: UITextView) {
attributedText = NSMutableAttributedString(attributedString: textView.attributedText)
cursor = textView.selectedRange.upperBound
}
}
}