From fe2f10138a3291ccf395c9b6393720a12bb1d2bf Mon Sep 17 00:00:00 2001 From: abraunegg Date: Sat, 29 May 2021 09:11:25 +1000 Subject: [PATCH 01/15] WIP: Implement international language support * Initial start on implementing international language support --- Makefile.in | 3 +- contrib/translations/EN-US.json | 117 +++++++++ src/config.d | 67 ++++-- src/main.d | 255 ++++++++++++++------ src/sync.d | 414 ++++++++++++++++++++------------ src/translations.d | 236 ++++++++++++++++++ 6 files changed, 843 insertions(+), 249 deletions(-) create mode 100644 contrib/translations/EN-US.json create mode 100644 src/translations.d diff --git a/Makefile.in b/Makefile.in index 5f6008fb6..f88cce128 100644 --- a/Makefile.in +++ b/Makefile.in @@ -78,7 +78,8 @@ SOURCES = \ src/sync.d \ src/upload.d \ src/util.d \ - src/progress.d + src/progress.d \ + src/translations.d ifeq ($(NOTIFICATIONS),yes) SOURCES += src/notifications/notify.d src/notifications/dnotify.d diff --git a/contrib/translations/EN-US.json b/contrib/translations/EN-US.json new file mode 100644 index 000000000..03204b3c4 --- /dev/null +++ b/contrib/translations/EN-US.json @@ -0,0 +1,117 @@ +{ + "language": "EN-US", + "list": [ + "No user or system config file found, using application defaults", + "System configuration file successfully loaded", + "System configuration file has errors - please check your configuration", + "Configuration file successfully loaded", + "Configuration file has errors - please check your configuration", + "Using config option for Global Azure AD Endpoints", + "Using config option for Azure AD for US Government Endpoints", + "Using config option for Azure AD for US Government Endpoints (DOD)", + "Using config option for Azure AD Germany", + "Using config option for Azure AD China operated by 21Vianet", + "Unknown Azure AD Endpoint - using Global Azure AD Endpoints", + "Unknown key in config file: ", + "Malformed config line: ", + "config file has been updated, checking if --resync needed", + "An application configuration change has been detected where a --resync is required", + "DRY-RUN Configured. Output below shows what 'would' have occurred", + "Using logfile dir: ", + "Database schema changed, resync needed", + "Deleting the saved status ...", + "ERROR: Unable to reach Microsoft OneDrive API service, unable to initialize application", + "ERROR: Unable to reach Microsoft OneDrive API service at this point in time, re-trying network tests", + "Internet connectivity to Microsoft OneDrive service has been restored", + "ERROR: The OneDrive Linux Client was unable to reconnect to the Microsoft OneDrive service after 10000 attempts lasting over 1.2 years!", + "Initializing the OneDrive API ...", + "Could not initialize the OneDrive API", + "Application has been successfully authorized, however no additional command switches were provided", + "Please use 'onedrive --help' for further assistance in regards to running this application", + "Application has not been successfully authorized. Please check your URI response entry and try again", + "ERROR: --synchronize or --monitor switches missing from your command line input. Please add one (not both) of these switches to your command line", + "No OneDrive sync will be performed without one of these two arguments being present", + "ERROR: --synchronize and --monitor cannot be used together", + "Opening the item database ...", + "ERROR: Invalid 'User|Group|Other' permissions set within config file. Please check your config file.", + "All operations will be performed in: ", + "ERROR: Unable to create local OneDrive syncDir - ", + "ERROR: Invalid skip_file entry '.*' detected", + "Initializing the Synchronization Engine ...", + "Cannot connect to Microsoft OneDrive Service - Network Connection Issue", + "WARNING: Application has been configured to bypass local data preservation in the event of file conflict", + "WARNING: Local data loss MAY occur in this scenario", + "ERROR: .nosync file found. Aborting synchronization process to safeguard data", + "ERROR: Unsupported account type for listing OneDrive Business Shared Folders", + "ERROR: Unsupported account type for syncing OneDrive Business Shared Folders", + "WARNING: The requested path for --single-directory does not exist locally. Creating requested path within: ", + "Initializing monitor ...", + "OneDrive monitor interval (seconds): ", + "[M] Skipping watching path - .folder found & --skip-dot-files enabled: ", + "[M] Directory created: ", + "Offline, cannot create remote directory!", + "Cannot create remote directory: ", + "[M] File changed: ", + "Offline, cannot upload changed item!", + "Cannot upload file changes/creation: ", + "[M] Item deleted: ", + "Offline, cannot delete item!", + "Item cannot be deleted from OneDrive because it was not found in the local database", + "Cannot delete remote item: ", + "[M] Item moved: ", + "Offline, cannot move item!", + "Cannot move item: ", + "ERROR: ", + "ERROR: The following inotify error was generated: ", + "Starting a sync with OneDrive", + "Sync with OneDrive is complete", + "Persistent connection errors, reinitializing connection", + "Authorization token invalid, use --logout to authorize the client again", + "Syncing changes from this selected path: ", + "Syncing changes from selected local path only - NOT syncing data changes from OneDrive ...", + "Syncing changes from selected local path first before downloading changes from OneDrive ...", + "Syncing changes from selected OneDrive path ...", + "Syncing changes from local path only - NOT syncing data changes from OneDrive ...", + "Syncing changes from local path first before downloading changes from OneDrive ...", + "Syncing changes from OneDrive ...", + "Giving up on sync after three attempts: ", + "Retry sync count: ", + " Got termination signal, shutting down DB connection", + "Syncing changes from OneDrive only - NOT syncing local data changes to OneDrive ...", + "The file does not have any hash", + "ERROR: Check your 'drive_id' entry in your configuration file as it may be incorrect", + "ERROR: Check your configuration as your refresh_token may be empty or invalid. You may need to issue a --logout and re-authorize this client.", + "ERROR: OneDrive account currently has zero space available. Please free up some space online.", + "WARNING: OneDrive quota information is being restricted or providing a zero value. Please fix by speaking to your OneDrive / Office 365 Administrator.", + "ERROR: OneDrive quota information is missing. Potentially your OneDrive account currently has zero space available. Please free up some space online.", + "ERROR: OneDrive quota information is being restricted. Please fix by speaking to your OneDrive / Office 365 Administrator.", + "Application version: ", + "Account Type: ", + "Default Drive ID: ", + "Default Root ID: ", + "Remaining Free Space: ", + "Continuing the upload session ...", + "Removing local file as --upload-only & --remove-source-files configured", + "ERROR: File failed to upload. Increase logging verbosity to determine why.", + "Skipping item - excluded by skip_dir config: ", + "Syncing this OneDrive Personal Shared Folder: ", + "Attempting to sync OneDrive Business Shared Folders", + "Syncing this OneDrive Business Shared Folder: ", + "OneDrive Business Shared Folder - Shared By: ", + "WARNING: Skipping shared folder due to existing name conflict: ", + "WARNING: Skipping changes of Path ID: ", + "WARNING: To sync this shared folder, this shared folder needs to be renamed", + "WARNING: Conflict Shared By: ", + "WARNING: Not syncing this OneDrive Business Shared File: ", + "OneDrive Business Shared File - Shared By: ", + "WARNING: Not syncing this OneDrive Business Shared item: ", + "ERROR: onedrive.getSharedWithMe call returned an invalid JSON Object", + "Getting path details from OneDrive ...", + "ERROR: The requested single directory to sync was not found on OneDrive", + "Fetching details for OneDrive Root", + "OneDrive Root does not exist in the database. We need to add it.", + "Added OneDrive Root to the local database", + "OneDrive Root exists in the database", + "ERROR: Unable to query OneDrive for account details", + ] +} \ No newline at end of file diff --git a/src/config.d b/src/config.d index 4b13c4e69..54d5f628e 100644 --- a/src/config.d +++ b/src/config.d @@ -2,6 +2,7 @@ import core.stdc.stdlib: EXIT_SUCCESS, EXIT_FAILURE, exit; import std.file, std.string, std.regex, std.stdio, std.process, std.algorithm.searching, std.getopt, std.conv, std.path; import std.algorithm.sorting: sort; import selective; +import translations; static import log; final class Config @@ -118,8 +119,10 @@ final class Config longValues["sync_file_permissions"] = defaultFilePermissionMode; // Configure download / upload rate limits longValues["rate_limit"] = 0; + // What language will be used for application output messaging - default EN-AU + stringValues["language_identifier"] = "EN-AU"; - // DEVELOPER OPTIONS + // DEVELOPER OPTIONS // display_memory = true | false // - It may be desirable to display the memory usage of the application to assist with diagnosing memory issues with the application // - This is especially beneficial when debugging or performing memory tests with Valgrind @@ -200,9 +203,12 @@ final class Config configDirName.setAttributes(returnRequiredDirectoryPermisions()); } - // configDirName has a trailing / - log.vlog("Using 'user' Config Dir: ", configDirName); - log.vlog("Using 'system' Config Dir: ", systemConfigDirName); + // Initialise the default language output as early as possible + translations.initialize(); + + // What has been determined as the 'user' and 'system' config directories? + log.vdebug("Using this 'user' Config Dir: ", configDirName); + log.vdebug("Using this 'system' Config Dir: ", systemConfigDirName); // Update application set variables based on configDirName refreshTokenFilePath = buildNormalizedPath(configDirName ~ "/refresh_token"); @@ -235,18 +241,25 @@ final class Config // Is there a system configuration file? if (!exists(systemConfigFilePath)) { // 'system' configuration file does not exist - log.vlog("No user or system config file found, using application defaults"); + // "No user or system config file found, using application defaults" + log.vlog(provideLanguageTranslation(getValueString("language_identifier"),1)); return true; } else { // 'system' configuration file exists // can we load the configuration file without error? if (load(systemConfigFilePath)) { // configuration file loaded without error - log.log("System configuration file successfully loaded"); + // Load the User Language File if this was updated from the default + if (getValueString("language_identifier") != "EN-AU") { + translations.initializeUserConfiguredLanguageTranslations(getValueString("language_identifier")); + } + // "System configuration file successfully loaded" + log.log(provideLanguageTranslation(getValueString("language_identifier"),2)); return true; } else { // there was a problem loading the configuration file - log.log("System configuration file has errors - please check your configuration"); + // "System configuration file has errors - please check your configuration" + log.log(provideLanguageTranslation(getValueString("language_identifier"),3)); return false; } } @@ -255,11 +268,17 @@ final class Config // can we load the configuration file without error? if (load(userConfigFilePath)) { // configuration file loaded without error - log.log("Configuration file successfully loaded"); + // Load the User Language File if this was updated from the default + if (getValueString("language_identifier") != "EN-AU") { + translations.initializeUserConfiguredLanguageTranslations(getValueString("language_identifier")); + } + // "Configuration file successfully loaded" + log.log(provideLanguageTranslation(getValueString("language_identifier"),4)); return true; } else { // there was a problem loading the configuration file - log.log("Configuration file has errors - please check your configuration"); + // "Configuration file has errors - please check your configuration", + log.log(provideLanguageTranslation(getValueString("language_identifier"),5)); return false; } } @@ -454,12 +473,14 @@ final class Config } } catch (GetOptException e) { log.error(e.msg); - log.error("Try 'onedrive -h' for more information"); + // "Please use 'onedrive --help' for further assistance in regards to running this application" + log.error(provideLanguageTranslation(getValueString("language_identifier"),27)); exit(EXIT_FAILURE); } catch (Exception e) { // error log.error(e.msg); - log.error("Try 'onedrive -h' for more information"); + // "Please use 'onedrive --help' for further assistance in regards to running this application" + log.error(provideLanguageTranslation(getValueString("language_identifier"),27)); exit(EXIT_FAILURE); } } @@ -587,23 +608,29 @@ final class Config string azureConfigValue = c.front.dup; switch(azureConfigValue) { case "": - log.log("Using config option for Global Azure AD Endpoints"); + // "Using config option for Global Azure AD Endpoints" + log.log(provideLanguageTranslation(getValueString("language_identifier"),6)); break; case "USL4": - log.log("Using config option for Azure AD for US Government Endpoints"); + // "Using config option for Azure AD for US Government Endpoints" + log.log(provideLanguageTranslation(getValueString("language_identifier"),7)); break; case "USL5": - log.log("Using config option for Azure AD for US Government Endpoints (DOD)"); + // "Using config option for Azure AD for US Government Endpoints (DOD)" + log.log(provideLanguageTranslation(getValueString("language_identifier"),8)); break; case "DE": - log.log("Using config option for Azure AD Germany"); + // "Using config option for Azure AD Germany" + log.log(provideLanguageTranslation(getValueString("language_identifier"),9)); break; case "CN": - log.log("Using config option for Azure AD China operated by 21Vianet"); + // "Using config option for Azure AD China operated by 21Vianet" + log.log(provideLanguageTranslation(getValueString("language_identifier"),10)); break; // Default - all other entries default: - log.log("Unknown Azure AD Endpoint - using Global Azure AD Endpoints"); + // "Unknown Azure AD Endpoint - using Global Azure AD Endpoints" + log.log(provideLanguageTranslation(getValueString("language_identifier"),11)); } } } else { @@ -612,13 +639,15 @@ final class Config c.popFront(); setValueLong(key, to!long(c.front.dup)); } else { - log.log("Unknown key in config file: ", key); + // "Unknown key in config file: " + log.log(provideLanguageTranslation(getValueString("language_identifier"),12), key); return false; } } } } else { - log.log("Malformed config line: ", lineBuffer); + // "Malformed config line: " + log.log(provideLanguageTranslation(getValueString("language_identifier"),13), lineBuffer); return false; } } diff --git a/src/main.d b/src/main.d index 3584a0229..08746732a 100644 --- a/src/main.d +++ b/src/main.d @@ -1,7 +1,7 @@ import core.stdc.stdlib: EXIT_SUCCESS, EXIT_FAILURE, exit; import core.memory, core.time, core.thread; import std.getopt, std.file, std.path, std.process, std.stdio, std.conv, std.algorithm.searching, std.string, std.regex; -import config, itemdb, monitor, onedrive, selective, sync, util; +import config, itemdb, monitor, onedrive, selective, sync, util, translations; import std.net.curl: CurlException; import core.stdc.signal; import std.traits; @@ -11,11 +11,13 @@ OneDriveApi oneDrive; ItemDatabase itemDb; const int EXIT_UNAUTHORIZED = 3; - enum MONITOR_LOG_SILENT = 2; enum MONITOR_LOG_QUIET = 1; enum LOG_NORMAL = 0; +// Language Identifier +shared string languageIdentifier = ""; + int main(string[] args) { // Disable buffering on stdout @@ -108,6 +110,8 @@ int main(string[] args) } // read in application options as passed in + // EN only error message + string helpMessage = "Please use 'onedrive --help' for further assistance in regards to running this application"; try { bool printVersion = false; auto opt = getopt( @@ -131,23 +135,35 @@ int main(string[] args) } catch (GetOptException e) { // option errors log.error(e.msg); - log.error("Try 'onedrive -h' for more information"); + // Language default for this message + log.error(helpMessage); return EXIT_FAILURE; } catch (Exception e) { // generic error log.error(e.msg); - log.error("Try 'onedrive -h' for more information"); + // Language default for this message + log.error(helpMessage); return EXIT_FAILURE; } // load configuration file if available auto cfg = new config.Config(confdirOption); + // initialise config options if (!cfg.initialize()) { // There was an error loading the configuration // Error message already printed return EXIT_FAILURE; } + // --verbose --verbose used .. override any language setting to force EN-AU + if (cfg.getValueLong("verbose") >= 2) { + log.vdebug("Force application language to EN-AU due to debug operation"); + cfg.setValueString("language_identifier", "EN-AU"); + } + // Use the configured application language + languageIdentifier = cfg.getValueString("language_identifier"); + log.vlog("Application Language set to: ", languageIdentifier); + // set memory display displayMemoryUsage = cfg.getValueBool("display_memory"); @@ -235,7 +251,8 @@ int main(string[] args) // Was config file updated between last execution ang this execution? if (currentConfigHash != previousConfigHash) { // config file was updated, however we only want to trigger a --resync requirement if sync_dir, skip_dir, skip_file or drive_id was modified - log.log("config file has been updated, checking if --resync needed"); + // "config file has been updated, checking if --resync needed" + log.log(provideLanguageTranslation(languageIdentifier,14)); if (exists(configBackupFile)) { // check backup config what has changed for these configuration options if anything // # sync_dir = "~/OneDrive" @@ -300,10 +317,10 @@ int main(string[] args) if (!cfg.getValueBool("dry_run")) { // we are not in a dry-run scenario // update config hash - log.vdebug("updating config hash as it is out of date"); + log.vdebug("Updating config hash as it is out of date"); std.file.write(configHashFile, computeQuickXorHash(configFilePath)); // create backup copy of current config file - log.vdebug("making backup of config file as it is out of date"); + log.vdebug("Making backup of config file as it is out of date"); std.file.copy(configFilePath, configBackupFile); } } @@ -360,7 +377,8 @@ int main(string[] args) // not testing configuration changes if (!cfg.getValueBool("resync")) { // --resync not issued, fail fast - log.error("An application configuration change has been detected where a --resync is required"); + // "An application configuration change has been detected where a --resync is required" + log.error(provideLanguageTranslation(languageIdentifier,15)); return EXIT_FAILURE; } else { // --resync issued, update hashes of config files if they exist @@ -368,20 +386,20 @@ int main(string[] args) // not doing a dry run, update hash files if config & sync_list exist if (exists(configFilePath)) { // update hash - log.vdebug("updating config hash as --resync issued"); + log.vdebug("Updating config hash as --resync issued"); std.file.write(configHashFile, computeQuickXorHash(configFilePath)); // create backup copy of current config file - log.vdebug("making backup of config file as --resync issued"); + log.vdebug("Making backup of config file as --resync issued"); std.file.copy(configFilePath, configBackupFile); } if (exists(syncListFilePath)) { // update sync_list hash - log.vdebug("updating sync_list hash as --resync issued"); + log.vdebug("Updating sync_list hash as --resync issued"); std.file.write(syncListHashFile, computeQuickXorHash(syncListFilePath)); } if (exists(businessSharedFolderFilePath)) { // update business_shared_folders hash - log.vdebug("updating business_shared_folders hash as --resync issued"); + log.vdebug("Updating business_shared_folders hash as --resync issued"); std.file.write(businessSharedFoldersHashFile, computeQuickXorHash(businessSharedFolderFilePath)); } } @@ -391,7 +409,8 @@ int main(string[] args) // dry-run notification and database setup if (cfg.getValueBool("dry_run")) { - log.log("DRY-RUN Configured. Output below shows what 'would' have occurred."); + // "DRY-RUN Configured. Output below shows what 'would' have occurred" + log.log(provideLanguageTranslation(languageIdentifier,16)); string dryRunShmFile = cfg.databaseFilePathDryRun ~ "-shm"; string dryRunWalFile = cfg.databaseFilePathDryRun ~ "-wal"; // If the dry run database exists, clean this up @@ -482,7 +501,8 @@ int main(string[] args) // Configure logging only if enabled if (cfg.getValueBool("enable_logging")){ // Initialise using the configured logging directory - log.vlog("Using logfile dir: ", logDir); + // "Using logfile dir: " + log.vlog(provideLanguageTranslation(languageIdentifier,17), logDir); log.init(logDir); } @@ -494,14 +514,16 @@ int main(string[] args) if (!cfg.getValueBool("dry_run")) { safeRemove(databaseFilePath); } - log.logAndNotify("Database schema changed, resync needed"); + // "Database schema changed, resync needed" + log.logAndNotify(provideLanguageTranslation(languageIdentifier,18)); cfg.setValueBool("resync", true); } // Handle --resync and --logout to remove local files if (cfg.getValueBool("resync") || cfg.getValueBool("logout")) { if (cfg.getValueBool("resync")) log.vdebug("--resync requested"); - log.vlog("Deleting the saved status ..."); + // "Deleting the saved status ..." + log.vlog(provideLanguageTranslation(languageIdentifier,19)); if (!cfg.getValueBool("dry_run")) { safeRemove(cfg.databaseFilePath); safeRemove(cfg.deltaLinkFilePath); @@ -525,6 +547,7 @@ int main(string[] args) writeln("Config file found in config path = ", exists(configFilePath)); // Config Options + writeln("Config option 'language_identifier' = ", languageIdentifier); writeln("Config option 'check_nosync' = ", cfg.getValueBool("check_nosync")); writeln("Config option 'sync_dir' = ", syncDir); writeln("Config option 'skip_dir' = ", cfg.getValueString("skip_dir")); @@ -587,11 +610,13 @@ int main(string[] args) // Cant initialise the API as we are not online if (!cfg.getValueBool("monitor")) { // Running as --synchronize - log.error("Unable to reach Microsoft OneDrive API service, unable to initialize application\n"); + // "Unable to reach Microsoft OneDrive API service, unable to initialise application" + log.error(provideLanguageTranslation(languageIdentifier,20),"\n"); return EXIT_FAILURE; } else { // Running as --monitor - log.error("Unable to reach Microsoft OneDrive API service at this point in time, re-trying network tests\n"); + // "Unable to reach Microsoft OneDrive API service at this point in time, re-trying network tests" + log.error(provideLanguageTranslation(languageIdentifier,21),"\n"); // re-try network connection to OneDrive // https://github.com/abraunegg/onedrive/issues/1184 @@ -618,7 +643,8 @@ int main(string[] args) online = testNetwork(); if (online) { // We are now online - log.log("Internet connectivity to Microsoft OneDrive service has been restored"); + // "Internet connectivity to Microsoft OneDrive service has been restored" + log.log(provideLanguageTranslation(languageIdentifier,22)); retrySuccess = true; } else { // We are still offline @@ -633,7 +659,8 @@ int main(string[] args) } if (!online) { // Not online after 1.2 years of trying - log.error("ERROR: Was unable to reconnect to the Microsoft OneDrive service after 10000 attempts lasting over 1.2 years!"); + // "ERROR: The OneDrive Linux Client was unable to reconnect to the Microsoft OneDrive service after 10000 attempts lasting over 1.2 years!" + log.error(provideLanguageTranslation(languageIdentifier,23)); return EXIT_FAILURE; } } @@ -642,14 +669,16 @@ int main(string[] args) // Initialize OneDrive, check for authorization if (online) { // we can only initialise if we are online - log.vlog("Initializing the OneDrive API ..."); + // "Initialising the OneDrive API ..." + log.vlog(provideLanguageTranslation(languageIdentifier,24)); oneDrive = new OneDriveApi(cfg); onedriveInitialised = oneDrive.init(); oneDrive.printAccessToken = cfg.getValueBool("print_token"); } if (!onedriveInitialised) { - log.error("Could not initialize the OneDrive API"); + // "Could not initialise the OneDrive API" + log.error(provideLanguageTranslation(languageIdentifier,25)); // Use exit scopes to shutdown API return EXIT_UNAUTHORIZED; } @@ -672,19 +701,26 @@ int main(string[] args) // Application was just authorised if (exists(cfg.refreshTokenFilePath)) { // OneDrive refresh token exists - log.log("\nApplication has been successfully authorised, however no additional command switches were provided.\n"); - log.log("Please use --help for further assistance in regards to running this application.\n"); + // "Application has been successfully authorised, however no additional command switches were provided" + log.log("\n", provideLanguageTranslation(languageIdentifier,26),"\n"); + // "Please use 'onedrive --help' for further assistance in regards to running this application" + log.log(provideLanguageTranslation(languageIdentifier,27),"\n"); // Use exit scopes to shutdown API return EXIT_SUCCESS; } else { // we just authorised, but refresh_token does not exist .. probably an auth error - log.log("\nApplication has not been successfully authorised. Please check your URI response entry and try again.\n"); + // "Application has not been successfully authorised. Please check your URI response entry and try again" + log.log("\n", provideLanguageTranslation(languageIdentifier,28),"\n"); return EXIT_FAILURE; } } else { - // Application was not just authorised - log.log("\n--synchronize or --monitor switches missing from your command line input. Please add one (not both) of these switches to your command line or use --help for further assistance.\n"); - log.log("No OneDrive sync will be performed without one of these two arguments being present.\n"); + // Application was not just authorised, attempted to be run without --synchronize or --monitor being present + // "ERROR: --synchronize or --monitor switches missing from your command line input. Please add one (not both) of these switches to your command line" + log.error("\n", provideLanguageTranslation(languageIdentifier,29),"\n"); + // "No OneDrive sync will be performed without one of these two arguments being present" + log.error(provideLanguageTranslation(languageIdentifier,30),"\n"); + // "Please use 'onedrive --help' for further assistance in regards to running this application" + log.error(provideLanguageTranslation(languageIdentifier,27),"\n"); // Use exit scopes to shutdown API return EXIT_FAILURE; } @@ -692,14 +728,17 @@ int main(string[] args) // if --synchronize && --monitor passed in, exit & display help as these conflict with each other if (cfg.getValueBool("synchronize") && cfg.getValueBool("monitor")) { - writeln("\nERROR: --synchronize and --monitor cannot be used together\n"); - writeln("Refer to --help to determine which command option you should use.\n"); + // "ERROR: --synchronize and --monitor cannot be used together" + log.error("\n", provideLanguageTranslation(languageIdentifier,31),"\n"); + // "Please use 'onedrive --help' for further assistance in regards to running this application" + log.log(provideLanguageTranslation(languageIdentifier,27),"\n"); // Use exit scopes to shutdown API return EXIT_FAILURE; } // Initialize the item database - log.vlog("Opening the item database ..."); + // "Opening the item database ..." + log.vlog(provideLanguageTranslation(languageIdentifier,32)); if (!cfg.getValueBool("dry_run")) { // Load the items.sqlite3 file as the database log.vdebug("Using database file: ", asNormalizedPath(cfg.databaseFilePath)); @@ -717,7 +756,8 @@ int main(string[] args) // - Any new file created under ~/OneDrive or 'sync_dir' // valid permissions are 000 -> 777 - anything else is invalid if ((cfg.getValueLong("sync_dir_permissions") < 0) || (cfg.getValueLong("sync_file_permissions") < 0) || (cfg.getValueLong("sync_dir_permissions") > 777) || (cfg.getValueLong("sync_file_permissions") > 777)) { - log.error("ERROR: Invalid 'User|Group|Other' permissions set within config file. Please check."); + // "ERROR: Invalid 'User|Group|Other' permissions set within config file. Please check your config file." + log.error(provideLanguageTranslation(languageIdentifier,33)); return EXIT_FAILURE; } else { // debug log output what permissions are being set to @@ -728,7 +768,8 @@ int main(string[] args) } // configure the sync direcory based on syncDir config option - log.vlog("All operations will be performed in: ", syncDir); + // "All operations will be performed in: " + log.vlog(provideLanguageTranslation(languageIdentifier,34), syncDir); if (!exists(syncDir)) { log.vdebug("syncDir: Configured syncDir is missing. Creating: ", syncDir); try { @@ -739,7 +780,8 @@ int main(string[] args) syncDir.setAttributes(cfg.returnRequiredDirectoryPermisions()); } catch (std.file.FileException e) { // Creating the sync directory failed - log.error("ERROR: Unable to create local OneDrive syncDir - ", e.msg); + // "ERROR: Unable to create local OneDrive syncDir - " + log.error(provideLanguageTranslation(languageIdentifier,35), e.msg); // Use exit scopes to shutdown API return EXIT_FAILURE; } @@ -810,7 +852,8 @@ int main(string[] args) foreach(entry; cfg.getValueString("skip_file").split("|")){ if (entry == ".*") { // invalid entry element detected - log.logAndNotify("ERROR: Invalid skip_file entry '.*' detected"); + // "ERROR: Invalid skip_file entry '.*' detected" + log.logAndNotify(provideLanguageTranslation(languageIdentifier,36)); return EXIT_FAILURE; } } @@ -827,12 +870,14 @@ int main(string[] args) } else { if ((cfg.getValueString("get_file_link") == "") && (cfg.getValueString("create_share_link") == "")) { // Print out that we are initializing the engine only if we are not grabbing the file link or creating a shareable link - log.logAndNotify("Initializing the Synchronization Engine ..."); + // "Initialising the Synchronisation Engine ..." + log.logAndNotify(provideLanguageTranslation(languageIdentifier,37)); } } } catch (CurlException e) { if (!cfg.getValueBool("monitor")) { - log.log("\nNo Internet connection."); + // "Cannot connect to Microsoft OneDrive Service - Network Connection Issue" + log.log("\n", provideLanguageTranslation(languageIdentifier,38)); // Use exit scopes to shutdown API return EXIT_FAILURE; } @@ -867,8 +912,10 @@ int main(string[] args) // Has the user enabled to bypass data preservation of renaming local files when there is a conflict? if (cfg.getValueBool("bypass_data_preservation")) { - log.log("WARNING: Application has been configured to bypass local data preservation in the event of file conflict."); - log.log("WARNING: Local data loss MAY occur in this scenario."); + // "WARNING: Application has been configured to bypass local data preservation in the event of file conflict" + log.log(provideLanguageTranslation(languageIdentifier,39)); + // "WARNING: Local data loss MAY occur in this scenario" + log.log(provideLanguageTranslation(languageIdentifier,40)); sync.setBypassDataPreservation(); } @@ -885,7 +932,8 @@ int main(string[] args) if (cfg.getValueBool("check_nomount")) { // we were asked to check the mounts if (exists(syncDir ~ "/.nosync")) { - log.logAndNotify("ERROR: .nosync file found. Aborting synchronization process to safeguard data."); + // "ERROR: .nosync file found. Aborting synchronisation process to safeguard data" + log.logAndNotify(provideLanguageTranslation(languageIdentifier,41)); // Use exit scopes to shutdown API return EXIT_FAILURE; } @@ -944,7 +992,8 @@ int main(string[] args) // List OneDrive Business Shared Folders sync.listOneDriveBusinessSharedFolders(); } else { - log.error("ERROR: Unsupported account type for listing OneDrive Business Shared Folders"); + // "ERROR: Unsupported account type for listing OneDrive Business Shared Folders" + log.error(provideLanguageTranslation(languageIdentifier,42)); } // Exit application // Use exit scopes to shutdown API @@ -958,7 +1007,8 @@ int main(string[] args) // Configure flag to sync business folders sync.setSyncBusinessFolders(); } else { - log.error("ERROR: Unsupported account type for syncing OneDrive Business Shared Folders"); + // "ERROR: Unsupported account type for syncing OneDrive Business Shared Folders" + log.error(provideLanguageTranslation(languageIdentifier,43)); } } @@ -986,7 +1036,8 @@ int main(string[] args) // Does the directory we want to sync actually exist? if (!exists(cfg.getValueString("single_directory"))) { // The requested path to use with --single-directory does not exist locally within the configured 'sync_dir' - log.logAndNotify("WARNING: The requested path for --single-directory does not exist locally. Creating requested path within ", syncDir); + // "WARNING: The requested path for --single-directory does not exist locally. Creating requested path within: " + log.logAndNotify(provideLanguageTranslation(languageIdentifier,44), syncDir); // Make the required --single-directory path locally string singleDirectoryPath = cfg.getValueString("single_directory"); mkdirRecurse(singleDirectoryPath); @@ -1007,52 +1058,68 @@ int main(string[] args) } if (cfg.getValueBool("monitor")) { - log.logAndNotify("Initializing monitor ..."); - log.log("OneDrive monitor interval (seconds): ", cfg.getValueLong("monitor_interval")); + // "Initialising monitor ..." + log.logAndNotify(provideLanguageTranslation(languageIdentifier,45)); + // "OneDrive monitor interval (seconds): " + log.log(provideLanguageTranslation(languageIdentifier,46), cfg.getValueLong("monitor_interval")); m.onDirCreated = delegate(string path) { // Handle .folder creation if skip_dotfiles is enabled if ((cfg.getValueBool("skip_dotfiles")) && (selectiveSync.isDotFile(path))) { - log.vlog("[M] Skipping watching path - .folder found & --skip-dot-files enabled: ", path); + // "[M] Skipping watching path - .folder found & --skip-dot-files enabled: " + log.vlog(provideLanguageTranslation(languageIdentifier,47), path); } else { - log.vlog("[M] Directory created: ", path); + // "[M] Directory created: " + log.vlog(provideLanguageTranslation(languageIdentifier,48), path); try { sync.scanForDifferences(path); } catch (CurlException e) { - log.vlog("Offline, cannot create remote dir!"); + // "Offline, cannot create remote directory!" + log.vlog(provideLanguageTranslation(languageIdentifier,49)); } catch(Exception e) { - log.logAndNotify("Cannot create remote directory: ", e.msg); + // "Cannot create remote directory: " + log.logAndNotify(provideLanguageTranslation(languageIdentifier,50), e.msg); } } }; m.onFileChanged = delegate(string path) { - log.vlog("[M] File changed: ", path); + // "[M] File changed: " + log.vlog(provideLanguageTranslation(languageIdentifier,51), path); try { sync.scanForDifferences(path); } catch (CurlException e) { - log.vlog("Offline, cannot upload changed item!"); + // "Offline, cannot upload changed item!" + log.vlog(provideLanguageTranslation(languageIdentifier,52)); } catch(Exception e) { - log.logAndNotify("Cannot upload file changes/creation: ", e.msg); + // "Cannot upload file changes/creation: " + log.logAndNotify(provideLanguageTranslation(languageIdentifier,53), e.msg); } }; m.onDelete = delegate(string path) { - log.vlog("[M] Item deleted: ", path); + // "[M] Item deleted: " + log.vlog(provideLanguageTranslation(languageIdentifier,54), path); try { sync.deleteByPath(path); } catch (CurlException e) { - log.vlog("Offline, cannot delete item!"); + // "Offline, cannot delete item!" + log.vlog(provideLanguageTranslation(languageIdentifier,55)); } catch(SyncException e) { + // this error is thrown from sync.d if (e.msg == "The item to delete is not in the local database") { - log.vlog("Item cannot be deleted from OneDrive because it was not found in the local database"); + // "Item cannot be deleted from OneDrive because it was not found in the local database" + log.vlog(provideLanguageTranslation(languageIdentifier,56)); } else { - log.logAndNotify("Cannot delete remote item: ", e.msg); + // "Cannot delete remote item: " + log.logAndNotify(provideLanguageTranslation(languageIdentifier,57), e.msg); } } catch(Exception e) { - log.logAndNotify("Cannot delete remote item: ", e.msg); + // "Cannot delete remote item: " + log.logAndNotify(provideLanguageTranslation(languageIdentifier,57), e.msg); } }; m.onMove = delegate(string from, string to) { - log.vlog("[M] Item moved: ", from, " -> ", to); + // "[M] Item moved: " + log.vlog(provideLanguageTranslation(languageIdentifier,58), from, " -> ", to); try { // Handle .folder -> folder if skip_dotfiles is enabled if ((cfg.getValueBool("skip_dotfiles")) && (selectiveSync.isDotFile(from))) { @@ -1062,9 +1129,11 @@ int main(string[] args) sync.uploadMoveItem(from, to); } } catch (CurlException e) { - log.vlog("Offline, cannot move item!"); + // "Offline, cannot move item!" + log.vlog(provideLanguageTranslation(languageIdentifier,59)); } catch(Exception e) { - log.logAndNotify("Cannot move item: ", e.msg); + // "Cannot move item: " + log.logAndNotify(provideLanguageTranslation(languageIdentifier,60), e.msg); } }; signal(SIGINT, &exitHandler); @@ -1076,7 +1145,8 @@ int main(string[] args) m.init(cfg, cfg.getValueLong("verbose") > 0, cfg.getValueBool("skip_symlinks"), cfg.getValueBool("check_nosync")); } catch (MonitorException e) { // monitor initialisation failed - log.error("ERROR: ", e.msg); + // "ERROR: " + e.msg + log.error(provideLanguageTranslation(languageIdentifier,61), e.msg); exit(-1); } } @@ -1105,7 +1175,8 @@ int main(string[] args) m.update(online); } catch (MonitorException e) { // Catch any exceptions thrown by inotify / monitor engine - log.error("ERROR: The following inotify error was generated: ", e.msg); + // "ERROR: The following inotify error was generated: " + log.error(provideLanguageTranslation(languageIdentifier,62), e.msg); } } @@ -1176,7 +1247,8 @@ int main(string[] args) } try { // perform a --monitor sync - if ((cfg.getValueLong("verbose") > 0) || (logMonitorCounter == logInterval)) log.log("Starting a sync with OneDrive"); + // "Starting a sync with OneDrive" + if ((cfg.getValueLong("verbose") > 0) || (logMonitorCounter == logInterval)) log.log(provideLanguageTranslation(languageIdentifier,63)); performSync(sync, cfg.getValueString("single_directory"), cfg.getValueBool("download_only"), cfg.getValueBool("local_first"), cfg.getValueBool("upload_only"), (logMonitorCounter == logInterval ? MONITOR_LOG_QUIET : MONITOR_LOG_SILENT), fullScanRequired, syncListConfiguredFullScanOverride, displaySyncOptions, cfg.getValueBool("monitor"), m); if (!cfg.getValueBool("download_only")) { // discard all events that may have been generated by the sync that have not already been handled @@ -1184,19 +1256,23 @@ int main(string[] args) m.update(false); } catch (MonitorException e) { // Catch any exceptions thrown by inotify / monitor engine - log.error("ERROR: The following inotify error was generated: ", e.msg); + // "ERROR: The following inotify error was generated: " + log.error(provideLanguageTranslation(languageIdentifier,62), e.msg); } } - if ((cfg.getValueLong("verbose") > 0) || (logMonitorCounter == logInterval)) log.log("Sync with OneDrive is complete"); + // "Sync with OneDrive is complete" + if ((cfg.getValueLong("verbose") > 0) || (logMonitorCounter == logInterval)) log.log(provideLanguageTranslation(languageIdentifier,64)); } catch (CurlException e) { // we already tried three times in the performSync routine // if we still have problems, then the sync handle might have // gone stale and we need to re-initialize the sync engine - log.log("Persistent connection errors, reinitializing connection"); + // "Persistent connection errors, reinitialising connection" + log.log(provideLanguageTranslation(languageIdentifier,65)); sync.reset(); } } catch (CurlException e) { - log.log("Cannot initialize connection to OneDrive"); + // "Unable to reach Microsoft OneDrive API service, unable to initialise application" + log.log(provideLanguageTranslation(languageIdentifier,20)); } // performSync complete, set lastCheckTime to current time fullScanRequired = false; @@ -1233,6 +1309,7 @@ int main(string[] args) // developer set option to limit --monitor loops if (monitorLoopFullCount == (cfg.getValueLong("monitor_max_loop"))) { performMonitor = false; + // No internationalisation for this log output - it is a developer set option log.log("Exiting after ", monitorLoopFullCount, " loops due to developer set option"); } } @@ -1275,7 +1352,8 @@ bool initSyncEngine(SyncEngine sync) } catch (OneDriveException e) { if (e.httpStatusCode == 400 || e.httpStatusCode == 401) { // Authorization is invalid - log.log("\nAuthorization token invalid, use --logout to authorize the client again\n"); + // "Authorisation token invalid, use --logout to authorise the client again" + log.log("\n", provideLanguageTranslation(languageIdentifier,66),"\n"); return false; } if (e.httpStatusCode >= 500) { @@ -1287,6 +1365,7 @@ bool initSyncEngine(SyncEngine sync) } // try to synchronize the folder three times +// we cant pass cfg into this function ... void performSync(SyncEngine sync, string singleDirectory, bool downloadOnly, bool localFirst, bool uploadOnly, long logLevel, bool fullScanRequired, bool syncListConfiguredFullScanOverride, bool displaySyncOptions, bool monitorEnabled, Monitor m) { int count; @@ -1326,21 +1405,28 @@ void performSync(SyncEngine sync, string singleDirectory, bool downloadOnly, boo } if (singleDirectory != ""){ // we were requested to sync a single directory - log.vlog("Syncing changes from this selected path: ", singleDirectory); + // "Syncing changes from this selected path: " + log.vlog(provideLanguageTranslation(languageIdentifier,67), singleDirectory); if (uploadOnly){ // Upload Only of selected single directory - if (logLevel < MONITOR_LOG_QUIET) log.log("Syncing changes from selected local path only - NOT syncing data changes from OneDrive ..."); + // "Syncing changes from selected local path only - NOT syncing data changes from OneDrive ..." + if (logLevel < MONITOR_LOG_QUIET) log.log(provideLanguageTranslation(languageIdentifier,68)); sync.scanForDifferences(localPath); } else { // No upload only if (localFirst) { // Local First - if (logLevel < MONITOR_LOG_QUIET) log.log("Syncing changes from selected local path first before downloading changes from OneDrive ..."); + // "Syncing changes from selected local path first before downloading changes from OneDrive ..." + if (logLevel < MONITOR_LOG_QUIET) log.log(provideLanguageTranslation(languageIdentifier,69)); sync.scanForDifferences(localPath); sync.applyDifferencesSingleDirectory(remotePath); } else { // OneDrive First - if (logLevel < MONITOR_LOG_QUIET) log.log("Syncing changes from selected OneDrive path ..."); + // "Syncing changes from selected OneDrive path ..." + if (logLevel < MONITOR_LOG_QUIET) log.log(provideLanguageTranslation(languageIdentifier,70)); + // If we are doing a --download-only sync, indicate that only changes from OneDrive will be downloaded + // "Syncing changes from OneDrive only - NOT syncing local data changes to OneDrive ..." + if (downloadOnly) log.log(provideLanguageTranslation(languageIdentifier,77)); sync.applyDifferencesSingleDirectory(remotePath); // is this a download only request? if (!downloadOnly) { @@ -1355,14 +1441,16 @@ void performSync(SyncEngine sync, string singleDirectory, bool downloadOnly, boo // no single directory sync if (uploadOnly){ // Upload Only of entire sync_dir - if (logLevel < MONITOR_LOG_QUIET) log.log("Syncing changes from local path only - NOT syncing data changes from OneDrive ..."); + // "Syncing changes from local path only - NOT syncing data changes from OneDrive ..." + if (logLevel < MONITOR_LOG_QUIET) log.log(provideLanguageTranslation(languageIdentifier,71)); sync.scanForDifferences(localPath); } else { // No upload only string syncCallLogOutput; if (localFirst) { // sync local files first before downloading from OneDrive - if (logLevel < MONITOR_LOG_QUIET) log.log("Syncing changes from local path first before downloading changes from OneDrive ..."); + // "Syncing changes from local path first before downloading changes from OneDrive ..." + if (logLevel < MONITOR_LOG_QUIET) log.log(provideLanguageTranslation(languageIdentifier,72)); sync.scanForDifferences(localPath); // if syncListConfiguredFullScanOverride = true if (syncListConfiguredFullScanOverride) { @@ -1374,7 +1462,8 @@ void performSync(SyncEngine sync, string singleDirectory, bool downloadOnly, boo } } else { // sync from OneDrive first before uploading files to OneDrive - if (logLevel < MONITOR_LOG_SILENT) log.log("Syncing changes from OneDrive ..."); + // "Syncing changes from OneDrive ..." + if (logLevel < MONITOR_LOG_SILENT) log.log(provideLanguageTranslation(languageIdentifier,73)); // For the initial sync, always use the delta link so that we capture all the right delta changes including adds, moves & deletes logOutputMessage = "Initial Scan: Call OneDrive Delta API for delta changes as compared to last successful sync."; @@ -1386,6 +1475,9 @@ void performSync(SyncEngine sync, string singleDirectory, bool downloadOnly, boo log.vdebug(logOutputMessage); log.vdebug(syncCallLogOutput); } + // If we are doing a --download-only sync, indicate that only changes from OneDrive will be downloaded + // "Syncing changes from OneDrive only - NOT syncing local data changes to OneDrive ..." + if (downloadOnly) log.log(provideLanguageTranslation(languageIdentifier,77)); sync.applyDifferences(false); // is this a download only request? @@ -1508,10 +1600,13 @@ void performSync(SyncEngine sync, string singleDirectory, bool downloadOnly, boo count = -1; } catch (Exception e) { if (++count == 3) { - log.log("Giving up on sync after three attempts: ", e.msg); + // "Giving up on sync after three attempts: " + log.log(provideLanguageTranslation(languageIdentifier,74), e.msg); throw e; - } else - log.log("Retry sync count: ", count, ": ", e.msg); + } else { + // "Retry sync count: " + log.log(provideLanguageTranslation(languageIdentifier,75), count, ": ", e.msg); + } } } while (count != -1); } @@ -1527,7 +1622,9 @@ auto assumeNoGC(T) (T t) if (isFunctionPointer!T || isDelegate!T) extern(C) nothrow @nogc @system void exitHandler(int value) { try { assumeNoGC ( () { - log.log("Got termination signal, shutting down db connection"); + // Generate log message + // " Got termination signal, shutting down DB connection" + log.log(provideLanguageTranslation(languageIdentifier,76)); // was itemDb initialised? if (itemDb !is null) { // Make sure the .wal file is incorporated into the main db before we exit diff --git a/src/sync.d b/src/sync.d index 707cb5d97..336ec3c8e 100644 --- a/src/sync.d +++ b/src/sync.d @@ -9,9 +9,12 @@ import std.conv; import std.encoding; import core.time, core.thread; import core.stdc.stdlib; -import config, itemdb, onedrive, selective, upload, util; +import config, itemdb, onedrive, selective, upload, util, translations; static import log; +// Language Identifier +private string languageIdentifier = ""; + // threshold after which files will be uploaded using an upload session private long thresholdFileSize = 4 * 2^^20; // 4 MiB @@ -167,7 +170,8 @@ private Item makeItem(const ref JSONValue driveItem) } else if ("quickXorHash" in driveItem["file"]["hashes"]) { item.quickXorHash = driveItem["file"]["hashes"]["quickXorHash"].str; } else { - log.vlog("The file does not have any hash"); + // "The file does not have any hash" + log.vlog(provideLanguageTranslation(languageIdentifier,78)); } } @@ -283,6 +287,9 @@ final class SyncEngine // Set accountType, defaultDriveId, defaultRootId & remainingFreeSpace once and reuse where possible JSONValue oneDriveDetails; JSONValue oneDriveRootDetails; + + // Update language identifier as used with this class + languageIdentifier = cfg.getValueString("language_identifier"); if (initDone) { return; @@ -302,7 +309,8 @@ final class SyncEngine // Check this if (cfg.getValueString("drive_id").length) { - log.error("\nERROR: Check your 'drive_id' entry in your configuration file as it may be incorrect\n"); + // "ERROR: Check your 'drive_id' entry in your configuration file as it may be incorrect" + log.error("\n", provideLanguageTranslation(languageIdentifier,79),"\n"); } // Must exit here exit(-1); @@ -310,7 +318,8 @@ final class SyncEngine if (e.httpStatusCode == 401) { // HTTP request returned status code 401 (Unauthorized) displayOneDriveErrorMessage(e.msg, getFunctionName!({})); - log.errorAndNotify("\nERROR: Check your configuration as your refresh_token may be empty or invalid. You may need to issue a --logout and re-authorise this client.\n"); + // "ERROR: Check your configuration as your refresh_token may be empty or invalid. You may need to issue a --logout and re-authorise this client." + log.errorAndNotify("\n", provideLanguageTranslation(languageIdentifier,80),"\n"); // Must exit here exit(-1); } @@ -341,7 +350,8 @@ final class SyncEngine displayOneDriveErrorMessage(e.msg, getFunctionName!({})); // Check this if (cfg.getValueString("drive_id").length) { - log.error("\nERROR: Check your 'drive_id' entry in your configuration file as it may be incorrect\n"); + // "ERROR: Check your 'drive_id' entry in your configuration file as it may be incorrect" + log.error("\n", provideLanguageTranslation(languageIdentifier,79),"\n"); } // Must exit here exit(-1); @@ -349,7 +359,8 @@ final class SyncEngine if (e.httpStatusCode == 401) { // HTTP request returned status code 401 (Unauthorized) displayOneDriveErrorMessage(e.msg, getFunctionName!({})); - log.errorAndNotify("\nERROR: Check your configuration as your refresh_token may be empty or invalid. You may need to issue a --logout and re-authorise this client.\n"); + // "ERROR: Check your configuration as your refresh_token may be empty or invalid. You may need to issue a --logout and re-authorise this client." + log.errorAndNotify("\n", provideLanguageTranslation(languageIdentifier,80),"\n"); // Must exit here exit(-1); } @@ -396,40 +407,49 @@ final class SyncEngine // json response contained a 'remaining' value if (accountType == "personal"){ // zero space available - log.error("ERROR: OneDrive account currently has zero space available. Please free up some space online."); + // "ERROR: OneDrive account currently has zero space available. Please free up some space online." + log.error(provideLanguageTranslation(languageIdentifier,81)); quotaAvailable = false; } else { // zero space available is being reported, maybe being restricted? - log.error("WARNING: OneDrive quota information is being restricted or providing a zero value. Please fix by speaking to your OneDrive / Office 365 Administrator."); + // "WARNING: OneDrive quota information is being restricted or providing a zero value. Please fix by speaking to your OneDrive / Office 365 Administrator." + log.error(provideLanguageTranslation(languageIdentifier,82)); quotaRestricted = true; } } else { // json response was missing a 'remaining' value if (accountType == "personal"){ - log.error("ERROR: OneDrive quota information is missing. Potentially your OneDrive account currently has zero space available. Please free up some space online."); + // "ERROR: OneDrive quota information is missing. Potentially your OneDrive account currently has zero space available. Please free up some space online." + log.error(provideLanguageTranslation(languageIdentifier,83)); } else { // quota details not available - log.error("ERROR: OneDrive quota information is being restricted. Please fix by speaking to your OneDrive / Office 365 Administrator."); + // "ERROR: OneDrive quota information is being restricted. Please fix by speaking to your OneDrive / Office 365 Administrator." + log.error(provideLanguageTranslation(languageIdentifier,84)); } } } // Display accountType, defaultDriveId, defaultRootId & remainingFreeSpace for verbose logging purposes - log.vlog("Application version: ", strip(import("version"))); - log.vlog("Account Type: ", accountType); - log.vlog("Default Drive ID: ", defaultDriveId); - log.vlog("Default Root ID: ", defaultRootId); + // "Application version: " + log.vlog(provideLanguageTranslation(languageIdentifier,85), strip(import("version"))); + // "Account Type: " + log.vlog(provideLanguageTranslation(languageIdentifier,86), accountType); + // "Default Drive ID: " + log.vlog(provideLanguageTranslation(languageIdentifier,87), defaultDriveId); + // "Default Root ID: " + log.vlog(provideLanguageTranslation(languageIdentifier,88), defaultRootId); // What do we display here if (remainingFreeSpace > 0) { // Display the actual value - log.vlog("Remaining Free Space: ", remainingFreeSpace); + // "Remaining Free Space: " + log.vlog(provideLanguageTranslation(languageIdentifier,89), remainingFreeSpace); } else { // zero or non-zero value or restricted if (!quotaRestricted){ - log.vlog("Remaining Free Space: 0"); + log.vlog(provideLanguageTranslation(languageIdentifier,89), "0"); } else { - log.vlog("Remaining Free Space: Not Available"); + log.vlog(provideLanguageTranslation(languageIdentifier,89), "Not Available"); } } @@ -444,7 +464,8 @@ final class SyncEngine // Check if there is an interrupted upload session if (session.restore()) { - log.log("Continuing the upload session ..."); + // "Continuing the upload session ..." + log.log(provideLanguageTranslation(languageIdentifier,90)); string uploadSessionLocalFilePath = session.getUploadSessionLocalFilePath(); auto item = session.upload(); @@ -455,7 +476,8 @@ final class SyncEngine // Use actual config values as we are doing an upload session recovery if ((cfg.getValueBool("upload_only")) && (cfg.getValueBool("remove_source_files"))) { // Log that we are deleting a local item - log.log("Removing local file as --upload-only & --remove-source-files configured"); + // "Removing local file as --upload-only & --remove-source-files configured" + log.log(provideLanguageTranslation(languageIdentifier,91)); // are we in a --dry-run scenario? if (!dryRun) { // No --dry-run ... process local file delete @@ -476,15 +498,17 @@ final class SyncEngine } } else { // JSON response was not valid, upload failed - log.error("ERROR: File failed to upload. Increase logging verbosity to determine why."); + // "ERROR: File failed to upload. Increase logging verbosity to determine why." + log.error(provideLanguageTranslation(languageIdentifier,92)); } } initDone = true; } else { // init failure initDone = false; - // log why - log.error("ERROR: Unable to query OneDrive to initialize application"); + // log why we cant initialise + // "ERROR: Unable to reach Microsoft OneDrive API service, unable to initialise application" + log.error(provideLanguageTranslation(languageIdentifier,20)); // Debug OneDrive Account details response log.vdebug("OneDrive Account Details: ", oneDriveDetails); log.vdebug("OneDrive Account Root Details: ", oneDriveRootDetails); @@ -605,16 +629,18 @@ final class SyncEngine // This due to if the user has specified in skip_dir an exclusive path: '/path' - that is what must be matched if (selectiveSync.isDirNameExcluded(item.name)) { // This directory name is excluded - log.vlog("Skipping item - excluded by skip_dir config: ", item.name); + // "Skipping item - excluded by skip_dir config: " + log.vlog(provideLanguageTranslation(languageIdentifier,93), item.name); continue; } } // Directory name is not excluded or skip_dir is not populated log.vdebug("------------------------------------------------------------------"); if (!cfg.getValueBool("monitor")) { - log.log("Syncing this OneDrive Personal Shared Folder: ", item.name); + // "Syncing this OneDrive Personal Shared Folder: " + log.log(provideLanguageTranslation(languageIdentifier,94), item.name); } else { - log.vlog("Syncing this OneDrive Personal Shared Folder: ", item.name); + log.vlog(provideLanguageTranslation(languageIdentifier,94), item.name); } // Check this OneDrive Personal Shared Folders applyDifferences(item.remoteDriveId, item.remoteId, performFullItemScan); @@ -629,7 +655,8 @@ final class SyncEngine // Check OneDrive Business Shared Folders, if configured to do so if (syncBusinessFolders){ // query OneDrive Business Shared Folders shared with me - log.vlog("Attempting to sync OneDrive Business Shared Folders"); + // "Attempting to sync OneDrive Business Shared Folders" + log.vlog(provideLanguageTranslation(languageIdentifier,95)); JSONValue graphQuery = onedrive.getSharedWithMe(); if (graphQuery.type() == JSONType.object) { string sharedFolderName; @@ -705,18 +732,20 @@ final class SyncEngine if ( ((!itemInDatabase) || (!itemLocalDirExists)) || (((databaseItem.driveId == searchResult["remoteItem"]["parentReference"]["driveId"].str) && (databaseItem.id == searchResult["remoteItem"]["id"].str)) && (!itemPathIsLocal)) ) { // This shared folder does not exist in the database if (!cfg.getValueBool("monitor")) { - log.log("Syncing this OneDrive Business Shared Folder: ", sharedFolderName); + // "Syncing this OneDrive Business Shared Folder: " + log.log(provideLanguageTranslation(languageIdentifier,96), sharedFolderName); } else { - log.vlog("Syncing this OneDrive Business Shared Folder: ", sharedFolderName); + log.vlog(provideLanguageTranslation(languageIdentifier,96), sharedFolderName); } Item businessSharedFolder = makeItem(searchResult); // Log who shared this to assist with sync data correlation - if ((sharedByName != "") && (sharedByEmail != "")) { - log.vlog("OneDrive Business Shared Folder - Shared By: ", sharedByName, " (", sharedByEmail, ")"); + if ((sharedByName != "") && (sharedByEmail != "")) { + // "OneDrive Business Shared Folder - Shared By: " + log.vlog(provideLanguageTranslation(languageIdentifier,97), sharedByName, " (", sharedByEmail, ")"); } else { if (sharedByName != "") { - log.vlog("OneDrive Business Shared Folder - Shared By: ", sharedByName); + log.vlog(provideLanguageTranslation(languageIdentifier,97), sharedByName); } } @@ -731,16 +760,20 @@ final class SyncEngine } } else { // Shared Folder Name Conflict ... - log.log("WARNING: Skipping shared folder due to existing name conflict: ", sharedFolderName); - log.log("WARNING: Skipping changes of Path ID: ", searchResult["remoteItem"]["id"].str); - log.log("WARNING: To sync this shared folder, this shared folder needs to be renamed"); + // "WARNING: Skipping shared folder due to existing name conflict: " + log.log(provideLanguageTranslation(languageIdentifier,98), sharedFolderName); + // "WARNING: Skipping changes of Path ID: " + log.log(provideLanguageTranslation(languageIdentifier,99), searchResult["remoteItem"]["id"].str); + // "WARNING: To sync this shared folder, this shared folder needs to be renamed" + log.log(provideLanguageTranslation(languageIdentifier,100)); // Log who shared this to assist with conflict resolution - if ((sharedByName != "") && (sharedByEmail != "")) { - log.vlog("WARNING: Conflict Shared By: ", sharedByName, " (", sharedByEmail, ")"); + if ((sharedByName != "") && (sharedByEmail != "")) { + // "WARNING: Conflict Shared By: " + log.vlog(provideLanguageTranslation(languageIdentifier,101), sharedByName, " (", sharedByEmail, ")"); } else { if (sharedByName != "") { - log.vlog("WARNING: Conflict Shared By: ", sharedByName); + log.vlog(provideLanguageTranslation(languageIdentifier,101), sharedByName); } } } @@ -751,25 +784,29 @@ final class SyncEngine // shared item is a file string sharedFileName = searchResult["name"].str; // log that this is not supported - log.vlog("WARNING: Not syncing this OneDrive Business Shared File: ", sharedFileName); + // "WARNING: Not syncing this OneDrive Business Shared File: " + log.vlog(provideLanguageTranslation(languageIdentifier,102), sharedFileName); // Log who shared this to assist with sync data correlation - if ((sharedByName != "") && (sharedByEmail != "")) { - log.vlog("OneDrive Business Shared File - Shared By: ", sharedByName, " (", sharedByEmail, ")"); + if ((sharedByName != "") && (sharedByEmail != "")) { + // "OneDrive Business Shared File - Shared By: " + log.vlog(provideLanguageTranslation(languageIdentifier,103), sharedByName, " (", sharedByEmail, ")"); } else { if (sharedByName != "") { - log.vlog("OneDrive Business Shared File - Shared By: ", sharedByName); + log.vlog(provideLanguageTranslation(languageIdentifier,103), sharedByName); } } } else { // something else entirely - log.log("WARNING: Not syncing this OneDrive Business Shared item: ", searchResult["name"].str); + // "WARNING: Not syncing this OneDrive Business Shared item: " + log.log(provideLanguageTranslation(languageIdentifier,104), searchResult["name"].str); } } } } else { // Log that an invalid JSON object was returned - log.error("ERROR: onedrive.getSharedWithMe call returned an invalid JSON Object"); + // "ERROR: onedrive.getSharedWithMe call returned an invalid JSON Object" + log.error(provideLanguageTranslation(languageIdentifier,105)); } } } @@ -792,7 +829,8 @@ final class SyncEngine // Check OneDrive Business Shared Folders, if configured to do so if (syncBusinessFolders){ - log.vlog("Attempting to sync OneDrive Business Shared Folders"); + // "Attempting to sync OneDrive Business Shared Folders" + log.vlog(provideLanguageTranslation(languageIdentifier,95)); // query OneDrive Business Shared Folders shared with me JSONValue graphQuery = onedrive.getSharedWithMe(); @@ -821,22 +859,24 @@ final class SyncEngine } } else { // Log that an invalid JSON object was returned - log.error("ERROR: onedrive.getSharedWithMe call returned an invalid JSON Object"); + // "ERROR: onedrive.getSharedWithMe call returned an invalid JSON Object" + log.error(provideLanguageTranslation(languageIdentifier,105)); } } // Test if the path we are going to sync from actually exists on OneDrive - log.vlog("Getting path details from OneDrive ..."); + // "Getting path details from OneDrive ..." + log.vlog(provideLanguageTranslation(languageIdentifier,106)); try { onedrivePathDetails = onedrive.getPathDetailsByDriveId(driveId, path); } catch (OneDriveException e) { log.vdebug("onedrivePathDetails = onedrive.getPathDetails(path) generated a OneDriveException"); if (e.httpStatusCode == 404) { // The directory was not found - log.error("ERROR: The requested single directory to sync was not found on OneDrive"); + // "ERROR: The requested single directory to sync was not found on OneDrive" + log.error(provideLanguageTranslation(languageIdentifier,107)); return; } - if (e.httpStatusCode == 429) { // HTTP request returned status code 429 (Too Many Requests). We need to leverage the response Retry-After HTTP header to ensure minimum delay until the throttle is removed. handleOneDriveThrottleRequest(); @@ -846,7 +886,6 @@ final class SyncEngine // return back to original call return; } - if (e.httpStatusCode >= 500) { // OneDrive returned a 'HTTP 5xx Server Side Error' - gracefully handling error - error message already logged return; @@ -888,7 +927,8 @@ final class SyncEngine // make sure the OneDrive root is in our database auto checkDatabaseForOneDriveRoot() { - log.vlog("Fetching details for OneDrive Root"); + // "Fetching details for OneDrive Root" + log.vlog(provideLanguageTranslation(languageIdentifier,108)); JSONValue rootPathDetails = onedrive.getDefaultRoot(); // Returns a JSON Value // validate object is a JSON value @@ -902,15 +942,19 @@ final class SyncEngine // Query the database if (!itemdb.selectById(driveId, rootId, rootPathItem)) { - log.vlog("OneDrive Root does not exist in the database. We need to add it."); + // "OneDrive Root does not exist in the database. We need to add it." + log.vlog(provideLanguageTranslation(languageIdentifier,109)); applyDifference(rootPathDetails, driveId, true); - log.vlog("Added OneDrive Root to the local database"); + // "Added OneDrive Root to the local database" + log.vlog(provideLanguageTranslation(languageIdentifier,110)); } else { - log.vlog("OneDrive Root exists in the database"); + // "OneDrive Root exists in the database" + log.vlog(provideLanguageTranslation(languageIdentifier,111)); } } else { // Log that an invalid JSON object was returned - log.error("ERROR: Unable to query OneDrive for account details"); + // "ERROR: Unable to query OneDrive for account details" + log.error(provideLanguageTranslation(languageIdentifier,112)); log.vdebug("onedrive.getDefaultRoot call returned an invalid JSON Object"); // Must exit here as we cant configure our required variables exit(-1); @@ -921,7 +965,8 @@ final class SyncEngine auto createDirectoryNoSync(const(string) path) { // Attempt to create the requested path within OneDrive without performing a sync - log.vlog("Attempting to create the requested path within OneDrive"); + // "Attempting to create the requested path within OneDrive" + log.vlog(provideLanguageTranslation(languageIdentifier,113)); // Handle the remote folder creation and updating of the local database without performing a sync uploadCreateDir(path); @@ -934,7 +979,8 @@ final class SyncEngine const(char)[] rootId = defaultRootId; // Attempt to delete the requested path within OneDrive without performing a sync - log.vlog("Attempting to delete the requested path within OneDrive"); + // "Attempting to delete the requested path within OneDrive" + log.vlog(provideLanguageTranslation(languageIdentifier,114)); // test if the path we are going to exists on OneDrive try { @@ -943,7 +989,8 @@ final class SyncEngine log.vdebug("onedrive.getPathDetails(path) generated a OneDriveException"); if (e.httpStatusCode == 404) { // The directory was not found on OneDrive - no need to delete it - log.vlog("The requested directory to delete was not found on OneDrive - skipping removing the remote directory as it doesn't exist"); + // "The requested directory to delete was not found on OneDrive - skipping removing the remote directory as it doesn't exist" + log.vlog(provideLanguageTranslation(languageIdentifier,115)); return; } @@ -976,12 +1023,14 @@ final class SyncEngine // Was the item found in the DB if (!itemInDB) { // this is odd .. this directory is not in the local database - just go delete it - log.vlog("The requested directory to delete was not found in the local database - pushing delete request direct to OneDrive"); + // "The requested directory to delete was not found in the local database - pushing delete request direct to OneDrive" + log.vlog(provideLanguageTranslation(languageIdentifier,116)); uploadDeleteItem(item, path); } else { // the folder was in the local database // Handle the deletion and saving any update to the local database - log.vlog("The requested directory to delete was found in the local database. Processing the deletion normally"); + // "The requested directory to delete was found in the local database. Processing the deletion normally" + log.vlog(provideLanguageTranslation(languageIdentifier,117)); deleteByPath(path); } } @@ -995,8 +1044,9 @@ final class SyncEngine } catch (OneDriveException e) { log.vdebug("onedrive.getPathDetails(source); generated a OneDriveException"); if (e.httpStatusCode == 404) { - // The directory was not found - log.vlog("The requested directory to rename was not found on OneDrive"); + // The directory was not found + // "The requested directory to rename was not found on OneDrive" + log.vlog(provideLanguageTranslation(languageIdentifier,118)); return; } @@ -1024,7 +1074,8 @@ final class SyncEngine // id is the root of the drive or a shared folder private void applyDifferences(string driveId, const(char)[] id, bool performFullItemScan) { - log.vlog("Applying changes of Path ID: " ~ id); + // "Applying changes of Path ID: " + log.vlog(provideLanguageTranslation(languageIdentifier,119), id); // function variables char[] idToQuery; JSONValue changes; @@ -1076,30 +1127,35 @@ final class SyncEngine if (remainingFreeSpace <= 0) { if (accountType == "personal"){ // zero space available - log.error("ERROR: OneDrive account currently has zero space available. Please free up some space online."); + // "ERROR: OneDrive account currently has zero space available. Please free up some space online." + log.error(provideLanguageTranslation(languageIdentifier,81)); quotaAvailable = false; } else { // zero space available is being reported, maybe being restricted? - log.error("WARNING: OneDrive quota information is being restricted or providing a zero value. Please fix by speaking to your OneDrive / Office 365 Administrator."); + // "WARNING: OneDrive quota information is being restricted or providing a zero value. Please fix by speaking to your OneDrive / Office 365 Administrator." + log.error(provideLanguageTranslation(languageIdentifier,82)); quotaRestricted = true; } } else { // Display the updated value - log.vlog("Updated Remaining Free Space: ", remainingFreeSpace); + // "Updated Remaining Free Space: " + log.vlog(provideLanguageTranslation(languageIdentifier,120)); } } } else { // quota details returned, but for a drive id that is not ours if (currentDriveQuota["quota"]["remaining"].integer <= 0) { // value returned is 0 or less than 0 - log.vlog("OneDrive quota information is set at zero, as this is not our drive id, ignoring"); + // "OneDrive quota information is set at zero, as this is not our drive id, ignoring" + log.vlog(provideLanguageTranslation(languageIdentifier,121)); } } } else { // No quota details returned if (driveId == defaultDriveId) { // no quota details returned for current drive id - log.error("ERROR: OneDrive quota information is missing. Potentially your OneDrive account currently has zero space available. Please free up some space online."); + // "ERROR: OneDrive quota information is missing. Potentially your OneDrive account currently has zero space available. Please free up some space online." + log.error(provideLanguageTranslation(languageIdentifier,83)); } else { // quota details not available log.vdebug("OneDrive quota information is being restricted as this is not our drive id."); @@ -1114,7 +1170,7 @@ final class SyncEngine log.vdebug("idDetails = onedrive.getPathDetailsById(driveId, id) generated a OneDriveException"); if (e.httpStatusCode == 404) { // id was not found - possibly a remote (shared) folder - log.vlog("No details returned for given Path ID"); + log.vlog(provideLanguageTranslation(languageIdentifier,122)); return; } @@ -1357,10 +1413,9 @@ final class SyncEngine // HTTP request returned status code 404 (Not Found) if (e.httpStatusCode == 404) { - // Stop application - log.log("\n\nOneDrive returned a 'HTTP 404 - Item not found'"); - log.log("The item id to query was not found on OneDrive"); - log.log("\nRemove your '", cfg.databaseFilePath, "' file and try to sync again\n"); + // Stop this sync action + // "ERROR: A potential local database consistency issue has been caught. Please retry your command with '--resync' to fix any local database consistency issues." + log.error(provideLanguageTranslation(languageIdentifier,123)); return; } @@ -1383,7 +1438,8 @@ final class SyncEngine // If an error is returned when querying 'changes' and we recall the original function, we go into a never ending loop where the sync never ends // re-try the specific changes queries if (e.httpStatusCode == 504) { - log.log("OneDrive returned a 'HTTP 504 - Gateway Timeout' when attempting to query OneDrive drive items - retrying applicable request"); + // "OneDrive returned a 'HTTP 504 - Gateway Timeout' when attempting to query the OneDrive API - retrying applicable request" + log.log(provideLanguageTranslation(languageIdentifier,124)); log.vdebug("changes = generateDeltaResponse(driveId, idToQuery) previously threw an error - retrying"); // The server, while acting as a proxy, did not receive a timely response from the upstream server it needed to access in attempting to complete the request. log.vdebug("Thread sleeping for 30 seconds as the server did not receive a timely response from the upstream server it needed to access in attempting to complete the request"); @@ -1431,10 +1487,9 @@ final class SyncEngine // HTTP request returned status code 404 (Not Found) if (e.httpStatusCode == 404) { - // Stop application - log.log("\n\nOneDrive returned a 'HTTP 404 - Item not found'"); - log.log("The item id to query was not found on OneDrive"); - log.log("\nRemove your '", cfg.databaseFilePath, "' file and try to sync again\n"); + // Stop this sync action + // "ERROR: A potential local database consistency issue has been caught. Please retry your command with '--resync' to fix any local database consistency issues." + log.error(provideLanguageTranslation(languageIdentifier,123)); return; } @@ -1464,7 +1519,8 @@ final class SyncEngine // If an error is returned when querying 'changes' and we recall the original function, we go into a never ending loop where the sync never ends // re-try the specific changes queries if (e.httpStatusCode == 504) { - log.log("OneDrive returned a 'HTTP 504 - Gateway Timeout' when attempting to query for changes - retrying applicable request"); + // "OneDrive returned a 'HTTP 504 - Gateway Timeout' when attempting to query the OneDrive API - retrying applicable request" + log.log(provideLanguageTranslation(languageIdentifier,124)); log.vdebug("changes = onedrive.viewChangesByItemId(driveId, idToQuery, deltaLink) previously threw an error - retrying"); // The server, while acting as a proxy, did not receive a timely response from the upstream server it needed to access in attempting to complete the request. log.vdebug("Thread sleeping for 30 seconds as the server did not receive a timely response from the upstream server it needed to access in attempting to complete the request"); @@ -1480,7 +1536,8 @@ final class SyncEngine // display what the error is log.vdebug("Query Error: changes = onedrive.viewChangesByItemId(driveId, idToQuery, deltaLink) on re-try after delay"); if (e.httpStatusCode == 504) { - log.log("OneDrive returned a 'HTTP 504 - Gateway Timeout' when attempting to query for changes - retrying applicable request"); + // "OneDrive returned a 'HTTP 504 - Gateway Timeout' when attempting to query the OneDrive API - retrying applicable request" + log.log(provideLanguageTranslation(languageIdentifier,124)); log.vdebug("changes = onedrive.viewChangesByItemId(driveId, idToQuery, deltaLink) previously threw an error - retrying with empty deltaLink"); try { // try query with empty deltaLink value @@ -1536,10 +1593,9 @@ final class SyncEngine // HTTP request returned status code 404 (Not Found) if (e.httpStatusCode == 404) { - // Stop application - log.log("\n\nOneDrive returned a 'HTTP 404 - Item not found'"); - log.log("The item id to query was not found on OneDrive"); - log.log("\nRemove your '", cfg.databaseFilePath, "' file and try to sync again\n"); + // Stop this sync action + // "ERROR: A potential local database consistency issue has been caught. Please retry your command with '--resync' to fix any local database consistency issues." + log.error(provideLanguageTranslation(languageIdentifier,123)); return; } @@ -1569,7 +1625,8 @@ final class SyncEngine // If an error is returned when querying 'changes' and we recall the original function, we go into a never ending loop where the sync never ends // re-try the specific changes queries if (e.httpStatusCode == 504) { - log.log("OneDrive returned a 'HTTP 504 - Gateway Timeout' when attempting to query for changes - retrying applicable request"); + // "OneDrive returned a 'HTTP 504 - Gateway Timeout' when attempting to query the OneDrive API - retrying applicable request" + log.log(provideLanguageTranslation(languageIdentifier,124)); log.vdebug("changesAvailable = onedrive.viewChangesByItemId(driveId, idToQuery, deltaLinkAvailable) previously threw an error - retrying"); // The server, while acting as a proxy, did not receive a timely response from the upstream server it needed to access in attempting to complete the request. log.vdebug("Thread sleeping for 30 seconds as the server did not receive a timely response from the upstream server it needed to access in attempting to complete the request"); @@ -1585,7 +1642,8 @@ final class SyncEngine // display what the error is log.vdebug("Query Error: changesAvailable = onedrive.viewChangesByItemId(driveId, idToQuery, deltaLinkAvailable) on re-try after delay"); if (e.httpStatusCode == 504) { - log.log("OneDrive returned a 'HTTP 504 - Gateway Timeout' when attempting to query for changes - retrying applicable request"); + // "OneDrive returned a 'HTTP 504 - Gateway Timeout' when attempting to query the OneDrive API - retrying applicable request" + log.log(provideLanguageTranslation(languageIdentifier,124)); log.vdebug("changesAvailable = onedrive.viewChangesByItemId(driveId, idToQuery, deltaLinkAvailable) previously threw an error - retrying with empty deltaLinkAvailable"); try { // try query with empty deltaLinkAvailable value @@ -1631,22 +1689,26 @@ final class SyncEngine // sync_list is not being used - lets use the right messaging here if (oneDriveFullScanTrigger) { // full scan was triggered out of cycle - log.vlog("Processing ", nrChanges, " OneDrive items to ensure consistent local state due to a full scan being triggered by actions on OneDrive"); + // "Processing ", nrChanges, " OneDrive items to ensure consistent local state due to a full scan being triggered by actions on OneDrive" + log.vlog(provideLanguageTranslation(languageIdentifier,125), nrChanges, provideLanguageTranslation(languageIdentifier,126)); // unset now the full scan trigger if set unsetOneDriveFullScanTrigger(); } else { // no sync_list in use, oneDriveFullScanTrigger not set via sync_list or skip_dir if (performFullItemScan){ // performFullItemScan was set - log.vlog("Processing ", nrChanges, " OneDrive items to ensure consistent local state due to a full scan being requested"); + // "Processing ", nrChanges, " OneDrive items to ensure consistent local state due to a full scan being requested" + log.vlog(provideLanguageTranslation(languageIdentifier,125), nrChanges, provideLanguageTranslation(languageIdentifier,127)); } else { // default processing message - log.vlog("Processing ", nrChanges, " OneDrive items to ensure consistent local state"); + // "Processing ", nrChanges, " OneDrive items to ensure consistent local state" + log.vlog(provideLanguageTranslation(languageIdentifier,125), nrChanges, provideLanguageTranslation(languageIdentifier,128)); } } } else { // sync_list is being used - why are we going through the entire OneDrive contents? - log.vlog("Processing ", nrChanges, " OneDrive items to ensure consistent local state due to sync_list being used"); + // "Processing ", nrChanges, " OneDrive items to ensure consistent local state due to sync_list being used" + log.vlog(provideLanguageTranslation(languageIdentifier,125), nrChanges, provideLanguageTranslation(languageIdentifier,129)); } } else { // There are valid changes but less than the min_notify_changes configured threshold @@ -1661,15 +1723,18 @@ final class SyncEngine // full scan was requested or triggered // use the right message if (oneDriveFullScanTrigger) { - log.vlog("Processing ", nrChanges, " OneDrive items to ensure consistent local state due to a full scan being triggered by actions on OneDrive"); + // "Processing ", nrChanges, " OneDrive items to ensure consistent local state due to a full scan being triggered by actions on OneDrive" + log.vlog(provideLanguageTranslation(languageIdentifier,125), nrChanges, provideLanguageTranslation(languageIdentifier,126)); // unset now the full scan trigger if set unsetOneDriveFullScanTrigger(); } else { - log.vlog("Processing ", nrChanges, " OneDrive items to ensure consistent local state due to a full scan being requested"); + // "Processing ", nrChanges, " OneDrive items to ensure consistent local state due to a full scan being requested" + log.vlog(provideLanguageTranslation(languageIdentifier,125), nrChanges, provideLanguageTranslation(languageIdentifier,127)); } } else { // standard message - log.vlog("Number of items from OneDrive to process: ", nrChanges); + // "Number of items from OneDrive to process: " + log.vlog(provideLanguageTranslation(languageIdentifier,130), nrChanges); } } @@ -1816,7 +1881,8 @@ final class SyncEngine log.vdebug("oneDriveMovedNotDeleted = onedrive.getPathDetailsById(driveId, item['id'].str); generated a OneDriveException"); if (e.httpStatusCode == 404) { // No .. that ID is GONE - log.vlog("Remote change discarded - item cannot be found"); + // "Remote change discarded - item cannot be found" + log.vlog(provideLanguageTranslation(languageIdentifier,131)); } if (e.httpStatusCode == 429) { // HTTP request returned status code 429 (Too Many Requests). We need to leverage the response Retry-After HTTP header to ensure minimum delay until the throttle is removed. @@ -1830,7 +1896,8 @@ final class SyncEngine // Rather than retry original function, retry the actual call and replicate error handling if (e.httpStatusCode == 404) { // No .. that ID is GONE - log.vlog("Remote change discarded - item cannot be found"); + // "Remote change discarded - item cannot be found" + log.vlog(provideLanguageTranslation(languageIdentifier,131)); } else { // not a 404 displayOneDriveErrorMessage(e.msg, getFunctionName!({})); @@ -1850,17 +1917,20 @@ final class SyncEngine } else { // out of scope for some other reason if (singleDirectoryScope){ - log.vlog("Remote change discarded - not in --single-directory sync scope (in DB)"); + // "Remote change discarded - not in --single-directory sync scope (in DB)" + log.vlog(provideLanguageTranslation(languageIdentifier,132)); } else { - log.vlog("Remote change discarded - not in sync scope"); + // "Remote change discarded - not in sync scope" + log.vlog(provideLanguageTranslation(languageIdentifier,133)); } - log.vdebug("Remote change discarded: ", item); + log.vdebug("Remote change discarded: ", item); } } else { // item is not in the database if (singleDirectoryScope){ // We are syncing a single directory, so this is the reason why it is out of scope - log.vlog("Remote change discarded - not in --single-directory sync scope (not in DB)"); + // "Remote change discarded - not in --single-directory sync scope (not in DB)" + log.vlog(provideLanguageTranslation(languageIdentifier,134)); log.vdebug("Remote change discarded: ", item); } else { // Not a single directory sync @@ -1868,11 +1938,13 @@ final class SyncEngine // if we are syncing shared business folders, a 'change' may be out of scope as we are not syncing that 'folder' // but we are sent all changes from the 'parent root' as we cannot query the 'delta' for this folder // as that is a 501 error - not implemented - log.vlog("Remote change discarded - not in business shared folders sync scope"); + // "Remote change discarded - not in business shared folders sync scope" + log.vlog(provideLanguageTranslation(languageIdentifier,135)); log.vdebug("Remote change discarded: ", item); } else { // out of scope for some other reason - log.vlog("Remote change discarded - not in sync scope"); + // "Remote change discarded - not in sync scope" + log.vlog(provideLanguageTranslation(languageIdentifier,133)); log.vdebug("Remote change discarded: ", item); } } @@ -2047,7 +2119,8 @@ final class SyncEngine } log.vdebug("Result: ", unwanted); - if (unwanted) log.vlog("Skipping item - excluded by skip_dir config: ", matchDisplay); + // "Skipping item - excluded by skip_dir config: " + if (unwanted) log.vlog(provideLanguageTranslation(languageIdentifier,93), matchDisplay); } } } @@ -2077,11 +2150,11 @@ final class SyncEngine log.vdebug("skip_file item to check: ", path); unwanted = selectiveSync.isFileNameExcluded(path); log.vdebug("Result: ", unwanted); - if (unwanted) log.vlog("Skipping item - excluded by skip_file config: ", item.name); + if (unwanted) log.vlog(provideLanguageTranslation(languageIdentifier,137), item.name); } else { // parent id is not in the database unwanted = true; - log.vlog("Skipping file - parent path not present in local database"); + log.vlog(provideLanguageTranslation(languageIdentifier,138)); } } } @@ -2104,13 +2177,16 @@ final class SyncEngine // Microsoft OneNote container objects present as neither folder or file but has file size if ((!isItemFile(driveItem)) && (!isItemFolder(driveItem)) && (hasFileSize(driveItem))) { // Log that this was skipped as this was a Microsoft OneNote item and unsupported - log.vlog("The Microsoft OneNote Notebook '", path, "' is not supported by this client"); + // "The Microsoft OneNote Notebook '", path, "' is not supported by this client" + log.vlog(provideLanguageTranslation(languageIdentifier,139), path, provideLanguageTranslation(languageIdentifier,140)); } else { - // Log that this item was skipped as unsupported - log.vlog("The OneDrive item '", path, "' is not supported by this client"); + // Log that this item was skipped as unsupported + // "The OneDrive item '", path, "' is not supported by this client" + log.vlog(provideLanguageTranslation(languageIdentifier,141), path, provideLanguageTranslation(languageIdentifier,140)); } unwanted = true; - log.vdebug("Flagging as unwanted: item type is not supported"); + // "Flagging as unwanted: item type is not supported" + log.vdebug(provideLanguageTranslation(languageIdentifier,142)); } } @@ -2131,10 +2207,12 @@ final class SyncEngine } else { // path is unwanted unwanted = true; - log.vlog("Skipping item - excluded by sync_list config: ", path); + // Skipping item - excluded by sync_list config: " + log.vlog(provideLanguageTranslation(languageIdentifier,143), path); // flagging to skip this file now, but does this exist in the DB thus needs to be removed / deleted? if (itemdb.idInLocalDatabase(item.driveId, item.id)){ - log.vlog("Flagging item for local delete as item exists in database: ", path); + // "Flagging item for local delete as item exists in database: " + log.vlog(provideLanguageTranslation(languageIdentifier,144), path); // flag to delete idsToDelete ~= [item.driveId, item.id]; } @@ -2176,7 +2254,8 @@ final class SyncEngine // skip downloading dot files if configured if (cfg.getValueBool("skip_dotfiles")) { if (isDotFile(path)) { - log.vlog("Skipping item - .file or .folder: ", path); + // "Skipping item - .file or .folder: " + log.vlog(provideLanguageTranslation(languageIdentifier,145), path); unwanted = true; } } @@ -2236,25 +2315,30 @@ final class SyncEngine // no local rename // no download needed if (localModifiedTime == item.mtime) { - log.vlog("Local item modified time is equal to OneDrive item modified time based on UTC time conversion - keeping local item"); + // "Local item modified time is equal to OneDrive item modified time based on UTC time conversion - keeping local item" + log.vlog(provideLanguageTranslation(languageIdentifier,146)); } else { - log.vlog("Local item modified time is newer than OneDrive item modified time based on UTC time conversion - keeping local item"); + // "Local item modified time is newer than OneDrive item modified time based on UTC time conversion - keeping local item" + log.vlog(provideLanguageTranslation(languageIdentifier,147)); } skippedItems ~= item.id; return; } else { // remote file is newer than local item - log.vlog("Remote item modified time is newer based on UTC time conversion"); // correct message, remote item is newer + // "Remote item modified time is newer based on UTC time conversion" + log.vlog(provideLanguageTranslation(languageIdentifier,148)); // correct message, remote item is newer auto ext = extension(oldPath); auto newPath = path.chomp(ext) ~ "-" ~ deviceName ~ ext; // has the user configured to IGNORE local data protection rules? if (bypassDataPreservation) { // The user has configured to ignore data safety checks and overwrite local data rather than preserve & rename - log.vlog("WARNING: Local Data Protection has been disabled. You may experience data loss on this file: ", oldPath); + // "WARNING: Local Data Protection has been disabled by your configuration. You may experience data loss on this file: " + log.vlog(provideLanguageTranslation(languageIdentifier,149), oldPath); } else { // local data protection is configured, renaming local file - log.vlog("The local item is out-of-sync with OneDrive, renaming to preserve existing file and prevent data loss: ", oldPath, " -> ", newPath); + // "The local item is out-of-sync with OneDrive, renaming to preserve existing file and prevent data loss: " + log.vlog(provideLanguageTranslation(languageIdentifier,150), oldPath, " -> ", newPath); // perform the rename action if (!dryRun) { @@ -2281,7 +2365,8 @@ final class SyncEngine if (isItemFile(driveItem)) { if (cfg.getValueLong("skip_size") != 0) { if (driveItem["size"].integer >= this.newSizeLimit) { - log.vlog("Skipping item - excluded by skip_size config: ", item.name, " (", driveItem["size"].integer/2^^20, " MB)"); + // "Skipping item - excluded by skip_size config: " + log.vlog(provideLanguageTranslation(languageIdentifier,151), item.name, " (", driveItem["size"].integer/2^^20, " MB)"); return; } } @@ -2341,7 +2426,8 @@ final class SyncEngine // item id is in the database // no local rename // no download needed - log.vlog("Local item modified time is newer based on UTC time conversion - keeping local item as this exists in the local database"); + // "Local item modified time is newer based on UTC time conversion - keeping local item as this exists in the local database" + log.vlog(provideLanguageTranslation(languageIdentifier,152)); log.vdebug("Skipping OneDrive change as this is determined to be unwanted due to local item modified time being newer than OneDrive item and present in the sqlite database"); return; } else { @@ -2352,17 +2438,20 @@ final class SyncEngine // need the parent path for this object string parentPath = dirName(path); if (exists(parentPath ~ "/.nosync")) { - log.vlog("Skipping downloading item - .nosync found in parent folder & --check-for-nosync is enabled: ", path); + // "Skipping downloading item - .nosync found in parent folder & --check-for-nosync is enabled: " + log.vlog(provideLanguageTranslation(languageIdentifier,153), path); // flag that this download failed, otherwise the 'item' is added to the database - then, as not present on the local disk, would get deleted from OneDrive downloadFailed = true; // clean up this partial file, otherwise every sync we will get theis warning - log.vlog("Removing previous partial file download due to .nosync found in parent folder & --check-for-nosync is enabled"); + // "Removing previous partial file download due to .nosync found in parent folder & --check-for-nosync is enabled" + log.vlog(provideLanguageTranslation(languageIdentifier,154)); safeRemove(path); return; } } // file exists locally but is not in the sqlite database - maybe a failed download? - log.vlog("Local item does not exist in local database - replacing with file from OneDrive - failed download?"); + // "Local item does not exist in local database - replacing with file from OneDrive - failed download?" + log.vlog(provideLanguageTranslation(languageIdentifier,155)); // was --resync issued? if (cfg.getValueBool("resync")) { @@ -2377,10 +2466,12 @@ final class SyncEngine // has the user configured to IGNORE local data protection rules? if (bypassDataPreservation) { // The user has configured to ignore data safety checks and overwrite local data rather than preserve & rename - log.vlog("WARNING: Local Data Protection has been disabled. You may experience data loss on this file: ", path); + // "WARNING: Local Data Protection has been disabled by your configuration. You may experience data loss on this file: " + log.vlog(provideLanguageTranslation(languageIdentifier,149), path); } else { // local data protection is configured, renaming local file - log.vlog("The local item is out-of-sync with OneDrive, renaming to preserve existing file and prevent data loss due to --resync: ", path, " -> ", newPath); + // "The local item is out-of-sync with OneDrive, renaming to preserve existing file and prevent data loss due to --resync: " + log.vlog(provideLanguageTranslation(languageIdentifier,156), path, " -> ", newPath); // perform the rename action of the local file if (!dryRun) { safeRename(path); @@ -2393,7 +2484,8 @@ final class SyncEngine } } else { // remote file is newer than local item - log.vlog("Remote item modified time is newer based on UTC time conversion"); // correct message, remote item is newer + // "Remote item modified time is newer based on UTC time conversion" + log.vlog(provideLanguageTranslation(languageIdentifier,157)); // correct message, remote item is newer log.vdebug("localModifiedTime (local file): ", localModifiedTime); log.vdebug("itemModifiedTime (OneDrive item): ", itemModifiedTime); @@ -2403,10 +2495,12 @@ final class SyncEngine // has the user configured to IGNORE local data protection rules? if (bypassDataPreservation) { // The user has configured to ignore data safety checks and overwrite local data rather than preserve & rename - log.vlog("WARNING: Local Data Protection has been disabled. You may experience data loss on this file: ", path); + // "WARNING: Local Data Protection has been disabled by your configuration. You may experience data loss on this file: " + log.vlog(provideLanguageTranslation(languageIdentifier,149), path); } else { // local data protection is configured, renaming local file - log.vlog("The local item is out-of-sync with OneDrive, renaming to preserve existing file and prevent data loss: ", path, " -> ", newPath); + // "The local item is out-of-sync with OneDrive, renaming to preserve existing file and prevent data loss: " + log.vlog(provideLanguageTranslation(languageIdentifier,150), path, " -> ", newPath); // perform the rename action of the local file if (!dryRun) { safeRename(path); @@ -2441,9 +2535,11 @@ final class SyncEngine if (selectiveSync.isDirNameExcluded(pathToCheck)) { // this path should be skipped if (item.type == ItemType.file) { - log.vlog("Skipping item - file path is excluded by skip_dir config: ", path); + // "Skipping item - file path is excluded by skip_dir config: " + log.vlog(provideLanguageTranslation(languageIdentifier,136), path); } else { - log.vlog("Skipping item - excluded by skip_dir config: ", path); + // "Skipping item - excluded by skip_dir config: " + log.vlog(provideLanguageTranslation(languageIdentifier,93), path); } // flag that this download failed, otherwise the 'item' is added to the database - then, as not present on the local disk, would get deleted from OneDrive downloadFailed = true; @@ -2457,7 +2553,8 @@ final class SyncEngine // need the parent path for this object string parentPath = dirName(path); if (exists(parentPath ~ "/.nosync")) { - log.vlog("Skipping downloading item - .nosync found in parent folder & --check-for-nosync is enabled: ", path); + // "Skipping downloading item - .nosync found in parent folder & --check-for-nosync is enabled: " + log.vlog(provideLanguageTranslation(languageIdentifier,153), path); // flag that this download failed, otherwise the 'item' is added to the database - then, as not present on the local disk, would get deleted from OneDrive downloadFailed = true; return; @@ -2476,7 +2573,8 @@ final class SyncEngine break; case ItemType.dir: case ItemType.remote: - log.log("Creating local directory: ", path); + // "Creating local directory: " + log.log(provideLanguageTranslation(languageIdentifier,158), path); // Issue #658 handling - is sync_list in use? if (syncListConfigured) { @@ -2533,24 +2631,26 @@ final class SyncEngine if (oldItem.eTag != newItem.eTag) { // handle changed name/path if (oldPath != newPath) { - log.log("Moving ", oldPath, " to ", newPath); + // "Moving ", oldPath, " to ", newPath + log.log(provideLanguageTranslation(languageIdentifier,159), oldPath, provideLanguageTranslation(languageIdentifier,160), newPath); if (exists(newPath)) { Item localNewItem; if (itemdb.selectByPath(newPath, defaultDriveId, localNewItem)) { // Query DB for new local item in specified path string itemSource = "database"; if (isItemSynced(localNewItem, newPath, itemSource)) { - log.vlog("Destination is in sync and will be overwritten"); + // "Destination is in sync and will be overwritten" + log.vlog(provideLanguageTranslation(languageIdentifier,161)); } else { - // TODO: force remote sync by deleting local item - log.vlog("The destination is occupied, renaming the conflicting file..."); + // "The destination is occupied, renaming the conflicting file..." + log.vlog(provideLanguageTranslation(languageIdentifier,162)); safeRename(newPath); } } else { // to be overwritten item is not already in the itemdb, so it should // be synced. Do a safe rename here, too. - // TODO: force remote sync by deleting local item - log.vlog("The destination is occupied by new file, renaming the conflicting file..."); + // "The destination is occupied by new file, renaming the conflicting file..." + log.vlog(provideLanguageTranslation(languageIdentifier,163)); safeRename(newPath); } } @@ -2586,13 +2686,15 @@ final class SyncEngine private void downloadFileItem(const ref Item item, const(string) path) { assert(item.type == ItemType.file); - write("Downloading file ", path, " ... "); + // "Downloading file ", path, " ... " + write(provideLanguageTranslation(languageIdentifier,164), path, " ... "); JSONValue fileDetails; try { fileDetails = onedrive.getFileDetails(item.driveId, item.id); } catch (OneDriveException e) { - log.error("ERROR: Query of OneDrive for file details failed"); + // "ERROR: Query of OneDrive for file details failed" + log.error(provideLanguageTranslation(languageIdentifier,165)); if (e.httpStatusCode >= 500) { // OneDrive returned a 'HTTP 5xx Server Side Error' - gracefully handling error - error message already logged downloadFailed = true; @@ -2604,14 +2706,15 @@ final class SyncEngine if (fileDetails.type() == JSONType.object){ if (isMalware(fileDetails)){ // OneDrive reports that this file is malware - log.error("ERROR: MALWARE DETECTED IN FILE - DOWNLOAD SKIPPED"); + // "ERROR: MALWARE DETECTED IN FILE - DOWNLOAD SKIPPED" + log.error(provideLanguageTranslation(languageIdentifier,166)); // set global flag malwareDetected = true; return; } } else { // Issue #550 handling - log.error("ERROR: Query of OneDrive for file details failed"); + log.error(provideLanguageTranslation(languageIdentifier,165)); log.vdebug("onedrive.getFileDetails call returned an invalid JSON Object"); // We want to return, cant download downloadFailed = true; @@ -2763,12 +2866,14 @@ final class SyncEngine // size error? if (getSize(path) != fileSize) { // downloaded file size does not match - log.error("ERROR: File download size mis-match. Increase logging verbosity to determine why."); + // "ERROR: File download size mis-match. Increase logging verbosity to determine why." + log.error(provideLanguageTranslation(languageIdentifier,167)); } // hash error? if ((OneDriveFileHash != quickXorHash) || (OneDriveFileHash != sha1Hash)) { // downloaded file hash does not match - log.error("ERROR: File download hash mis-match. Increase logging verbosity to determine why."); + // "ERROR: File download hash mis-match. Increase logging verbosity to determine why." + log.error(provideLanguageTranslation(languageIdentifier,168)); } // we do not want this local file to remain on the local file system safeRemove(path); @@ -2776,15 +2881,18 @@ final class SyncEngine return; } } else { - log.error("ERROR: File failed to download. Increase logging verbosity to determine why."); + // "ERROR: File failed to download. Increase logging verbosity to determine why." + log.error(provideLanguageTranslation(languageIdentifier,169)); downloadFailed = true; return; } } if (!downloadFailed) { - writeln("done."); - log.fileOnly("Downloading file ", path, " ... done."); + // "done." + writeln(provideLanguageTranslation(languageIdentifier,170)); + // "Downloading file ", path, " ... done." + log.fileOnly(provideLanguageTranslation(languageIdentifier,164), path, provideLanguageTranslation(languageIdentifier,171)); } } @@ -2806,20 +2914,24 @@ final class SyncEngine if (localModifiedTime == itemModifiedTime) { return true; } else { - log.vlog("The local item has a different modified time ", localModifiedTime, " when compared to ", itemSource, " modified time ", itemModifiedTime); + // "The local item has a different modified time ", localModifiedTime, " when compared to ", itemSource, " modified time ", itemModifiedTime) + log.vlog(provideLanguageTranslation(languageIdentifier,172), localModifiedTime, provideLanguageTranslation(languageIdentifier,173), itemSource, provideLanguageTranslation(languageIdentifier,174), itemModifiedTime); } if (testFileHash(path, item)) { return true; } else { - log.vlog("The local item has a different hash when compared to ", itemSource, " item hash"); + // "The local item has a different hash when compared to ", itemSource, " item hash" + log.vlog(provideLanguageTranslation(languageIdentifier,175), itemSource, provideLanguageTranslation(languageIdentifier,176)); } } else { // Unable to read local file - log.log("Unable to determine the sync state of this file as it cannot be read (file permissions or file corruption): ", path); + // "Unable to determine the sync state of this file as it cannot be read (file permissions or file corruption): " + log.log(provideLanguageTranslation(languageIdentifier,177), path); return false; } } else { - log.vlog("The local item is a directory but should be a file"); + // "The local item is a directory but should be a file" + log.vlog(provideLanguageTranslation(languageIdentifier,178)); } break; case ItemType.dir: @@ -2827,7 +2939,8 @@ final class SyncEngine if (isDir(path)) { return true; } else { - log.vlog("The local item is a file but should be a directory"); + // "The local item is a file but should be a directory" + log.vlog(provideLanguageTranslation(languageIdentifier,179)); } break; } @@ -2843,7 +2956,8 @@ final class SyncEngine // Compute this item path path = computeItemPath(i[0], i[1]); // Try to delete item object - log.log("Trying to delete item ", path); + // "Trying to delete item " + log.log(provideLanguageTranslation(languageIdentifier,180), path); if (!dryRun) { // Actually process the database entry removal itemdb.deleteById(item.driveId, item.id); diff --git a/src/translations.d b/src/translations.d new file mode 100644 index 000000000..1802470c7 --- /dev/null +++ b/src/translations.d @@ -0,0 +1,236 @@ +// The aim is to provide language translations for the following application logging output: +// - log.log +// - log.vlog +// - log.error +// - log.logAndNotify +import std.string, std.stdio, std.json, std.file; + +ulong defaultMessageCount = 0; +string[] languageResponsesEN_AU; +string[] languageResponsesEN_US; +string defaultBadLookupResponse = "ERROR: BAD LOOKUP INDEX "; + +// Initialise default message lookup using EN-AU +void initialize() { + // Initialise default messages + initialise_EN_AU(); + defaultMessageCount = count(languageResponsesEN_AU); +} + +// Load user configured translation files from a file +void initializeUserConfiguredLanguageTranslations(string languageIdentifier) { + // Path to translation files + string translationPath = "/usr/share/onedrive/"; + + // Translation files + string EN_US_TranslationFile = translationPath ~ "EN-US.json"; + + switch (languageIdentifier) { + case "EN-US": + // Load Translation Files if they exist + if (exists(EN_US_TranslationFile)) { + // Load the file + auto fileContents = readText(EN_US_TranslationFile); + JSONValue languageList = parseJSON(fileContents); + + // Load the message into the required array + foreach (translationItem; languageList["list"].array) { + string responseString = translationItem.toString; + responseString = responseString[1 .. $-1]; + languageResponsesEN_US ~= responseString; + } + // If the loaded responses != defaultMessageCount there will be an issue in translation .. warn + writeln("WARNING: " ~ EN_US_TranslationFile ~ " is out of sync with default application messages - application output will be inaccurate"); + } + break; + + case "DE": + //logMessageResponse = getResponseFromIndex_EN_US(requiredResponseIndex); + break; + default: + //logMessageResponse = getResponseFromIndex_EN_AU(requiredResponseIndex); + break; + } +} + +// Provide a language response based on the setting of a 'config' file language option +string provideLanguageTranslation(string languageIdentifier, int requiredResponseIndex) { + string logMessageResponse; + // Application message indexes start at '1', however array index's start at '0' + // Need to decrement the requiredResponseIndex so we get the right message + requiredResponseIndex--; + + switch (languageIdentifier) { + case "EN-AU": + // Language Maintainer: abraunegg + logMessageResponse = getResponseFromIndex_EN_AU(requiredResponseIndex); + break; + case "EN-US": + // Language Maintainer: abraunegg + logMessageResponse = getResponseFromIndex_EN_US(requiredResponseIndex); + break; + default: + logMessageResponse = getResponseFromIndex_EN_AU(requiredResponseIndex); + break; + } + + // Return log message to application + return logMessageResponse; +} + +// Load EN-AU application messages +void initialise_EN_AU(){ + // The below JSON array contains all the default application messages + JSONValue languageList = [ "language": "EN-AU"]; + languageList.object["list"] = JSONValue([ + "No user or system config file found, using application defaults", + "System configuration file successfully loaded", + "System configuration file has errors - please check your configuration", + "Configuration file successfully loaded", + "Configuration file has errors - please check your configuration", + "Using config option for Global Azure AD Endpoints", + "Using config option for Azure AD for US Government Endpoints", + "Using config option for Azure AD for US Government Endpoints (DOD)", + "Using config option for Azure AD Germany", + "Using config option for Azure AD China operated by 21Vianet", + "Unknown Azure AD Endpoint - using Global Azure AD Endpoints", + "Unknown key in config file: ", + "Malformed config line: ", + "config file has been updated, checking if --resync needed", + "An application configuration change has been detected where a --resync is required", + "DRY-RUN Configured. Output below shows what 'would' have occurred", + "Using logfile dir: ", + "Database schema changed, resync needed", + "Deleting the saved status ...", + "ERROR: Unable to reach Microsoft OneDrive API service, unable to initialise application", + "ERROR: Unable to reach Microsoft OneDrive API service at this point in time, re-trying network tests", + "Internet connectivity to Microsoft OneDrive service has been restored", + "ERROR: The OneDrive Linux Client was unable to reconnect to the Microsoft OneDrive service after 10000 attempts lasting over 1.2 years!", + "Initialising the OneDrive API ...", + "Could not initialise the OneDrive API", + "Application has been successfully authorised, however no additional command switches were provided", + "Please use 'onedrive --help' for further assistance in regards to running this application", + "Application has not been successfully authorised. Please check your URI response entry and try again", + "ERROR: --synchronize or --monitor switches missing from your command line input. Please add one (not both) of these switches to your command line", + "No OneDrive sync will be performed without one of these two arguments being present", + "ERROR: --synchronize and --monitor cannot be used together", + "Opening the item database ...", + "ERROR: Invalid 'User|Group|Other' permissions set within config file. Please check your config file.", + "All operations will be performed in: ", + "ERROR: Unable to create local OneDrive syncDir - ", + "ERROR: Invalid skip_file entry '.*' detected", + "Initialising the Synchronisation Engine ...", + "Cannot connect to Microsoft OneDrive Service - Network Connection Issue", + "WARNING: Application has been configured to bypass local data preservation in the event of file conflict", + "WARNING: Local data loss MAY occur in this scenario", + "ERROR: .nosync file found. Aborting synchronisation process to safeguard data", + "ERROR: Unsupported account type for listing OneDrive Business Shared Folders", + "ERROR: Unsupported account type for syncing OneDrive Business Shared Folders", + "WARNING: The requested path for --single-directory does not exist locally. Creating requested path within: ", + "Initialising monitor ...", + "OneDrive monitor interval (seconds): ", + "[M] Skipping watching path - .folder found & --skip-dot-files enabled: ", + "[M] Directory created: ", + "Offline, cannot create remote directory!", + "Cannot create remote directory: ", + "[M] File changed: ", + "Offline, cannot upload changed item!", + "Cannot upload file changes/creation: ", + "[M] Item deleted: ", + "Offline, cannot delete item!", + "Item cannot be deleted from OneDrive because it was not found in the local database", + "Cannot delete remote item: ", + "[M] Item moved: ", + "Offline, cannot move item!", + "Cannot move item: ", + "ERROR: ", + "ERROR: The following inotify error was generated: ", + "Starting a sync with OneDrive", + "Sync with OneDrive is complete", + "Persistent connection errors, reinitialising connection", + "Authorisation token invalid, use --logout to authorise the client again", + "Syncing changes from this selected path: ", + "Syncing changes from selected local path only - NOT syncing data changes from OneDrive ...", + "Syncing changes from selected local path first before downloading changes from OneDrive ...", + "Syncing changes from selected OneDrive path ...", + "Syncing changes from local path only - NOT syncing data changes from OneDrive ...", + "Syncing changes from local path first before downloading changes from OneDrive ...", + "Syncing changes from OneDrive ...", + "Giving up on sync after three attempts: ", + "Retry sync count: ", + " Got termination signal, shutting down DB connection", + "Syncing changes from OneDrive only - NOT syncing local data changes to OneDrive ...", + "The file does not have any hash", + "ERROR: Check your 'drive_id' entry in your configuration file as it may be incorrect", + "ERROR: Check your configuration as your refresh_token may be empty or invalid. You may need to issue a --logout and re-authorise this client.", + "ERROR: OneDrive account currently has zero space available. Please free up some space online.", + "WARNING: OneDrive quota information is being restricted or providing a zero value. Please fix by speaking to your OneDrive / Office 365 Administrator.", + "ERROR: OneDrive quota information is missing. Potentially your OneDrive account currently has zero space available. Please free up some space online.", + "ERROR: OneDrive quota information is being restricted. Please fix by speaking to your OneDrive / Office 365 Administrator.", + "Application version: ", + "Account Type: ", + "Default Drive ID: ", + "Default Root ID: ", + "Remaining Free Space: ", + "Continuing the upload session ...", + "Removing local file as --upload-only & --remove-source-files configured", + "ERROR: File failed to upload. Increase logging verbosity to determine why.", + "Skipping item - excluded by skip_dir config: ", + "Syncing this OneDrive Personal Shared Folder: ", + "Attempting to sync OneDrive Business Shared Folders", + "Syncing this OneDrive Business Shared Folder: ", + "OneDrive Business Shared Folder - Shared By: ", + "WARNING: Skipping shared folder due to existing name conflict: ", + "WARNING: Skipping changes of Path ID: ", + "WARNING: To sync this shared folder, this shared folder needs to be renamed", + "WARNING: Conflict Shared By: ", + "WARNING: Not syncing this OneDrive Business Shared File: ", + "OneDrive Business Shared File - Shared By: ", + "WARNING: Not syncing this OneDrive Business Shared item: ", + "ERROR: onedrive.getSharedWithMe call returned an invalid JSON Object", + "Getting path details from OneDrive ...", + "ERROR: The requested single directory to sync was not found on OneDrive", + "Fetching details for OneDrive Root", + "OneDrive Root does not exist in the database. We need to add it.", + "Added OneDrive Root to the local database", + "OneDrive Root exists in the database", + "ERROR: Unable to query OneDrive for account details", + ]); + + // Load the message into the array + foreach (translationItem; languageList["list"].array) { + string responseString = translationItem.toString; + responseString = responseString[1 .. $-1]; + languageResponsesEN_AU ~= responseString; + } +} + +// Provide the application message based on the index as provided +string getResponseFromIndex_EN_AU(int requiredResponseIndex) { + string requiredResponse; + // get response from message array + try { + // try and get the message from the required index + requiredResponse = languageResponsesEN_AU[requiredResponseIndex]; + } catch (core.exception.RangeError e) { + // invalid index provided + requiredResponse = defaultBadLookupResponse; + } + // Return language response + return requiredResponse; +} + +// Provide the application message based on the index as provided +string getResponseFromIndex_EN_US(int requiredResponseIndex) { + string requiredResponse; + // get response from message array + try { + // try and get the message from the required index + requiredResponse = languageResponsesEN_US[requiredResponseIndex]; + } catch (core.exception.RangeError e) { + // invalid index provided + requiredResponse = defaultBadLookupResponse; + } + // Return language response + return requiredResponse; +} \ No newline at end of file From 7f92f2b9429f67abf22275509aee87645abd9645 Mon Sep 17 00:00:00 2001 From: abraunegg Date: Mon, 31 May 2021 14:29:18 +1000 Subject: [PATCH 02/15] update * update initial WIP --- contrib/translations/DE.json | 28 +++ contrib/translations/EN-US.json | 135 ++--------- src/translations.d | 404 ++++++++++++++++++++------------ 3 files changed, 306 insertions(+), 261 deletions(-) create mode 100644 contrib/translations/DE.json diff --git a/contrib/translations/DE.json b/contrib/translations/DE.json new file mode 100644 index 000000000..e77514608 --- /dev/null +++ b/contrib/translations/DE.json @@ -0,0 +1,28 @@ +{ + "language": "DE", + "list": [ + { + "1": "Keine Benutzer- oder Systemkonfigurationsdatei gefunden, die Anwendungsstandardwerte verwendet", + "2": "Systemkonfigurationsdatei erfolgreich geladen", + "3": "Die Systemkonfigurationsdatei weist Fehler auf. Bitte überprüfen Sie Ihre Konfiguration", + "4": "Konfigurationsdatei erfolgreich geladen", + "5": "Konfigurationsdatei hat Fehler - bitte überprüfen Sie Ihre Konfiguration", + "6": "Verwenden der Konfigurationsoption für globale Azure AD-Endpunkte", + "7": "Verwenden der Konfigurationsoption für Azure AD für Endpunkte der US-Regierung", + "8": "Verwenden der Konfigurationsoption für Azure AD für US Government Endpoints (DOD)", + "9": "Verwenden der Konfigurationsoption für Azure AD Germany", + "10": "Verwenden der Konfigurationsoption für Azure AD China, das von 21Vianet betrieben wird", + "11": "Unbekannter Azure AD-Endpunkt – mit globalen Azure AD-Endpunkten", + "12": "Unbekannter Schlüssel in der Konfigurationsdatei: ", + "13": "Fehlerhafte Konfigurationszeile: ", + "14": "Die Konfigurationsdatei wurde aktualisiert und überprüft, ob --resync erforderlich ist", + "15": "Eine Änderung der Anwendungskonfiguration wurde festgestellt, wenn eine --resync erforderlich ist", + "16": "DRY-RUN Konfiguriert. Die folgende Ausgabe zeigt, was passiert wäre", + "17": "Verwenden des Protokolldateiverzeichnisses: ", + "18": "Datenbankschema geändert, Resync erforderlich", + "19": "Gespeicherten Status löschen ...", + "20": "FEHLER: Microsoft OneDrive-API-Dienst kann nicht erreicht werden, Anwendung kann nicht initialisiert werden" + + }, + ] +} \ No newline at end of file diff --git a/contrib/translations/EN-US.json b/contrib/translations/EN-US.json index 03204b3c4..7191070d3 100644 --- a/contrib/translations/EN-US.json +++ b/contrib/translations/EN-US.json @@ -1,117 +1,28 @@ { "language": "EN-US", "list": [ - "No user or system config file found, using application defaults", - "System configuration file successfully loaded", - "System configuration file has errors - please check your configuration", - "Configuration file successfully loaded", - "Configuration file has errors - please check your configuration", - "Using config option for Global Azure AD Endpoints", - "Using config option for Azure AD for US Government Endpoints", - "Using config option for Azure AD for US Government Endpoints (DOD)", - "Using config option for Azure AD Germany", - "Using config option for Azure AD China operated by 21Vianet", - "Unknown Azure AD Endpoint - using Global Azure AD Endpoints", - "Unknown key in config file: ", - "Malformed config line: ", - "config file has been updated, checking if --resync needed", - "An application configuration change has been detected where a --resync is required", - "DRY-RUN Configured. Output below shows what 'would' have occurred", - "Using logfile dir: ", - "Database schema changed, resync needed", - "Deleting the saved status ...", - "ERROR: Unable to reach Microsoft OneDrive API service, unable to initialize application", - "ERROR: Unable to reach Microsoft OneDrive API service at this point in time, re-trying network tests", - "Internet connectivity to Microsoft OneDrive service has been restored", - "ERROR: The OneDrive Linux Client was unable to reconnect to the Microsoft OneDrive service after 10000 attempts lasting over 1.2 years!", - "Initializing the OneDrive API ...", - "Could not initialize the OneDrive API", - "Application has been successfully authorized, however no additional command switches were provided", - "Please use 'onedrive --help' for further assistance in regards to running this application", - "Application has not been successfully authorized. Please check your URI response entry and try again", - "ERROR: --synchronize or --monitor switches missing from your command line input. Please add one (not both) of these switches to your command line", - "No OneDrive sync will be performed without one of these two arguments being present", - "ERROR: --synchronize and --monitor cannot be used together", - "Opening the item database ...", - "ERROR: Invalid 'User|Group|Other' permissions set within config file. Please check your config file.", - "All operations will be performed in: ", - "ERROR: Unable to create local OneDrive syncDir - ", - "ERROR: Invalid skip_file entry '.*' detected", - "Initializing the Synchronization Engine ...", - "Cannot connect to Microsoft OneDrive Service - Network Connection Issue", - "WARNING: Application has been configured to bypass local data preservation in the event of file conflict", - "WARNING: Local data loss MAY occur in this scenario", - "ERROR: .nosync file found. Aborting synchronization process to safeguard data", - "ERROR: Unsupported account type for listing OneDrive Business Shared Folders", - "ERROR: Unsupported account type for syncing OneDrive Business Shared Folders", - "WARNING: The requested path for --single-directory does not exist locally. Creating requested path within: ", - "Initializing monitor ...", - "OneDrive monitor interval (seconds): ", - "[M] Skipping watching path - .folder found & --skip-dot-files enabled: ", - "[M] Directory created: ", - "Offline, cannot create remote directory!", - "Cannot create remote directory: ", - "[M] File changed: ", - "Offline, cannot upload changed item!", - "Cannot upload file changes/creation: ", - "[M] Item deleted: ", - "Offline, cannot delete item!", - "Item cannot be deleted from OneDrive because it was not found in the local database", - "Cannot delete remote item: ", - "[M] Item moved: ", - "Offline, cannot move item!", - "Cannot move item: ", - "ERROR: ", - "ERROR: The following inotify error was generated: ", - "Starting a sync with OneDrive", - "Sync with OneDrive is complete", - "Persistent connection errors, reinitializing connection", - "Authorization token invalid, use --logout to authorize the client again", - "Syncing changes from this selected path: ", - "Syncing changes from selected local path only - NOT syncing data changes from OneDrive ...", - "Syncing changes from selected local path first before downloading changes from OneDrive ...", - "Syncing changes from selected OneDrive path ...", - "Syncing changes from local path only - NOT syncing data changes from OneDrive ...", - "Syncing changes from local path first before downloading changes from OneDrive ...", - "Syncing changes from OneDrive ...", - "Giving up on sync after three attempts: ", - "Retry sync count: ", - " Got termination signal, shutting down DB connection", - "Syncing changes from OneDrive only - NOT syncing local data changes to OneDrive ...", - "The file does not have any hash", - "ERROR: Check your 'drive_id' entry in your configuration file as it may be incorrect", - "ERROR: Check your configuration as your refresh_token may be empty or invalid. You may need to issue a --logout and re-authorize this client.", - "ERROR: OneDrive account currently has zero space available. Please free up some space online.", - "WARNING: OneDrive quota information is being restricted or providing a zero value. Please fix by speaking to your OneDrive / Office 365 Administrator.", - "ERROR: OneDrive quota information is missing. Potentially your OneDrive account currently has zero space available. Please free up some space online.", - "ERROR: OneDrive quota information is being restricted. Please fix by speaking to your OneDrive / Office 365 Administrator.", - "Application version: ", - "Account Type: ", - "Default Drive ID: ", - "Default Root ID: ", - "Remaining Free Space: ", - "Continuing the upload session ...", - "Removing local file as --upload-only & --remove-source-files configured", - "ERROR: File failed to upload. Increase logging verbosity to determine why.", - "Skipping item - excluded by skip_dir config: ", - "Syncing this OneDrive Personal Shared Folder: ", - "Attempting to sync OneDrive Business Shared Folders", - "Syncing this OneDrive Business Shared Folder: ", - "OneDrive Business Shared Folder - Shared By: ", - "WARNING: Skipping shared folder due to existing name conflict: ", - "WARNING: Skipping changes of Path ID: ", - "WARNING: To sync this shared folder, this shared folder needs to be renamed", - "WARNING: Conflict Shared By: ", - "WARNING: Not syncing this OneDrive Business Shared File: ", - "OneDrive Business Shared File - Shared By: ", - "WARNING: Not syncing this OneDrive Business Shared item: ", - "ERROR: onedrive.getSharedWithMe call returned an invalid JSON Object", - "Getting path details from OneDrive ...", - "ERROR: The requested single directory to sync was not found on OneDrive", - "Fetching details for OneDrive Root", - "OneDrive Root does not exist in the database. We need to add it.", - "Added OneDrive Root to the local database", - "OneDrive Root exists in the database", - "ERROR: Unable to query OneDrive for account details", + { + "1": "No user or system config file found, using application defaults", + "2": "System configuration file successfully loaded", + "3": "System configuration file has errors - please check your configuration", + "4": "Configuration file successfully loaded", + "5": "Configuration file has errors - please check your configuration", + "6": "Using config option for Global Azure AD Endpoints", + "7": "Using config option for Azure AD for US Government Endpoints", + "8": "Using config option for Azure AD for US Government Endpoints (DOD)", + "9": "Using config option for Azure AD Germany", + "10": "Using config option for Azure AD China operated by 21Vianet", + "11": "Unknown Azure AD Endpoint - using Global Azure AD Endpoints", + "12": "Unknown key in config file: ", + "13": "Malformed config line: ", + "14": "config file has been updated, checking if --resync needed", + "15": "An application configuration change has been detected where a --resync is required", + "16": "DRY-RUN Configured. Output below shows what 'would' have occurred", + "17": "Using logfile dir: ", + "18": "Database schema changed, resync needed", + "19": "Deleting the saved status ...", + "20": "ERROR: Unable to reach Microsoft OneDrive API service, unable to initialize application" + + }, ] } \ No newline at end of file diff --git a/src/translations.d b/src/translations.d index 1802470c7..afc182d88 100644 --- a/src/translations.d +++ b/src/translations.d @@ -3,18 +3,19 @@ // - log.vlog // - log.error // - log.logAndNotify -import std.string, std.stdio, std.json, std.file; +import std.string, std.stdio, std.json, std.file, std.conv; +static import log; ulong defaultMessageCount = 0; -string[] languageResponsesEN_AU; -string[] languageResponsesEN_US; -string defaultBadLookupResponse = "ERROR: BAD LOOKUP INDEX "; +string[] languageResponsesDefault; +string[] languageResponsesTranslations; +string defaultBadLookupResponse = "ERROR: BAD LOOKUP INDEX FOR LANGUAGE TRANSLATION"; // Initialise default message lookup using EN-AU void initialize() { // Initialise default messages initialise_EN_AU(); - defaultMessageCount = count(languageResponsesEN_AU); + defaultMessageCount = count(languageResponsesDefault); } // Load user configured translation files from a file @@ -24,7 +25,9 @@ void initializeUserConfiguredLanguageTranslations(string languageIdentifier) { // Translation files string EN_US_TranslationFile = translationPath ~ "EN-US.json"; + string DE_TranslationFile = translationPath ~ "DE.json"; + // Load the right file switch (languageIdentifier) { case "EN-US": // Load Translation Files if they exist @@ -32,20 +35,19 @@ void initializeUserConfiguredLanguageTranslations(string languageIdentifier) { // Load the file auto fileContents = readText(EN_US_TranslationFile); JSONValue languageList = parseJSON(fileContents); - // Load the message into the required array - foreach (translationItem; languageList["list"].array) { - string responseString = translationItem.toString; - responseString = responseString[1 .. $-1]; - languageResponsesEN_US ~= responseString; - } - // If the loaded responses != defaultMessageCount there will be an issue in translation .. warn - writeln("WARNING: " ~ EN_US_TranslationFile ~ " is out of sync with default application messages - application output will be inaccurate"); + languageResponsesTranslations = loadTranslationFromJSON(EN_US_TranslationFile, languageList, languageIdentifier); } break; - case "DE": - //logMessageResponse = getResponseFromIndex_EN_US(requiredResponseIndex); + // Load Translation Files if they exist + if (exists(DE_TranslationFile)) { + // Load the file + auto fileContents = readText(DE_TranslationFile); + JSONValue languageList = parseJSON(fileContents); + // Load the message into the required array + languageResponsesTranslations = loadTranslationFromJSON(DE_TranslationFile, languageList, languageIdentifier); + } break; default: //logMessageResponse = getResponseFromIndex_EN_AU(requiredResponseIndex); @@ -62,15 +64,12 @@ string provideLanguageTranslation(string languageIdentifier, int requiredRespons switch (languageIdentifier) { case "EN-AU": - // Language Maintainer: abraunegg + // Use EN-AU for application output logMessageResponse = getResponseFromIndex_EN_AU(requiredResponseIndex); break; - case "EN-US": - // Language Maintainer: abraunegg - logMessageResponse = getResponseFromIndex_EN_US(requiredResponseIndex); - break; default: - logMessageResponse = getResponseFromIndex_EN_AU(requiredResponseIndex); + // Default is to use any 'loaded' translations + logMessageResponse = getResponseFromIndex(requiredResponseIndex); break; } @@ -78,131 +77,41 @@ string provideLanguageTranslation(string languageIdentifier, int requiredRespons return logMessageResponse; } -// Load EN-AU application messages -void initialise_EN_AU(){ - // The below JSON array contains all the default application messages - JSONValue languageList = [ "language": "EN-AU"]; - languageList.object["list"] = JSONValue([ - "No user or system config file found, using application defaults", - "System configuration file successfully loaded", - "System configuration file has errors - please check your configuration", - "Configuration file successfully loaded", - "Configuration file has errors - please check your configuration", - "Using config option for Global Azure AD Endpoints", - "Using config option for Azure AD for US Government Endpoints", - "Using config option for Azure AD for US Government Endpoints (DOD)", - "Using config option for Azure AD Germany", - "Using config option for Azure AD China operated by 21Vianet", - "Unknown Azure AD Endpoint - using Global Azure AD Endpoints", - "Unknown key in config file: ", - "Malformed config line: ", - "config file has been updated, checking if --resync needed", - "An application configuration change has been detected where a --resync is required", - "DRY-RUN Configured. Output below shows what 'would' have occurred", - "Using logfile dir: ", - "Database schema changed, resync needed", - "Deleting the saved status ...", - "ERROR: Unable to reach Microsoft OneDrive API service, unable to initialise application", - "ERROR: Unable to reach Microsoft OneDrive API service at this point in time, re-trying network tests", - "Internet connectivity to Microsoft OneDrive service has been restored", - "ERROR: The OneDrive Linux Client was unable to reconnect to the Microsoft OneDrive service after 10000 attempts lasting over 1.2 years!", - "Initialising the OneDrive API ...", - "Could not initialise the OneDrive API", - "Application has been successfully authorised, however no additional command switches were provided", - "Please use 'onedrive --help' for further assistance in regards to running this application", - "Application has not been successfully authorised. Please check your URI response entry and try again", - "ERROR: --synchronize or --monitor switches missing from your command line input. Please add one (not both) of these switches to your command line", - "No OneDrive sync will be performed without one of these two arguments being present", - "ERROR: --synchronize and --monitor cannot be used together", - "Opening the item database ...", - "ERROR: Invalid 'User|Group|Other' permissions set within config file. Please check your config file.", - "All operations will be performed in: ", - "ERROR: Unable to create local OneDrive syncDir - ", - "ERROR: Invalid skip_file entry '.*' detected", - "Initialising the Synchronisation Engine ...", - "Cannot connect to Microsoft OneDrive Service - Network Connection Issue", - "WARNING: Application has been configured to bypass local data preservation in the event of file conflict", - "WARNING: Local data loss MAY occur in this scenario", - "ERROR: .nosync file found. Aborting synchronisation process to safeguard data", - "ERROR: Unsupported account type for listing OneDrive Business Shared Folders", - "ERROR: Unsupported account type for syncing OneDrive Business Shared Folders", - "WARNING: The requested path for --single-directory does not exist locally. Creating requested path within: ", - "Initialising monitor ...", - "OneDrive monitor interval (seconds): ", - "[M] Skipping watching path - .folder found & --skip-dot-files enabled: ", - "[M] Directory created: ", - "Offline, cannot create remote directory!", - "Cannot create remote directory: ", - "[M] File changed: ", - "Offline, cannot upload changed item!", - "Cannot upload file changes/creation: ", - "[M] Item deleted: ", - "Offline, cannot delete item!", - "Item cannot be deleted from OneDrive because it was not found in the local database", - "Cannot delete remote item: ", - "[M] Item moved: ", - "Offline, cannot move item!", - "Cannot move item: ", - "ERROR: ", - "ERROR: The following inotify error was generated: ", - "Starting a sync with OneDrive", - "Sync with OneDrive is complete", - "Persistent connection errors, reinitialising connection", - "Authorisation token invalid, use --logout to authorise the client again", - "Syncing changes from this selected path: ", - "Syncing changes from selected local path only - NOT syncing data changes from OneDrive ...", - "Syncing changes from selected local path first before downloading changes from OneDrive ...", - "Syncing changes from selected OneDrive path ...", - "Syncing changes from local path only - NOT syncing data changes from OneDrive ...", - "Syncing changes from local path first before downloading changes from OneDrive ...", - "Syncing changes from OneDrive ...", - "Giving up on sync after three attempts: ", - "Retry sync count: ", - " Got termination signal, shutting down DB connection", - "Syncing changes from OneDrive only - NOT syncing local data changes to OneDrive ...", - "The file does not have any hash", - "ERROR: Check your 'drive_id' entry in your configuration file as it may be incorrect", - "ERROR: Check your configuration as your refresh_token may be empty or invalid. You may need to issue a --logout and re-authorise this client.", - "ERROR: OneDrive account currently has zero space available. Please free up some space online.", - "WARNING: OneDrive quota information is being restricted or providing a zero value. Please fix by speaking to your OneDrive / Office 365 Administrator.", - "ERROR: OneDrive quota information is missing. Potentially your OneDrive account currently has zero space available. Please free up some space online.", - "ERROR: OneDrive quota information is being restricted. Please fix by speaking to your OneDrive / Office 365 Administrator.", - "Application version: ", - "Account Type: ", - "Default Drive ID: ", - "Default Root ID: ", - "Remaining Free Space: ", - "Continuing the upload session ...", - "Removing local file as --upload-only & --remove-source-files configured", - "ERROR: File failed to upload. Increase logging verbosity to determine why.", - "Skipping item - excluded by skip_dir config: ", - "Syncing this OneDrive Personal Shared Folder: ", - "Attempting to sync OneDrive Business Shared Folders", - "Syncing this OneDrive Business Shared Folder: ", - "OneDrive Business Shared Folder - Shared By: ", - "WARNING: Skipping shared folder due to existing name conflict: ", - "WARNING: Skipping changes of Path ID: ", - "WARNING: To sync this shared folder, this shared folder needs to be renamed", - "WARNING: Conflict Shared By: ", - "WARNING: Not syncing this OneDrive Business Shared File: ", - "OneDrive Business Shared File - Shared By: ", - "WARNING: Not syncing this OneDrive Business Shared item: ", - "ERROR: onedrive.getSharedWithMe call returned an invalid JSON Object", - "Getting path details from OneDrive ...", - "ERROR: The requested single directory to sync was not found on OneDrive", - "Fetching details for OneDrive Root", - "OneDrive Root does not exist in the database. We need to add it.", - "Added OneDrive Root to the local database", - "OneDrive Root exists in the database", - "ERROR: Unable to query OneDrive for account details", - ]); +// Load specific application messages +string[] loadTranslationFromJSON(string translationFile, JSONValue languageList, string languageIdentifier) { + // parse the input JSON and provide back the loaded array for use + string[] languageResponsesTemp; - // Load the message into the array + // Load the message into the required array foreach (translationItem; languageList["list"].array) { - string responseString = translationItem.toString; - responseString = responseString[1 .. $-1]; - languageResponsesEN_AU ~= responseString; + // translationItem["2"].str + ulong thisMessageID = 0; + log.vdebug("Loading Language Translations for " ~ languageIdentifier); + while (thisMessageID != defaultMessageCount) { + // iterate through message ID's + thisMessageID++; + // If the translation JSON has an unequal number of entries to default, the 'key' will not be found + try { + // debug output what we are loading and at what index + log.vdebug("translationItem['" ~ to!string(thisMessageID) ~ "']: ", translationItem[to!string(thisMessageID)].str); + string responseString = translationItem[to!string(thisMessageID)].str; + languageResponsesTemp ~= responseString; + } catch (std.json.JSONException) { + // dont print anything out - catch error and move on + } + } + } + + // If the loaded responses != defaultMessageCount there will be an issue in translation .. warn the user + if (count(languageResponsesTemp) < defaultMessageCount) { + log.log("WARNING: " ~ translationFile ~ " is out of sync with default application messages - application output will be inaccurate"); + ulong missing = 0; + missing = defaultMessageCount - count(languageResponsesTemp); + log.vdebug("Number of missing translations: ", missing); } + + // Return the loaded translations + return languageResponsesTemp; } // Provide the application message based on the index as provided @@ -211,7 +120,7 @@ string getResponseFromIndex_EN_AU(int requiredResponseIndex) { // get response from message array try { // try and get the message from the required index - requiredResponse = languageResponsesEN_AU[requiredResponseIndex]; + requiredResponse = languageResponsesDefault[requiredResponseIndex]; } catch (core.exception.RangeError e) { // invalid index provided requiredResponse = defaultBadLookupResponse; @@ -221,16 +130,213 @@ string getResponseFromIndex_EN_AU(int requiredResponseIndex) { } // Provide the application message based on the index as provided -string getResponseFromIndex_EN_US(int requiredResponseIndex) { +string getResponseFromIndex(int requiredResponseIndex) { string requiredResponse; // get response from message array try { // try and get the message from the required index - requiredResponse = languageResponsesEN_US[requiredResponseIndex]; + requiredResponse = languageResponsesTranslations[requiredResponseIndex]; } catch (core.exception.RangeError e) { - // invalid index provided - requiredResponse = defaultBadLookupResponse; + // invalid index was provided + // get the required response from EN-AU ... whilst might not be ideal (potentially different language) better than a generic error response + requiredResponse = getResponseFromIndex_EN_AU(requiredResponseIndex); } // Return language response return requiredResponse; -} \ No newline at end of file +} + +// Load EN-AU application messages +void initialise_EN_AU(){ + // The below JSON array contains all the default application messages + JSONValue languageList = [ "language": "EN-AU"]; + languageList.object["list"] = JSONValue([ + JSONValue([ "1": "No user or system config file found, using application defaults" ]), + JSONValue([ "2": "System configuration file successfully loaded" ]), + JSONValue([ "3": "System configuration file has errors - please check your configuration" ]), + JSONValue([ "4": "Configuration file successfully loaded" ]), + JSONValue([ "5": "Configuration file has errors - please check your configuration" ]), + JSONValue([ "6": "Using config option for Global Azure AD Endpoints" ]), + JSONValue([ "7": "Using config option for Azure AD for US Government Endpoints" ]), + JSONValue([ "8": "Using config option for Azure AD for US Government Endpoints (DOD)" ]), + JSONValue([ "9": "Using config option for Azure AD Germany" ]), + JSONValue([ "10": "Using config option for Azure AD China operated by 21Vianet" ]), + JSONValue([ "11": "Unknown Azure AD Endpoint - using Global Azure AD Endpoints" ]), + JSONValue([ "12": "Unknown key in config file: " ]), + JSONValue([ "13": "Malformed config line: " ]), + JSONValue([ "14": "config file has been updated, checking if --resync needed" ]), + JSONValue([ "15": "An application configuration change has been detected where a --resync is required" ]), + JSONValue([ "16": "DRY-RUN Configured. Output below shows what 'would' have occurred" ]), + JSONValue([ "17": "Using logfile dir: " ]), + JSONValue([ "18": "Database schema changed, resync needed" ]), + JSONValue([ "19": "Deleting the saved status ..." ]), + JSONValue([ "20": "ERROR: Unable to reach Microsoft OneDrive API service, unable to initialise application" ]), + JSONValue([ "21": "ERROR: Unable to reach Microsoft OneDrive API service at this point in time, re-trying network tests" ]), + JSONValue([ "22": "Internet connectivity to Microsoft OneDrive service has been restored" ]), + JSONValue([ "23": "ERROR: The OneDrive Linux Client was unable to reconnect to the Microsoft OneDrive service after 10000 attempts lasting over 1.2 years!" ]), + JSONValue([ "24": "Initialising the OneDrive API ..." ]), + JSONValue([ "25": "Could not initialise the OneDrive API" ]), + JSONValue([ "26": "Application has been successfully authorised, however no additional command switches were provided" ]), + JSONValue([ "27": "Please use 'onedrive --help' for further assistance in regards to running this application" ]), + JSONValue([ "28": "Application has not been successfully authorised. Please check your URI response entry and try again" ]), + JSONValue([ "29": "ERROR: --synchronize or --monitor switches missing from your command line input. Please add one (not both) of these switches to your command line" ]), + JSONValue([ "30": "No OneDrive sync will be performed without one of these two arguments being present" ]), + JSONValue([ "31": "ERROR: --synchronize and --monitor cannot be used together" ]), + JSONValue([ "32": "Opening the item database ..." ]), + JSONValue([ "33": "ERROR: Invalid 'User|Group|Other' permissions set within config file. Please check your config file." ]), + JSONValue([ "34": "All operations will be performed in: " ]), + JSONValue([ "35": "ERROR: Unable to create local OneDrive syncDir - " ]), + JSONValue([ "36": "ERROR: Invalid skip_file entry '.*' detected" ]), + JSONValue([ "37": "Initialising the Synchronisation Engine ..." ]), + JSONValue([ "38": "Cannot connect to Microsoft OneDrive Service - Network Connection Issue" ]), + JSONValue([ "39": "WARNING: Application has been configured to bypass local data preservation in the event of file conflict" ]), + JSONValue([ "40": "WARNING: Local data loss MAY occur in this scenario" ]), + JSONValue([ "41": "ERROR: .nosync file found. Aborting synchronisation process to safeguard data" ]), + JSONValue([ "42": "ERROR: Unsupported account type for listing OneDrive Business Shared Folders" ]), + JSONValue([ "43": "ERROR: Unsupported account type for syncing OneDrive Business Shared Folders" ]), + JSONValue([ "44": "WARNING: The requested path for --single-directory does not exist locally. Creating requested path within: " ]), + JSONValue([ "45": "Initialising monitor ..." ]), + JSONValue([ "46": "OneDrive monitor interval (seconds): " ]), + JSONValue([ "47": "[M] Skipping watching path - .folder found & --skip-dot-files enabled: " ]), + JSONValue([ "48": "[M] Directory created: " ]), + JSONValue([ "49": "Offline, cannot create remote directory!" ]), + JSONValue([ "50": "Cannot create remote directory: " ]), + JSONValue([ "51": "[M] File changed: " ]), + JSONValue([ "52": "Offline, cannot upload changed item!" ]), + JSONValue([ "53": "Cannot upload file changes/creation: " ]), + JSONValue([ "54": "[M] Item deleted: " ]), + JSONValue([ "55": "Offline, cannot delete item!" ]), + JSONValue([ "56": "Item cannot be deleted from OneDrive because it was not found in the local database" ]), + JSONValue([ "57": "Cannot delete remote item: " ]), + JSONValue([ "58": "[M] Item moved: " ]), + JSONValue([ "59": "Offline, cannot move item!" ]), + JSONValue([ "60": "Cannot move item: " ]), + JSONValue([ "61": "ERROR: " ]), + JSONValue([ "62": "ERROR: The following inotify error was generated: " ]), + JSONValue([ "63": "Starting a sync with OneDrive" ]), + JSONValue([ "64": "Sync with OneDrive is complete" ]), + JSONValue([ "65": "Persistent connection errors, reinitialising connection" ]), + JSONValue([ "66": "Authorisation token invalid, use --logout to authorise the client again" ]), + JSONValue([ "67": "Syncing changes from this selected path: " ]), + JSONValue([ "68": "Syncing changes from selected local path only - NOT syncing data changes from OneDrive ..." ]), + JSONValue([ "69": "Syncing changes from selected local path first before downloading changes from OneDrive ..." ]), + JSONValue([ "70": "Syncing changes from selected OneDrive path ..." ]), + JSONValue([ "71": "Syncing changes from local path only - NOT syncing data changes from OneDrive ..." ]), + JSONValue([ "72": "Syncing changes from local path first before downloading changes from OneDrive ..." ]), + JSONValue([ "73": "Syncing changes from OneDrive ..." ]), + JSONValue([ "74": "Giving up on sync after three attempts: " ]), + JSONValue([ "75": "Retry sync count: " ]), + JSONValue([ "76": " Got termination signal, shutting down DB connection" ]), + JSONValue([ "77": "Syncing changes from OneDrive only - NOT syncing local data changes to OneDrive ..." ]), + JSONValue([ "78": "The file does not have any hash" ]), + JSONValue([ "79": "ERROR: Check your 'drive_id' entry in your configuration file as it may be incorrect" ]), + JSONValue([ "80": "ERROR: Check your configuration as your refresh_token may be empty or invalid. You may need to issue a --logout and re-authorise this client." ]), + JSONValue([ "81": "ERROR: OneDrive account currently has zero space available. Please free up some space online." ]), + JSONValue([ "82": "WARNING: OneDrive quota information is being restricted or providing a zero value. Please fix by speaking to your OneDrive / Office 365 Administrator." ]), + JSONValue([ "83": "ERROR: OneDrive quota information is missing. Potentially your OneDrive account currently has zero space available. Please free up some space online." ]), + JSONValue([ "84": "ERROR: OneDrive quota information is being restricted. Please fix by speaking to your OneDrive / Office 365 Administrator." ]), + JSONValue([ "85": "Application version: " ]), + JSONValue([ "86": "Account Type: " ]), + JSONValue([ "87": "Default Drive ID: " ]), + JSONValue([ "88": "Default Root ID: " ]), + JSONValue([ "89": "Remaining Free Space: " ]), + JSONValue([ "90": "Continuing the upload session ..." ]), + JSONValue([ "91": "Removing local file as --upload-only & --remove-source-files configured" ]), + JSONValue([ "92": "ERROR: File failed to upload. Increase logging verbosity to determine why." ]), + JSONValue([ "93": "Skipping item - excluded by skip_dir config: " ]), + JSONValue([ "94": "Syncing this OneDrive Personal Shared Folder: " ]), + JSONValue([ "95": "Attempting to sync OneDrive Business Shared Folders" ]), + JSONValue([ "96": "Syncing this OneDrive Business Shared Folder: " ]), + JSONValue([ "97": "OneDrive Business Shared Folder - Shared By: " ]), + JSONValue([ "98": "WARNING: Skipping shared folder due to existing name conflict: " ]), + JSONValue([ "99": "WARNING: Skipping changes of Path ID: " ]), + JSONValue([ "100": "WARNING: To sync this shared folder, this shared folder needs to be renamed" ]), + JSONValue([ "101": "WARNING: Conflict Shared By: " ]), + JSONValue([ "102": "WARNING: Not syncing this OneDrive Business Shared File: " ]), + JSONValue([ "103": "OneDrive Business Shared File - Shared By: " ]), + JSONValue([ "104": "WARNING: Not syncing this OneDrive Business Shared item: " ]), + JSONValue([ "105": "ERROR: onedrive.getSharedWithMe call returned an invalid JSON Object" ]), + JSONValue([ "106": "Getting path details from OneDrive ..." ]), + JSONValue([ "107": "ERROR: The requested single directory to sync was not found on OneDrive" ]), + JSONValue([ "108": "Fetching details for OneDrive Root" ]), + JSONValue([ "109": "OneDrive Root does not exist in the database. We need to add it." ]), + JSONValue([ "110": "Added OneDrive Root to the local database" ]), + JSONValue([ "111": "OneDrive Root exists in the database" ]), + JSONValue([ "112": "ERROR: Unable to query OneDrive for account details" ]), + JSONValue([ "113": "Attempting to create the requested path within OneDrive" ]), + JSONValue([ "114": "Attempting to delete the requested path within OneDrive" ]), + JSONValue([ "115": "The requested directory to delete was not found on OneDrive - skipping removing the remote directory as it doesn't exist" ]), + JSONValue([ "116": "The requested directory to delete was not found in the local database - pushing delete request direct to OneDrive" ]), + JSONValue([ "117": "The requested directory to delete was found in the local database. Processing the deletion normally" ]), + JSONValue([ "118": "The requested directory to rename was not found on OneDrive" ]), + JSONValue([ "119": "Applying changes of Path ID: " ]), + JSONValue([ "120": "Updated Remaining Free Space: " ]), + JSONValue([ "121": "OneDrive quota information is set at zero, as this is not our drive id, ignoring" ]), + JSONValue([ "122": "No details returned for given Path ID" ]), + JSONValue([ "123": "ERROR: A potential local database consistency issue has been caught. Please retry your command with '--resync' to fix any local database consistency issues." ]), + JSONValue([ "124": "OneDrive returned a 'HTTP 504 - Gateway Timeout' when attempting to query the OneDrive API - retrying the applicable request" ]), + JSONValue([ "125": "Processing " ]), + JSONValue([ "126": " OneDrive items to ensure consistent local state due to a full scan being triggered by actions on OneDrive" ]), + JSONValue([ "127": " OneDrive items to ensure consistent local state due to a full scan being requested" ]), + JSONValue([ "128": " OneDrive items to ensure consistent local state" ]), + JSONValue([ "129": " OneDrive items to ensure consistent local state due to sync_list being used" ]), + JSONValue([ "130": "Number of items from OneDrive to process: " ]), + JSONValue([ "131": "Remote change discarded - item cannot be found" ]), + JSONValue([ "132": "Remote change discarded - not in --single-directory sync scope (in DB)" ]), + JSONValue([ "133": "Remote change discarded - not in sync scope" ]), + JSONValue([ "134": "Remote change discarded - not in --single-directory sync scope (not in DB)" ]), + JSONValue([ "135": "Remote change discarded - not in business shared folders sync scope" ]), + JSONValue([ "136": "Skipping item - file path is excluded by skip_dir config: " ]), + JSONValue([ "137": "Skipping item - excluded by skip_file config: " ]), + JSONValue([ "138": "Skipping file - parent path not present in local database" ]), + JSONValue([ "139": "The Microsoft OneNote Notebook '" ]), + JSONValue([ "140": "' is not supported by this client" ]), + JSONValue([ "141": "The OneDrive item '" ]), + JSONValue([ "142": "Flagging as unwanted: item type is not supported" ]), + JSONValue([ "143": "Skipping item - excluded by sync_list config: " ]), + JSONValue([ "144": "Flagging item for local delete as item exists in database: " ]), + JSONValue([ "145": "Skipping item - .file or .folder: " ]), + JSONValue([ "146": "Local item modified time is equal to OneDrive item modified time based on UTC time conversion - keeping local item" ]), + JSONValue([ "147": "Local item modified time is newer than OneDrive item modified time based on UTC time conversion - keeping local item" ]), + JSONValue([ "148": "Remote item modified time is newer based on UTC time conversion" ]), + JSONValue([ "149": "WARNING: Local Data Protection has been disabled by your configuration. You may experience data loss on this file: " ]), + JSONValue([ "150": "The local item is out-of-sync with OneDrive, renaming to preserve existing file and prevent data loss: " ]), + JSONValue([ "151": "Skipping item - excluded by skip_size config: " ]), + JSONValue([ "152": "Local item modified time is newer based on UTC time conversion - keeping local item as this exists in the local database" ]), + JSONValue([ "153": "Skipping downloading item - .nosync found in parent folder & --check-for-nosync is enabled: " ]), + JSONValue([ "154": "Removing previous partial file download due to .nosync found in parent folder & --check-for-nosync is enabled" ]), + JSONValue([ "155": "Local item does not exist in local database - replacing with file from OneDrive - failed download?" ]), + JSONValue([ "156": "The local item is out-of-sync with OneDrive, renaming to preserve existing file and prevent data loss due to --resync: " ]), + JSONValue([ "157": "Remote item modified time is newer based on UTC time conversion" ]), + JSONValue([ "158": "Creating local directory: " ]), + JSONValue([ "159": "Moving " ]), + JSONValue([ "160": " to " ]), + JSONValue([ "161": "Destination is in sync and will be overwritten" ]), + JSONValue([ "162": "The destination is occupied, renaming the conflicting file..." ]), + JSONValue([ "163": "The destination is occupied by new file, renaming the conflicting file..." ]), + JSONValue([ "164": "Downloading file " ]), + JSONValue([ "165": "ERROR: Query of OneDrive for file details failed" ]), + JSONValue([ "166": "ERROR: MALWARE DETECTED IN FILE - DOWNLOAD SKIPPED" ]), + JSONValue([ "167": "ERROR: File download size mis-match. Increase logging verbosity to determine why." ]), + JSONValue([ "168": "ERROR: File download hash mis-match. Increase logging verbosity to determine why." ]), + JSONValue([ "169": "ERROR: File failed to download. Increase logging verbosity to determine why." ]), + JSONValue([ "170": "done." ]), + JSONValue([ "171": " ... done." ]), + JSONValue([ "172": "The local item has a different modified time " ]), + JSONValue([ "173": " when compared to " ]), + JSONValue([ "174": " modified time " ]), + JSONValue([ "175": "The local item has a different hash when compared to " ]), + JSONValue([ "176": " item hash" ]), + JSONValue([ "177": "Unable to determine the sync state of this file as it cannot be read (file permissions or file corruption): " ]), + JSONValue([ "178": "The local item is a directory but should be a file" ]), + JSONValue([ "179": "The local item is a file but should be a directory" ]), + JSONValue([ "180": "Trying to delete item " ]), + ]); + + // Load the message into the array + ulong thisMessageID = 0; + foreach (translationItem; languageList["list"].array) { + thisMessageID++; + string responseString = translationItem[to!string(thisMessageID)].str; + languageResponsesDefault ~= responseString; + } +} From eae4bba3a9df24bd7dad4cab250aa1b10aeb47a7 Mon Sep 17 00:00:00 2001 From: abraunegg Date: Mon, 31 May 2021 14:56:10 +1000 Subject: [PATCH 03/15] updates * updates --- contrib/translations/DE.json | 2 +- contrib/translations/EN-US.json | 2 +- contrib/translations/example.json | 31 +++++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 contrib/translations/example.json diff --git a/contrib/translations/DE.json b/contrib/translations/DE.json index e77514608..ef57aea77 100644 --- a/contrib/translations/DE.json +++ b/contrib/translations/DE.json @@ -23,6 +23,6 @@ "19": "Gespeicherten Status löschen ...", "20": "FEHLER: Microsoft OneDrive-API-Dienst kann nicht erreicht werden, Anwendung kann nicht initialisiert werden" - }, + } ] } \ No newline at end of file diff --git a/contrib/translations/EN-US.json b/contrib/translations/EN-US.json index 7191070d3..acd7f6b19 100644 --- a/contrib/translations/EN-US.json +++ b/contrib/translations/EN-US.json @@ -23,6 +23,6 @@ "19": "Deleting the saved status ...", "20": "ERROR: Unable to reach Microsoft OneDrive API service, unable to initialize application" - }, + } ] } \ No newline at end of file diff --git a/contrib/translations/example.json b/contrib/translations/example.json new file mode 100644 index 000000000..f340c6bff --- /dev/null +++ b/contrib/translations/example.json @@ -0,0 +1,31 @@ +{ + "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#Collection(driveItem)", + "@odata.deltaLink": "https://graph.microsoft.com/v1.0/drives/b!bO8V7s9SSk6r7mWHpIjURotN33W1W2tEv3OXV_oFIdQimEdOHR-1So7CqeT1MfHA/items/01WIXGO5V6Y2GOVW7725BZO354PWSELRRZ/delta?select=id%2cname%2ceTag%2ccTag%2cdeleted%2cfile%2cfolder%2croot%2cfileSystemInfo%2cremoteItem%2cparentReference%2csize&token=MzslMjM0OyUyMzE7Mzs0ZTQ3OTgyMi0xZjFkLTRhYjUtOGVjMi1hOWU0ZjUzMWYxYzA7NjM3NTgwMTQzMDU3MzAwMDAwOzE0ODQ3MTA5ODslMjM7JTIzOyUyMzA", + "value": [ + { + "@odata.etag": "\"{7869190A-D219-4363-B262-4EF7A79B28B4},5\"", + "@odata.type": "#microsoft.graph.driveItem", + "cTag": "\"c:{7869190A-D219-4363-B262-4EF7A79B28B4},2\"", + "eTag": "\"{7869190A-D219-4363-B262-4EF7A79B28B4},5\"", + "file": { + "hashes": { + "quickXorHash": "YZgDGcwQhjmQwQwKCQAAAAAAAAA=" + }, + "mimeType": "text/plain" + }, + "fileSystemInfo": { + "createdDateTime": "2021-05-30T23:31:30Z", + "lastModifiedDateTime": "2021-03-03T19:26:31Z" + }, + "id": "01WIXGO5QKDFUXQGOSMNB3EYSO66TZWKFU", + "name": "hhhhhhhh.txt", + "parentReference": { + "driveId": "b!bO8V7s9SSk6r7mWHpIjURotN33W1W2tEv3OXV_oFIdQimEdOHR-1So7CqeT1MfHA", + "driveType": "business", + "id": "01WIXGO5V6Y2GOVW7725BZO354PWSELRRZ", + "path": "/drives/b!bO8V7s9SSk6r7mWHpIjURotN33W1W2tEv3OXV_oFIdQimEdOHR-1So7CqeT1MfHA/root:" + }, + "size": 9 + } + ] +} \ No newline at end of file From aa97a9c59cb17fed761492204b1e453c7d0a97a4 Mon Sep 17 00:00:00 2001 From: abraunegg Date: Mon, 31 May 2021 15:22:21 +1000 Subject: [PATCH 04/15] updates * updates --- Makefile.in | 2 +- contrib/translations/example.json | 31 ------------------------------- 2 files changed, 1 insertion(+), 32 deletions(-) delete mode 100644 contrib/translations/example.json diff --git a/Makefile.in b/Makefile.in index f88cce128..5b3566a3d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -79,7 +79,7 @@ SOURCES = \ src/upload.d \ src/util.d \ src/progress.d \ - src/translations.d + src/translations.d ifeq ($(NOTIFICATIONS),yes) SOURCES += src/notifications/notify.d src/notifications/dnotify.d diff --git a/contrib/translations/example.json b/contrib/translations/example.json deleted file mode 100644 index f340c6bff..000000000 --- a/contrib/translations/example.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#Collection(driveItem)", - "@odata.deltaLink": "https://graph.microsoft.com/v1.0/drives/b!bO8V7s9SSk6r7mWHpIjURotN33W1W2tEv3OXV_oFIdQimEdOHR-1So7CqeT1MfHA/items/01WIXGO5V6Y2GOVW7725BZO354PWSELRRZ/delta?select=id%2cname%2ceTag%2ccTag%2cdeleted%2cfile%2cfolder%2croot%2cfileSystemInfo%2cremoteItem%2cparentReference%2csize&token=MzslMjM0OyUyMzE7Mzs0ZTQ3OTgyMi0xZjFkLTRhYjUtOGVjMi1hOWU0ZjUzMWYxYzA7NjM3NTgwMTQzMDU3MzAwMDAwOzE0ODQ3MTA5ODslMjM7JTIzOyUyMzA", - "value": [ - { - "@odata.etag": "\"{7869190A-D219-4363-B262-4EF7A79B28B4},5\"", - "@odata.type": "#microsoft.graph.driveItem", - "cTag": "\"c:{7869190A-D219-4363-B262-4EF7A79B28B4},2\"", - "eTag": "\"{7869190A-D219-4363-B262-4EF7A79B28B4},5\"", - "file": { - "hashes": { - "quickXorHash": "YZgDGcwQhjmQwQwKCQAAAAAAAAA=" - }, - "mimeType": "text/plain" - }, - "fileSystemInfo": { - "createdDateTime": "2021-05-30T23:31:30Z", - "lastModifiedDateTime": "2021-03-03T19:26:31Z" - }, - "id": "01WIXGO5QKDFUXQGOSMNB3EYSO66TZWKFU", - "name": "hhhhhhhh.txt", - "parentReference": { - "driveId": "b!bO8V7s9SSk6r7mWHpIjURotN33W1W2tEv3OXV_oFIdQimEdOHR-1So7CqeT1MfHA", - "driveType": "business", - "id": "01WIXGO5V6Y2GOVW7725BZO354PWSELRRZ", - "path": "/drives/b!bO8V7s9SSk6r7mWHpIjURotN33W1W2tEv3OXV_oFIdQimEdOHR-1So7CqeT1MfHA/root:" - }, - "size": 9 - } - ] -} \ No newline at end of file From bdeeb6f2e4a2f32a0ec3d47a09f6c4c54e042772 Mon Sep 17 00:00:00 2001 From: abraunegg Date: Sun, 18 Jul 2021 09:37:15 +1000 Subject: [PATCH 05/15] Update translations.d DMD 2.097.0 compatibility --- src/translations.d | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/translations.d b/src/translations.d index 99b80a6f0..9c98b6663 100644 --- a/src/translations.d +++ b/src/translations.d @@ -116,6 +116,7 @@ string[] loadTranslationFromJSON(string translationFile, JSONValue languageList, // Provide the application message based on the index as provided string getResponseFromIndex_EN_AU(int requiredResponseIndex) { + static import core.exception; string requiredResponse; // get response from message array try { @@ -131,6 +132,7 @@ string getResponseFromIndex_EN_AU(int requiredResponseIndex) { // Provide the application message based on the index as provided string getResponseFromIndex(int requiredResponseIndex) { + static import core.exception; string requiredResponse; // get response from message array try { From 3714756e559c1b0500f69ba447a5ce06f73f93d3 Mon Sep 17 00:00:00 2001 From: abraunegg Date: Mon, 19 Jul 2021 12:15:18 +1000 Subject: [PATCH 06/15] Update PR * Update PR --- src/sync.d | 193 ++++++++++++++++++++++++++++----------------- src/translations.d | 21 +++++ 2 files changed, 143 insertions(+), 71 deletions(-) diff --git a/src/sync.d b/src/sync.d index 2c8354902..54335de25 100644 --- a/src/sync.d +++ b/src/sync.d @@ -3064,7 +3064,8 @@ final class SyncEngine if (pathItem.id == item.id) { needsRemoval = true; } else { - log.log("Skipped due to id difference!"); + // Skipped due to id difference! + log.log(provideLanguageTranslation(languageIdentifier,182)); } } else { // item has disappeared completely @@ -3072,7 +3073,8 @@ final class SyncEngine } } if (needsRemoval) { - log.log("Deleting item ", path); + // "Deleting item " + log.log(provideLanguageTranslation(languageIdentifier,183), path); if (!dryRun) { if (isFile(path)) { remove(path); @@ -3152,7 +3154,8 @@ final class SyncEngine if (isDir(path)) { // if this path is a directory, output this message. // if a file, potentially leads to confusion as to what the client is actually doing - log.log("Uploading differences of ", logPath); + // "Uploading differences of " + log.log(provideLanguageTranslation(languageIdentifier,184), logPath); } Item item; @@ -3190,7 +3193,8 @@ final class SyncEngine if (isDir(path)) { // if this path is a directory, output this message. // if a file, potentially leads to confusion as to what the client is actually doing - log.log("Uploading new items of ", logPath); + // "Uploading new items of " + log.log(provideLanguageTranslation(languageIdentifier,185), logPath); } // Filesystem walk to find new files not uploaded @@ -3253,7 +3257,8 @@ final class SyncEngine if (isDir(path)) { // if this path is a directory, output this message. // if a file, potentially leads to confusion as to what the client is actually doing - log.vlog("Uploading differences of ", logPath); + // "Uploading differences of " + log.vlog(provideLanguageTranslation(languageIdentifier,184), logPath); } Item item; // For each unique OneDrive driveID we know about @@ -3385,7 +3390,8 @@ final class SyncEngine if (isDir(path)) { // if this path is a directory, output this message. // if a file, potentially leads to confusion as to what the client is actually doing - log.vlog("Uploading new items of ", logPath); + // "Uploading new items of " + log.vlog(provideLanguageTranslation(languageIdentifier,185), logPath); } // Filesystem walk to find new files not uploaded @@ -3411,7 +3417,8 @@ final class SyncEngine path = computeItemPath(item.driveId, item.id); // item.id was in the database associated with the item.driveId specified - log.vlog("Processing ", buildNormalizedPath(path)); + // "Processing " + log.vlog(provideLanguageTranslation(languageIdentifier,125), buildNormalizedPath(path)); // What type of DB item are we processing // Is this item excluded by user configuration of skip_dir or skip_file? @@ -3420,7 +3427,8 @@ final class SyncEngine // Do we need to check for .nosync? Only if --check-for-nosync was passed in if (cfg.getValueBool("check_nosync")) { if (exists(path ~ "/.nosync")) { - log.vlog("Skipping item - .nosync found & --check-for-nosync enabled: ", path); + // "Skipping item - .nosync found & --check-for-nosync enabled: " + log.vlog(provideLanguageTranslation(languageIdentifier,186), path); return; } } @@ -3443,25 +3451,29 @@ final class SyncEngine // skip unwanted items if (unwanted) { - //log.vlog("Filtered out"); + // debug log output that this item is skipped + log.vdebug("Skipping item - filtered out due to application configuration: ", path); return; } // Restriction and limitations about windows naming files if (!isValidName(path)) { - log.log("Skipping item - invalid name (Microsoft Naming Convention): ", path); + // "Skipping item - invalid name (Microsoft Naming Convention): " + log.log(provideLanguageTranslation(languageIdentifier,187), path); return; } // Check for bad whitespace items if (!containsBadWhiteSpace(path)) { - log.log("Skipping item - invalid name (Contains an invalid whitespace item): ", path); + // "Skipping item - invalid name (Contains an invalid whitespace item): " + log.log(provideLanguageTranslation(languageIdentifier,188), path); return; } // Check for HTML ASCII Codes as part of file name if (!containsASCIIHTMLCodes(path)) { - log.log("Skipping item - invalid name (Contains HTML ASCII Code): ", path); + // "Skipping item - invalid name (Contains HTML ASCII Code): " + log.log(provideLanguageTranslation(languageIdentifier,189), path); return; } @@ -3483,11 +3495,13 @@ final class SyncEngine assert(item.type == ItemType.dir); if (exists(path)) { if (!isDir(path)) { - log.vlog("The item was a directory but now it is a file"); + // "The item was a directory but now it is a file" + log.vlog(provideLanguageTranslation(languageIdentifier,190)); uploadDeleteItem(item, path); uploadNewFile(path); } else { - log.vlog("The directory has not changed"); + // "The directory has not changed" + log.vlog(provideLanguageTranslation(languageIdentifier,191)); // loop through the children foreach (Item child; itemdb.selectChildren(item.driveId, item.id)) { uploadDifferences(child); @@ -3500,16 +3514,19 @@ final class SyncEngine // Not --dry-run situation if (!cfg.getValueBool("monitor")) { // Not in --monitor mode - log.vlog("The directory has been deleted locally"); + // "The directory has been deleted locally" + log.vlog(provideLanguageTranslation(languageIdentifier,192)); } else { // Appropriate message as we are in --monitor mode - log.vlog("The directory appears to have been deleted locally .. but we are running in --monitor mode. This may have been 'moved' on the local filesystem rather than being 'deleted'"); + // "The directory appears to have been deleted locally .. but we are running in --monitor mode. This may have been 'moved' on the local filesystem rather than being 'deleted'" + log.vlog(provideLanguageTranslation(languageIdentifier,193)); log.vdebug("Most likely cause - 'inotify' event was missing for whatever action was taken locally or action taken when application was stopped"); } // A moved file will be uploaded as 'new', delete the old file and reference if (noRemoteDelete) { // do not process remote directory delete - log.vlog("Skipping remote directory delete as --upload-only & --no-remote-delete configured"); + // "Skipping remote directory delete as --upload-only & --no-remote-delete configured" + log.vlog(provideLanguageTranslation(languageIdentifier,194)); } else { uploadDeleteItem(item, path); } @@ -3519,10 +3536,12 @@ final class SyncEngine Item databaseItem; if (!itemdb.selectByPath(path, defaultDriveId, databaseItem)) { // Path not found in database - log.vlog("The directory has been deleted locally"); + // "The directory has been deleted locally" + log.vlog(provideLanguageTranslation(languageIdentifier,192)); if (noRemoteDelete) { // do not process remote directory delete - log.vlog("Skipping remote directory delete as --upload-only & --no-remote-delete configured"); + // "Skipping remote directory delete as --upload-only & --no-remote-delete configured" + log.vlog(provideLanguageTranslation(languageIdentifier,194)); } else { uploadDeleteItem(item, path); } @@ -3532,12 +3551,14 @@ final class SyncEngine foreach (i; idsFaked) { if (i[1] == item.id) { log.vdebug("Matched faked dir which is 'supposed' to exist but not created due to --dry-run use"); - log.vlog("The directory has not changed"); + // "The directory has not changed" + log.vlog(provideLanguageTranslation(languageIdentifier,191)); return; } } // item.id did not match a 'faked' download new directory creation - log.vlog("The directory has been deleted locally"); + // "The directory has been deleted locally" + log.vlog(provideLanguageTranslation(languageIdentifier,192)); uploadDeleteItem(item, path); } } @@ -3549,11 +3570,13 @@ final class SyncEngine assert(item.type == ItemType.remote); if (exists(path)) { if (!isDir(path)) { - log.vlog("The item was a directory but now it is a file"); + // "The item was a directory but now it is a file" + log.vlog(provideLanguageTranslation(languageIdentifier,190)); uploadDeleteItem(item, path); uploadNewFile(path); } else { - log.vlog("The directory has not changed"); + // "The directory has not changed" + log.vlog(provideLanguageTranslation(languageIdentifier,191)); // continue through the linked folder assert(item.remoteDriveId && item.remoteId); Item remoteItem; @@ -3567,10 +3590,12 @@ final class SyncEngine // are we in a dry-run scenario if (!dryRun) { // no dry-run - log.vlog("The directory has been deleted locally"); + // "The directory has been deleted locally" + log.vlog(provideLanguageTranslation(languageIdentifier,192)); if (noRemoteDelete) { // do not process remote directory delete - log.vlog("Skipping remote directory delete as --upload-only & --no-remote-delete configured"); + // "Skipping remote directory delete as --upload-only & --no-remote-delete configured" + log.vlog(provideLanguageTranslation(languageIdentifier,194)); } else { uploadDeleteItem(item, path); } @@ -3580,10 +3605,12 @@ final class SyncEngine Item databaseItem; if (!itemdb.selectByPathWithoutRemote(path, defaultDriveId, databaseItem)) { // Path not found in database - log.vlog("The directory has been deleted locally"); + // "The directory has been deleted locally" + log.vlog(provideLanguageTranslation(languageIdentifier,192)); if (noRemoteDelete) { // do not process remote directory delete - log.vlog("Skipping remote directory delete as --upload-only & --no-remote-delete configured"); + // "Skipping remote directory delete as --upload-only & --no-remote-delete configured" + log.vlog(provideLanguageTranslation(languageIdentifier,194)); } else { uploadDeleteItem(item, path); } @@ -3593,12 +3620,14 @@ final class SyncEngine foreach (i; idsFaked) { if (i[1] == item.id) { log.vdebug("Matched faked dir which is 'supposed' to exist but not created due to --dry-run use"); - log.vlog("The directory has not changed"); + // "The directory has not changed" + log.vlog(provideLanguageTranslation(languageIdentifier,191)); return; } } // item.id did not match a 'faked' download new directory creation - log.vlog("The directory has been deleted locally"); + // "The directory has been deleted locally" + log.vlog(provideLanguageTranslation(languageIdentifier,192)); uploadDeleteItem(item, path); } } @@ -3627,15 +3656,18 @@ final class SyncEngine localModifiedTime.fracSecs = Duration.zero; if (localModifiedTime != itemModifiedTime) { - log.vlog("The file last modified time has changed"); + // "The file last modified time has changed" + log.vlog(provideLanguageTranslation(languageIdentifier,195)); log.vdebug("The local item has a different modified time ", localModifiedTime, " when compared to ", itemSource, " modified time ", itemModifiedTime); string eTag = item.eTag; // perform file hash tests - has the content of the file changed? if (!testFileHash(path, item)) { - log.vlog("The file content has changed"); + // "The file content has changed" + log.vlog(provideLanguageTranslation(languageIdentifier,196)); log.vdebug("The local item has a different hash when compared to ", itemSource, " item hash"); - write("Uploading modified file ", path, " ... "); + // "Uploading modified file " , " ... " + write(provideLanguageTranslation(languageIdentifier,197), path, " ... "); JSONValue response; if (!dryRun) { @@ -3650,9 +3682,12 @@ final class SyncEngine try { response = onedrive.simpleUploadReplace(path, item.driveId, item.id, item.eTag); } catch (OneDriveException e) { + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); + // error handling based on API response code if (e.httpStatusCode == 401) { // OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded - writeln("skipped."); log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); uploadFailed = true; return; @@ -3660,7 +3695,6 @@ final class SyncEngine if (e.httpStatusCode == 404) { // HTTP request returned status code 404 - the eTag provided does not exist // Delete record from the local database - file will be uploaded as a new file - writeln("skipped."); log.vlog("OneDrive returned a 'HTTP 404 - eTag Issue' - gracefully handling error"); itemdb.deleteById(item.driveId, item.id); uploadFailed = true; @@ -3670,19 +3704,18 @@ final class SyncEngine if ((e.httpStatusCode == 409) || (e.httpStatusCode == 423)) { // The file is currently checked out or locked for editing by another user // We cant upload this file at this time - writeln("skipped."); - log.fileOnly("Uploading modified file ", path, " ... skipped."); - write("", path, " is currently checked out or locked for editing by another user."); - log.fileOnly(path, " is currently checked out or locked for editing by another user."); + // "Uploading modified file ", path, " ... skipped." + log.fileOnly(provideLanguageTranslation(languageIdentifier,197), path, " ... ", provideLanguageTranslation(languageIdentifier,198)); + // " is currently checked out or locked for editing by another user." + log.log("", path, provideLanguageTranslation(languageIdentifier,199)); uploadFailed = true; return; } if (e.httpStatusCode == 412) { // HTTP request returned status code 412 - ETag does not match current item's value // Delete record from the local database - file will be uploaded as a new file - writeln("skipped."); - log.vdebug("Simple Upload Replace Failed - OneDrive eTag / cTag match issue (Personal Account)"); log.vlog("OneDrive returned a 'HTTP 412 - Precondition Failed' - gracefully handling error. Will upload as new file."); + log.vdebug("Simple Upload Replace Failed - OneDrive eTag / cTag match issue (Personal Account)"); itemdb.deleteById(item.driveId, item.id); uploadFailed = true; return; @@ -3694,28 +3727,31 @@ final class SyncEngine response = session.upload(path, item.driveId, item.parentId, baseName(path), item.eTag); } else { // display what the error is - writeln("skipped."); displayOneDriveErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return; } } catch (FileException e) { - // display the error message - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); displayFileSystemErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return; } // upload done without error - writeln("done."); + // "done." + writeln(provideLanguageTranslation(languageIdentifier,170)); } else { writeln(""); try { response = session.upload(path, item.driveId, item.parentId, baseName(path), item.eTag); } catch (OneDriveException e) { + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); if (e.httpStatusCode == 401) { // OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded - writeln("skipped."); log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); uploadFailed = true; return; @@ -3723,28 +3759,29 @@ final class SyncEngine if (e.httpStatusCode == 412) { // HTTP request returned status code 412 - ETag does not match current item's value // Delete record from the local database - file will be uploaded as a new file - writeln("skipped."); - log.vdebug("Session Upload Replace Failed - OneDrive eTag / cTag match issue (Personal Account)"); log.vlog("OneDrive returned a 'HTTP 412 - Precondition Failed' - gracefully handling error. Will upload as new file."); + log.vdebug("Session Upload Replace Failed - OneDrive eTag / cTag match issue (Personal Account)"); itemdb.deleteById(item.driveId, item.id); uploadFailed = true; return; } else { // display what the error is - writeln("skipped."); displayOneDriveErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return; } } catch (FileException e) { + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); // display the error message - writeln("skipped."); displayFileSystemErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return; } // upload done without error - writeln("done."); + // "done." + writeln(provideLanguageTranslation(languageIdentifier,170)); } } else { // OneDrive Business Account @@ -3755,9 +3792,12 @@ final class SyncEngine if (thisFileSize == 0) { // the file we are trying to upload as a session is a zero byte file - we cant use a session to upload or replace the file // as OneDrive technically does not support zero byte files - writeln("skipped."); - log.fileOnly("Uploading modified file ", path, " ... skipped."); - log.vlog("Skip Reason: Microsoft OneDrive does not support 'zero-byte' files as a modified upload. Will upload as new file."); + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); + // "Uploading modified file ", path, " ... skipped." + log.fileOnly(provideLanguageTranslation(languageIdentifier,197), path, " ... ", provideLanguageTranslation(languageIdentifier,198)); + // "Skip Reason: Microsoft OneDrive does not support 'zero-byte' files as a modified upload. Will upload as new file." + log.vlog(provideLanguageTranslation(languageIdentifier,200)); // delete file on OneDrive onedrive.deleteById(item.driveId, item.id, item.eTag); // delete file from local database @@ -3778,9 +3818,11 @@ final class SyncEngine } } } catch (OneDriveException e) { + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); if (e.httpStatusCode == 401) { // OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded - writeln("skipped."); log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); uploadFailed = true; return; @@ -3789,32 +3831,32 @@ final class SyncEngine if ((e.httpStatusCode == 409) || (e.httpStatusCode == 423)) { // The file is currently checked out or locked for editing by another user // We cant upload this file at this time - writeln("skipped."); - log.fileOnly("Uploading modified file ", path, " ... skipped."); - writeln("", path, " is currently checked out or locked for editing by another user."); - log.fileOnly(path, " is currently checked out or locked for editing by another user."); + // "Uploading modified file ", path, " ... skipped." + log.fileOnly(provideLanguageTranslation(languageIdentifier,197), path, " ... ", provideLanguageTranslation(languageIdentifier,198)); + // " is currently checked out or locked for editing by another user." + log.log("", path, provideLanguageTranslation(languageIdentifier,199)); uploadFailed = true; return; } if (e.httpStatusCode == 412) { // HTTP request returned status code 412 - ETag does not match current item's value // Delete record from the local database - file will be uploaded as a new file - writeln("skipped."); - log.vdebug("Session Upload Replace Failed - OneDrive eTag / cTag match issue (Business Account)"); log.vlog("OneDrive returned a 'HTTP 412 - Precondition Failed' - gracefully handling error. Will upload as new file."); + log.vdebug("Session Upload Replace Failed - OneDrive eTag / cTag match issue (Business Account)"); itemdb.deleteById(item.driveId, item.id); uploadFailed = true; return; } else { // display what the error is - writeln("skipped."); displayOneDriveErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return; } } catch (FileException e) { + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); // display the error message - writeln("skipped."); displayFileSystemErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return; @@ -3822,7 +3864,8 @@ final class SyncEngine // Did the upload fail? if (!uploadFailed){ // upload done without error or failure - writeln("done."); + // "done." + writeln(provideLanguageTranslation(languageIdentifier,170)); // As the session.upload includes the last modified time, save the response // Is the response a valid JSON object - validation checking done in saveItem saveItem(response); @@ -3838,9 +3881,12 @@ final class SyncEngine if (thisFileSize == 0) { // the file we are trying to upload as a session is a zero byte file - we cant use a session to upload or replace the file // as OneDrive technically does not support zero byte files - writeln("skipped."); - log.fileOnly("Uploading modified file ", path, " ... skipped."); - log.vlog("Skip Reason: Microsoft OneDrive does not support 'zero-byte' files as a modified upload. Will upload as new file."); + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); + // "Uploading modified file ", path, " ... skipped." + log.fileOnly(provideLanguageTranslation(languageIdentifier,197), path, " ... ", provideLanguageTranslation(languageIdentifier,198)); + // "Skip Reason: Microsoft OneDrive does not support 'zero-byte' files as a modified upload. Will upload as new file." + log.vlog(provideLanguageTranslation(languageIdentifier,200)); // delete file on OneDrive onedrive.deleteById(item.driveId, item.id, item.eTag); // delete file from local database @@ -3854,7 +3900,8 @@ final class SyncEngine // Did the upload fail? if (!uploadFailed){ // upload done without error or failure - writeln("done."); + // "done." + writeln(provideLanguageTranslation(languageIdentifier,170)); // As the session.upload includes the last modified time, save the response // Is the response a valid JSON object - validation checking done in saveItem saveItem(response); @@ -3882,20 +3929,24 @@ final class SyncEngine } // log that the modified file was uploaded successfully - log.fileOnly("Uploading modified file ", path, " ... done."); + // "Uploading modified file ", path, " ... done." + log.fileOnly(provideLanguageTranslation(languageIdentifier,197), path, " ... ", provideLanguageTranslation(languageIdentifier,170)); // update free space tracking if this is our drive id if (item.driveId == defaultDriveId) { // how much space is left on OneDrive after upload? remainingFreeSpace = (remainingFreeSpace - thisFileSize); - log.vlog("Remaining free space on OneDrive: ", remainingFreeSpace); + // "Remaining free space on OneDrive: ", remainingFreeSpace + log.vlog(provideLanguageTranslation(languageIdentifier,201), remainingFreeSpace); } } else { // we are --dry-run - simulate the file upload - writeln("done."); + // "done." + writeln(provideLanguageTranslation(languageIdentifier,170)); response = createFakeResponse(path); // Log action to log file - log.fileOnly("Uploading modified file ", path, " ... done."); + // "Uploading modified file ", path, " ... done." + log.fileOnly(provideLanguageTranslation(languageIdentifier,197), path, " ... ", provideLanguageTranslation(languageIdentifier,170)); // Is the response a valid JSON object - validation checking done in saveItem saveItem(response); return; diff --git a/src/translations.d b/src/translations.d index 9c98b6663..39a14870e 100644 --- a/src/translations.d +++ b/src/translations.d @@ -333,6 +333,27 @@ void initialise_EN_AU(){ JSONValue([ "179": "The local item is a file but should be a directory" ]), JSONValue([ "180": "Trying to delete item " ]), JSONValue([ "181": "ERROR: The requested single directory to sync was not found on OneDrive - Check folder permissions and sharing status with folder owner" ]), + JSONValue([ "182": "Skipped due to id difference!" ]), + JSONValue([ "183": "Deleting item " ]), + JSONValue([ "184": "Uploading differences of " ]), + JSONValue([ "185": "Uploading new items of " ]), + JSONValue([ "186": "Skipping item - .nosync found & --check-for-nosync enabled: " ]), + JSONValue([ "187": "Skipping item - invalid name (Microsoft Naming Convention): " ]), + JSONValue([ "188": "Skipping item - invalid name (Contains an invalid whitespace item): " ]), + JSONValue([ "189": "Skipping item - invalid name (Contains HTML ASCII Code): " ]), + JSONValue([ "190": "The item was a directory but now it is a file" ]), + JSONValue([ "191": "The directory has not changed" ]), + JSONValue([ "192": "The directory has been deleted locally" ]), + JSONValue([ "193": "The directory appears to have been deleted locally .. but we are running in --monitor mode. This may have been 'moved' on the local filesystem rather than being 'deleted'" ]), + JSONValue([ "194": "Skipping remote directory delete as --upload-only & --no-remote-delete configured" ]), + JSONValue([ "195": "The file last modified time has changed" ]), + JSONValue([ "196": "The file content has changed" ]), + JSONValue([ "197": "Uploading modified file " ]), + JSONValue([ "198": "skipped." ]), + JSONValue([ "199": " is currently checked out or locked for editing by another user." ]), + JSONValue([ "200": "Skip Reason: Microsoft OneDrive does not support 'zero-byte' files as a modified upload. Will upload as new file." ]), + JSONValue([ "201": "Remaining free space on OneDrive: " ]), + ]); // Load the message into the array From 23bdd6d5200a4070650633956d1d8a6e90b3185f Mon Sep 17 00:00:00 2001 From: abraunegg Date: Mon, 26 Jul 2021 10:42:23 +1000 Subject: [PATCH 07/15] Update PR * Update PR --- src/sync.d | 367 +++++++++++++++++++++++++++++++-------------- src/translations.d | 43 ++++++ 2 files changed, 301 insertions(+), 109 deletions(-) diff --git a/src/sync.d b/src/sync.d index a05d47dbd..1b7c39bad 100644 --- a/src/sync.d +++ b/src/sync.d @@ -3680,17 +3680,20 @@ final class SyncEngine try { response = onedrive.simpleUploadReplace(path, item.driveId, item.id, item.eTag); } catch (OneDriveException e) { - // caught an error, write out we are skipping this item - // "skipped." - writeln(provideLanguageTranslation(languageIdentifier,198)); // error handling based on API response code if (e.httpStatusCode == 401) { + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); // OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); uploadFailed = true; return; } if (e.httpStatusCode == 404) { + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); // HTTP request returned status code 404 - the eTag provided does not exist // Delete record from the local database - file will be uploaded as a new file log.vlog("OneDrive returned a 'HTTP 404 - eTag Issue' - gracefully handling error"); @@ -3700,6 +3703,9 @@ final class SyncEngine } // Resolve https://github.com/abraunegg/onedrive/issues/36 if ((e.httpStatusCode == 409) || (e.httpStatusCode == 423)) { + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); // The file is currently checked out or locked for editing by another user // We cant upload this file at this time // "Uploading modified file ", path, " ... skipped." @@ -3710,6 +3716,9 @@ final class SyncEngine return; } if (e.httpStatusCode == 412) { + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); // HTTP request returned status code 412 - ETag does not match current item's value // Delete record from the local database - file will be uploaded as a new file log.vlog("OneDrive returned a 'HTTP 412 - Precondition Failed' - gracefully handling error. Will upload as new file."); @@ -3724,6 +3733,9 @@ final class SyncEngine // Try upload as a session response = session.upload(path, item.driveId, item.parentId, baseName(path), item.eTag); } else { + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); // display what the error is displayOneDriveErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; @@ -3745,16 +3757,19 @@ final class SyncEngine try { response = session.upload(path, item.driveId, item.parentId, baseName(path), item.eTag); } catch (OneDriveException e) { - // caught an error, write out we are skipping this item - // "skipped." - writeln(provideLanguageTranslation(languageIdentifier,198)); if (e.httpStatusCode == 401) { + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); // OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); uploadFailed = true; return; } if (e.httpStatusCode == 412) { + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); // HTTP request returned status code 412 - ETag does not match current item's value // Delete record from the local database - file will be uploaded as a new file log.vlog("OneDrive returned a 'HTTP 412 - Precondition Failed' - gracefully handling error. Will upload as new file."); @@ -3763,6 +3778,9 @@ final class SyncEngine uploadFailed = true; return; } else { + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); // display what the error is displayOneDriveErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; @@ -3816,10 +3834,10 @@ final class SyncEngine } } } catch (OneDriveException e) { - // caught an error, write out we are skipping this item - // "skipped." - writeln(provideLanguageTranslation(languageIdentifier,198)); if (e.httpStatusCode == 401) { + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); // OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); uploadFailed = true; @@ -3827,6 +3845,9 @@ final class SyncEngine } // Resolve https://github.com/abraunegg/onedrive/issues/36 if ((e.httpStatusCode == 409) || (e.httpStatusCode == 423)) { + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); // The file is currently checked out or locked for editing by another user // We cant upload this file at this time // "Uploading modified file ", path, " ... skipped." @@ -3837,6 +3858,9 @@ final class SyncEngine return; } if (e.httpStatusCode == 412) { + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); // HTTP request returned status code 412 - ETag does not match current item's value // Delete record from the local database - file will be uploaded as a new file log.vlog("OneDrive returned a 'HTTP 412 - Precondition Failed' - gracefully handling error. Will upload as new file."); @@ -3845,6 +3869,9 @@ final class SyncEngine uploadFailed = true; return; } else { + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); // display what the error is displayOneDriveErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; @@ -3957,15 +3984,17 @@ final class SyncEngine } } } else { - log.vlog("The file has not changed"); + // "The file has not changed" + log.vlog(provideLanguageTranslation(languageIdentifier,202)); } } else { - //The file is not readable - skipped - log.log("Skipping processing this file as it cannot be read (file permissions or file corruption): ", path); + // "Skipping processing this file as it cannot be read (file permissions or file corruption): " + log.log(provideLanguageTranslation(languageIdentifier,203), path); uploadFailed = true; } } else { - log.vlog("The item was a file but now is a directory"); + // "The item was a file but now is a directory" + log.vlog(provideLanguageTranslation(languageIdentifier,204)); uploadDeleteItem(item, path); uploadCreateDir(path); } @@ -3975,16 +4004,19 @@ final class SyncEngine if (!dryRun) { // Not --dry-run situation if (!cfg.getValueBool("monitor")) { - log.vlog("The file has been deleted locally"); + // "The file has been deleted locally" + log.vlog(provideLanguageTranslation(languageIdentifier,205)); } else { // Appropriate message as we are in --monitor mode - log.vlog("The file appears to have been deleted locally .. but we are running in --monitor mode. This may have been 'moved' on the local filesystem rather than being 'deleted'"); + // "The file appears to have been deleted locally .. but we are running in --monitor mode. This may have been 'moved' on the local filesystem rather than being 'deleted'" + log.vlog(provideLanguageTranslation(languageIdentifier,206)); log.vdebug("Most likely cause - 'inotify' event was missing for whatever action was taken locally or action taken when application was stopped"); } // A moved file will be uploaded as 'new', delete the old file and reference if (noRemoteDelete) { // do not process remote file delete - log.vlog("Skipping remote file delete as --upload-only & --no-remote-delete configured"); + // "Skipping remote file delete as --upload-only & --no-remote-delete configured" + log.vlog(provideLanguageTranslation(languageIdentifier,207)); } else { uploadDeleteItem(item, path); } @@ -3994,10 +4026,12 @@ final class SyncEngine Item databaseItem; if (!itemdb.selectByPath(path, defaultDriveId, databaseItem)) { // file not found in database - log.vlog("The file has been deleted locally"); + // "The file has been deleted locally" + log.vlog(provideLanguageTranslation(languageIdentifier,205)); if (noRemoteDelete) { // do not process remote file delete - log.vlog("Skipping remote file delete as --upload-only & --no-remote-delete configured"); + // "Skipping remote file delete as --upload-only & --no-remote-delete configured" + log.vlog(provideLanguageTranslation(languageIdentifier,207)); } else { uploadDeleteItem(item, path); } @@ -4006,16 +4040,19 @@ final class SyncEngine // Did we 'fake create it' as part of --dry-run ? foreach (i; idsFaked) { if (i[1] == item.id) { + // "The file has not changed" + log.vlog(provideLanguageTranslation(languageIdentifier,202)); log.vdebug("Matched faked file which is 'supposed' to exist but not created due to --dry-run use"); - log.vlog("The file has not changed"); return; } } // item.id did not match a 'faked' download new file creation - log.vlog("The file has been deleted locally"); + // "The file has been deleted locally" + log.vlog(provideLanguageTranslation(languageIdentifier,205)); if (noRemoteDelete) { // do not process remote file delete - log.vlog("Skipping remote file delete as --upload-only & --no-remote-delete configured"); + // "Skipping remote file delete as --upload-only & --no-remote-delete configured" + log.vlog(provideLanguageTranslation(languageIdentifier,207)); } else { uploadDeleteItem(item, path); } @@ -4037,55 +4074,70 @@ final class SyncEngine response = session.upload(path, item.driveId, item.parentId, baseName(path), item.eTag); } catch (OneDriveException e) { if (e.httpStatusCode == 401) { + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); // OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded - writeln("skipped."); log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); uploadFailed = true; return response; } // Resolve https://github.com/abraunegg/onedrive/issues/36 if ((e.httpStatusCode == 409) || (e.httpStatusCode == 423)) { + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); // The file is currently checked out or locked for editing by another user // We cant upload this file at this time - writeln("skipped."); - log.fileOnly("Uploading modified file ", path, " ... skipped."); - writeln("", path, " is currently checked out or locked for editing by another user."); - log.fileOnly(path, " is currently checked out or locked for editing by another user."); + // "Uploading modified file ", path, " ... skipped." + log.fileOnly(provideLanguageTranslation(languageIdentifier,197), path, " ... ", provideLanguageTranslation(languageIdentifier,198)); + // " is currently checked out or locked for editing by another user." + log.log("", path, provideLanguageTranslation(languageIdentifier,199)); uploadFailed = true; return response; } if (e.httpStatusCode == 412) { + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); // HTTP request returned status code 412 - ETag does not match current item's value // Delete record from the local database - file will be uploaded as a new file - writeln("skipped."); - log.vdebug("Session Upload Replace Failed - OneDrive eTag / cTag match issue (Sharepoint Library)"); log.vlog("OneDrive returned a 'HTTP 412 - Precondition Failed' - gracefully handling error. Will upload as new file."); + log.vdebug("Session Upload Replace Failed - OneDrive eTag / cTag match issue (Sharepoint Library)"); itemdb.deleteById(item.driveId, item.id); uploadFailed = true; return response; } else { + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); // display what the error is - writeln("skipped."); displayOneDriveErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return response; } } catch (FileException e) { - // display the error message - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); displayFileSystemErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return response; } // upload done without error - writeln("done."); + writeln(provideLanguageTranslation(languageIdentifier,170)); } else { // Due to https://github.com/OneDrive/onedrive-api-docs/issues/935 Microsoft modifies all PDF, MS Office & HTML files with added XML content. It is a 'feature' of SharePoint. // This means, as a session upload, on 'completion' the file is 'moved' and generates a 404 ...... - writeln("skipped."); - log.fileOnly("Uploading modified file ", path, " ... skipped."); - log.vlog("Skip Reason: Microsoft Sharepoint 'enrichment' after upload issue"); - log.vlog("See: https://github.com/OneDrive/onedrive-api-docs/issues/935 for further details"); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); + // "Uploading modified file ", path, " ... skipped." + log.fileOnly(provideLanguageTranslation(languageIdentifier,197), path, " ... ", provideLanguageTranslation(languageIdentifier,198)); + // "Skip Reason: Microsoft Sharepoint 'enrichment' after upload issue" + log.vlog(provideLanguageTranslation(languageIdentifier,208)); + // "See: https://github.com/OneDrive/onedrive-api-docs/issues/935 for further details" + log.vlog(provideLanguageTranslation(languageIdentifier,209)); // Delete record from the local database - file will be uploaded as a new file itemdb.deleteById(item.driveId, item.id); uploadFailed = true; @@ -4121,7 +4173,8 @@ final class SyncEngine // A short lived file that has disappeared will cause an error - is the path valid? if (!exists(path)) { - log.log("Skipping item - path has disappeared: ", path); + // "Skipping item - path has disappeared: ", path + log.log(provideLanguageTranslation(languageIdentifier,210), path); return; } @@ -4132,7 +4185,8 @@ final class SyncEngine pathWalkLength = path.byGrapheme.walkLength; } catch (std.utf.UTFException e) { // path contains characters which generate a UTF exception - log.vlog("Skipping item - invalid UTF sequence: ", path); + // "Skipping item - invalid UTF sequence: " + log.vlog(provideLanguageTranslation(languageIdentifier,211), path); log.vdebug(" Error Reason:", e.msg); return; } @@ -4142,7 +4196,8 @@ final class SyncEngine // https://github.com/abraunegg/onedrive/issues/487 if(!isValid(path)) { // Path is not valid according to https://dlang.org/phobos/std_encoding.html - log.vlog("Skipping item - invalid character encoding sequence: ", path); + // "Skipping item - invalid character encoding sequence: " + log.vlog(provideLanguageTranslation(languageIdentifier,212), path); return; } @@ -4151,7 +4206,8 @@ final class SyncEngine // skip dot files if configured if (cfg.getValueBool("skip_dotfiles")) { if (isDotFile(path)) { - log.vlog("Skipping item - .file or .folder: ", path); + // "Skipping item - .file or .folder: " + log.vlog(provideLanguageTranslation(languageIdentifier,145), path); return; } } @@ -4159,7 +4215,8 @@ final class SyncEngine // Do we need to check for .nosync? Only if --check-for-nosync was passed in if (cfg.getValueBool("check_nosync")) { if (exists(path ~ "/.nosync")) { - log.vlog("Skipping item - .nosync found & --check-for-nosync enabled: ", path); + // "Skipping item - .nosync found & --check-for-nosync enabled: " + log.vlog(provideLanguageTranslation(languageIdentifier,186), path); return; } } @@ -4168,7 +4225,8 @@ final class SyncEngine if (isSymlink(path)) { // if config says so we skip all symlinked items if (cfg.getValueBool("skip_symlinks")) { - log.vlog("Skipping item - skip symbolic links configured: ", path); + // "Skipping item - skip symbolic links configured: " + log.vlog(provideLanguageTranslation(languageIdentifier,213), path); return; } @@ -4195,7 +4253,8 @@ final class SyncEngine if (relativeLinkTest) { log.vdebug("Not skipping item - symbolic link is a 'relative link' to target ('", relativeLink, "') which can be supported: ", path); } else { - log.log("Skipping item - invalid symbolic link: ", path); + // "Skipping item - invalid symbolic link: " + log.log(provideLanguageTranslation(languageIdentifier,214), path); return; } } @@ -4203,19 +4262,22 @@ final class SyncEngine // Restriction and limitations about windows naming files if (!isValidName(path)) { - log.log("Skipping item - invalid name (Microsoft Naming Convention): ", path); + //"Skipping item - invalid name (Microsoft Naming Convention): " + log.log(provideLanguageTranslation(languageIdentifier,187), path); return; } // Check for bad whitespace items if (!containsBadWhiteSpace(path)) { - log.log("Skipping item - invalid name (Contains an invalid whitespace item): ", path); + // "Skipping item - invalid name (Contains an invalid whitespace item): " + log.log(provideLanguageTranslation(languageIdentifier,188), path); return; } // Check for HTML ASCII Codes as part of file name if (!containsASCIIHTMLCodes(path)) { - log.log("Skipping item - invalid name (Contains HTML ASCII Code): ", path); + // "Skipping item - invalid name (Contains HTML ASCII Code): " + log.log(provideLanguageTranslation(languageIdentifier,189), path); return; } @@ -4228,7 +4290,8 @@ final class SyncEngine // The path that needs to be checked needs to include the '/' // This due to if the user has specified in skip_dir an exclusive path: '/path' - that is what must be matched if (selectiveSync.isDirNameExcluded(path.strip('.'))) { - log.vlog("Skipping item - excluded by skip_dir config: ", path); + // "Skipping item - excluded by skip_dir config: " + log.vlog(provideLanguageTranslation(languageIdentifier,93), path); return; } } @@ -4242,8 +4305,10 @@ final class SyncEngine // The file contents can only contain 'folder' names, so we need to strip './' from any path we are checking if(selectiveSync.isSharedFolderMatched(strip(path,"./"))){ // path detected as a 'new item' is matched as a path in business_shared_folders - log.vlog("Skipping item - excluded as included in business_shared_folders config: ", path); - log.vlog("To sync this directory to your OneDrive Account update your business_shared_folders config"); + // "Skipping item - excluded as included in business_shared_folders config: " + log.vlog(provideLanguageTranslation(languageIdentifier,215), path); + // "To sync this directory to your OneDrive Account update your business_shared_folders config" + log.vlog(provideLanguageTranslation(languageIdentifier,216)); return; } } @@ -4254,23 +4319,27 @@ final class SyncEngine // The path that needs to be checked needs to include the '/' // This due to if the user has specified in skip_file an exclusive path: '/path/file' - that is what must be matched if (selectiveSync.isFileNameExcluded(path.strip('.'))) { - log.vlog("Skipping item - excluded by skip_file config: ", path); + // "Skipping item - excluded by skip_file config: " + log.vlog(provideLanguageTranslation(languageIdentifier,137), path); return; } } if (selectiveSync.isPathExcludedViaSyncList(path)) { if ((isFile(path)) && (cfg.getValueBool("sync_root_files")) && (rootName(path.strip('.').strip('/')) == "")) { + // not skipping this file log.vdebug("Not skipping path due to sync_root_files inclusion: ", path); } else { string userSyncList = cfg.configDirName ~ "/sync_list"; if (exists(userSyncList)){ // skipped most likely due to inclusion in sync_list - log.vlog("Skipping item - excluded by sync_list config: ", path); + // "Skipping item - excluded by sync_list config: " + log.vlog(provideLanguageTranslation(languageIdentifier,143), path); return; } else { // skipped for some other reason - log.vlog("Skipping item - path excluded by user config: ", path); + // "Skipping item - path excluded by user config: " + log.vlog(provideLanguageTranslation(languageIdentifier,217), path); return; } } @@ -4297,7 +4366,8 @@ final class SyncEngine // the above operation takes time and the directory might have // disappeared in the meantime if (!exists(path)) { - log.vlog("Directory disappeared during upload: ", path); + // "Directory disappeared during upload: " + log.vlog(provideLanguageTranslation(languageIdentifier,218), path); return; } @@ -4340,7 +4410,8 @@ final class SyncEngine // are we in an --upload-only & --remove-source-files scenario? if ((uploadOnly) && (localDeleteAfterUpload)) { // Log that we are deleting a local item - log.log("Removing local file as --upload-only & --remove-source-files configured"); + // "Removing local file as --upload-only & --remove-source-files configured" + log.log(provideLanguageTranslation(languageIdentifier,91)); // are we in a --dry-run scenario? if (!dryRun) { // No --dry-run ... process local file delete @@ -4352,19 +4423,22 @@ final class SyncEngine } } else { // path is not a valid file - log.log("Skipping item - item is not a valid file: ", path); + // "Skipping item - item is not a valid file: " + log.log(provideLanguageTranslation(languageIdentifier,219), path); } } } else { // This path was skipped - why? - log.log("Skipping item '", path, "' due to the full path exceeding ", maxPathLength, " characters (Microsoft OneDrive limitation)"); + // "Skipping item '", path, "' due to the full path exceeding ", maxPathLength, " characters (Microsoft OneDrive limitation)" + log.log(provideLanguageTranslation(languageIdentifier,220), path, provideLanguageTranslation(languageIdentifier,221), maxPathLength, provideLanguageTranslation(languageIdentifier,222)); } } // create new directory on OneDrive private void uploadCreateDir(const(string) path) { - log.vlog("OneDrive Client requested to create remote path: ", path); + // "OneDrive Client requested to create remote path: " + log.vlog(provideLanguageTranslation(languageIdentifier,223), path); JSONValue onedrivePathDetails; Item parent; @@ -4445,7 +4519,8 @@ final class SyncEngine log.vdebug("response = onedrive.getPathDetails(path); generated a OneDriveException"); if (e.httpStatusCode == 404) { // The directory was not found on the drive id we queried - log.vlog("The requested directory to create was not found on OneDrive - creating remote directory: ", path); + // "The requested directory to create was not found on OneDrive - creating remote directory: " + log.vlog(provideLanguageTranslation(languageIdentifier,224), path); if (!dryRun) { // Perform the database lookup - is the parent in the database? @@ -4477,11 +4552,12 @@ final class SyncEngine if (e.httpStatusCode == 409) { // OneDrive API returned a 404 (above) to say the directory did not exist // but when we attempted to create it, OneDrive responded that it now already exists - log.vlog("OneDrive reported that ", path, " already exists .. OneDrive API race condition"); + log.vdebug("OneDrive reported that ", path, " already exists .. OneDrive API race condition"); return; } else { // some other error from OneDrive was returned - display what it is - log.error("OneDrive generated an error when creating this path: ", path); + // "OneDrive generated an error when creating this path: ", path + log.error(provideLanguageTranslation(languageIdentifier,225), path); displayOneDriveErrorMessage(e.msg, getFunctionName!({})); return; } @@ -4494,8 +4570,8 @@ final class SyncEngine auto fakeResponse = createFakeResponse(path); saveItem(fakeResponse); } - - log.vlog("Successfully created the remote directory ", path, " on OneDrive"); + // "Successfully created the remote directory ", path, " on OneDrive" + log.vlog(provideLanguageTranslation(languageIdentifier,226), path, provideLanguageTranslation(languageIdentifier,227)); return; } @@ -4524,16 +4600,19 @@ final class SyncEngine if (response["name"].str == baseName(path)){ // OneDrive 'name' matches local path name - log.vlog("The requested directory to create was found on OneDrive - skipping creating the directory: ", path ); + // "The requested directory to create was found on OneDrive - skipping creating the directory: " + log.vlog(provideLanguageTranslation(languageIdentifier,228), path ); // Check that this path is in the database if (!itemdb.selectById(parent.driveId, parent.id, parent)){ // parent for 'path' is NOT in the database - log.vlog("The parent for this path is not in the local database - need to add parent to local database"); + // "The parent for this path is not in the local database - need to add parent to local database" + log.vlog(provideLanguageTranslation(languageIdentifier,229)); parentPath = dirName(path); // add the parent into the database uploadCreateDir(parentPath); // save this child item into the database - log.vlog("The parent for this path has been added to the local database - adding requested path (", path ,") to database"); + // "The parent for this path has been added to the local database - adding requested path (", path ,") to database" + log.vlog(provideLanguageTranslation(languageIdentifier,230), path ,provideLanguageTranslation(languageIdentifier,231)); if (!dryRun) { // save the live data saveItem(response); @@ -4544,7 +4623,8 @@ final class SyncEngine } } else { // parent is in database - log.vlog("The parent for this path is in the local database - adding requested path (", path ,") to database"); + // "The parent for this path is in the local database - adding requested path (", path ,") to database" + log.vlog(provideLanguageTranslation(languageIdentifier,232), path ,provideLanguageTranslation(languageIdentifier,231)); // are we in a --dry-run scenario? if (!dryRun) { // get the live data @@ -4554,8 +4634,9 @@ final class SyncEngine } catch (OneDriveException e) { log.vdebug("pathDetails = onedrive.getPathDetailsByDriveId(parent.driveId, path) generated a OneDriveException"); if (e.httpStatusCode == 404) { - // The directory was not found - log.error("ERROR: The requested single directory to sync was not found on OneDrive"); + // The directory was not found + // "ERROR: The requested single directory to sync was not found on OneDrive" + log.error(provideLanguageTranslation(languageIdentifier,107)); return; } @@ -4612,17 +4693,23 @@ final class SyncEngine } } else { // They are the "same" name wise but different in case sensitivity - log.error("ERROR: Current directory has a 'case-insensitive match' to an existing directory on OneDrive"); - log.error("ERROR: To resolve, rename this local directory: ", buildNormalizedPath(absolutePath(path))); - log.error("ERROR: Remote OneDrive directory: ", response["name"].str); - log.log("Skipping: ", buildNormalizedPath(absolutePath(path))); + // "ERROR: Current directory has a 'case-insensitive match' to an existing directory on OneDrive" + log.error(provideLanguageTranslation(languageIdentifier,233)); + // "ERROR: To resolve, rename this local directory: ", buildNormalizedPath(absolutePath(path)) + log.error(provideLanguageTranslation(languageIdentifier,234), buildNormalizedPath(absolutePath(path))); + // "ERROR: Remote OneDrive directory: ", response["name"].str + log.error(provideLanguageTranslation(languageIdentifier,235), response["name"].str); + log.log(provideLanguageTranslation(languageIdentifier,236), buildNormalizedPath(absolutePath(path))); return; } } else { // response is not valid JSON, an error was returned from OneDrive - log.error("ERROR: There was an error performing this operation on OneDrive"); - log.error("ERROR: Increase logging verbosity to assist determining why."); - log.log("Skipping: ", buildNormalizedPath(absolutePath(path))); + // "ERROR: There was an error performing this operation on OneDrive" + log.error(provideLanguageTranslation(languageIdentifier,237)); + // "ERROR: Increase logging verbosity to assist determining why." + log.error(provideLanguageTranslation(languageIdentifier,238)); + //"Skipping: ", buildNormalizedPath(absolutePath(path)) + log.log(provideLanguageTranslation(languageIdentifier,236), buildNormalizedPath(absolutePath(path))); return; } } @@ -4720,9 +4807,11 @@ final class SyncEngine // OneDrive returned a 'HTTP/1.1 400 Bad Request' // If the 'path', when encoded, cannot be interpreted by the OneDrive API, the API will generate a 400 error if (e.httpStatusCode == 400) { - log.log("Skipping uploading this new file: ", buildNormalizedPath(absolutePath(path))); + // "Skipping uploading this new file: ", buildNormalizedPath(absolutePath(path)) + log.log(provideLanguageTranslation(languageIdentifier,239), buildNormalizedPath(absolutePath(path))); log.vlog("Skipping item - OneDrive returned a 'HTTP 400 - Bad Request' when attempting to query if file exists"); - log.error("ERROR: To resolve, rename this local file: ", buildNormalizedPath(absolutePath(path))); + // "ERROR: To resolve, rename this local file: ", buildNormalizedPath(absolutePath(path)) + log.error(provideLanguageTranslation(languageIdentifier,240), buildNormalizedPath(absolutePath(path))); uploadFailed = true; return; } @@ -4737,12 +4826,14 @@ final class SyncEngine // The file was not found on OneDrive, need to upload it // Check if file should be skipped based on skip_size config if (thisFileSize >= this.newSizeLimit) { - log.vlog("Skipping item - excluded by skip_size config: ", path, " (", thisFileSize/2^^20," MB)"); + // "Skipping item - excluded by skip_size config: ", path, " (", thisFileSize/2^^20," MB)" + log.vlog(provideLanguageTranslation(languageIdentifier,241), path, " (", thisFileSize/2^^20," MB)"); return; } // start of upload file - write("Uploading new file ", path, " ... "); + // "Uploading new file ", path, " ... " + write(provideLanguageTranslation(languageIdentifier,242), path, " ... "); JSONValue response; // Calculate upload speed @@ -4758,8 +4849,10 @@ final class SyncEngine } catch (OneDriveException e) { // error uploading file if (e.httpStatusCode == 401) { + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); // OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded - writeln("skipped."); log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); uploadFailed = true; return; @@ -4780,15 +4873,19 @@ final class SyncEngine // return back to original call return; } else { + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); // display what the error is - writeln("skipped."); displayOneDriveErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return; } } catch (FileException e) { // display the error message - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); displayFileSystemErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return; @@ -4804,9 +4901,12 @@ final class SyncEngine try { response = onedrive.simpleUpload(path, parent.driveId, parent.id, baseName(path)); } catch (OneDriveException e) { + // error uploading file if (e.httpStatusCode == 401) { + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); // OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded - writeln("skipped."); log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); uploadFailed = true; return; @@ -4837,8 +4937,9 @@ final class SyncEngine // return back to original call return; } else { - // display what the error is - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); displayOneDriveErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return; @@ -4846,14 +4947,18 @@ final class SyncEngine } } else { // display what the error is - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); displayOneDriveErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return; } } catch (FileException e) { // display the error message - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); displayFileSystemErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return; @@ -4866,7 +4971,9 @@ final class SyncEngine } catch (OneDriveException e) { if (e.httpStatusCode == 401) { // OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); uploadFailed = true; return; @@ -4888,14 +4995,18 @@ final class SyncEngine return; } else { // display what the error is - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); displayOneDriveErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return; } } catch (FileException e) { // display the error message - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); displayFileSystemErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return; @@ -4909,7 +5020,9 @@ final class SyncEngine } catch (OneDriveException e) { if (e.httpStatusCode == 401) { // OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); uploadFailed = true; return; @@ -4931,14 +5044,18 @@ final class SyncEngine return; } else { // display what the error is - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); displayOneDriveErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return; } } catch (FileException e) { // display the error message - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); displayFileSystemErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return; @@ -5111,7 +5228,9 @@ final class SyncEngine log.vdebug("response = onedrive.simpleUpload(path, parent.driveId, parent.id, baseName(path)); generated a OneDriveException"); if (e.httpStatusCode == 401) { // OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); uploadFailed = true; return; @@ -5145,7 +5264,9 @@ final class SyncEngine } else { // error uploading file // display what the error is - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); displayOneDriveErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return; @@ -5153,14 +5274,18 @@ final class SyncEngine } } else { // display what the error is - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); displayOneDriveErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return; } } catch (FileException e) { // display the error message - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); displayFileSystemErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return; @@ -5175,7 +5300,9 @@ final class SyncEngine log.vdebug("response = session.upload(path, parent.driveId, parent.id, baseName(path)); generated a OneDriveException"); if (e.httpStatusCode == 401) { // OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); uploadFailed = true; return; @@ -5199,14 +5326,18 @@ final class SyncEngine } else { // error uploading file // display what the error is - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); displayOneDriveErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return; } } catch (FileException e) { // display the error message - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); displayFileSystemErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return; @@ -5260,7 +5391,9 @@ final class SyncEngine log.vdebug("response = session.upload(path, parent.driveId, parent.id, baseName(path), fileDetailsFromOneDrive['eTag'].str); generated a OneDriveException"); if (e.httpStatusCode == 401) { // OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); uploadFailed = true; return; @@ -5284,14 +5417,18 @@ final class SyncEngine } else { // error uploading file // display what the error is - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); displayOneDriveErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return; } } catch (FileException e) { // display the error message - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); displayFileSystemErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return; @@ -5428,20 +5565,26 @@ final class SyncEngine } catch (OneDriveException e) { if (e.httpStatusCode == 401) { // OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); uploadFailed = true; return response; } else { // display what the error is - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); displayOneDriveErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return response; } } catch (FileException e) { // display the error message - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); displayFileSystemErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return response; @@ -5457,20 +5600,26 @@ final class SyncEngine } catch (OneDriveException e) { if (e.httpStatusCode == 401) { // OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); uploadFailed = true; return response; } else { // display what the error is - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); displayOneDriveErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return response; } } catch (FileException e) { // display the error message - writeln("skipped."); + // caught an error, write out we are skipping this item + // "skipped." + writeln(provideLanguageTranslation(languageIdentifier,198)); displayFileSystemErrorMessage(e.msg, getFunctionName!({})); uploadFailed = true; return response; diff --git a/src/translations.d b/src/translations.d index 39a14870e..1b24a80f8 100644 --- a/src/translations.d +++ b/src/translations.d @@ -353,6 +353,49 @@ void initialise_EN_AU(){ JSONValue([ "199": " is currently checked out or locked for editing by another user." ]), JSONValue([ "200": "Skip Reason: Microsoft OneDrive does not support 'zero-byte' files as a modified upload. Will upload as new file." ]), JSONValue([ "201": "Remaining free space on OneDrive: " ]), + JSONValue([ "202": "The file has not changed" ]), + JSONValue([ "203": "Skipping processing this file as it cannot be read (file permissions or file corruption): " ]), + JSONValue([ "204": "The item was a file but now is a directory" ]), + JSONValue([ "205": "The file has been deleted locally" ]), + JSONValue([ "206": "The file appears to have been deleted locally .. but we are running in --monitor mode. This may have been 'moved' on the local filesystem rather than being 'deleted'" ]), + JSONValue([ "207": "Skipping remote file delete as --upload-only & --no-remote-delete configured" ]), + JSONValue([ "208": "Skip Reason: Microsoft Sharepoint 'enrichment' after upload issue" ]), + JSONValue([ "209": "See: https://github.com/OneDrive/onedrive-api-docs/issues/935 for further details" ]), + JSONValue([ "210": "Skipping item - path has disappeared: " ]), + JSONValue([ "211": "Skipping item - invalid UTF sequence: " ]), + JSONValue([ "212": "Skipping item - invalid character encoding sequence: " ]), + JSONValue([ "213": "Skipping item - skip symbolic links configured: " ]), + JSONValue([ "214": "Skipping item - invalid symbolic link: " ]), + JSONValue([ "215": "Skipping item - excluded as included in business_shared_folders config: " ]), + JSONValue([ "216": "To sync this directory to your OneDrive Account update your business_shared_folders config" ]), + JSONValue([ "217": "Skipping item - path excluded by user config: " ]), + JSONValue([ "218": "Directory disappeared during upload: " ]), + JSONValue([ "219": "Skipping item - item is not a valid file: " ]), + JSONValue([ "220": "Skipping item '" ]), + JSONValue([ "221": "' due to the full path exceeding " ]), + JSONValue([ "222": " characters (Microsoft OneDrive limitation)" ]), + JSONValue([ "223": "OneDrive Client requested to create remote path: " ]), + JSONValue([ "224": "The requested directory to create was not found on OneDrive - creating remote directory: " ]), + JSONValue([ "225": "OneDrive generated an error when creating this path: " ]), + JSONValue([ "226": "Successfully created the remote directory " ]), + JSONValue([ "227": " on OneDrive" ]), + JSONValue([ "228": "The requested directory to create was found on OneDrive - skipping creating the directory: " ]), + JSONValue([ "229": "The parent for this path is not in the local database - need to add parent to local database" ]), + JSONValue([ "230": "The parent for this path has been added to the local database - adding requested path (" ]), + JSONValue([ "231": ") to the database" ]), + JSONValue([ "232": "The parent for this path is in the local database - adding requested path (" ]), + JSONValue([ "233": "ERROR: Current directory has a 'case-insensitive match' to an existing directory on OneDrive" ]), + JSONValue([ "234": "ERROR: To resolve, rename this local directory: " ]), + JSONValue([ "235": "ERROR: Remote OneDrive directory: " ]), + JSONValue([ "236": "Skipping: " ]), + JSONValue([ "237": "ERROR: There was an error performing this operation on OneDrive" ]), + JSONValue([ "238": "ERROR: Increase logging verbosity to assist determining why." ]), + JSONValue([ "239": "Skipping uploading this new file: " ]), + JSONValue([ "240": "ERROR: To resolve, rename this local file: " ]), + JSONValue([ "241": "Skipping item - excluded by skip_size config: " ]), + JSONValue([ "242": "Uploading new file " ]), + + ]); From 8431d894125566657123b1152ddbc1eca79188e6 Mon Sep 17 00:00:00 2001 From: abraunegg Date: Sun, 8 Aug 2021 07:09:28 +1000 Subject: [PATCH 08/15] Update PR * Update PR --- src/sync.d | 108 ++++++++++++++++++++++++++++++--------------- src/translations.d | 15 +++++++ 2 files changed, 87 insertions(+), 36 deletions(-) diff --git a/src/sync.d b/src/sync.d index 1b7c39bad..553c471b4 100644 --- a/src/sync.d +++ b/src/sync.d @@ -750,10 +750,11 @@ final class SyncEngine // Log who shared this to assist with sync data correlation if ((sharedByName != "") && (sharedByEmail != "")) { - // "OneDrive Business Shared Folder - Shared By: " + // "OneDrive Business Shared Folder - Shared By: ", sharedByName, " (", sharedByEmail, ")" log.vlog(provideLanguageTranslation(languageIdentifier,97), sharedByName, " (", sharedByEmail, ")"); } else { if (sharedByName != "") { + // "OneDrive Business Shared Folder - Shared By: " log.vlog(provideLanguageTranslation(languageIdentifier,97), sharedByName); } } @@ -892,10 +893,12 @@ final class SyncEngine // Log who shared this to assist with sync data correlation if ((sharedByName != "") && (sharedByEmail != "")) { - log.vlog("OneDrive Business Shared Folder - Shared By: ", sharedByName, " (", sharedByEmail, ")"); + // "OneDrive Business Shared Folder - Shared By: ", sharedByName, " (", sharedByEmail, ")" + log.vlog(provideLanguageTranslation(languageIdentifier,97), sharedByName, " (", sharedByEmail, ")"); } else { if (sharedByName != "") { - log.vlog("OneDrive Business Shared Folder - Shared By: ", sharedByName); + // "OneDrive Business Shared Folder - Shared By: " + log.vlog(provideLanguageTranslation(languageIdentifier,97), sharedByName); } } } @@ -5066,7 +5069,8 @@ final class SyncEngine // response from OneDrive has to be a valid JSON object if (response.type() == JSONType.object){ // upload done without error - writeln("done."); + // "done." + writeln(provideLanguageTranslation(languageIdentifier,170)); // upload finished auto uploadFinishTime = Clock.currTime(); @@ -5077,7 +5081,8 @@ final class SyncEngine log.vdebug("Upload Speed: ", uploadSpeed, " Mbps (approx)"); // Log upload action to log file - log.fileOnly("Uploading new file ", path, " ... done."); + // "Uploading new file ", path, " ... done" + log.fileOnly(provideLanguageTranslation(languageIdentifier,242), path, provideLanguageTranslation(languageIdentifier,171)); // The file was uploaded, or a 4xx / 5xx error was generated if ("size" in response){ // The response JSON contains size, high likelihood valid response returned @@ -5098,12 +5103,16 @@ final class SyncEngine // Print a warning message - should only be triggered if: // - disableUploadValidation gets flagged (documentLibrary account type) // - syncBusinessFolders is being used & parent.driveId != defaultDriveId - log.log("WARNING: Uploaded file size does not match local file - skipping upload validation"); - log.vlog("WARNING: Due to Microsoft Sharepoint 'enrichment' of files, this file is now technically different to your local copy"); - log.vlog("See: https://github.com/OneDrive/onedrive-api-docs/issues/935 for further details"); + // "WARNING: Uploaded file size does not match local file - skipping upload validation" + log.log(provideLanguageTranslation(languageIdentifier,243)); + // "WARNING: Due to Microsoft Sharepoint 'enrichment' of files, this file is now technically different to your local copy" + log.vlog(provideLanguageTranslation(languageIdentifier,244)); + // "See: https://github.com/OneDrive/onedrive-api-docs/issues/935 for further details" + log.vlog(provideLanguageTranslation(languageIdentifier,209)); } else { // OK .. the uploaded file does not match and we did not disable this validation - log.log("Uploaded file size does not match local file - upload failure - retrying"); + // "Uploaded file size does not match local file - upload failure - retrying" + log.log(provideLanguageTranslation(languageIdentifier,245)); // Delete uploaded bad file onedrive.deleteById(response["parentReference"]["driveId"].str, response["id"].str, response["eTag"].str); // Re-upload @@ -5139,7 +5148,8 @@ final class SyncEngine uploadLastModifiedTime(parent.driveId, id, cTag, mtime); } else { // will be removed in different event! - log.log("File disappeared after upload: ", path); + // "File disappeared after upload: " + log.log(provideLanguageTranslation(languageIdentifier,246), path); } } else { // OneDrive Business Account - always use a session to upload @@ -5154,22 +5164,26 @@ final class SyncEngine if (parent.driveId == defaultDriveId) { // how much space is left on OneDrive after upload? remainingFreeSpace = (remainingFreeSpace - thisFileSize); - log.vlog("Remaining free space on OneDrive: ", remainingFreeSpace); + // "Remaining free space on OneDrive: " + log.vlog(provideLanguageTranslation(languageIdentifier,201), remainingFreeSpace); } // File uploaded successfully, space details updated if required return; } else { // response is not valid JSON, an error was returned from OneDrive - log.fileOnly("Uploading new file ", path, " ... error"); + // "Uploading new file ", path, " ... error" + log.fileOnly(provideLanguageTranslation(languageIdentifier,242), path, provideLanguageTranslation(languageIdentifier,247)); uploadFailed = true; return; } } else { // we are --dry-run - simulate the file upload - writeln("done."); + // "done." + writeln(provideLanguageTranslation(languageIdentifier,170)); response = createFakeResponse(path); // Log action to log file - log.fileOnly("Uploading new file ", path, " ... done."); + // "Uploading new file ", path, " ... done." + log.fileOnly(provideLanguageTranslation(languageIdentifier,242), path, provideLanguageTranslation(languageIdentifier,171)); // Is the response a valid JSON object - validation checking done in saveItem saveItem(response); return; @@ -5204,7 +5218,8 @@ final class SyncEngine // Check that 'name' is in the JSON response (validates data) and that 'name' == the path we are looking for if (("name" in fileDetailsFromOneDrive) && (fileDetailsFromOneDrive["name"].str == baseName(path))) { // OneDrive 'name' matches local path name - log.vlog("Requested file to upload exists on OneDrive - local database is out of sync for this file: ", path); + // "Requested file to upload exists on OneDrive - local database is out of sync for this file:" + log.vlog(provideLanguageTranslation(languageIdentifier,248), path); // Is the local file newer than the uploaded file? SysTime localFileModifiedTime = timeLastModified(path).toUTC(); @@ -5213,8 +5228,10 @@ final class SyncEngine if (localFileModifiedTime > remoteFileModifiedTime){ // local file is newer - log.vlog("Requested file to upload is newer than existing file on OneDrive"); - write("Uploading modified file ", path, " ... "); + // "Requested file to upload is newer than existing file on OneDrive" + log.vlog(provideLanguageTranslation(languageIdentifier,249)); + // "Uploading modified file " + write(provideLanguageTranslation(languageIdentifier,197), path, " ... "); JSONValue response; if (!dryRun) { @@ -5223,7 +5240,8 @@ final class SyncEngine if (thisFileSize <= thresholdFileSize) { try { response = onedrive.simpleUpload(path, parent.driveId, parent.id, baseName(path)); - writeln("done."); + // "done." + writeln(provideLanguageTranslation(languageIdentifier,170)); } catch (OneDriveException e) { log.vdebug("response = onedrive.simpleUpload(path, parent.driveId, parent.id, baseName(path)); generated a OneDriveException"); if (e.httpStatusCode == 401) { @@ -5252,7 +5270,8 @@ final class SyncEngine // Try upload as a session try { response = session.upload(path, parent.driveId, parent.id, baseName(path)); - writeln("done."); + // "done." + writeln(provideLanguageTranslation(languageIdentifier,170)); } catch (OneDriveException e) { if (e.httpStatusCode == 429) { // HTTP request returned status code 429 (Too Many Requests). We need to leverage the response Retry-After HTTP header to ensure minimum delay until the throttle is removed. @@ -5295,7 +5314,8 @@ final class SyncEngine writeln(""); try { response = session.upload(path, parent.driveId, parent.id, baseName(path)); - writeln("done."); + // "done." + writeln(provideLanguageTranslation(languageIdentifier,170)); } catch (OneDriveException e) { log.vdebug("response = session.upload(path, parent.driveId, parent.id, baseName(path)); generated a OneDriveException"); if (e.httpStatusCode == 401) { @@ -5370,7 +5390,8 @@ final class SyncEngine uploadLastModifiedTime(parent.driveId, id, cTag, mtime); } else { // will be removed in different event! - log.log("File disappeared after upload: ", path); + // "File disappeared after upload: " + log.log(provideLanguageTranslation(languageIdentifier,246), path); } } else { // Log that an invalid JSON object was returned @@ -5434,7 +5455,8 @@ final class SyncEngine return; } // upload complete - writeln("done."); + // "done." + writeln(provideLanguageTranslation(languageIdentifier,170)); saveItem(response); } else { // If we are uploading to a shared business folder, there are a couple of corner cases here: @@ -5473,20 +5495,24 @@ final class SyncEngine } // Log action to log file - log.fileOnly("Uploading modified file ", path, " ... done."); + // "Uploading modified file ", path, " ... done." + log.fileOnly(provideLanguageTranslation(languageIdentifier,197), path, provideLanguageTranslation(languageIdentifier,171)); // update free space tracking if this is our drive id if (parent.driveId == defaultDriveId) { // how much space is left on OneDrive after upload? remainingFreeSpace = (remainingFreeSpace - thisFileSize); - log.vlog("Remaining free space on OneDrive: ", remainingFreeSpace); + // "Remaining free space on OneDrive: " + log.vlog(provideLanguageTranslation(languageIdentifier,201), remainingFreeSpace); } } else { // we are --dry-run - simulate the file upload - writeln("done."); + // "done." + writeln(provideLanguageTranslation(languageIdentifier,170)); response = createFakeResponse(path); // Log action to log file - log.fileOnly("Uploading modified file ", path, " ... done."); + // "Uploading modified file ", path, " ... done." + log.fileOnly(provideLanguageTranslation(languageIdentifier,197), path, provideLanguageTranslation(languageIdentifier,171)); // Is the response a valid JSON object - validation checking done in saveItem saveItem(response); return; @@ -5494,7 +5520,8 @@ final class SyncEngine } else { // Save the details of the file that we got from OneDrive // --dry-run safe - log.vlog("Updating the local database with details for this file: ", path); + // "Updating the local database with details for this file: ", path + log.vlog(provideLanguageTranslation(languageIdentifier,250), path); if (!dryRun) { // use the live data saveItem(fileDetailsFromOneDrive); @@ -5506,38 +5533,47 @@ final class SyncEngine } } else { // The files are the "same" name wise but different in case sensitivity - log.error("ERROR: A local file has the same name as another local file."); - log.error("ERROR: To resolve, rename this local file: ", buildNormalizedPath(absolutePath(path))); - log.log("Skipping uploading this new file: ", buildNormalizedPath(absolutePath(path))); + // "ERROR: A local file has the same name as another local file." + log.error(provideLanguageTranslation(languageIdentifier,251)); + // "ERROR: To resolve, rename this local file: " + log.error(provideLanguageTranslation(languageIdentifier,240), buildNormalizedPath(absolutePath(path))); + // "Skipping uploading this new file: " + log.log(provideLanguageTranslation(languageIdentifier,239), buildNormalizedPath(absolutePath(path))); } } else { // fileDetailsFromOneDrive is not valid JSON, an error was returned from OneDrive - log.error("ERROR: An error was returned from OneDrive and the resulting response is not a valid JSON object"); - log.error("ERROR: Increase logging verbosity to assist determining why."); + // "ERROR: An error was returned from OneDrive and the resulting response is not a valid JSON object" + log.error(provideLanguageTranslation(languageIdentifier,252)); + // "ERROR: Increase logging verbosity to assist determining why." + log.error(provideLanguageTranslation(languageIdentifier,253)); uploadFailed = true; return; } } else { // Skip file - too large - log.log("Skipping uploading this new file as it exceeds the maximum size allowed by OneDrive: ", path); + // "Skipping uploading this new file as it exceeds the maximum size allowed by OneDrive: " + log.log(provideLanguageTranslation(languageIdentifier,254), path); uploadFailed = true; return; } } else { // unable to read local file - log.log("Skipping uploading this file as it cannot be read (file permissions or file corruption): ", path); + // "Skipping uploading this file as it cannot be read (file permissions or file corruption): " + log.log(provideLanguageTranslation(languageIdentifier,255), path); } } else { // Upload of the new file did not occur .. why? if (!parentPathFoundInDB) { // Parent path was not found - log.log("Skipping uploading this new file as parent path is not in the database: ", path); + // "Skipping uploading this new file as parent path is not in the database: ", path + log.log(provideLanguageTranslation(languageIdentifier,256), path); uploadFailed = true; return; } if (!quotaAvailable) { // Not enough free space - log.log("Skipping item '", path, "' due to insufficient free space available on OneDrive"); + // "Skipping item '", path, "' due to insufficient free space available on OneDrive" + log.log(provideLanguageTranslation(languageIdentifier,220), path, provideLanguageTranslation(languageIdentifier,257)); uploadFailed = true; return; } diff --git a/src/translations.d b/src/translations.d index 1b24a80f8..b6c3446d6 100644 --- a/src/translations.d +++ b/src/translations.d @@ -394,6 +394,21 @@ void initialise_EN_AU(){ JSONValue([ "240": "ERROR: To resolve, rename this local file: " ]), JSONValue([ "241": "Skipping item - excluded by skip_size config: " ]), JSONValue([ "242": "Uploading new file " ]), + JSONValue([ "243": "WARNING: Uploaded file size does not match local file - skipping upload validation" ]), + JSONValue([ "244": "WARNING: Due to Microsoft Sharepoint 'enrichment' of files, this file is now technically different to your local copy" ]), + JSONValue([ "245": "Uploaded file size does not match local file - upload failure - retrying" ]), + JSONValue([ "246": "File disappeared after upload: " ]), + JSONValue([ "247": " ... error" ]), + JSONValue([ "248": "Requested file to upload exists on OneDrive - local database is out of sync for this file: " ]), + JSONValue([ "249": "Requested file to upload is newer than existing file on OneDrive" ]), + JSONValue([ "250": "Updating the local database with details for this file: " ]), + JSONValue([ "251": "ERROR: A local file has the same name as another local file." ]), + JSONValue([ "252": "ERROR: An error was returned from OneDrive and the resulting response is not a valid JSON object" ]), + JSONValue([ "253": "ERROR: Increase logging verbosity to assist determining why." ]), + JSONValue([ "254": "Skipping uploading this new file as it exceeds the maximum size allowed by OneDrive: " ]), + JSONValue([ "255": "Skipping uploading this file as it cannot be read (file permissions or file corruption): " ]), + JSONValue([ "256": "Skipping uploading this new file as parent path is not in the database: " ]), + JSONValue([ "257": "' due to insufficient free space available on OneDrive" ]), From 6c5927d9932e2f83600128c96cc6f2542058ec16 Mon Sep 17 00:00:00 2001 From: abraunegg Date: Sun, 8 Aug 2021 07:31:08 +1000 Subject: [PATCH 09/15] Update PR * Update PR --- src/sync.d | 15 ++++++++++----- src/translations.d | 4 +++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/sync.d b/src/sync.d index 553c471b4..a78444fe4 100644 --- a/src/sync.d +++ b/src/sync.d @@ -5661,7 +5661,8 @@ final class SyncEngine return response; } } - writeln("done."); + // "done." + writeln(provideLanguageTranslation(languageIdentifier,170)); // Due to https://github.com/OneDrive/onedrive-api-docs/issues/935 Microsoft modifies all PDF, MS Office & HTML files with added XML content. It is a 'feature' of SharePoint. // So - now the 'local' and 'remote' file is technically DIFFERENT ... thanks Microsoft .. NO way to disable this stupidity string uploadNewFileHash; @@ -5677,14 +5678,18 @@ final class SyncEngine if(!uploadOnly){ // Download the Microsoft 'modified' file so 'local' is now in sync - log.vlog("Due to Microsoft Sharepoint 'enrichment' of files, downloading 'enriched' file to ensure local file is in-sync"); - log.vlog("See: https://github.com/OneDrive/onedrive-api-docs/issues/935 for further details"); + // "Due to Microsoft Sharepoint 'enrichment' of files, downloading 'enriched' file to ensure local file is in-sync" + log.vlog(provideLanguageTranslation(languageIdentifier,258)); + // "See: https://github.com/OneDrive/onedrive-api-docs/issues/935 for further details" + log.vlog(provideLanguageTranslation(languageIdentifier,259)); auto fileSize = response["size"].integer; onedrive.downloadById(response["parentReference"]["driveId"].str, response["id"].str, path, fileSize); } else { // we are not downloading a file, warn that file differences will exist - log.vlog("WARNING: Due to Microsoft Sharepoint 'enrichment' of files, this file is now technically different to your local copy"); - log.vlog("See: https://github.com/OneDrive/onedrive-api-docs/issues/935 for further details"); + // "WARNING: Due to Microsoft Sharepoint 'enrichment' of files, this file is now technically different to your local copy" + log.vlog(provideLanguageTranslation(languageIdentifier,260)); + // "See: https://github.com/OneDrive/onedrive-api-docs/issues/935 for further details" + log.vlog(provideLanguageTranslation(languageIdentifier,259)); } } diff --git a/src/translations.d b/src/translations.d index b6c3446d6..2ea0b438c 100644 --- a/src/translations.d +++ b/src/translations.d @@ -409,7 +409,9 @@ void initialise_EN_AU(){ JSONValue([ "255": "Skipping uploading this file as it cannot be read (file permissions or file corruption): " ]), JSONValue([ "256": "Skipping uploading this new file as parent path is not in the database: " ]), JSONValue([ "257": "' due to insufficient free space available on OneDrive" ]), - + JSONValue([ "258": "Due to Microsoft Sharepoint 'enrichment' of files, downloading 'enriched' file to ensure local file is in-sync" ]), + JSONValue([ "259": "See: https://github.com/OneDrive/onedrive-api-docs/issues/935 for further details" ]), + JSONValue([ "260": "WARNING: Due to Microsoft Sharepoint 'enrichment' of files, this file is now technically different to your local copy" ]), ]); From 415d4cc5a47a63cd0e17c70fe077f1fa835bfaae Mon Sep 17 00:00:00 2001 From: abraunegg Date: Sat, 14 Aug 2021 10:44:13 +1000 Subject: [PATCH 10/15] Update PR * Update PR --- src/sync.d | 59 ++++++++++++++++++++++++++++++---------------- src/translations.d | 12 ++++++++++ 2 files changed, 51 insertions(+), 20 deletions(-) diff --git a/src/sync.d b/src/sync.d index a78444fe4..e2473e1cf 100644 --- a/src/sync.d +++ b/src/sync.d @@ -5700,7 +5700,8 @@ final class SyncEngine // delete an item on OneDrive private void uploadDeleteItem(Item item, const(string) path) { - log.log("Deleting item from OneDrive: ", path); + \\ "Deleting item from OneDrive:" + log.log(provideLanguageTranslation(languageIdentifier,261), path); bool flagAsBigDelete = false; // query the database - how many objects will this remove? @@ -5715,8 +5716,10 @@ final class SyncEngine // A big delete detected flagAsBigDelete = true; if (!cfg.getValueBool("force")) { - log.error("ERROR: An attempt to remove a large volume of data from OneDrive has been detected. Exiting client to preserve data on OneDrive"); - log.error("ERROR: To delete a large volume of data use --force or increase the config value 'classify_as_big_delete' to a larger value"); + // "ERROR: An attempt to remove a large volume of data from OneDrive has been detected. Exiting client to preserve data on OneDrive" + log.error(provideLanguageTranslation(languageIdentifier,262)); + // "ERROR: To delete a large volume of data use --force or increase the config value 'classify_as_big_delete' to a larger value" + log.error(provideLanguageTranslation(languageIdentifier,263)); // Must exit here to preserve data on OneDrive exit(-1); } @@ -5746,7 +5749,8 @@ final class SyncEngine } catch (OneDriveException e) { if (e.httpStatusCode == 404) { // item.id, item.eTag could not be found on driveId - log.vlog("OneDrive reported: The resource could not be found."); + // "OneDrive reported: The resource to delete could not be found." + log.vlog(provideLanguageTranslation(languageIdentifier,264)); } else { // Not a 404 response .. is this a 401 response due to some sort of OneDrive Business security policy? if ((e.httpStatusCode == 401) && (accountType != "personal")) { @@ -5897,13 +5901,17 @@ final class SyncEngine } } else { // log error - log.error("ERROR: OneDrive response missing required 'id' element"); - log.error("ERROR: ", jsonItem); + // "ERROR: OneDrive response missing required 'id' element" + log.error(provideLanguageTranslation(languageIdentifier,265)); + // "ERROR: jsonItem + log.error(provideLanguageTranslation(languageIdentifier,61), jsonItem); } } else { // log error - log.error("ERROR: An error was returned from OneDrive and the resulting response is not a valid JSON object"); - log.error("ERROR: Increase logging verbosity to assist determining why."); + // "ERROR: An error was returned from OneDrive and the resulting response is not a valid JSON object" + log.error(provideLanguageTranslation(languageIdentifier,266)); + // "ERROR: Increase logging verbosity to assist determining why." + log.error(provideLanguageTranslation(languageIdentifier,238)); } } @@ -5912,46 +5920,53 @@ final class SyncEngine // inotify and we try to move the item. void uploadMoveItem(string from, string to) { - log.log("Moving ", from, " to ", to); + // "Moving ", from, " to ", to + log.log(provideLanguageTranslation(languageIdentifier,267), from, provideLanguageTranslation(languageIdentifier,268), to); // 'to' file validation .. is the 'to' file valid for upload? if (isSymlink(to)) { // if config says so we skip all symlinked items if (cfg.getValueBool("skip_symlinks")) { - log.vlog("Skipping item - skip symbolic links configured: ", to); + // "Skipping item - skip symbolic links configured: ", to + log.vlog(provideLanguageTranslation(languageIdentifier,213), to); return; } // skip unexisting symbolic links else if (!exists(readLink(to))) { - log.log("Skipping item - invalid symbolic link: ", to); + // "Skipping item - invalid symbolic link: ", to + log.log(provideLanguageTranslation(languageIdentifier,214), to); return; } } // Restriction and limitations about windows naming files if (!isValidName(to)) { - log.log("Skipping item - invalid name (Microsoft Naming Convention): ", to); + // "Skipping item - invalid name (Microsoft Naming Convention): ", to + log.log(provideLanguageTranslation(languageIdentifier,187), to); return; } // Check for bad whitespace items if (!containsBadWhiteSpace(to)) { - log.log("Skipping item - invalid name (Contains an invalid whitespace item): ", to); + // "Skipping item - invalid name (Contains an invalid whitespace item): ", to + log.log(provideLanguageTranslation(languageIdentifier,188), to); return; } // Check for HTML ASCII Codes as part of file name if (!containsASCIIHTMLCodes(to)) { - log.log("Skipping item - invalid name (Contains HTML ASCII Code): ", to); + // "Skipping item - invalid name (Contains HTML ASCII Code): ", to + log.log(provideLanguageTranslation(languageIdentifier,189), to); return; } // 'to' file has passed file validation Item fromItem, toItem, parentItem; if (!itemdb.selectByPath(from, defaultDriveId, fromItem)) { - if (cfg.getValueBool("skip_dotfiles") && isDotFile(to)){ - log.log("Skipping upload due to skip_dotfile = true"); + if (cfg.getValueBool("skip_dotfiles") && isDotFile(to)){ + // "Skipping upload due to skip_dotfile = true" + log.log(provideLanguageTranslation(languageIdentifier,269)); return; } else { uploadNewFile(to); @@ -5975,17 +5990,20 @@ final class SyncEngine // target location is a .folder log.vdebug("Target location is excluded from sync due to skip_dotfiles = true"); // item will have been moved locally, but as this is now to a location that is not synced, needs to be removed from OneDrive - log.log("Item has been moved to a location that is excluded from sync operations. Removing item from OneDrive"); + // "Item has been moved to a location that is excluded from sync operations. Removing item from OneDrive" + log.log(provideLanguageTranslation(languageIdentifier,270)); uploadDeleteItem(fromItem, from); return; } } // some other error - throw new SyncException("Can't move an item to an unsynced directory"); + // "Can't move an item to an unsynced directory" + throw new SyncException(provideLanguageTranslation(languageIdentifier,271)); } if (cfg.getValueBool("skip_dotfiles") && isDotFile(to)){ - log.log("Removing item from OneDrive due to skip_dotfiles = true"); + // "Removing item from OneDrive due to skip_dotfiles = true" + log.log(provideLanguageTranslation(languageIdentifier,272)); uploadDeleteItem(fromItem, from); return; } @@ -5995,7 +6013,8 @@ final class SyncEngine uploadNewFile(to); } else { if (!exists(to)) { - log.vlog("uploadMoveItem target has disappeared: ", to); + // Skipping item - path has disappeared: + log.vlog(provideLanguageTranslation(languageIdentifier,210), to); return; } SysTime mtime = timeLastModified(to).toUTC(); diff --git a/src/translations.d b/src/translations.d index 2ea0b438c..31a01ded7 100644 --- a/src/translations.d +++ b/src/translations.d @@ -412,6 +412,18 @@ void initialise_EN_AU(){ JSONValue([ "258": "Due to Microsoft Sharepoint 'enrichment' of files, downloading 'enriched' file to ensure local file is in-sync" ]), JSONValue([ "259": "See: https://github.com/OneDrive/onedrive-api-docs/issues/935 for further details" ]), JSONValue([ "260": "WARNING: Due to Microsoft Sharepoint 'enrichment' of files, this file is now technically different to your local copy" ]), + JSONValue([ "261": "Deleting item from OneDrive: " ]), + JSONValue([ "262": "ERROR: An attempt to remove a large volume of data from OneDrive has been detected. Exiting client to preserve data on OneDrive" ]), + JSONValue([ "263": "ERROR: To delete a large volume of data use --force or increase the config value 'classify_as_big_delete' to a larger value" ]), + JSONValue([ "264": "OneDrive reported: The resource to delete could not be found." ]), + JSONValue([ "265": "ERROR: OneDrive response missing required 'id' element" ]), + JSONValue([ "266": "ERROR: An error was returned from OneDrive and the resulting response is not a valid JSON object" ]), + JSONValue([ "267": "Moving " ]), + JSONValue([ "268": " to " ]), + JSONValue([ "269": "Skipping upload due to skip_dotfile = true" ]), + JSONValue([ "270": "Item has been moved to a location that is excluded from sync operations. Removing item from OneDrive" ]), + JSONValue([ "271": "Can't move an item to an unsynced directory" ]), + JSONValue([ "272": "Removing item from OneDrive due to skip_dotfiles = true" ]), ]); From 69efb0ef3987bb6090ba4f7918e3f49062eafd79 Mon Sep 17 00:00:00 2001 From: abraunegg Date: Wed, 3 Nov 2021 18:57:07 +1100 Subject: [PATCH 11/15] Update PR * Update PR --- src/main.d | 22 ++++--- src/sync.d | 147 +++++++++++++++++++++++++++++---------------- src/translations.d | 30 +++++++++ 3 files changed, 139 insertions(+), 60 deletions(-) diff --git a/src/main.d b/src/main.d index 08746732a..404e21b60 100644 --- a/src/main.d +++ b/src/main.d @@ -518,10 +518,20 @@ int main(string[] args) log.logAndNotify(provideLanguageTranslation(languageIdentifier,18)); cfg.setValueBool("resync", true); } + + // Handle --logout as separate item, do not 'resync' on a --logout / reauth + if (cfg.getValueBool("logout")) { + // log action + log.vdebug("--logout requested"); + if (!cfg.getValueBool("dry_run")) { + safeRemove(cfg.refreshTokenFilePath); + } + } - // Handle --resync and --logout to remove local files - if (cfg.getValueBool("resync") || cfg.getValueBool("logout")) { - if (cfg.getValueBool("resync")) log.vdebug("--resync requested"); + // Handle --resync to remove local files + if (cfg.getValueBool("resync")) { + // log action + log.vdebug("--resync requested"); // "Deleting the saved status ..." log.vlog(provideLanguageTranslation(languageIdentifier,19)); if (!cfg.getValueBool("dry_run")) { @@ -529,12 +539,6 @@ int main(string[] args) safeRemove(cfg.deltaLinkFilePath); safeRemove(cfg.uploadStateFilePath); } - if (cfg.getValueBool("logout")) { - log.vdebug("--logout requested"); - if (!cfg.getValueBool("dry_run")) { - safeRemove(cfg.refreshTokenFilePath); - } - } } // Display current application configuration, no application initialisation diff --git a/src/sync.d b/src/sync.d index e2473e1cf..b9f68e991 100644 --- a/src/sync.d +++ b/src/sync.d @@ -4707,10 +4707,7 @@ final class SyncEngine } } else { // response is not valid JSON, an error was returned from OneDrive - // "ERROR: There was an error performing this operation on OneDrive" - log.error(provideLanguageTranslation(languageIdentifier,237)); - // "ERROR: Increase logging verbosity to assist determining why." - log.error(provideLanguageTranslation(languageIdentifier,238)); + displayInvalidJSONObjectLogMessage(); //"Skipping: ", buildNormalizedPath(absolutePath(path)) log.log(provideLanguageTranslation(languageIdentifier,236), buildNormalizedPath(absolutePath(path))); return; @@ -5700,7 +5697,7 @@ final class SyncEngine // delete an item on OneDrive private void uploadDeleteItem(Item item, const(string) path) { - \\ "Deleting item from OneDrive:" + // "Deleting item from OneDrive:" log.log(provideLanguageTranslation(languageIdentifier,261), path); bool flagAsBigDelete = false; @@ -6063,7 +6060,8 @@ final class SyncEngine } } if (!itemInDB) { - throw new SyncException("The item to delete is not in the local database"); + // "Item cannot be deleted from OneDrive because it was not found in the local database" + throw new SyncException(provideLanguageTranslation(languageIdentifier,56)); } if (item.parentId == null) { @@ -6073,13 +6071,24 @@ final class SyncEngine try { if (noRemoteDelete) { // do not process remote delete - log.vlog("Skipping remote delete as --upload-only & --no-remote-delete configured"); + if (isDir(path)) { + // directory - needs directory message + // "Skipping remote directory delete as --upload-only & --no-remote-delete configured" + log.vlog(provideLanguageTranslation(languageIdentifier,194)); + } else { + // file - needs file message + // "Skipping remote file delete as --upload-only & --no-remote-delete configured" + log.vlog(provideLanguageTranslation(languageIdentifier,207)); + } } else { uploadDeleteItem(item, path); } } catch (OneDriveException e) { if (e.httpStatusCode == 404) { - log.log(e.msg); + // item to delete cannot be found + log.log(provideLanguageTranslation(languageIdentifier,264)); + // debug output of actual error from OneDrive API + log.vdebug(e.msg); } else { // display what the error is displayOneDriveErrorMessage(e.msg, getFunctionName!({})); @@ -6090,7 +6099,8 @@ final class SyncEngine // move a OneDrive folder from one name to another void moveByPath(const(string) source, const(string) destination) { - log.vlog("Moving remote folder: ", source, " -> ", destination); + // "Moving remote folder: ", source, " -> ", destination + log.vlog(provideLanguageTranslation(languageIdentifier,273), source, " -> ", destination); // Source and Destination are relative to ~/OneDrive string sourcePath = source; @@ -6129,17 +6139,19 @@ final class SyncEngine JSONValue siteQuery; string nextLink; string[] siteSearchResults; - - log.log("Office 365 Library Name Query: ", o365SharedLibraryName); + // "Office 365 Library Name Query: ", o365SharedLibraryName + log.log(provideLanguageTranslation(languageIdentifier,274), o365SharedLibraryName); for (;;) { try { siteQuery = onedrive.o365SiteSearch(nextLink); } catch (OneDriveException e) { - log.error("ERROR: Query of OneDrive for Office 365 Library Name failed"); + // "ERROR: Query of OneDrive for Office 365 Library Name failed" + log.error(provideLanguageTranslation(languageIdentifier,275)); if (e.httpStatusCode == 403) { // Forbidden - most likely authentication scope needs to be updated - log.error("ERROR: Authentication scope needs to be updated. Use --logout and re-authenticate client."); + // "ERROR: Authentication scope needs to be updated. Use --logout and re-authenticate client." + log.error(provideLanguageTranslation(languageIdentifier,276)); return; } // HTTP request returned status code 429 (Too Many Requests) @@ -6196,7 +6208,8 @@ final class SyncEngine try { siteDriveQuery = onedrive.o365SiteDrives(site_id); } catch (OneDriveException e) { - log.error("ERROR: Query of OneDrive for Office Site ID failed"); + // "ERROR: Query of OneDrive for Office Site ID failed" + log.error(provideLanguageTranslation(languageIdentifier,277)); // display what the error is displayOneDriveErrorMessage(e.msg, getFunctionName!({})); return; @@ -6210,6 +6223,7 @@ final class SyncEngine writeln("-----------------------------------------------"); log.vdebug("Site Details: ", driveResult); found = true; + // No language translation for these writeln("Site Name: ", searchResult["displayName"].str); writeln("Library Name: ", driveResult["name"].str); writeln("drive_id: ", driveResult["id"].str); @@ -6218,15 +6232,15 @@ final class SyncEngine // closeout writeln("-----------------------------------------------"); } else { - // not a valid JSON object - log.error("ERROR: There was an error performing this operation on OneDrive"); - log.error("ERROR: Increase logging verbosity to assist determining why."); + // response is not valid JSON, an error was returned from OneDrive + displayInvalidJSONObjectLogMessage(); return; } } } else { // 'displayName', 'id' or ''webUrl' not present in JSON results for a specific site - string siteNameAvailable = "Site 'name' was restricted by OneDrive API permissions"; + // "Site 'name' was restricted by OneDrive API permissions" + string siteNameAvailable = provideLanguageTranslation(languageIdentifier,278); bool displayNameAvailable = false; bool idAvailable = false; if ("name" in searchResult) siteNameAvailable = searchResult["name"].str; @@ -6234,12 +6248,18 @@ final class SyncEngine if ("id" in searchResult) idAvailable = true; // Display error details for this site data - log.error("\nERROR: SharePoint Site details not provided for: ", siteNameAvailable); - log.error("ERROR: The SharePoint Site results returned from OneDrive API do not contain the required items to match. Please check your permissions with your site administrator."); - log.error("ERROR: Your site security settings is preventing the following details from being accessed: 'displayName' or 'id'"); - log.vlog(" - Is 'displayName' available = ", displayNameAvailable); - log.vlog(" - Is 'id' available = ", idAvailable); - log.error("ERROR: To debug this further, please increase verbosity (--verbose or --verbose --verbose) to provide further insight as to what details are actually being returned."); + // "\nERROR: SharePoint Site details not provided for: " + log.error(provideLanguageTranslation(languageIdentifier,279), siteNameAvailable); + // "ERROR: The SharePoint Site results returned from OneDrive API do not contain the required items to match. Please check your permissions with your site administrator." + log.error(provideLanguageTranslation(languageIdentifier,280)); + // "ERROR: Your site security settings is preventing the following details from being accessed: 'displayName' or 'id'" + log.error(provideLanguageTranslation(languageIdentifier,281)); + // " - Is 'displayName' available = " + log.vlog(provideLanguageTranslation(languageIdentifier,282), displayNameAvailable); + // " - Is 'id' available = " + log.vlog(provideLanguageTranslation(languageIdentifier,283), idAvailable); + // "ERROR: To debug this further, please increase verbosity (--verbose or --verbose --verbose) to provide further insight as to what details are actually being returned." + log.error(provideLanguageTranslation(languageIdentifier,284)); } } @@ -6256,7 +6276,8 @@ final class SyncEngine } else { // Add, but indicate displayName unavailable, use id if ("id" in searchResult) { - siteSearchResultsEntry = " * " ~ "Unknown displayName (Data not provided by API), Site ID: " ~ searchResult["id"].str; + // " * " ~ "Unknown displayName (Data not provided by API), Site ID: " ~ searchResult["id"].str; + siteSearchResultsEntry = " * " ~ provideLanguageTranslation(languageIdentifier,285) ~ searchResult["id"].str; siteSearchResults ~= siteSearchResultsEntry; } else { // displayName and id unavailable, display in debug log the entry @@ -6266,9 +6287,8 @@ final class SyncEngine } } } else { - // not a valid JSON object - log.error("ERROR: There was an error performing this operation on OneDrive"); - log.error("ERROR: Increase logging verbosity to assist determining why."); + // response is not valid JSON, an error was returned from OneDrive + displayInvalidJSONObjectLogMessage(); return; } @@ -6283,9 +6303,11 @@ final class SyncEngine // Was the intended target found? if(!found) { - log.error("\nERROR: The requested SharePoint site could not be found. Please check it's name and your permissions to access the site."); + // "\nERROR: The requested SharePoint site could not be found. Please check it's name and your permissions to access the site." + log.error(provideLanguageTranslation(languageIdentifier,286)); // List all sites returned to assist user - log.log("\nThe following SharePoint site names were returned:"); + // "\nThe following SharePoint site names were returned:" + log.log(provideLanguageTranslation(languageIdentifier,287)); foreach (searchResultEntry; siteSearchResults) { // list the display name that we use to match against the user query log.log(searchResultEntry); @@ -6309,7 +6331,8 @@ final class SyncEngine log.vdebug("onedrivePathDetails = onedrive.getPathDetails(filePath); generated a OneDriveException"); if (e.httpStatusCode == 404) { // Requested path could not be found - log.error("ERROR: The requested path to query was not found on OneDrive"); + // "ERROR: The requested path to query was not found on OneDrive" + log.error(provideLanguageTranslation(languageIdentifier,288)); return; } @@ -6355,21 +6378,29 @@ final class SyncEngine if ((createShareableLinkResponse.type() == JSONType.object) && ("link" in createShareableLinkResponse)) { // Extract the file share link from the JSON response fileShareLink = createShareableLinkResponse["link"]["webUrl"].str; - writeln("File Shareable Link: ", fileShareLink); + // "File Shareable Link: ", fileShareLink + writeln(provideLanguageTranslation(languageIdentifier,289), fileShareLink); } else { - // not a valid JSON object - log.error("ERROR: There was an error performing this operation on OneDrive"); - log.error("ERROR: Increase logging verbosity to assist determining why."); + // response is not valid JSON, an error was returned from OneDrive + displayInvalidJSONObjectLogMessage(); return; } } else { - // not a valid JSON object - log.error("ERROR: There was an error performing this operation on OneDrive"); - log.error("ERROR: Increase logging verbosity to assist determining why."); + // response is not valid JSON, an error was returned from OneDrive + displayInvalidJSONObjectLogMessage(); return; } } + // Error message to display when OneDrive generates an error performing an operation, generating an invalid JSON object + void displayInvalidJSONObjectLogMessage() + { + // "ERROR: There was an error performing this operation on OneDrive" + log.error(provideLanguageTranslation(languageIdentifier,237)); + // "ERROR: Increase logging verbosity to assist determining why." + log.error(provideLanguageTranslation(languageIdentifier,238)); + } + // Query OneDrive for a URL path of a file void queryOneDriveForFileURL(string localFilePath, string syncDir) { @@ -6403,11 +6434,13 @@ final class SyncEngine // was file found? if (!fileInDB) { // File has not been synced with OneDrive - log.error("File has not been synced with OneDrive: ", localFilePath); + // "File has not been synced with OneDrive: ", localFilePath + log.error(provideLanguageTranslation(languageIdentifier,290), localFilePath); } } else { // File does not exist locally - log.error("File not found on local system: ", localFilePath); + // "File not found on local filesystem: ", localFilePath + log.error(provideLanguageTranslation(languageIdentifier,291), localFilePath); } } @@ -6436,7 +6469,8 @@ final class SyncEngine log.vdebug("onedrivePathDetails = onedrive.getPathDetails(path); generated a OneDriveException"); if (e.httpStatusCode == 404) { // Requested path could not be found - log.error("ERROR: The requested path to query was not found on OneDrive"); + // "ERROR: The requested path to query was not found on OneDrive" + log.error(provideLanguageTranslation(languageIdentifier,288)); return; } @@ -6560,16 +6594,20 @@ final class SyncEngine } // Are there any valid changes? if (validChanges != 0){ - writeln("Selected directory is out of sync with OneDrive"); + // "Selected directory is out of sync with OneDrive" + writeln(provideLanguageTranslation(languageIdentifier,292)); if (downloadSize > 0){ downloadSize = downloadSize / 1000; - writeln("Approximate data to download from OneDrive: ", downloadSize, " KB"); + // "Approximate data to download from OneDrive: ", downloadSize, " KB" + writeln(provideLanguageTranslation(languageIdentifier,293), downloadSize, " KB"); } } else { - writeln("No pending remote changes - selected directory is in sync"); + // "No pending remote changes - selected directory is in sync" + writeln(provideLanguageTranslation(languageIdentifier,294)); } } else { - writeln("Local directory is out of sync with OneDrive"); + // "Local directory is out of sync with OneDrive" + writeln(provideLanguageTranslation(languageIdentifier,295)); foreach (item; changes["value"].array) { if ((isItemFile(item)) && (hasFileSize(item))) { downloadSize = downloadSize + item["size"].integer; @@ -6577,11 +6615,13 @@ final class SyncEngine } if (downloadSize > 0){ downloadSize = downloadSize / 1000; - writeln("Approximate data to download from OneDrive: ", downloadSize, " KB"); + // "Approximate data to download from OneDrive: ", downloadSize, " KB" + writeln(provideLanguageTranslation(languageIdentifier,293), downloadSize, " KB"); } } } else { - writeln("No pending remote changes - in sync"); + // "No pending remote changes - in sync" + writeln(provideLanguageTranslation(languageIdentifier,296)); } } @@ -6677,6 +6717,7 @@ final class SyncEngine return fakeResponse; } + // Handle OneDrive sending a 429 response to retry-after void handleOneDriveThrottleRequest() { // If OneDrive sends a status code 429 then this function will be used to process the Retry-After response header which contains the value by which we need to wait @@ -6702,8 +6743,10 @@ final class SyncEngine } // Sleep thread as per request - log.log("Thread sleeping due to 'HTTP request returned status code 429' - The request has been throttled"); - log.log("Sleeping for ", delayBeforeRetry, " seconds"); + // "Thread sleeping due to 'HTTP request returned status code 429' - The request has been throttled" + log.log(provideLanguageTranslation(languageIdentifier,297)); + // "Sleeping for ", delayBeforeRetry, " seconds" + log.log(provideLanguageTranslation(languageIdentifier,298), delayBeforeRetry, provideLanguageTranslation(languageIdentifier,299)); Thread.sleep(dur!"seconds"(delayBeforeRetry)); // Reset retry-after value to zero as we have used this value now and it may be changed in the future to a different value @@ -6777,12 +6820,14 @@ final class SyncEngine } } // Add driveData JSON data to array - log.vlog("Adding OneDrive root details for processing"); + // "Adding OneDrive root details for processing" + log.vlog(provideLanguageTranslation(languageIdentifier,300)); childrenData ~= rootData; } // Add driveData JSON data to array - log.vlog("Adding OneDrive folder details for processing"); + // "Adding OneDrive folder details for processing" + log.vlog(provideLanguageTranslation(languageIdentifier,301)); childrenData ~= driveData; for (;;) { diff --git a/src/translations.d b/src/translations.d index 31a01ded7..20e70bfe0 100644 --- a/src/translations.d +++ b/src/translations.d @@ -424,6 +424,36 @@ void initialise_EN_AU(){ JSONValue([ "270": "Item has been moved to a location that is excluded from sync operations. Removing item from OneDrive" ]), JSONValue([ "271": "Can't move an item to an unsynced directory" ]), JSONValue([ "272": "Removing item from OneDrive due to skip_dotfiles = true" ]), + JSONValue([ "273": "Moving remote folder: " ]), + JSONValue([ "274": "Office 365 Library Name Query: " ]), + JSONValue([ "275": "ERROR: Query of OneDrive for Office 365 Library Name failed" ]), + JSONValue([ "276": "ERROR: Authentication scope needs to be updated. Use --logout and re-authenticate client." ]), + JSONValue([ "277": "ERROR: Query of OneDrive for Office Site ID failed" ]), + JSONValue([ "278": "Site 'name' was restricted by OneDrive API permissions" ]), + JSONValue([ "279": "\nERROR: SharePoint Site details not provided for: " ]), + JSONValue([ "280": "ERROR: The SharePoint Site results returned from OneDrive API do not contain the required items to match. Please check your permissions with your site administrator." ]), + JSONValue([ "281": "ERROR: Your site security settings is preventing the following details from being accessed: 'displayName' or 'id'" ]), + JSONValue([ "282": " - Is 'displayName' available = " ]), + JSONValue([ "283": " - Is 'id' available = " ]), + JSONValue([ "284": "ERROR: To debug this further, please increase verbosity (--verbose or --verbose --verbose) to provide further insight as to what details are actually being returned." ]), + JSONValue([ "285": "Unknown displayName (Data not provided by API), Site ID: " ]), + JSONValue([ "286": "\nERROR: The requested SharePoint site could not be found. Please check it's name and your permissions to access the site." ]), + JSONValue([ "287": "\nThe following SharePoint site names were returned:" ]), + JSONValue([ "288": "ERROR: The requested path to query was not found on OneDrive" ]), + JSONValue([ "289": "File Shareable Link: " ]), + JSONValue([ "290": "File has not been synced with OneDrive: " ]), + JSONValue([ "291": "File not found on local filesystem: " ]), + JSONValue([ "292": "Selected directory is out of sync with OneDrive" ]), + JSONValue([ "293": "Approximate data to download from OneDrive: " ]), + JSONValue([ "294": "No pending remote changes - selected directory is in sync" ]), + JSONValue([ "295": "Local directory is out of sync with OneDrive" ]), + JSONValue([ "296": "No pending remote changes - in sync" ]), + JSONValue([ "297": "Thread sleeping due to 'HTTP request returned status code 429' - The request has been throttled" ]), + JSONValue([ "298": "Sleeping for " ]), + JSONValue([ "299": " seconds" ]), + JSONValue([ "300": "Adding OneDrive root details for processing" ]), + JSONValue([ "301": "Adding OneDrive folder details for processing" ]), + ]); From 0728b1d7c81353ac241738ef0f920419ac99a301 Mon Sep 17 00:00:00 2001 From: abraunegg Date: Thu, 4 Nov 2021 11:50:28 +1100 Subject: [PATCH 12/15] Update PR * Update PR --- src/sync.d | 133 ++++++++++++++++++++++++++------------------- src/translations.d | 18 ++++++ 2 files changed, 95 insertions(+), 56 deletions(-) diff --git a/src/sync.d b/src/sync.d index b9f68e991..e301b5b6c 100644 --- a/src/sync.d +++ b/src/sync.d @@ -1527,7 +1527,7 @@ final class SyncEngine // If an error is returned when querying 'changes' and we recall the original function, we go into a never ending loop where the sync never ends // re-try the specific changes queries if (e.httpStatusCode == 504) { - // "OneDrive returned a 'HTTP 504 - Gateway Timeout' when attempting to query the OneDrive API - retrying applicable request" + // OneDrive returned a 'HTTP 504 - Gateway Timeout' when attempting to query the OneDrive API - retrying applicable request log.log(provideLanguageTranslation(languageIdentifier,124)); log.vdebug("changes = generateDeltaResponse(driveId, idToQuery) previously threw an error - retrying"); // The server, while acting as a proxy, did not receive a timely response from the upstream server it needed to access in attempting to complete the request. @@ -1608,7 +1608,7 @@ final class SyncEngine // If an error is returned when querying 'changes' and we recall the original function, we go into a never ending loop where the sync never ends // re-try the specific changes queries if (e.httpStatusCode == 504) { - // "OneDrive returned a 'HTTP 504 - Gateway Timeout' when attempting to query the OneDrive API - retrying applicable request" + // OneDrive returned a 'HTTP 504 - Gateway Timeout' when attempting to query the OneDrive API - retrying applicable request log.log(provideLanguageTranslation(languageIdentifier,124)); log.vdebug("changes = onedrive.viewChangesByItemId(driveId, idToQuery, deltaLink) previously threw an error - retrying"); // The server, while acting as a proxy, did not receive a timely response from the upstream server it needed to access in attempting to complete the request. @@ -1625,7 +1625,7 @@ final class SyncEngine // display what the error is log.vdebug("Query Error: changes = onedrive.viewChangesByItemId(driveId, idToQuery, deltaLink) on re-try after delay"); if (e.httpStatusCode == 504) { - // "OneDrive returned a 'HTTP 504 - Gateway Timeout' when attempting to query the OneDrive API - retrying applicable request" + // OneDrive returned a 'HTTP 504 - Gateway Timeout' when attempting to query the OneDrive API - retrying applicable request log.log(provideLanguageTranslation(languageIdentifier,124)); log.vdebug("changes = onedrive.viewChangesByItemId(driveId, idToQuery, deltaLink) previously threw an error - retrying with empty deltaLink"); try { @@ -1714,7 +1714,7 @@ final class SyncEngine // If an error is returned when querying 'changes' and we recall the original function, we go into a never ending loop where the sync never ends // re-try the specific changes queries if (e.httpStatusCode == 504) { - // "OneDrive returned a 'HTTP 504 - Gateway Timeout' when attempting to query the OneDrive API - retrying applicable request" + // OneDrive returned a 'HTTP 504 - Gateway Timeout' when attempting to query the OneDrive API - retrying applicable request log.log(provideLanguageTranslation(languageIdentifier,124)); log.vdebug("changesAvailable = onedrive.viewChangesByItemId(driveId, idToQuery, deltaLinkAvailable) previously threw an error - retrying"); // The server, while acting as a proxy, did not receive a timely response from the upstream server it needed to access in attempting to complete the request. @@ -1731,7 +1731,7 @@ final class SyncEngine // display what the error is log.vdebug("Query Error: changesAvailable = onedrive.viewChangesByItemId(driveId, idToQuery, deltaLinkAvailable) on re-try after delay"); if (e.httpStatusCode == 504) { - // "OneDrive returned a 'HTTP 504 - Gateway Timeout' when attempting to query the OneDrive API - retrying applicable request" + // OneDrive returned a 'HTTP 504 - Gateway Timeout' when attempting to query the OneDrive API - retrying applicable request log.log(provideLanguageTranslation(languageIdentifier,124)); log.vdebug("changesAvailable = onedrive.viewChangesByItemId(driveId, idToQuery, deltaLinkAvailable) previously threw an error - retrying with empty deltaLinkAvailable"); try { @@ -3689,7 +3689,7 @@ final class SyncEngine // "skipped." writeln(provideLanguageTranslation(languageIdentifier,198)); // OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded - log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); + log.vlog(provideLanguageTranslation(languageIdentifier,312)); uploadFailed = true; return; } @@ -3697,9 +3697,10 @@ final class SyncEngine // caught an error, write out we are skipping this item // "skipped." writeln(provideLanguageTranslation(languageIdentifier,198)); - // HTTP request returned status code 404 - the eTag provided does not exist + // HTTP request returned status code 404 - the eTag provided does not exist on OneDrive // Delete record from the local database - file will be uploaded as a new file - log.vlog("OneDrive returned a 'HTTP 404 - eTag Issue' - gracefully handling error"); + // "OneDrive returned a 'HTTP 404 - item eTag does not exist' - gracefully handling error" + log.vlog(provideLanguageTranslation(languageIdentifier,314)); itemdb.deleteById(item.driveId, item.id); uploadFailed = true; return; @@ -3724,7 +3725,8 @@ final class SyncEngine writeln(provideLanguageTranslation(languageIdentifier,198)); // HTTP request returned status code 412 - ETag does not match current item's value // Delete record from the local database - file will be uploaded as a new file - log.vlog("OneDrive returned a 'HTTP 412 - Precondition Failed' - gracefully handling error. Will upload as new file."); + // "OneDrive returned a 'HTTP 412 - Precondition Failed' - gracefully handling error. Will upload as new file." + log.vlog(provideLanguageTranslation(languageIdentifier,316)); log.vdebug("Simple Upload Replace Failed - OneDrive eTag / cTag match issue (Personal Account)"); itemdb.deleteById(item.driveId, item.id); uploadFailed = true; @@ -3732,9 +3734,9 @@ final class SyncEngine } if (e.httpStatusCode == 504) { // HTTP request returned status code 504 (Gateway Timeout) - log.log("OneDrive returned a 'HTTP 504 - Gateway Timeout' - retrying upload request as a session"); - // Try upload as a session - response = session.upload(path, item.driveId, item.parentId, baseName(path), item.eTag); + log.log(provideLanguageTranslation(languageIdentifier,124)); + // Retry original action + response = onedrive.simpleUploadReplace(path, item.driveId, item.id, item.eTag); } else { // caught an error, write out we are skipping this item // "skipped." @@ -3765,7 +3767,7 @@ final class SyncEngine // "skipped." writeln(provideLanguageTranslation(languageIdentifier,198)); // OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded - log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); + log.vlog(provideLanguageTranslation(languageIdentifier,312)); uploadFailed = true; return; } @@ -3775,7 +3777,8 @@ final class SyncEngine writeln(provideLanguageTranslation(languageIdentifier,198)); // HTTP request returned status code 412 - ETag does not match current item's value // Delete record from the local database - file will be uploaded as a new file - log.vlog("OneDrive returned a 'HTTP 412 - Precondition Failed' - gracefully handling error. Will upload as new file."); + // "OneDrive returned a 'HTTP 412 - Precondition Failed' - gracefully handling error. Will upload as new file." + log.vlog(provideLanguageTranslation(languageIdentifier,316)); log.vdebug("Session Upload Replace Failed - OneDrive eTag / cTag match issue (Personal Account)"); itemdb.deleteById(item.driveId, item.id); uploadFailed = true; @@ -3842,7 +3845,7 @@ final class SyncEngine // "skipped." writeln(provideLanguageTranslation(languageIdentifier,198)); // OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded - log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); + log.vlog(provideLanguageTranslation(languageIdentifier,312)); uploadFailed = true; return; } @@ -3866,7 +3869,8 @@ final class SyncEngine writeln(provideLanguageTranslation(languageIdentifier,198)); // HTTP request returned status code 412 - ETag does not match current item's value // Delete record from the local database - file will be uploaded as a new file - log.vlog("OneDrive returned a 'HTTP 412 - Precondition Failed' - gracefully handling error. Will upload as new file."); + // "OneDrive returned a 'HTTP 412 - Precondition Failed' - gracefully handling error. Will upload as new file." + log.vlog(provideLanguageTranslation(languageIdentifier,316)); log.vdebug("Session Upload Replace Failed - OneDrive eTag / cTag match issue (Business Account)"); itemdb.deleteById(item.driveId, item.id); uploadFailed = true; @@ -4081,7 +4085,7 @@ final class SyncEngine // "skipped." writeln(provideLanguageTranslation(languageIdentifier,198)); // OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded - log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); + log.vlog(provideLanguageTranslation(languageIdentifier,312)); uploadFailed = true; return response; } @@ -4105,7 +4109,8 @@ final class SyncEngine writeln(provideLanguageTranslation(languageIdentifier,198)); // HTTP request returned status code 412 - ETag does not match current item's value // Delete record from the local database - file will be uploaded as a new file - log.vlog("OneDrive returned a 'HTTP 412 - Precondition Failed' - gracefully handling error. Will upload as new file."); + // "OneDrive returned a 'HTTP 412 - Precondition Failed' - gracefully handling error. Will upload as new file." + log.vlog(provideLanguageTranslation(languageIdentifier,316)); log.vdebug("Session Upload Replace Failed - OneDrive eTag / cTag match issue (Sharepoint Library)"); itemdb.deleteById(item.driveId, item.id); uploadFailed = true; @@ -4809,7 +4814,8 @@ final class SyncEngine if (e.httpStatusCode == 400) { // "Skipping uploading this new file: ", buildNormalizedPath(absolutePath(path)) log.log(provideLanguageTranslation(languageIdentifier,239), buildNormalizedPath(absolutePath(path))); - log.vlog("Skipping item - OneDrive returned a 'HTTP 400 - Bad Request' when attempting to query if file exists"); + // "Skipping item - OneDrive returned a 'HTTP 400 - Bad Request' when attempting to query if file exists" + log.vlog(provideLanguageTranslation(languageIdentifier,319)); // "ERROR: To resolve, rename this local file: ", buildNormalizedPath(absolutePath(path)) log.error(provideLanguageTranslation(languageIdentifier,240), buildNormalizedPath(absolutePath(path))); uploadFailed = true; @@ -4817,7 +4823,8 @@ final class SyncEngine } // OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' if (e.httpStatusCode == 401) { - log.vlog("Skipping item - OneDrive returned a 'HTTP 401 - Unauthorized' when attempting to query if file exists"); + // "Skipping item - OneDrive returned a 'HTTP 401 - Unauthorized' when attempting to query if file exists" + log.vlog(provideLanguageTranslation(languageIdentifier,313)); uploadFailed = true; return; } @@ -4853,7 +4860,7 @@ final class SyncEngine // "skipped." writeln(provideLanguageTranslation(languageIdentifier,198)); // OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded - log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); + log.vlog(provideLanguageTranslation(languageIdentifier,312)); uploadFailed = true; return; } @@ -4867,7 +4874,7 @@ final class SyncEngine } if (e.httpStatusCode == 504) { // HTTP request returned status code 504 (Gateway Timeout) - log.log("OneDrive returned a 'HTTP 504 - Gateway Timeout' - retrying upload request"); + log.log(provideLanguageTranslation(languageIdentifier,124)); // Retry original request by calling function again to avoid replicating any further error handling uploadNewFile(path); // return back to original call @@ -4907,7 +4914,7 @@ final class SyncEngine // "skipped." writeln(provideLanguageTranslation(languageIdentifier,198)); // OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded - log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); + log.vlog(provideLanguageTranslation(languageIdentifier,312)); uploadFailed = true; return; } @@ -4923,7 +4930,7 @@ final class SyncEngine if (e.httpStatusCode == 504) { // HTTP request returned status code 504 (Gateway Timeout) - log.log("OneDrive returned a 'HTTP 504 - Gateway Timeout' - retrying upload request as a session"); + log.log(provideLanguageTranslation(languageIdentifier,124)); // Try upload as a session try { response = session.upload(path, parent.driveId, parent.id, baseName(path)); @@ -4974,7 +4981,7 @@ final class SyncEngine // caught an error, write out we are skipping this item // "skipped." writeln(provideLanguageTranslation(languageIdentifier,198)); - log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); + log.vlog(provideLanguageTranslation(languageIdentifier,312)); uploadFailed = true; return; } @@ -4988,7 +4995,7 @@ final class SyncEngine } if (e.httpStatusCode == 504) { // HTTP request returned status code 504 (Gateway Timeout) - log.log("OneDrive returned a 'HTTP 504 - Gateway Timeout' - retrying upload request"); + log.log(provideLanguageTranslation(languageIdentifier,124)); // Retry original request by calling function again to avoid replicating any further error handling uploadNewFile(path); // return back to original call @@ -5023,7 +5030,7 @@ final class SyncEngine // caught an error, write out we are skipping this item // "skipped." writeln(provideLanguageTranslation(languageIdentifier,198)); - log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); + log.vlog(provideLanguageTranslation(languageIdentifier,312)); uploadFailed = true; return; } @@ -5037,7 +5044,7 @@ final class SyncEngine } if (e.httpStatusCode == 504) { // HTTP request returned status code 504 (Gateway Timeout) - log.log("OneDrive returned a 'HTTP 504 - Gateway Timeout' - retrying upload request"); + log.log(provideLanguageTranslation(languageIdentifier,124)); // Retry original request by calling function again to avoid replicating any further error handling uploadNewFile(path); // return back to original call @@ -5246,7 +5253,7 @@ final class SyncEngine // caught an error, write out we are skipping this item // "skipped." writeln(provideLanguageTranslation(languageIdentifier,198)); - log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); + log.vlog(provideLanguageTranslation(languageIdentifier,312)); uploadFailed = true; return; } @@ -5263,7 +5270,7 @@ final class SyncEngine if (e.httpStatusCode == 504) { // HTTP request returned status code 504 (Gateway Timeout) - log.log("OneDrive returned a 'HTTP 504 - Gateway Timeout' - retrying upload request as a session"); + log.log(provideLanguageTranslation(languageIdentifier,124)); // Try upload as a session try { response = session.upload(path, parent.driveId, parent.id, baseName(path)); @@ -5320,7 +5327,7 @@ final class SyncEngine // caught an error, write out we are skipping this item // "skipped." writeln(provideLanguageTranslation(languageIdentifier,198)); - log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); + log.vlog(provideLanguageTranslation(languageIdentifier,312)); uploadFailed = true; return; } @@ -5335,7 +5342,7 @@ final class SyncEngine } if (e.httpStatusCode == 504) { // HTTP request returned status code 504 (Gateway Timeout) - log.log("OneDrive returned a 'HTTP 504 - Gateway Timeout' - retrying upload request"); + log.log(provideLanguageTranslation(languageIdentifier,124)); // Retry original request by calling function again to avoid replicating any further error handling uploadNewFile(path); // return back to original call @@ -5412,7 +5419,7 @@ final class SyncEngine // caught an error, write out we are skipping this item // "skipped." writeln(provideLanguageTranslation(languageIdentifier,198)); - log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); + log.vlog(provideLanguageTranslation(languageIdentifier,312)); uploadFailed = true; return; } @@ -5427,7 +5434,7 @@ final class SyncEngine } if (e.httpStatusCode == 504) { // HTTP request returned status code 504 (Gateway Timeout) - log.log("OneDrive returned a 'HTTP 504 - Gateway Timeout' - retrying upload request"); + log.log(provideLanguageTranslation(languageIdentifier,124)); // Retry original request by calling function again to avoid replicating any further error handling uploadNewFile(path); // return back to original call @@ -5601,7 +5608,7 @@ final class SyncEngine // caught an error, write out we are skipping this item // "skipped." writeln(provideLanguageTranslation(languageIdentifier,198)); - log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); + log.vlog(provideLanguageTranslation(languageIdentifier,312)); uploadFailed = true; return response; } else { @@ -5636,7 +5643,7 @@ final class SyncEngine // caught an error, write out we are skipping this item // "skipped." writeln(provideLanguageTranslation(languageIdentifier,198)); - log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error"); + log.vlog(provideLanguageTranslation(languageIdentifier,312)); uploadFailed = true; return response; } else { @@ -5855,7 +5862,8 @@ final class SyncEngine // OneDrive threw a 412 error, most likely: ETag does not match current item's value // Retry without eTag log.vdebug("File Metadata Update Failed - OneDrive eTag / cTag match issue"); - log.vlog("OneDrive returned a 'HTTP 412 - Precondition Failed' when attempting file time stamp update - gracefully handling error"); + // "OneDrive returned a 'HTTP 412 - Precondition Failed' when attempting file time stamp update - gracefully handling error" + log.vlog(provideLanguageTranslation(languageIdentifier,317)); string nullTag = null; response = onedrive.updateById(driveId, id, data, nullTag); } @@ -6034,7 +6042,8 @@ final class SyncEngine // OneDrive threw a 412 error, most likely: ETag does not match current item's value // Retry without eTag log.vdebug("File Move Failed - OneDrive eTag / cTag match issue"); - log.vlog("OneDrive returned a 'HTTP 412 - Precondition Failed' when attempting to move the file - gracefully handling error"); + // "OneDrive returned a 'HTTP 412 - Precondition Failed' when attempting to move the file - gracefully handling error" + log.vlog(provideLanguageTranslation(languageIdentifier,318)); string nullTag = null; // move the file but without the eTag response = onedrive.updateById(fromItem.driveId, fromItem.id, diff, nullTag); @@ -6164,7 +6173,7 @@ final class SyncEngine if ((e.httpStatusCode == 429) || (e.httpStatusCode == 504)) { // re-try the specific changes queries if (e.httpStatusCode == 504) { - log.log("OneDrive returned a 'HTTP 504 - Gateway Timeout' when attempting to query Sharepoint Sites - retrying applicable request"); + log.log(provideLanguageTranslation(languageIdentifier,124)); log.vdebug("siteQuery = onedrive.o365SiteSearch(nextLink) previously threw an error - retrying"); // The server, while acting as a proxy, did not receive a timely response from the upstream server it needed to access in attempting to complete the request. log.vdebug("Thread sleeping for 30 seconds as the server did not receive a timely response from the upstream server it needed to access in attempting to complete the request"); @@ -6348,7 +6357,7 @@ final class SyncEngine if (e.httpStatusCode == 504) { // HTTP request returned status code 504 (Gateway Timeout) - log.log("OneDrive returned a 'HTTP 504 - Gateway Timeout' - retrying request"); + log.log(provideLanguageTranslation(languageIdentifier,124)); // Retry original request by calling function again to avoid replicating any further error handling createShareableLinkForFile(filePath); // return back to original call @@ -6486,7 +6495,7 @@ final class SyncEngine if (e.httpStatusCode == 504) { // HTTP request returned status code 504 (Gateway Timeout) - log.log("OneDrive returned a 'HTTP 504 - Gateway Timeout' - retrying request"); + log.log(provideLanguageTranslation(languageIdentifier,124)); // Retry original request by calling function again to avoid replicating any further error handling queryDriveForChanges(path); // return back to original call @@ -6845,9 +6854,12 @@ final class SyncEngine // HTTP request returned status code 404 (Not Found) if (e.httpStatusCode == 404) { // Stop application - log.log("\n\nOneDrive returned a 'HTTP 404 - Item not found'"); - log.log("The item id to query was not found on OneDrive"); - log.log("\nRemove your '", cfg.databaseFilePath, "' file and try to sync again\n"); + // "OneDrive returned a 'HTTP 404 - Item not found' - gracefully handling error" + log.log(provideLanguageTranslation(languageIdentifier,315)); + // "ERROR: The requested item to query was not found on OneDrive" + log.log(provideLanguageTranslation(languageIdentifier,302)); + // "\nRemove your '", cfg.databaseFilePath, "' file and try to sync again\n" + log.log(provideLanguageTranslation(languageIdentifier,303), cfg.databaseFilePath, provideLanguageTranslation(languageIdentifier,304)); } // HTTP request returned status code 429 (Too Many Requests) @@ -6867,7 +6879,7 @@ final class SyncEngine if ((e.httpStatusCode == 429) || (e.httpStatusCode == 504)) { // re-try the specific changes queries if (e.httpStatusCode == 504) { - log.log("OneDrive returned a 'HTTP 504 - Gateway Timeout' when attempting to query OneDrive drive children - retrying applicable request"); + log.log(provideLanguageTranslation(languageIdentifier,124)); log.vdebug("topLevelChildren = onedrive.listChildren(driveId, idToQuery, nextLink) previously threw an error - retrying"); // The server, while acting as a proxy, did not receive a timely response from the upstream server it needed to access in attempting to complete the request. log.vdebug("Thread sleeping for 30 seconds as the server did not receive a timely response from the upstream server it needed to access in attempting to complete the request"); @@ -6892,7 +6904,8 @@ final class SyncEngine } // process top level children - log.vlog("Adding ", count(topLevelChildren["value"].array), " OneDrive items for processing from OneDrive folder"); + // "Adding ", count(topLevelChildren["value"].array), " OneDrive items for processing from OneDrive folder" + log.vlog(provideLanguageTranslation(languageIdentifier,305), count(topLevelChildren["value"].array), provideLanguageTranslation(languageIdentifier,306)); foreach (child; topLevelChildren["value"].array) { // add this child to the array of objects childrenData ~= child; @@ -6956,9 +6969,12 @@ final class SyncEngine // HTTP request returned status code 404 (Not Found) if (e.httpStatusCode == 404) { // Stop application - log.log("\n\nOneDrive returned a 'HTTP 404 - Item not found'"); - log.log("The item id to query was not found on OneDrive"); - log.log("\nRemove your '", cfg.databaseFilePath, "' file and try to sync again\n"); + // "OneDrive returned a 'HTTP 404 - Item not found' - gracefully handling error" + log.log(provideLanguageTranslation(languageIdentifier,315)); + // "ERROR: The requested item to query was not found on OneDrive" + log.log(provideLanguageTranslation(languageIdentifier,302)); + // "\nRemove your '", cfg.databaseFilePath, "' file and try to sync again\n" + log.log(provideLanguageTranslation(languageIdentifier,303), cfg.databaseFilePath, provideLanguageTranslation(languageIdentifier,304)); } // HTTP request returned status code 429 (Too Many Requests) @@ -6978,7 +6994,7 @@ final class SyncEngine if ((e.httpStatusCode == 429) || (e.httpStatusCode == 504)) { // re-try the specific changes queries if (e.httpStatusCode == 504) { - log.log("OneDrive returned a 'HTTP 504 - Gateway Timeout' when attempting to query OneDrive drive children - retrying applicable request"); + log.log(provideLanguageTranslation(languageIdentifier,124)); log.vdebug("thisLevelChildren = onedrive.listChildren(driveId, idToQuery, nextLink) previously threw an error - retrying"); // The server, while acting as a proxy, did not receive a timely response from the upstream server it needed to access in attempting to complete the request. log.vdebug("Thread sleeping for 30 seconds as the server did not receive a timely response from the upstream server it needed to access in attempting to complete the request"); @@ -7009,7 +7025,8 @@ final class SyncEngine // /Level 1/Level 2/Level 3/Child Shared Folder/some folder/another folder // But 'Child Shared Folder' is what is shared, thus '/Level 1/Level 2/Level 3/' is a potential information leak if logged. // Plus, the application output now shows accuratly what is being shared - so that is a good thing. - log.vlog("Adding ", count(thisLevelChildren["value"].array), " OneDrive items for processing from ", pathForLogging); + // "Adding ", count(thisLevelChildren["value"].array), " OneDrive items for processing from ", pathForLogging + log.vlog(provideLanguageTranslation(languageIdentifier,305), count(thisLevelChildren["value"].array), provideLanguageTranslation(languageIdentifier,307), pathForLogging); } foreach (child; thisLevelChildren["value"].array) { // add this child to the array of objects @@ -7049,13 +7066,15 @@ final class SyncEngine void listOneDriveBusinessSharedFolders() { // List OneDrive Business Shared Folders - log.log("\nListing available OneDrive Business Shared Folders:"); + // "\nListing available OneDrive Business Shared Folders:" + log.log(provideLanguageTranslation(languageIdentifier,308)); // Query the GET /me/drive/sharedWithMe API JSONValue graphQuery = onedrive.getSharedWithMe(); if (graphQuery.type() == JSONType.object) { if (count(graphQuery["value"].array) == 0) { // no shared folders returned - write("\nNo OneDrive Business Shared Folders were returned\n"); + // "\nNo OneDrive Business Shared Folders were returned\n" + log.log(provideLanguageTranslation(languageIdentifier,309)); } else { // shared folders were returned log.vdebug("onedrive.getSharedWithMe API Response: ", graphQuery); @@ -7099,10 +7118,11 @@ final class SyncEngine } } } - write("\n"); + writeln(""); } else { // Log that an invalid JSON object was returned - log.error("ERROR: onedrive.getSharedWithMe call returned an invalid JSON Object"); + // "ERROR: onedrive.getSharedWithMe call returned an invalid JSON Object" + log.error(provideLanguageTranslation(languageIdentifier,310)); } } @@ -7116,7 +7136,8 @@ final class SyncEngine calculatedPath = itemdb.computePath(thisDriveId, thisItemId); } catch (core.exception.AssertError) { // broken tree in the database, we cant compute the path for this item id, exit - log.error("ERROR: A database consistency issue has been caught. A --resync is needed to rebuild the database."); + // "ERROR: A database consistency issue has been caught. A --resync is needed to rebuild the database." + log.error(provideLanguageTranslation(languageIdentifier,311)); // Must exit here to preserve data exit(-1); } diff --git a/src/translations.d b/src/translations.d index 20e70bfe0..4521b40ab 100644 --- a/src/translations.d +++ b/src/translations.d @@ -453,6 +453,24 @@ void initialise_EN_AU(){ JSONValue([ "299": " seconds" ]), JSONValue([ "300": "Adding OneDrive root details for processing" ]), JSONValue([ "301": "Adding OneDrive folder details for processing" ]), + JSONValue([ "302": "ERROR: The requested item to query was not found on OneDrive" ]), + JSONValue([ "303": "\nRemove your '" ]), + JSONValue([ "304": "' file and try to sync again\n" ]), + JSONValue([ "305": "Adding " ]), + JSONValue([ "306": " OneDrive items for processing from OneDrive folder" ]), + JSONValue([ "307": " OneDrive items for processing from " ]), + JSONValue([ "308": "\nListing available OneDrive Business Shared Folders:" ]), + JSONValue([ "309": "\nNo OneDrive Business Shared Folders were returned\n" ]), + JSONValue([ "310": "ERROR: onedrive.getSharedWithMe call returned an invalid JSON Object" ]), + JSONValue([ "311": "ERROR: A database consistency issue has been caught. A --resync is needed to rebuild the database." ]), + JSONValue([ "312": "OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error" ]), + JSONValue([ "313": "Skipping item - OneDrive returned a 'HTTP 401 - Unauthorized' when attempting to query if file exists" ]), + JSONValue([ "314": "OneDrive returned a 'HTTP 404 - Item eTag does not exist' - gracefully handling error" ]), + JSONValue([ "315": "OneDrive returned a 'HTTP 404 - Item not found' - gracefully handling error" ]), + JSONValue([ "316": "OneDrive returned a 'HTTP 412 - Precondition Failed' - gracefully handling error. Will upload as new file." ]), + JSONValue([ "317": "OneDrive returned a 'HTTP 412 - Precondition Failed' when attempting file time stamp update - gracefully handling error" ]), + JSONValue([ "318": "OneDrive returned a 'HTTP 412 - Precondition Failed' when attempting to move the file - gracefully handling error" ]), + JSONValue([ "319": "Skipping item - OneDrive returned a 'HTTP 400 - Bad Request' when attempting to query if file exists" ]), From 74235b7239a08712d0a59f1bc9baa21f923fa781 Mon Sep 17 00:00:00 2001 From: abraunegg Date: Fri, 5 Nov 2021 11:38:12 +1100 Subject: [PATCH 13/15] Update PR Update PR --- src/monitor.d | 42 ++++++++++++++++++++++++++++-------------- src/translations.d | 12 +++++++++++- 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/src/monitor.d b/src/monitor.d index 06aac0d7a..7f2d3a7b1 100644 --- a/src/monitor.d +++ b/src/monitor.d @@ -81,7 +81,8 @@ final class Monitor { // skip non existing/disappeared items if (!exists(dirname)) { - log.vlog("Not adding non-existing/disappeared directory: ", dirname); + // "Directory disappeared during upload: " + log.vlog(provideLanguageTranslation(languageIdentifier,218), dirname); return; } @@ -127,7 +128,8 @@ final class Monitor // Do we need to check for .nosync? Only if check_nosync is true if (check_nosync) { if (exists(buildNormalizedPath(dirname) ~ "/.nosync")) { - log.vlog("Skipping watching path - .nosync found & --check-for-nosync enabled: ", buildNormalizedPath(dirname)); + // "Skipping watching path - .nosync found & --check-for-nosync enabled: " + log.vlog(provideLanguageTranslation(languageIdentifier,320), buildNormalizedPath(dirname)); return; } } @@ -158,10 +160,14 @@ final class Monitor // Need to check for: Failed to stat file in error message if (canFind(e.msg, "Failed to stat file")) { // File system access issue - log.error("ERROR: The local file system returned an error with the following message:"); - log.error(" Error Message: ", e.msg); - log.error("ACCESS ERROR: Please check your UID and GID access to this file, as the permissions on this file is preventing this application to read it"); - log.error("\nFATAL: Exiting application to avoid deleting data due to local file system access issues\n"); + // "ERROR: The local file system returned an error with the following message:" + log.error(provideLanguageTranslation(languageIdentifier,321)); + // " Error Message: " + log.error(provideLanguageTranslation(languageIdentifier,322), e.msg); + // "ACCESS ERROR: Please check your UID and GID access to this file, as the permissions on this file is preventing this application to read it" + log.error(provideLanguageTranslation(languageIdentifier,323)); + // "\nFATAL: Exiting application to avoid deleting data due to local file system access issues\n" + log.error(provideLanguageTranslation(languageIdentifier,324)); // Must exit here exit(-1); } else { @@ -178,10 +184,13 @@ final class Monitor int wd = inotify_add_watch(fd, toStringz(pathname), mask); if (wd < 0) { if (errno() == ENOSPC) { - log.log("The user limit on the total number of inotify watches has been reached."); - log.log("To see the current max number of watches run:"); + // "The user limit on the total number of inotify watches has been reached.\nTo see the current max number of watches run:" + log.log(provideLanguageTranslation(languageIdentifier,325)); + // This line cannot be translated log.log("sysctl fs.inotify.max_user_watches"); - log.log("To change the current max number of watches to 524288 run:"); + // "To change the current max number of watches to 524288 run:" + log.log(provideLanguageTranslation(languageIdentifier,326)); + // This line cannot be translated log.log("sudo sysctl fs.inotify.max_user_watches=524288"); } if (errno() == 13) { @@ -189,12 +198,14 @@ final class Monitor // no misleading output that we could not add a watch due to permission denied return; } else { - log.vlog("WARNING: inotify_add_watch failed - permission denied: ", pathname); + // "WARNING: inotify_add_watch failed - permission denied: " + log.vlog(provideLanguageTranslation(languageIdentifier,327), pathname); return; } } // Flag any other errors - log.error("ERROR: inotify_add_watch failed: ", pathname); + // "ERROR: inotify_add_watch failed: " + log.error(provideLanguageTranslation(languageIdentifier,328), pathname); return; } @@ -211,7 +222,8 @@ final class Monitor return; } // Log that this is directory is being monitored - log.vlog("Monitor directory: ", pathname); + // "Monitoring this directory for local changes: " + log.vlog(provideLanguageTranslation(languageIdentifier,329), pathname); } } @@ -221,7 +233,8 @@ final class Monitor assert(wd in wdToDirName); int ret = inotify_rm_watch(fd, wd); if (ret < 0) throw new MonitorException("inotify_rm_watch failed"); - log.vlog("Monitored directory removed: ", wdToDirName[wd]); + // "Removed this directory from being monitored for local changes: " + log.vlog(provideLanguageTranslation(languageIdentifier,330), wdToDirName[wd]); wdToDirName.remove(wd); } @@ -234,7 +247,8 @@ final class Monitor int ret = inotify_rm_watch(fd, wd); if (ret < 0) throw new MonitorException("inotify_rm_watch failed"); wdToDirName.remove(wd); - log.vlog("Monitored directory removed: ", dirname); + // "Removed this directory from being monitored for local changes: " + log.vlog(provideLanguageTranslation(languageIdentifier,330), dirname); } } } diff --git a/src/translations.d b/src/translations.d index 4521b40ab..e456afa0e 100644 --- a/src/translations.d +++ b/src/translations.d @@ -471,7 +471,17 @@ void initialise_EN_AU(){ JSONValue([ "317": "OneDrive returned a 'HTTP 412 - Precondition Failed' when attempting file time stamp update - gracefully handling error" ]), JSONValue([ "318": "OneDrive returned a 'HTTP 412 - Precondition Failed' when attempting to move the file - gracefully handling error" ]), JSONValue([ "319": "Skipping item - OneDrive returned a 'HTTP 400 - Bad Request' when attempting to query if file exists" ]), - + JSONValue([ "320": "Skipping watching path - .nosync found & --check-for-nosync enabled: " ]), + JSONValue([ "321": "ERROR: The local file system returned an error with the following message:" ]), + JSONValue([ "322": " Error Message: " ]), + JSONValue([ "323": "ACCESS ERROR: Please check your UID and GID access to this file, as the permissions on this file is preventing this application to read it" ]), + JSONValue([ "324": "\nFATAL: Exiting application to avoid deleting data due to local file system access issues\n" ]), + JSONValue([ "325": "The user limit on the total number of inotify watches has been reached.\nTo see the current max number of watches run:" ]), + JSONValue([ "326": "To change the current max number of watches to 524288 run:" ]), + JSONValue([ "327": "WARNING: inotify_add_watch failed - permission denied: " ]), + JSONValue([ "328": "ERROR: inotify_add_watch failed: " ]), + JSONValue([ "329": "Monitoring this directory for local changes: " ]), + JSONValue([ "330": "Removed this directory from being monitored for local changes: " ]), ]); From 820e4b1e3928d848db5174f2c40a9c4e6f319b77 Mon Sep 17 00:00:00 2001 From: abraunegg Date: Fri, 5 Nov 2021 11:44:02 +1100 Subject: [PATCH 14/15] Update PR Update PR --- src/itemdb.d | 6 ++++-- src/translations.d | 4 ++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/itemdb.d b/src/itemdb.d index ce2fd84c5..34e84ab10 100644 --- a/src/itemdb.d +++ b/src/itemdb.d @@ -51,14 +51,16 @@ final class ItemDatabase dbVersion = db.getVersion(); } catch (SqliteException e) { // An error was generated - what was the error? - log.error("\nAn internal database error occurred: " ~ e.msg ~ "\n"); + // "\nAn internal database error occurred: " ~ e.msg ~ "\n" + log.error(provideLanguageTranslation(languageIdentifier,331) ~ e.msg ~ "\n"); exit(-1); } if (dbVersion == 0) { createTable(); } else if (db.getVersion() != itemDatabaseVersion) { - log.log("The item database is incompatible, re-creating database table structures"); + // "The item database is incompatible, re-creating database table structures" + log.log(provideLanguageTranslation(languageIdentifier,332)); db.exec("DROP TABLE item"); createTable(); } diff --git a/src/translations.d b/src/translations.d index e456afa0e..412e58f0a 100644 --- a/src/translations.d +++ b/src/translations.d @@ -482,6 +482,10 @@ void initialise_EN_AU(){ JSONValue([ "328": "ERROR: inotify_add_watch failed: " ]), JSONValue([ "329": "Monitoring this directory for local changes: " ]), JSONValue([ "330": "Removed this directory from being monitored for local changes: " ]), + JSONValue([ "331": "\nAn internal database error occurred: " ]), + JSONValue([ "332": "The item database is incompatible, re-creating database table structures" ]), + JSONValue([ "330": "Removed this directory from being monitored for local changes: " ]), + ]); From 5c04e35a3a693205e53d29064351eccc0f9f5239 Mon Sep 17 00:00:00 2001 From: abraunegg Date: Fri, 5 Nov 2021 19:22:33 +1100 Subject: [PATCH 15/15] Update PR Update PR --- src/config.d | 10 +++++++--- src/itemdb.d | 10 ++++++++-- src/main.d | 21 +++++++++++++++++++-- src/monitor.d | 6 ++++++ src/sqlite.d | 7 +++---- src/sync.d | 4 +++- src/translations.d | 32 ++++++++++++++++++++++++++------ 7 files changed, 72 insertions(+), 18 deletions(-) diff --git a/src/config.d b/src/config.d index 54d5f628e..d04841e88 100644 --- a/src/config.d +++ b/src/config.d @@ -134,7 +134,7 @@ final class Config // display_sync_options = true | false // - It may be desirable to see what options are being passed in to performSync() without enabling the full verbose debug logging boolValues["display_sync_options"] = false; - + // Determine the users home directory. // Need to avoid using ~ here as expandTilde() below does not interpret correctly when running under init.d or systemd scripts // Check for HOME environment variable @@ -304,7 +304,7 @@ final class Config boolValues["synchronize"] = false; boolValues["force"] = false; boolValues["list_business_shared_folders"] = false; - + // Application Startup option validation try { string tmpStr; @@ -465,7 +465,11 @@ final class Config &boolValues["list_business_shared_folders"], "sync-shared-folders", "Sync OneDrive Business Shared Folders", - &boolValues["sync_business_shared_folders"] + &boolValues["sync_business_shared_folders"], + "export-translations", + "Export existing default application messages in JSON format", + &tmpBol + ); if (opt.helpWanted) { outputLongHelp(opt.options); diff --git a/src/itemdb.d b/src/itemdb.d index 34e84ab10..a75b1546d 100644 --- a/src/itemdb.d +++ b/src/itemdb.d @@ -6,6 +6,7 @@ import std.stdio; import std.algorithm.searching; import core.stdc.stdlib; import sqlite; +import translations; static import log; enum ItemType { @@ -42,16 +43,21 @@ final class ItemDatabase string selectItemByIdStmt; string selectItemByParentIdStmt; string deleteItemByIdStmt; - + string languageIdentifier; + this(const(char)[] filename) { + languageIdentifier = getConfigLanguageIdentifier(); + + writeln("itemdb.d languageIdentifier: ", languageIdentifier); + db = Database(filename); int dbVersion; + try { dbVersion = db.getVersion(); } catch (SqliteException e) { // An error was generated - what was the error? - // "\nAn internal database error occurred: " ~ e.msg ~ "\n" log.error(provideLanguageTranslation(languageIdentifier,331) ~ e.msg ~ "\n"); exit(-1); } diff --git a/src/main.d b/src/main.d index 404e21b60..82f8f56b3 100644 --- a/src/main.d +++ b/src/main.d @@ -114,12 +114,16 @@ int main(string[] args) string helpMessage = "Please use 'onedrive --help' for further assistance in regards to running this application"; try { bool printVersion = false; + bool exportTranslations = false; auto opt = getopt( args, std.getopt.config.passThrough, std.getopt.config.bundling, std.getopt.config.caseSensitive, "confdir", "Set the directory used to store the configuration files", &confdirOption, + + "export-translations", "Export existing default application messages in JSON format", &exportTranslations, + "verbose|v+", "Print more details, useful for debugging (repeat for extra debugging)", &log.verbose, "version", "Print the version and exit", &printVersion ); @@ -132,6 +136,17 @@ int main(string[] args) writeln("onedrive ", strip(import("version"))); return EXIT_SUCCESS; } + + // If we are dumping the existing default application messages in JSON format, do so, then exit + if (exportTranslations){ + // EN only message + writeln("Exporting existing application messages in JSON format"); + // Export application default messages + exportDefaultMessages(); + // exit + return EXIT_SUCCESS; + } + } catch (GetOptException e) { // option errors log.error(e.msg); @@ -154,7 +169,7 @@ int main(string[] args) // Error message already printed return EXIT_FAILURE; } - + // --verbose --verbose used .. override any language setting to force EN-AU if (cfg.getValueLong("verbose") >= 2) { log.vdebug("Force application language to EN-AU due to debug operation"); @@ -162,7 +177,9 @@ int main(string[] args) } // Use the configured application language languageIdentifier = cfg.getValueString("language_identifier"); - log.vlog("Application Language set to: ", languageIdentifier); + // Set the language identifier for wider use + setConfigLanguageIdentifier(languageIdentifier); + log.log("Application Language set to: ", languageIdentifier); // set memory display displayMemoryUsage = cfg.getValueBool("display_memory"); diff --git a/src/monitor.d b/src/monitor.d index 7f2d3a7b1..7311b76fb 100644 --- a/src/monitor.d +++ b/src/monitor.d @@ -6,6 +6,7 @@ import core.stdc.stdlib; import config; import selective; import util; +import translations; static import log; // relevant inotify events @@ -21,6 +22,7 @@ class MonitorException: ErrnoException final class Monitor { + // verbosity flag bool verbose; // inotify file descriptor private int fd; @@ -34,6 +36,7 @@ final class Monitor bool skip_symlinks; // check for .nosync if enabled bool check_nosync; + string languageIdentifier; private SelectiveSync selectiveSync; @@ -53,6 +56,9 @@ final class Monitor this.verbose = verbose; this.skip_symlinks = skip_symlinks; this.check_nosync = check_nosync; + this.languageIdentifier = getConfigLanguageIdentifier(); + + writeln("monitor.d languageIdentifier: ", languageIdentifier); assert(onDirCreated && onFileChanged && onDelete && onMove); fd = inotify_init(); diff --git a/src/sqlite.d b/src/sqlite.d index 5e1839ece..da7a340b7 100644 --- a/src/sqlite.d +++ b/src/sqlite.d @@ -54,22 +54,21 @@ struct Database void dump_open_statements() { - log.log("Dumpint open statements: \n"); + writeln("Dumping open SQL statements: \n"); auto p = sqlite3_next_stmt(pDb, null); while (p != null) { - log.log (" - " ~ ifromStringz(sqlite3_sql(p)) ~ "\n"); + writeln(" - " ~ ifromStringz(sqlite3_sql(p)) ~ "\n"); p = sqlite3_next_stmt(pDb, p); } } - void open(const(char)[] filename) { // https://www.sqlite.org/c3ref/open.html int rc = sqlite3_open(toStringz(filename), &pDb); if (rc == SQLITE_CANTOPEN) { // Database cannot be opened - log.error("\nThe database cannot be opened. Please check the permissions of ~/.config/onedrive/items.sqlite3\n"); + log.error("\nThe database cannot be opened. Please check the permissions of " ~ filename ~ "\n"); close(); exit(-1); } diff --git a/src/sync.d b/src/sync.d index e301b5b6c..e479c5963 100644 --- a/src/sync.d +++ b/src/sync.d @@ -296,7 +296,9 @@ final class SyncEngine JSONValue oneDriveRootDetails; // Update language identifier as used with this class - languageIdentifier = cfg.getValueString("language_identifier"); + languageIdentifier = getConfigLanguageIdentifier(); + + writeln("sync.d languageIdentifier: ", languageIdentifier); if (initDone) { return; diff --git a/src/translations.d b/src/translations.d index 412e58f0a..b90906068 100644 --- a/src/translations.d +++ b/src/translations.d @@ -10,14 +10,33 @@ ulong defaultMessageCount = 0; string[] languageResponsesDefault; string[] languageResponsesTranslations; string defaultBadLookupResponse = "ERROR: BAD LOOKUP INDEX FOR LANGUAGE TRANSLATION"; +JSONValue languageListDefault; +string configLanguageIdentifier; // Initialise default message lookup using EN-AU void initialize() { // Initialise default messages - initialise_EN_AU(); + initialise_defaults(); defaultMessageCount = count(languageResponsesDefault); } +void exportDefaultMessages() { + // Initialise default messages + initialise_defaults(); + // Print JSON Array + writeln(languageListDefault); +} + +void setConfigLanguageIdentifier(string languageIdentifier) { + // set the local variable + configLanguageIdentifier = languageIdentifier; +} + +string getConfigLanguageIdentifier() { + // return the current set language identifier as per config or set by user + return configLanguageIdentifier; +} + // Load user configured translation files from a file void initializeUserConfiguredLanguageTranslations(string languageIdentifier) { // Path to translation files @@ -148,10 +167,12 @@ string getResponseFromIndex(int requiredResponseIndex) { } // Load EN-AU application messages -void initialise_EN_AU(){ +void initialise_defaults(){ // The below JSON array contains all the default application messages - JSONValue languageList = [ "language": "EN-AU"]; - languageList.object["list"] = JSONValue([ + // Default Language Type + languageListDefault = [ "language": "EN-AU"]; + // Application Messages + languageListDefault.object["list"] = JSONValue([ JSONValue([ "1": "No user or system config file found, using application defaults" ]), JSONValue([ "2": "System configuration file successfully loaded" ]), JSONValue([ "3": "System configuration file has errors - please check your configuration" ]), @@ -484,7 +505,6 @@ void initialise_EN_AU(){ JSONValue([ "330": "Removed this directory from being monitored for local changes: " ]), JSONValue([ "331": "\nAn internal database error occurred: " ]), JSONValue([ "332": "The item database is incompatible, re-creating database table structures" ]), - JSONValue([ "330": "Removed this directory from being monitored for local changes: " ]), @@ -492,7 +512,7 @@ void initialise_EN_AU(){ // Load the message into the array ulong thisMessageID = 0; - foreach (translationItem; languageList["list"].array) { + foreach (translationItem; languageListDefault["list"].array) { thisMessageID++; string responseString = translationItem[to!string(thisMessageID)].str; languageResponsesDefault ~= responseString;