From bbf28aa9c7714e1136ff11d970750d39266f304f Mon Sep 17 00:00:00 2001 From: mtkennerly Date: Fri, 27 May 2022 11:13:17 +0800 Subject: [PATCH] #34: Use Project Fluent for translation and integrate Crowdin --- .gitignore | 1 + CHANGELOG.md | 4 + README.md | 3 + crowdin.yml | 10 + lang/en-US.ftl | 96 ++++++ src/LudusaviPlaynite.cs | 2 +- src/LudusaviPlaynite.csproj | 9 + src/Translator.cs | 614 ++++++++++++++---------------------- tasks.py | 5 + 9 files changed, 372 insertions(+), 372 deletions(-) create mode 100644 crowdin.yml create mode 100644 lang/en-US.ftl diff --git a/.gitignore b/.gitignore index 3eb8b38..5befb1f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ bin/ dist/ obj/ tmp/ +vendor/ *.sln diff --git a/CHANGELOG.md b/CHANGELOG.md index c348200..f40fb1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ ## Unreleased * Changed: + * Localization now uses [Project Fluent](https://projectfluent.org) instead of pure C# code internally. + Although English currently remains the only language supported, this change + should make it easier for other people to contribute. If you'd like to help, + [check out the new Crowdin project](https://crowdin.com/project/ludusavi-playnite). * The `ludusavi-skip` tag is now `[Ludusavi] Skip`. If you were using the old tag, it will be automatically renamed for you. * Added: diff --git a/README.md b/README.md index 6c7b65e..a157216 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,9 @@ is ultimately sourced from [PCGamingWiki](https://www.pcgamingwiki.com/wiki/Home so please contribute any new or fixed data back to the wiki itself, and your improvements will be incorporated into Ludusavi's data as well. +If you'd like to help translate this plugin into other languages, +[check out the Crowdin project](https://crowdin.com/project/ludusavi-playnite). + ## Setup ### Ludusavi Refer to the [Ludusavi project](https://github.com/mtkennerly/ludusavi) diff --git a/crowdin.yml b/crowdin.yml new file mode 100644 index 0000000..32a206a --- /dev/null +++ b/crowdin.yml @@ -0,0 +1,10 @@ +project_id: "518284" +base_path: . +base_url: https://api.crowdin.com + +preserve_hierarchy: true + +files: + - source: /lang/en-US.ftl + translation: /lang/%locale%.ftl + update_option: update_as_unapproved diff --git a/lang/en-US.ftl b/lang/en-US.ftl new file mode 100644 index 0000000..b34d563 --- /dev/null +++ b/lang/en-US.ftl @@ -0,0 +1,96 @@ +ludusavi = Ludusavi +file-filter-executable = Executable + +button-browse = Browse +button-open = Open +button-yes = Yes +button-yes-remembered = Yes, always +button-no = No +button-no-remembered = No, never + +label-launch = Launch + +may-need-custom-entry = {$total-custom -> + [0] {""} + [one] This game requires a matching custom entry in {ludusavi}. + *[other] {$total-custom} games require a matching custom entry in {ludusavi}. +} + +## Backup + +back-up-specific-game = + .confirm = Back up save data for {$game}? {may-need-custom-entry} + .on-success = Backed up saves for {$game} ({$processed-size}) + .on-empty = No save data found to back up for {$game} + .on-failure = Backed up saves for {$game} ({$processed-size} of {$total-size}), but some saves failed + +# Defers to `back-up-specific-game.*`. +back-up-last-game = Back up save data for last game played + +# Defers to `back-up-specific-game.*` for each game individually. +# In `.confirm`, there will always be more than one game. +back-up-selected-games = Back up save data for selected games + .confirm = Back up save data for {$total-games} selected games? {may-need-custom-entry} + +back-up-all-games = Back up save data for all games + .confirm = Back up save data for all games that Ludusavi can find? + .on-success = Backed up saves for {$processed-games} games ({$processed-size}); click for full list + .on-failure = Backed up saves for {$processed-games} of {$total-games} games ({$processed-size} of {$total-size}), but some failed; click for full list + +## Restore + +restore-specific-game = + .confirm = Restore save data for {$game}? {may-need-custom-entry} + .on-success = Restored saves for {$game} ({$processed-size}) + .on-empty = No save data found to restore for {$game} + .on-failure = Restored saves for {$game} ({$processed-size} of {$total-size}), but some saves failed + +# Defers to `restore-specific-game.*`. +restore-last-game = Restore save data for last game played + +# Defers to `restore-specific-game.*` for each game individually. +# In `.confirm`, there will always be more than one game. +restore-selected-games = Restore save data for selected games + .confirm = Restore save data for {$total-games} selected games? {may-need-custom-entry} + +restore-all-games = Restore save data for all games + .confirm = Restore save data for all games that Ludusavi can find? + .on-success = Restored saves for {$processed-games} games ({$processed-size}); click for full list + .on-failure = Restored saves for {$processed-games} of {$total-games} games ({$processed-size} of {$total-size}), but some failed; click for full list + +## Tags + +add-tag-for-selected-games = Tag: "{$tag}" - Add for selected games + .confirm = Add "{$tag}" tag for {$total-games} selected games and remove any conflicting tags? + +remove-tag-for-selected-games = Tag: "{$tag}" - Remove for selected games + .confirm = Remove "{$tag}" tag for {$total-games} selected games and remove any conflicting tags? + +## Generic errors + +operation-still-pending = {ludusavi} is still working on a previous request. Please try again when you see the notification that it's done. +no-game-played-yet = You haven't played anything yet in this session. +unable-to-run-ludusavi = Unable to run {ludusavi}. + +## Full backup/restore error reporting + +full-list-game-line-item = {$status -> + [failed] [FAILED] {$game} ({$size}) + [ignored] [IGNORED] {$game} ({$size}) + *[success] {$game} ({$size}) +} + +## Settings + +config-executable-path = Name or full path of the Ludusavi executable: +config-backup-path = Full path to directory for storing backups: +config-do-backup-on-game-stopped = Back up save data for a game after playing it +config-do-restore-on-game-starting = Also restore save data for a game before playing it +config-ask-backup-on-game-stopped = Ask first instead of doing it automatically +config-only-backup-on-game-stopped-if-pc = Only do this for PC games +config-add-suffix-for-non-pc-game-names = Look up non-PC games by adding this suffix to their names (requires custom entry): +config-retry-non-pc-games-without-suffix = If not found with the suffix, then try again without it +config-do-platform-backup-on-non-pc-game-stopped = Back up save data by platform name after playing non-PC games (requires custom entry) +config-do-platform-restore-on-non-pc-game-starting = Also restore save data by platform name before playing non-PC games +config-ask-platform-backup-on-non-pc-game-stopped = Ask first instead of doing it automatically +config-ignore-benign-notifications = Only show notifications on failure diff --git a/src/LudusaviPlaynite.cs b/src/LudusaviPlaynite.cs index 2fdd489..d437955 100644 --- a/src/LudusaviPlaynite.cs +++ b/src/LudusaviPlaynite.cs @@ -64,7 +64,7 @@ public class LudusaviPlaynite : GenericPlugin public LudusaviPlaynite(IPlayniteAPI api) : base(api) { - translator = new Translator(DetermineLanguage()); + translator = new Translator(PlayniteApi.ApplicationSettings.Language); settings = new LudusaviPlayniteSettings(this, translator); Properties = new GenericPluginProperties { diff --git a/src/LudusaviPlaynite.csproj b/src/LudusaviPlaynite.csproj index 654e031..9d6ceb1 100644 --- a/src/LudusaviPlaynite.csproj +++ b/src/LudusaviPlaynite.csproj @@ -27,4 +27,13 @@ + + + + + + + + + diff --git a/src/Translator.cs b/src/Translator.cs index fccdbfe..96f9f46 100644 --- a/src/Translator.cs +++ b/src/Translator.cs @@ -1,167 +1,170 @@ using ByteSizeLib; +using Linguini.Bundle; +using Linguini.Bundle.Builder; +using Linguini.Shared.Types.Bundle; using Playnite.SDK.Models; using System; using System.Collections.Generic; +using System.Globalization; +using System.IO; using System.Linq; +using System.Reflection; namespace LudusaviPlaynite { + using FluentArgs = Dictionary; + public class Translator { - private Language language; + readonly static string GAME = "game"; + readonly static string PROCESSED_GAMES = "processed-games"; + readonly static string PROCESSED_SIZE = "processed-size"; + readonly static string TOTAL_CUSTOM = "total-custom"; + readonly static string TOTAL_GAMES = "total-games"; + readonly static string TOTAL_SIZE = "total-size"; + readonly static string SIZE = "size"; + readonly static string STATUS = "status"; + readonly static string TAG = "tag"; + + private FluentBundle bundle; - public Translator(Language language) + public Translator(string language) { - this.language = language; + SetLanguage(language); } - public string Ludusavi() + private FluentBundle MakeBundle(string language) + { + return LinguiniBuilder.Builder() + .CultureInfo(new CultureInfo(language)) + .AddResource(ReadFtl(language)) + .SetUseIsolating(false) + .UncheckedBuild(); + } + + private string ReadFtl(string language) { - switch (language) + var assembly = Assembly.GetExecutingAssembly(); + using (var stream = assembly.GetManifestResourceStream("LudusaviPlaynite." + language.Replace("_", "-") + ".ftl")) { - default: - return "Ludusavi"; + using (var reader = new StreamReader(stream)) + { + return reader.ReadToEnd(); + } } } - public string AdjustedSize(ulong bytes) + private void SetLanguage(string language) { - switch (language) + this.bundle = MakeBundle("en-US"); + + string target; + try + { + target = ReadFtl(language); + } + catch { - default: - return ByteSize.FromBytes(bytes).ToBinaryString(); + // No translation for this language. + return; } + this.bundle.AddResourceOverriding(target); + } + + private int TotalCustom(bool needsCustomEntry) + { + return needsCustomEntry ? 1 : 0; + } + + private int TotalCustom(List<(string, bool)> games) + { + return games.Where(x => x.Item2).Count(); + } + + private string Translate(string id, FluentArgs args = null) + { + return this.bundle.GetAttrMessage(id, args); + } + + public string Ludusavi() + { + return Translate("ludusavi"); + } + + public string AdjustedSize(ulong bytes) + { + return ByteSize.FromBytes(bytes).ToBinaryString(); } public string SelectFileExecutableFilter() { - switch (language) - { - default: - return "Executable|*.exe"; - } + return Translate("file-filter-executable") + "|*.exe"; } public string BrowseButton() { - switch (language) - { - default: - return "Browse"; - } + return Translate("button-browse"); } public string OpenButton() { - switch (language) - { - default: - return "Open"; - } + return Translate("button-open"); } public string YesButton() { - switch (language) - { - default: - return "Yes"; - } + return Translate("button-yes"); } public string YesRememberedButton() { - switch (language) - { - default: - return "Yes, always"; - } + return Translate("button-yes-remembered"); } public string NoButton() { - switch (language) - { - default: - return "No"; - } + return Translate("button-no"); } public string NoRememberedButton() { - switch (language) - { - default: - return "No, never"; - } + return Translate("button-no-remembered"); } public string Launch_Label() { - switch (language) - { - default: - return "Launch"; - } + return Translate("label-launch"); } public string BackUpLastGame_Label() { - switch (language) - { - default: - return "Back up save data for last game played"; - } - } - - string GetCustomNoteForSingleGame(bool needsCustomEntry) - { - if (needsCustomEntry) - { - switch (language) - { - default: - return " This requires a matching custom entry in Ludusavi."; - } - } - return ""; + return Translate("back-up-last-game"); } public string BackUpOneGame_Confirm(string gameName, bool needsCustomEntry) { - var customNote = GetCustomNoteForSingleGame(needsCustomEntry); - switch (language) - { - default: - return string.Format("Back up save data for {0}?{1}", gameName, customNote); - } + return Translate( + "back-up-specific-game.confirm", + new FluentArgs() { + {GAME, (FluentString)gameName}, + {TOTAL_CUSTOM, (FluentNumber)TotalCustom(needsCustomEntry)}, + } + ); } public string BackUpAllGames_Label() { - switch (language) - { - default: - return "Back up save data for all games"; - } + return Translate("back-up-all-games"); } public string BackUpAllGames_Confirm() { - switch (language) - { - default: - return "Back up save data for all games that Ludusavi can find?"; - } + return Translate("back-up-all-games.confirm"); } public string BackUpSelectedGames_Label() { - switch (language) - { - default: - return "Back up save data for selected games"; - } + return Translate("back-up-selected-games"); } string GetSelectionFormattedNames(IEnumerable games) @@ -173,19 +176,6 @@ string GetSelectionFormattedNames(IEnumerable games) return ""; } - string GetSelectionCustomNote(List<(string, bool)> games) - { - if (games.Any(x => x.Item2)) - { - switch (language) - { - default: - return " Some games require a matching custom entry in Ludusavi."; - } - } - return ""; - } - // games: (name, requiresCustomEntry) public string BackUpSelectedGames_Confirm(List<(string, bool)> games) { @@ -196,59 +186,45 @@ public string BackUpSelectedGames_Confirm(List<(string, bool)> games) } var formattedNames = GetSelectionFormattedNames(games.Select(x => x.Item1)); - var customNote = GetSelectionCustomNote(games); - switch (language) - { - default: - return string.Format("Back up save data for {0} selected games?{1}{2}", count, customNote, formattedNames); - } + return Translate( + "back-up-selected-games.confirm", + new FluentArgs() { + {TOTAL_GAMES, (FluentNumber)count}, + {TOTAL_CUSTOM, (FluentNumber)TotalCustom(games)}, + } + ) + formattedNames; } public string RestoreLastGame_Label() { - switch (language) - { - default: - return "Restore save data for last game played"; - } + return Translate("restore-last-game"); } public string RestoreOneGame_Confirm(string gameName, bool needsCustomEntry) { - var customNote = GetCustomNoteForSingleGame(needsCustomEntry); - switch (language) - { - default: - return string.Format("Restore save data for {0}?{1}", gameName, customNote); - } + return Translate( + "restore-specific-game.confirm", + new FluentArgs() { + {GAME, (FluentString)gameName}, + {TOTAL_CUSTOM, (FluentNumber)TotalCustom(needsCustomEntry)}, + } + ); } public string RestoreAllGames_Label() { - switch (language) - { - default: - return "Restore save data for all games"; - } + return Translate("restore-all-games"); } public string RestoreAllGames_Confirm() { - switch (language) - { - default: - return "Restore save data for all games that Ludusavi can find?"; - } + return Translate("restore-all-games.confirm"); } public string RestoreSelectedGames_Label() { - switch (language) - { - default: - return "Restore save data for selected games"; - } + return Translate("restore-selected-games"); } // games: (name, requiresCustomEntry) @@ -261,366 +237,262 @@ public string RestoreSelectedGames_Confirm(List<(string, bool)> games) } var formattedNames = GetSelectionFormattedNames(games.Select(x => x.Item1)); - var customNote = GetSelectionCustomNote(games); - - switch (language) - { - default: - return string.Format("Restore save data for {0} selected games?{1}{2}", count, customNote, formattedNames); - } + return Translate( + "restore-selected-games.confirm", + new FluentArgs() { + {TOTAL_GAMES, (FluentNumber)count}, + {TOTAL_CUSTOM, (FluentNumber)TotalCustom(games)}, + } + ) + formattedNames; } public string AddTagForSelectedGames_Label(string tag) { - switch (language) - { - default: - return string.Format("Tag: '{0}' - Add for selected games", tag); - } + return Translate( + "add-tag-for-selected-games", + new FluentArgs() { + {TAG, (FluentString)tag}, + } + ); } public string AddTagForSelectedGames_Confirm(string tag, IEnumerable games) { - var count = games.Count(); var formattedNames = GetSelectionFormattedNames(games); - - switch (language) - { - default: - return string.Format("Add '{0}' tag for {1} selected games and remove any conflicting tags?{2}", tag, count, formattedNames); - } + return Translate( + "add-tag-for-selected-games.confirm", + new FluentArgs() { + {TAG, (FluentString)tag}, + {TOTAL_GAMES, (FluentNumber)games.Count()}, + } + ) + formattedNames; } public string RemoveTagForSelectedGames_Label(string tag) { - switch (language) - { - default: - return string.Format("Tag: '{0}' - Remove for selected games", tag); - } + return Translate( + "remove-tag-for-selected-games", + new FluentArgs() { + {TAG, (FluentString)tag}, + } + ); } public string RemoveTagForSelectedGames_Confirm(string tag, IEnumerable games) { - var count = games.Count(); var formattedNames = GetSelectionFormattedNames(games); - - switch (language) - { - default: - return string.Format("Remove '{0}' tag for {1} selected games?{2}", tag, count, formattedNames); - } + return Translate( + "remove-tag-for-selected-games.confirm", + new FluentArgs() { + {TAG, (FluentString)tag}, + {TOTAL_GAMES, (FluentNumber)games.Count()}, + } + ) + formattedNames; } - public string OperationStillPending() { - switch (language) - { - default: - return "Ludusavi is still working on a previous request. Please try again when you see the notification that it's done."; - } + return Translate("operation-still-pending"); } public string NoGamePlayedYet() { - switch (language) - { - default: - return "You haven't played anything yet in this session."; - } + return Translate("no-game-played-yet"); } public string UnableToRunLudusavi() { - switch (language) - { - default: - return "Unable to run Ludusavi."; - } + return Translate("unable-to-run-ludusavi"); } public string BackUpOneGame_Success(OperationResult result) { - switch (language) - { - default: - return string.Format( - "Backed up saves for {0} ({1})", - result.Name, - AdjustedSize(result.Response.Overall.ProcessedBytes) - ); - } + return Translate( + "back-up-specific-game.on-success", + new FluentArgs() { + {GAME, (FluentString)result.Name}, + {PROCESSED_SIZE, (FluentString)AdjustedSize(result.Response.Overall.ProcessedBytes)}, + } + ); } public string BackUpOneGame_Empty(OperationResult result) { - switch (language) - { - default: - return string.Format( - "No save data found to back up for {0}", - result.Name - ); - } + return Translate( + "back-up-specific-game.on-empty", + new FluentArgs() { + {GAME, (FluentString)result.Name}, + } + ); } public string BackUpOneGame_Failure(OperationResult result) { - switch (language) - { - default: - return string.Format( - "Backed up saves for {0} ({1} of {2}), but some saves failed", - result.Name, - AdjustedSize(result.Response.Overall.ProcessedBytes), - AdjustedSize(result.Response.Overall.TotalBytes) - ); - } + return Translate( + "back-up-specific-game.on-failure", + new FluentArgs() { + {GAME, (FluentString)result.Name}, + {PROCESSED_SIZE, (FluentString)AdjustedSize(result.Response.Overall.ProcessedBytes)}, + {TOTAL_SIZE, (FluentString)AdjustedSize(result.Response.Overall.TotalBytes)}, + } + ); } public string BackUpAllGames_Success(OperationResult result) { - switch (language) - { - default: - return string.Format( - "Backed up saves for {0} games ({1}); click for full list", - result.Response.Overall.ProcessedGames, - AdjustedSize(result.Response.Overall.ProcessedBytes) - ); - } + return Translate( + "back-up-all-games.on-success", + new FluentArgs() { + {PROCESSED_GAMES, (FluentNumber)result.Response.Overall.ProcessedGames}, + {PROCESSED_SIZE, (FluentString)AdjustedSize(result.Response.Overall.ProcessedBytes)}, + } + ); } public string BackUpAllGames_Failure(OperationResult result) { - switch (language) - { - default: - return string.Format( - "Backed up saves for {0} of {1} games ({2} of {3}), but some failed; click for full list", - result.Response.Overall.ProcessedGames, - result.Response.Overall.TotalGames, - AdjustedSize(result.Response.Overall.ProcessedBytes), - AdjustedSize(result.Response.Overall.TotalBytes) - ); - } + return Translate( + "back-up-all-games.on-failure", + new FluentArgs() { + {PROCESSED_GAMES, (FluentNumber)result.Response.Overall.ProcessedGames}, + {TOTAL_GAMES, (FluentNumber)result.Response.Overall.TotalGames}, + {PROCESSED_SIZE, (FluentString)AdjustedSize(result.Response.Overall.ProcessedBytes)}, + {TOTAL_SIZE, (FluentString)AdjustedSize(result.Response.Overall.TotalBytes)}, + } + ); } public string RestoreOneGame_Success(OperationResult result) { - switch (language) - { - default: - return string.Format( - "Restored saves for {0} ({1})", - result.Name, - AdjustedSize(result.Response.Overall.ProcessedBytes) - ); - } + return Translate( + "restore-specific-game.on-success", + new FluentArgs() { + {GAME, (FluentString)result.Name}, + {PROCESSED_SIZE, (FluentString)AdjustedSize(result.Response.Overall.ProcessedBytes)} + } + ); } public string RestoreOneGame_Empty(OperationResult result) { - switch (language) - { - default: - return string.Format( - "No save data found to restore for {0}", - result.Name - ); - } + return Translate( + "restore-specific-game.on-empty", + new FluentArgs() { + {GAME, (FluentString)result.Name}, + } + ); } public string RestoreOneGame_Failure(OperationResult result) { - switch (language) - { - default: - return string.Format( - "Restored saves for {0} ({1} of {2}), but some saves failed", - result.Name, - AdjustedSize(result.Response.Overall.ProcessedBytes), - AdjustedSize(result.Response.Overall.TotalBytes) - ); - } + return Translate( + "restore-specific-game.on-failure", + new FluentArgs() { + {GAME, (FluentString)result.Name}, + {PROCESSED_SIZE, (FluentString)AdjustedSize(result.Response.Overall.ProcessedBytes)}, + {TOTAL_SIZE, (FluentString)AdjustedSize(result.Response.Overall.TotalBytes)}, + } + ); } public string RestoreAllGames_Success(OperationResult result) { - switch (language) - { - default: - return string.Format( - "Restored saves for {0} games ({1}); click for full list", - result.Response.Overall.ProcessedGames, - AdjustedSize(result.Response.Overall.ProcessedBytes) - ); - } + return Translate( + "restore-all-games.on-success", + new FluentArgs() { + {PROCESSED_GAMES, (FluentNumber)result.Response.Overall.ProcessedGames}, + {PROCESSED_SIZE, (FluentString)AdjustedSize(result.Response.Overall.ProcessedBytes)}, + } + ); } public string RestoreAllGames_Failure(OperationResult result) { - switch (language) - { - default: - return string.Format( - "Restored saves for {0} of {1} games ({2} of {3}), but some failed; click for full list", - result.Response.Overall.ProcessedGames, - result.Response.Overall.TotalGames, - AdjustedSize(result.Response.Overall.ProcessedBytes), - AdjustedSize(result.Response.Overall.TotalBytes) - ); - } - } - - public string FullListGameLineItem_Failed() - { - switch (language) - { - default: - return "FAILED"; - } - } - - public string FullListGameLineItem_Ignored() - { - switch (language) - { - default: - return "IGNORED"; - } + return Translate( + "restore-all-games.on-failure", + new FluentArgs() { + {PROCESSED_GAMES, (FluentNumber)result.Response.Overall.ProcessedGames}, + {TOTAL_GAMES, (FluentNumber)result.Response.Overall.TotalGames}, + {PROCESSED_SIZE, (FluentString)AdjustedSize(result.Response.Overall.ProcessedBytes)}, + {TOTAL_SIZE, (FluentString)AdjustedSize(result.Response.Overall.TotalBytes)}, + } + ); } public string FullListGameLineItem(string name, ApiGame game) { var size = AdjustedSize(Convert.ToUInt64(game.Files.Sum(x => Convert.ToDecimal(x.Value.Bytes)))); var failed = game.Files.Any(x => x.Value.Failed) || game.Registry.Any(x => x.Value.Failed); - - switch (language) - { - default: - if (failed) - { - return string.Format("[{0}] {1} ({2})", FullListGameLineItem_Failed(), name, size); - } - else if (game.Decision == "Ignored") - { - return string.Format("[{0}] {1} ({2})", FullListGameLineItem_Ignored(), name, size); - } - else - { - return string.Format("{0} ({1})", name, size); - } - } + var status = failed ? "failed" : (game.Decision == "Ignored" ? "ignored" : "success"); + + return Translate( + "full-list-game-line-item", + new FluentArgs() { + {STATUS, (FluentString)status}, + {GAME, (FluentString)name}, + {SIZE, (FluentString)size}, + } + ); } public string ExecutablePath_Label() { - switch (language) - { - default: - return "Name or full path of the Ludusavi executable:"; - } + return Translate("config-executable-path"); } public string BackupPath_Label() { - switch (language) - { - default: - return "Full path to directory for storing backups:"; - } + return Translate("config-backup-path"); } public string DoBackupOnGameStopped_Label() { - switch (language) - { - default: - return "Back up save data for a game after playing it"; - } + return Translate("config-do-backup-on-game-stopped"); } public string DoRestoreOnGameStarting_Label() { - switch (language) - { - default: - return "Also restore save data for a game before playing it"; - } + return Translate("config-do-restore-on-game-starting"); } public string AskBackupOnGameStopped_Label() { - switch (language) - { - default: - return "Ask first instead of doing it automatically"; - } + return Translate("config-ask-backup-on-game-stopped"); } public string OnlyBackupOnGameStoppedIfPc_Label() { - switch (language) - { - default: - return "Only do this for PC games"; - } + return Translate("config-only-backup-on-game-stopped-if-pc"); } public string AddSuffixForNonPcGameNames_Label() { - switch (language) - { - default: - return "Look up non-PC games by adding this suffix to their names (requires custom entry):"; - } + return Translate("config-add-suffix-for-non-pc-game-names"); } public string RetryNonPcGamesWithoutSuffix_Label() { - switch (language) - { - default: - return "If not found with the suffix, then try again without it"; - } + return Translate("config-retry-non-pc-games-without-suffix"); } public string DoPlatformBackupOnNonPcGameStopped_Label() { - switch (language) - { - default: - return "Back up save data by platform name after playing non-PC games (requires custom entry)"; - } + return Translate("config-do-platform-backup-on-non-pc-game-stopped"); } public string DoPlatformRestoreOnNonPcGameStarting_Label() { - switch (language) - { - default: - return "Also restore save data by platform name before playing non-PC games"; - } + return Translate("config-do-platform-restore-on-non-pc-game-starting"); } public string AskPlatformBackupOnNonPcGameStopped_Label() { - switch (language) - { - default: - return "Ask first instead of doing it automatically"; - } + return Translate("config-ask-platform-backup-on-non-pc-game-stopped"); } public string IgnoreBenignNotifications_Label() { - switch (language) - { - default: - return "Only show notifications on failure"; - } + return Translate("config-ignore-benign-notifications"); } } } diff --git a/tasks.py b/tasks.py index a94b6aa..253358e 100644 --- a/tasks.py +++ b/tasks.py @@ -16,6 +16,11 @@ def get_version(): @task def build(ctx): + if not (REPO / "vendor" / "Linguini").exists(): + ctx.run("git clone git@github.com:Ygg01/Linguini.git vendor/Linguini") + with ctx.cd("vendor/Linguini"): + ctx.run("git checkout 9a7939b00c3ca68df19b45afc0e39bad05c0b483") + ctx.run("dotnet build src -c Release")