From 21e5875f31436dad6a4a3333606bd68bf991c8b0 Mon Sep 17 00:00:00 2001 From: Jan Klass Date: Fri, 22 Dec 2023 15:29:30 +0100 Subject: [PATCH] Replace NGettext dependency The FTP protocol supports translation of response texts (while FTP commands and codes never change). Support for text translations was implemented through ILocalizationFeature and the NGettext dependency and its ICatalog and Catalog types. The NGettext catalog attempts to load translation files - but by default fails as there are no translation files by default. This changeset drops the NGettext dependency in favor of implementing our own interface. The interface surface is reduced by defining only the methods we use. This is a *breaking change* (although with low impact). * Users who previously implemented and registered an ICatalog for custom text translation will have to instead implement ILocalizationCatalog. This is a trivial type reference replacement - the two methods we use are equal on both interfaces. * Users who made use of NGettext library magic translation file loading (I assume it may identify and load files if placed correctly) will need to implement a simple forwarding catalog type. References: * #144 https://github.com/FubarDevelopment/FtpServer/issues/144 * RFC 2640 Internationalization of the File Transfer Protocol * https://github.com/VitaliiTsilnyk/NGettext --- .../Features/ILocalizationFeature.cs | 4 +-- .../Features/Impl/LocalizationFeature.cs | 4 +-- .../FtpConnectionData.cs | 4 +-- .../FubarDev.FtpServer.Abstractions.csproj | 1 - .../Localization/EmptyLocalizationCatalog.cs | 31 +++++++++++++++++++ .../Localization/IFtpCatalogLoader.cs | 6 ++-- .../Localization/ILocalizationCatalog.cs | 20 ++++++++++++ .../Localization/DefaultFtpCatalogLoader.cs | 8 ++--- 8 files changed, 60 insertions(+), 18 deletions(-) create mode 100644 src/FubarDev.FtpServer.Abstractions/Localization/EmptyLocalizationCatalog.cs create mode 100644 src/FubarDev.FtpServer.Abstractions/Localization/ILocalizationCatalog.cs diff --git a/src/FubarDev.FtpServer.Abstractions/Features/ILocalizationFeature.cs b/src/FubarDev.FtpServer.Abstractions/Features/ILocalizationFeature.cs index a3d672eb..efc30fb1 100644 --- a/src/FubarDev.FtpServer.Abstractions/Features/ILocalizationFeature.cs +++ b/src/FubarDev.FtpServer.Abstractions/Features/ILocalizationFeature.cs @@ -4,7 +4,7 @@ using System.Globalization; -using NGettext; +using FubarDev.FtpServer.Localization; namespace FubarDev.FtpServer.Features { @@ -21,6 +21,6 @@ public interface ILocalizationFeature /// /// Gets or sets the catalog to be used by the default FTP server implementation. /// - ICatalog Catalog { get; set; } + ILocalizationCatalog Catalog { get; set; } } } diff --git a/src/FubarDev.FtpServer.Abstractions/Features/Impl/LocalizationFeature.cs b/src/FubarDev.FtpServer.Abstractions/Features/Impl/LocalizationFeature.cs index 91fb1d62..f4902336 100644 --- a/src/FubarDev.FtpServer.Abstractions/Features/Impl/LocalizationFeature.cs +++ b/src/FubarDev.FtpServer.Abstractions/Features/Impl/LocalizationFeature.cs @@ -6,8 +6,6 @@ using FubarDev.FtpServer.Localization; -using NGettext; - namespace FubarDev.FtpServer.Features.Impl { /// @@ -29,6 +27,6 @@ public LocalizationFeature(IFtpCatalogLoader catalogLoader) public CultureInfo Language { get; set; } /// - public ICatalog Catalog { get; set; } + public ILocalizationCatalog Catalog { get; set; } } } diff --git a/src/FubarDev.FtpServer.Abstractions/FtpConnectionData.cs b/src/FubarDev.FtpServer.Abstractions/FtpConnectionData.cs index c1e48ae8..88aac0b6 100644 --- a/src/FubarDev.FtpServer.Abstractions/FtpConnectionData.cs +++ b/src/FubarDev.FtpServer.Abstractions/FtpConnectionData.cs @@ -22,8 +22,6 @@ using Microsoft.AspNetCore.Http.Features; -using NGettext; - namespace FubarDev.FtpServer { /// @@ -144,7 +142,7 @@ public CultureInfo Language /// [Obsolete("Query the information using the ILocalizationFeature instead.")] - public ICatalog Catalog + public ILocalizationCatalog Catalog { get => _featureCollection.Get().Catalog; set => _featureCollection.Get().Catalog = value; diff --git a/src/FubarDev.FtpServer.Abstractions/FubarDev.FtpServer.Abstractions.csproj b/src/FubarDev.FtpServer.Abstractions/FubarDev.FtpServer.Abstractions.csproj index d58c1db1..56df1ab9 100644 --- a/src/FubarDev.FtpServer.Abstractions/FubarDev.FtpServer.Abstractions.csproj +++ b/src/FubarDev.FtpServer.Abstractions/FubarDev.FtpServer.Abstractions.csproj @@ -11,7 +11,6 @@ - diff --git a/src/FubarDev.FtpServer.Abstractions/Localization/EmptyLocalizationCatalog.cs b/src/FubarDev.FtpServer.Abstractions/Localization/EmptyLocalizationCatalog.cs new file mode 100644 index 00000000..52293513 --- /dev/null +++ b/src/FubarDev.FtpServer.Abstractions/Localization/EmptyLocalizationCatalog.cs @@ -0,0 +1,31 @@ +// +// Copyright (c) Jan Klass. All rights reserved. +// + +using System; +using System.Globalization; + +namespace FubarDev.FtpServer.Localization +{ + /// A localization catalog that returns text as-is. + /// + /// The texts in-code are written in English, so the effectively serves as an English catalog by returning texts as-is. + /// The culture formatting for values still applies though. + /// + public class EmptyLocalizationCatalog : ILocalizationCatalog + { + public EmptyLocalizationCatalog(CultureInfo cultureInfo) + { + CultureInfo = cultureInfo ?? throw new ArgumentNullException(nameof(cultureInfo)); + FormatProvider = cultureInfo; + } + + public CultureInfo CultureInfo { get; } + + public IFormatProvider FormatProvider { get; } + + public virtual string GetString(string text) => text; + + public virtual string GetString(string text, params object[] args) => string.Format(FormatProvider, text, args); + } +} diff --git a/src/FubarDev.FtpServer.Abstractions/Localization/IFtpCatalogLoader.cs b/src/FubarDev.FtpServer.Abstractions/Localization/IFtpCatalogLoader.cs index 8e6beb31..bf79dfe0 100644 --- a/src/FubarDev.FtpServer.Abstractions/Localization/IFtpCatalogLoader.cs +++ b/src/FubarDev.FtpServer.Abstractions/Localization/IFtpCatalogLoader.cs @@ -7,8 +7,6 @@ using System.Threading; using System.Threading.Tasks; -using NGettext; - namespace FubarDev.FtpServer.Localization { /// @@ -19,7 +17,7 @@ public interface IFtpCatalogLoader /// /// Gets the catalog for the . /// - ICatalog DefaultCatalog { get; } + ILocalizationCatalog DefaultCatalog { get; } /// /// Gets the default language. @@ -38,6 +36,6 @@ public interface IFtpCatalogLoader /// The language to load the catalog for. /// The cancellation token. /// The loaded catalog. - Task LoadAsync(CultureInfo language, CancellationToken cancellationToken = default); + Task LoadAsync(CultureInfo language, CancellationToken cancellationToken = default); } } diff --git a/src/FubarDev.FtpServer.Abstractions/Localization/ILocalizationCatalog.cs b/src/FubarDev.FtpServer.Abstractions/Localization/ILocalizationCatalog.cs new file mode 100644 index 00000000..668fd41f --- /dev/null +++ b/src/FubarDev.FtpServer.Abstractions/Localization/ILocalizationCatalog.cs @@ -0,0 +1,20 @@ +// +// Copyright (c) Jan Klass. All rights reserved. +// + +namespace FubarDev.FtpServer.Localization +{ + public interface ILocalizationCatalog + { + /// Translate . + /// The text to be translated. + /// The translated text. + string GetString(string text); + + /// Translate with format values . + /// The text to be translated. + /// The format arguments. + /// The translated text. + string GetString(string text, params object[] args); + } +} diff --git a/src/FubarDev.FtpServer/Localization/DefaultFtpCatalogLoader.cs b/src/FubarDev.FtpServer/Localization/DefaultFtpCatalogLoader.cs index 0aea56c1..da81cbd2 100644 --- a/src/FubarDev.FtpServer/Localization/DefaultFtpCatalogLoader.cs +++ b/src/FubarDev.FtpServer/Localization/DefaultFtpCatalogLoader.cs @@ -7,8 +7,6 @@ using System.Threading; using System.Threading.Tasks; -using NGettext; - namespace FubarDev.FtpServer.Localization { /// @@ -19,7 +17,7 @@ public class DefaultFtpCatalogLoader : IFtpCatalogLoader private static readonly CultureInfo _defaultLanguage = new CultureInfo("en"); /// - public ICatalog DefaultCatalog { get; } = new Catalog(_defaultLanguage); + public ILocalizationCatalog DefaultCatalog { get; } = new EmptyLocalizationCatalog(_defaultLanguage); /// public CultureInfo DefaultLanguage { get; } = _defaultLanguage; @@ -34,9 +32,9 @@ public IReadOnlyCollection GetSupportedLanguages() } /// - public Task LoadAsync(CultureInfo language, CancellationToken cancellationToken = default) + public Task LoadAsync(CultureInfo language, CancellationToken cancellationToken = default) { - return Task.FromResult(new Catalog(language)); + return Task.FromResult(new EmptyLocalizationCatalog(language)); } } }