Skip to content

Commit

Permalink
Feature/Add hover modifier to see the full directory path and click t…
Browse files Browse the repository at this point in the history
…o copy it (#217)
  • Loading branch information
yllfejziu authored Nov 21, 2024
1 parent 7409b23 commit 562ba6f
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 64 deletions.
116 changes: 59 additions & 57 deletions Lingua-App/Lingua/Lingua/Resources/Localization/Lingua.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,132 +4,134 @@

import Foundation

enum Lingua {
enum App {
public enum Lingua {
public enum App {
/// About Lingua
static let about = tr("App", "about")
public static let about = tr("App", "about")
/// Copyright
static let copyright = tr("App", "copyright")
public static let copyright = tr("App", "copyright")
/// © 2023 Povio Inc.
static let copyrightYear = tr("App", "copyright_year")
public static let copyrightYear = tr("App", "copyright_year")
/// A unified localization management tool for iOS & Android
static let description = tr("App", "description")
public static let description = tr("App", "description")
/// Lingua Settings...
static let settings = tr("App", "settings")
public static let settings = tr("App", "settings")
}

enum General {
public enum General {
/// Choose
static let choose = tr("General", "choose")
public static let choose = tr("General", "choose")
/// Delete
static let delete = tr("General", "delete")
public static let delete = tr("General", "delete")
/// Duplicate
static let duplicate = tr("General", "duplicate")
public static let duplicate = tr("General", "duplicate")
/// Error
static let error = tr("General", "error")
public static let error = tr("General", "error")
/// Save
static let save = tr("General", "save")
public static let save = tr("General", "save")
/// Search
static let search = tr("General", "search")
public static let search = tr("General", "search")
/// Success
static let success = tr("General", "success")
public static let success = tr("General", "success")
/// this
static let this = tr("General", "this")
public static let this = tr("General", "this")
}

enum ProjectForm {
public enum ProjectForm {
/// Here are the steps to enable the Google Sheets API and create an API key:\n\n* Go to the https://console.cloud.google.com/.\n* If you haven't already, create a new project or select an existing one.\n* In the left sidebar, click on "APIs & Services"\n* Click on "+ ENABLE APIS AND SERVICES" at the top of the page.\n* In the search bar, type "Google Sheets API" and select it from the list.\n* Click on "ENABLE" to enable the Google Sheets API for your project.\n* After the API is enabled, go back to the "APIs & Services" > "Credendtials" page.\n* Click on "CREATE CREDENTIALS" at the top of the page.\n* In the dropdown, select "API key"\n* Wait a bit until the key is generated and an information modal with the message API key created will be shown.
static let apiKeyHelp = tr("ProjectForm", "api_key_help")
public static let apiKeyHelp = tr("ProjectForm", "api_key_help")
/// Configuration
static let configurationSection = tr("ProjectForm", "configuration_section")
public static let configurationSection = tr("ProjectForm", "configuration_section")
/// Copied to clipboard!
public static let copiedToClipboard = tr("ProjectForm", "copied_to_clipboard")
/// Add section
static let filteringAddSectionButtonTitle = tr("ProjectForm", "filtering_add_section_button_title")
public static let filteringAddSectionButtonTitle = tr("ProjectForm", "filtering_add_section_button_title")
/// Add the sections that you want to include into the project, otherwise if it is disabled all the sections will be included
static let filteringSectionDescription = tr("ProjectForm", "filtering_section_description")
public static let filteringSectionDescription = tr("ProjectForm", "filtering_section_description")
/// Enter a section
static let filteringSectionTextfieldPlaceholder = tr("ProjectForm", "filtering_section_textfield_placeholder")
public static let filteringSectionTextfieldPlaceholder = tr("ProjectForm", "filtering_section_textfield_placeholder")
/// Enable sections filtering
static let filteringSectionTitle = tr("ProjectForm", "filtering_section_title")
public static let filteringSectionTitle = tr("ProjectForm", "filtering_section_title")
/// Info
static let infoHeader = tr("ProjectForm", "info_header")
public static let infoHeader = tr("ProjectForm", "info_header")
/// API Key *
static let inputApiKey = tr("ProjectForm", "input_api_key")
public static let inputApiKey = tr("ProjectForm", "input_api_key")
/// Choose Directory
static let inputDirectoryButton = tr("ProjectForm", "input_directory_button")
public static let inputDirectoryButton = tr("ProjectForm", "input_directory_button")
/// Output directory *
static let inputDirectoryOutput = tr("ProjectForm", "input_directory_output")
public static let inputDirectoryOutput = tr("ProjectForm", "input_directory_output")
/// Name *
static let inputProjectName = tr("ProjectForm", "input_project_name")
public static let inputProjectName = tr("ProjectForm", "input_project_name")
/// Sheet ID *
static let inputSheetId = tr("ProjectForm", "input_sheet_id")
public static let inputSheetId = tr("ProjectForm", "input_sheet_id")
/// After you "Localize", you have to Add files to "%@"... in Xcode, if they are not added already.\n\nNOTE: If you are using Xcode 16 and have structured your project using 'Folders' instead of 'Groups', this step is not necessary.
static func iosLocalizationInfoMessage(_ param1: String) -> String {
public static func iosLocalizationInfoMessage(_ param1: String) -> String {
return tr("ProjectForm", "ios_localization_info_message", param1)
}
/// Last localized: %@
static func lastLocalizedSubtitle(_ param1: String) -> String {
public static func lastLocalizedSubtitle(_ param1: String) -> String {
return tr("ProjectForm", "last_localized_subtitle", param1)
}
/// Lingua.swift Directory *
static let linguaSwiftOutputDirectory = tr("ProjectForm", "lingua_swift_output_directory")
public static let linguaSwiftOutputDirectory = tr("ProjectForm", "lingua_swift_output_directory")
/// This should be the directory where you want to store the generated Lingua.swift file
static let linguaSwiftOutputDirectoryHelp = tr("ProjectForm", "lingua_swift_output_directory_help")
public static let linguaSwiftOutputDirectoryHelp = tr("ProjectForm", "lingua_swift_output_directory_help")
/// Localize
static let localizeButton = tr("ProjectForm", "localize_button")
public static let localizeButton = tr("ProjectForm", "localize_button")
/// The .lproj directory should be the directory where .strings files are saved.\nIt serves as base language directory from where the Lingua.swift file will be created
static let lprojDirectoryHelp = tr("ProjectForm", "lproj_directory_help")
public static let lprojDirectoryHelp = tr("ProjectForm", "lproj_directory_help")
/// The output directory property should be the path where you want the tool to create localization files.\n\n* For iOS it can be any directory on your project. After you run the command, for the first time, \n you have to Add files to 'YourProject' in Xcode.\n\n* For Android, since the translation are placed in a specific project directory,\n the output directory it should look something like this: path/YourProject/app/src/main/res
static let outputDirectoryHelp = tr("ProjectForm", "output_directory_help")
public static let outputDirectoryHelp = tr("ProjectForm", "output_directory_help")
/// Platform *
static let platformPickerTitle = tr("ProjectForm", "platform_picker_title")
public static let platformPickerTitle = tr("ProjectForm", "platform_picker_title")
/// * Make a copy of the [Sheet Template](https://docs.google.com/spreadsheets/d/1Cnqy4gZqh9pGcTF_0jb8QGOnysejZ8dVfSj8dgX4kzM) from menu "File > Make a copy"\n* Ensure that the Google Sheet you're trying to access has its sharing settings configured to allow access to anyone with the link.\n You can do this by clicking on "Share" in the upper right corner of the Google Sheet and selecting "Anyone with the link."\n* The sheet id can easly be accessed from the url after you have create a copy of the document tamplate.\n\nExample:\n\nhttps://docs.google.com/spreadsheets/d/ 1GpaPpO4JMleZPd8paSW4qPBQxjImm2xD8yJhvZOP-8w
static let sheetIdHelp = tr("ProjectForm", "sheet_id_help")
public static let sheetIdHelp = tr("ProjectForm", "sheet_id_help")
/// .lproj Directory *
static let stringsDirectory = tr("ProjectForm", "strings_directory")
public static let stringsDirectory = tr("ProjectForm", "strings_directory")
/// Since iOS does not have a built in feature to access the localization safely, we have made this possible using Lingua tool. Below you have to provide the path where the Swift file you want to be created. With that the tool will create Lingua.swift with an enumeration to easily access localizations in your app.
static let swiftCodeDescription = tr("ProjectForm", "swift_code_description")
public static let swiftCodeDescription = tr("ProjectForm", "swift_code_description")
/// iOS Swift Code Settings
static let swiftCodeSection = tr("ProjectForm", "swift_code_section")
public static let swiftCodeSection = tr("ProjectForm", "swift_code_section")
/// Generate Swift Code
static let swiftCodeToggleTitle = tr("ProjectForm", "swift_code_toggle_title")
public static let swiftCodeToggleTitle = tr("ProjectForm", "swift_code_toggle_title")
}

enum ProjectMenu {
public enum ProjectMenu {
/// Delete
static let delete = tr("ProjectMenu", "delete")
public static let delete = tr("ProjectMenu", "delete")
/// Duplicate
static let duplicate = tr("ProjectMenu", "duplicate")
public static let duplicate = tr("ProjectMenu", "duplicate")
/// Localize
static let localize = tr("ProjectMenu", "localize")
public static let localize = tr("ProjectMenu", "localize")
/// New
static let new = tr("ProjectMenu", "new")
public static let new = tr("ProjectMenu", "new")
/// Project
static let title = tr("ProjectMenu", "title")
public static let title = tr("ProjectMenu", "title")
}

enum Projects {
public enum Projects {
/// %@ copy
static func copyProject(_ param1: String) -> String {
public static func copyProject(_ param1: String) -> String {
return tr("Projects", "copy_project", param1)
}
/// Are you sure you want to delete "%@" project?
static func deleteAlertMessage(_ param1: String) -> String {
public static func deleteAlertMessage(_ param1: String) -> String {
return tr("Projects", "delete_alert_message", param1)
}
/// Confirmation
static let deleteAlertTitle = tr("Projects", "delete_alert_title")
public static let deleteAlertTitle = tr("Projects", "delete_alert_title")
/// Projects
static let listSectionHeader = tr("Projects", "list_section_header")
public static let listSectionHeader = tr("Projects", "list_section_header")
/// "%@" has been successfully localized.
static func localizedMessage(_ param1: String) -> String {
public static func localizedMessage(_ param1: String) -> String {
return tr("Projects", "localized_message", param1)
}
/// Localizing...
static let localizing = tr("Projects", "localizing")
public static let localizing = tr("Projects", "localizing")
/// New project
static let newProject = tr("Projects", "new_project")
public static let newProject = tr("Projects", "new_project")
/// Select a project or add a new one.
static let placeholder = tr("Projects", "placeholder")
public static let placeholder = tr("Projects", "placeholder")
}

private static func tr(_ table: String, _ key: String, _ args: CVarArg...) -> String {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,4 @@ It serves as base language directory from where the Lingua.swift file will be cr
"filtering_section_description" = "Add the sections that you want to include into the project, otherwise if it is disabled all the sections will be included";
"filtering_section_textfield_placeholder" = "Enter a section";
"filtering_add_section_button_title" = "Add section";
"copied_to_clipboard" = "Copied to clipboard!";
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ struct ProjectFormView: View {
@State private var outputPathValid = false
@State private var stringsDirectoryValid = false
@State private var outputSwiftCodeFileDirectoryValid = false

@State private var copied = false

var onSave: ((Project) -> Void)? = nil
var onDelete: ((Project) -> Void)? = nil
var onLocalize: ((Project) -> Void)? = nil
Expand Down Expand Up @@ -52,6 +53,18 @@ struct ProjectFormView: View {
deleteButton(for: viewModel.project).padding()
}
.padding()
.overlay {
Text(Lingua.ProjectForm.copiedToClipboard)
.padding(8)
.background(
Color.black
.opacity(0.4)
)
.clipShape(RoundedRectangle(cornerRadius: 6))
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
.padding(.top, 6)
.shouldAddView(copied)
}
}
}

Expand All @@ -65,7 +78,7 @@ private extension ProjectFormView {
Text(type.title)
.tag(type)
}
}.padding(.leading, 8)
}

ValidatingTextField(
title: Lingua.ProjectForm.inputProjectName,
Expand Down Expand Up @@ -104,7 +117,8 @@ private extension ProjectFormView {
bookmarkDataKey: viewModel.project.bookmarkDataForDirectoryPath,
directoryPath: $viewModel.project.directoryPath,
isValid: $outputPathValid,
onDirectorySelected: updateDirectoryPaths
onDirectorySelected: updateDirectoryPaths,
onDirectoryCopied: showCopiedMessage
)
}) {
Text(.init(Lingua.ProjectForm.outputDirectoryHelp))
Expand Down Expand Up @@ -135,7 +149,8 @@ private extension ProjectFormView {
title: Lingua.ProjectForm.stringsDirectory,
bookmarkDataKey: viewModel.project.bookmarkDataForStringsDirectory,
directoryPath: $viewModel.project.swiftCode.stringsDirectory,
isValid: $stringsDirectoryValid
isValid: $stringsDirectoryValid,
onDirectoryCopied: showCopiedMessage
)
}) {
Text(.init(Lingua.ProjectForm.lprojDirectoryHelp))
Expand All @@ -147,7 +162,8 @@ private extension ProjectFormView {
title: Lingua.ProjectForm.linguaSwiftOutputDirectory,
bookmarkDataKey: viewModel.project.bookmarkDataForOutputSwiftCodeFileDirectory ,
directoryPath: $viewModel.project.swiftCode.outputSwiftCodeFileDirectory,
isValid: $outputSwiftCodeFileDirectoryValid
isValid: $outputSwiftCodeFileDirectoryValid,
onDirectoryCopied: showCopiedMessage
)
}) {
Text(.init(Lingua.ProjectForm.linguaSwiftOutputDirectoryHelp))
Expand Down Expand Up @@ -242,4 +258,15 @@ private extension ProjectFormView {
try? firstLprojFullURL.saveBookmarkData(forKey: viewModel.project.bookmarkDataForStringsDirectory)
}
}

func showCopiedMessage() {
withAnimation {
copied = true
}
DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) {
withAnimation {
self.copied = false
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,45 @@ struct DirectoryInputField: View {

@Binding var directoryPath: String
@Binding var isValid: Bool

@State private var isHovered = false

var onDirectorySelected: ((String) -> Void)? = nil

var onDirectoryCopied: (() -> Void)? = nil

var body: some View {
HStack {
ValidatingTextField(title: title, validation: RequiredRule(), isDisabled: true, text: $directoryPath, isValid: $isValid)
.overlay {
// Transparent overlay to capture tap gesture
Color.clear
.contentShape(Rectangle())
.onTapGesture {
copyPathToClipboard()
onDirectoryCopied?()
}
}
.onHover { hovering in
isHovered = hovering
}
Button(Lingua.ProjectForm.inputDirectoryButton) {
chooseDirectory()
}
}
.padding(.vertical, 5)
.background(
GeometryReader { geometry in
Text(directoryPath)
.font(.caption)
.padding(8)
.background(Color.black.opacity(0.8))
.foregroundColor(.white)
.cornerRadius(8)
.frame(width: geometry.size.width, alignment: .center)
.offset(y: -geometry.size.height)
.transition(.opacity)
.shouldAddView(isHovered)
}
)
}
}

Expand Down Expand Up @@ -53,4 +81,9 @@ private extension DirectoryInputField {
directoryPath = ""
}
}

private func copyPathToClipboard() {
NSPasteboard.general.clearContents()
NSPasteboard.general.setString(directoryPath, forType: .string)
}
}

0 comments on commit 562ba6f

Please sign in to comment.