From: Bruno Haible Date: Wed, 9 Oct 2024 02:06:47 +0000 (+0200) Subject: C#: Add support for dotnet. X-Git-Tag: v0.23~78 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8329be8d9f9e3e9a44a7458983d09e29ce9b6030;p=thirdparty%2Fgettext.git C#: Add support for dotnet. Reported by Michele Locati at . * DEPENDENCIES: Mention dotnet as an alternative to Mono. * NEWS: Mention the change. * PACKAGING: Mention the new file $prefix/lib/gettext/GNU.Gettext.dll. * gettext-runtime/intl-csharp/Makefile.am (pkglibdir): New variable. (CLEANFILES): Add GNU.Gettext.pdb. (install-dll-no, install-dll-yes): Install also into $(pkglibdir). (installdirs-dll, uninstall-dll): Update accordingly. * gettext-runtime/intl-csharp/intl.cs (GettextResourceSet): Add field Table. Override GetEnumerator, GetObject to handle it. Change the Keys method to handle it as well. * gettext-tools/tests/lang-csharp: In the program, on Windows, produce UTF-8 output with Unix end-of-lines and set the culture manually. --- diff --git a/.gitignore b/.gitignore index 04c65990d..a6e84a141 100644 --- a/.gitignore +++ b/.gitignore @@ -693,6 +693,7 @@ autom4te.cache/ /gettext-runtime/intl/libgnuintl.la /gettext-runtime/intl-csharp/GNU.Gettext.dll /gettext-runtime/intl-csharp/GNU.Gettext.dll.mdb +/gettext-runtime/intl-csharp/GNU.Gettext.pdb /gettext-runtime/intl-java/**/*.class /gettext-runtime/intl-java/libintl.jar /gettext-runtime/libasprintf/libasprintf.la diff --git a/DEPENDENCIES b/DEPENDENCIES index bedc4e2d3..02040cc12 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -83,18 +83,28 @@ The following packages should be installed before GNU gettext is installed java-11-openjdk or java-1.8.0-openjdk or java-1.7.0-openjdk. - Other: https://repology.org/project/openjdk/versions -* A C# runtime and compiler (e.g. mono). +* A C# runtime and compiler (e.g. mono or dotnet). + Recommended. Needed for building GNU.Gettext.dll. Also needed for 'msgfmt' and 'msgunfmt', so that they can handle C# resources and assemblies. - + Homepage: - http://www.mono-project.com/ - + Download: - http://www.mono-project.com/download/ - + Pre-built package name: - - On Debian and Debian-based systems: mono-runtime, - - On Red Hat distributions: mono. - - Other: https://repology.org/project/mono/versions + o Mono: + + Homepage: + https://www.mono-project.com/ + + Download: + https://www.mono-project.com/download/ + + Pre-built package name: + - On Debian and Debian-based systems: mono-runtime, + - On Red Hat distributions: mono. + - Other: https://repology.org/project/mono/versions + o dotnet: + + Homepage: + https://dotnet.microsoft.com/ + + Download: + https://dotnet.microsoft.com/en-us/download + + Pre-built package name: + - On Debian and Debian-based systems: dotnet7, dotnet8, + - On Red Hat distributions: dotnet7.0, dotnet8.0. + - Other: https://repology.org/project/dotnet/versions + If more than one C# is installed, pass the option --enable-csharp=IMPL to 'configure', to disambiguate. diff --git a/NEWS b/NEWS index 46e57bee8..dc19a852e 100644 --- a/NEWS +++ b/NEWS @@ -35,8 +35,12 @@ Version 0.23 - October 2024 o xgettext now parses template literals inside JSX correctly. o xgettext has a new option --tag that customizes the behaviour of tagged template literals. - - C#: Strings with embedded expressions (a.k.a. interpolated strings) are now - recognized. + - C#: + o The build system and tools now also support 'dotnet' (.NET) as C# + implementation. In order to declare a preference for 'dotnet' over + 'mono', you can use the configure option '--enable-csharp=dotnet'. + o Strings with embedded expressions (a.k.a. interpolated strings) are now + recognized. - awk: String concatenation by juxtaposition is now recognized. - Smalltalk: The string concatenation operator ',' is now recognized. - Vala: Improved recognition of format strings when the string.printf method diff --git a/PACKAGING b/PACKAGING index 942309c33..849cddaf6 100644 --- a/PACKAGING +++ b/PACKAGING @@ -82,6 +82,7 @@ is according to the following file list. $prefix/share/doc/gettext/javadoc2/* $prefix/lib/GNU.Gettext.dll + $prefix/lib/gettext/GNU.Gettext.dll $prefix/share/doc/gettext/csharpdoc/* $prefix/lib/libasprintf.* diff --git a/gettext-runtime/intl-csharp/Makefile.am b/gettext-runtime/intl-csharp/Makefile.am index 316b27d14..c273e7587 100644 --- a/gettext-runtime/intl-csharp/Makefile.am +++ b/gettext-runtime/intl-csharp/Makefile.am @@ -1,5 +1,5 @@ ## Makefile for the gettext-runtime/intl-csharp subdirectory of GNU gettext -## Copyright (C) 2003-2004, 2006, 2013, 2015, 2018 Free Software Foundation, Inc. +## Copyright (C) 2003-2024 Free Software Foundation, Inc. ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by @@ -25,6 +25,8 @@ RM = rm -f CSHARPCOMP = $(SHELL) ../csharpcomp.sh CSHARPCOMPFLAGS = @CSHARPCOMPFLAGS@ +pkglibdir = $(libdir)/gettext + all-local: all-dll all-doc install-data-local: install-dll install-doc @@ -43,20 +45,29 @@ GNU.Gettext.dll: intl.cs EXTRA_DIST += intl.cs -CLEANFILES += GNU.Gettext.dll GNU.Gettext.dll.mdb +CLEANFILES += GNU.Gettext.dll GNU.Gettext.dll.mdb GNU.Gettext.pdb +# Install GNU.Gettext.dll +# - in $(libdir), as a user-visible package-independent location, +# - in $(pkglibdir), because msgunfmt.net.exe will be installed there +# and its needs all its dependency DLLs in the same directory. install-dll: install-dll-@BUILDCSHARP@ install-dll-no: $(MKDIR_P) $(DESTDIR)$(libdir) + $(MKDIR_P) $(DESTDIR)$(pkglibdir) install-dll-yes: all-dll-yes $(MKDIR_P) $(DESTDIR)$(libdir) + $(MKDIR_P) $(DESTDIR)$(pkglibdir) $(INSTALL_DATA) GNU.Gettext.dll $(DESTDIR)$(libdir)/GNU.Gettext.dll + $(INSTALL_DATA) GNU.Gettext.dll $(DESTDIR)$(pkglibdir)/GNU.Gettext.dll installdirs-dll: $(MKDIR_P) $(DESTDIR)$(libdir) + $(MKDIR_P) $(DESTDIR)$(pkglibdir) uninstall-dll: $(RM) $(DESTDIR)$(libdir)/GNU.Gettext.dll + $(RM) $(DESTDIR)$(pkglibdir)/GNU.Gettext.dll # C# reference documentation. Requires the pnet tools. diff --git a/gettext-runtime/intl-csharp/intl.cs b/gettext-runtime/intl-csharp/intl.cs index e2e6930a7..b93f35448 100644 --- a/gettext-runtime/intl-csharp/intl.cs +++ b/gettext-runtime/intl-csharp/intl.cs @@ -1,5 +1,5 @@ /* GNU gettext for C# - * Copyright (C) 2003-2005, 2007 Free Software Foundation, Inc. + * Copyright (C) 2003-2024 Free Software Foundation, Inc. * Written by Bruno Haible , 2003. * * This program is free software: you can redistribute it and/or modify @@ -45,11 +45,11 @@ * program can be used. */ -using System; /* String, InvalidOperationException, Console */ +using System; /* String, InvalidOperationException, NotSupportedException, Console */ using System.Globalization; /* CultureInfo */ using System.Resources; /* ResourceManager, ResourceSet, IResourceReader */ using System.Reflection; /* Assembly, ConstructorInfo */ -using System.Collections; /* Hashtable, ICollection, IEnumerator, IDictionaryEnumerator */ +using System.Collections; /* Hashtable, ICollection, IEnumerator, IDictionaryEnumerator, ArrayList */ using System.IO; /* Path, FileNotFoundException, Stream */ using System.Text; /* StringBuilder */ @@ -460,6 +460,48 @@ namespace GNU.Gettext { : base (fileName) { } + /// + /// Contains the (key,value) pairs, in instances that override the + /// ReadResources method in a way that fills this table. + /// In other instances of this class, this field is null + /// and the methods from ResourceSet are relevant. + /// + // This property was defined in the superclass in .NET Framework, see + // https://learn.microsoft.com/en-us/dotnet/api/system.resources.resourceset?view=netframework-4.8.1 , + // and in Mono, but has been dropped in .NET Core and .NET + // https://learn.microsoft.com/en-us/dotnet/api/system.resources.resourceset?view=netcore-2.0 . + protected Hashtable /* String -> Object */ Table; + + public override IDictionaryEnumerator GetEnumerator () { + if (Table != null) + // An instance which uses the Table from this class. + return Table.GetEnumerator(); + else + // An instance which behaves like the superclass. + return base.GetEnumerator(); + } + + public override Object GetObject (String msgid) { + if (Table != null) + // An instance which uses the Table from this class. + return Table[msgid]; + else + // An instance which behaves like the superclass. + return base.GetObject(msgid); + } + + public override Object GetObject (String msgid, bool ignoreCase) { + if (Table != null) { + // An instance which uses the Table from this class. + if (ignoreCase) + throw new NotSupportedException("only ignoreCase=false is supported in this subclass"); + else + return Table[msgid]; + } else + // An instance which behaves like the superclass. + return base.GetObject(msgid, ignoreCase); + } + /// /// Returns the translation of . /// @@ -468,7 +510,8 @@ namespace GNU.Gettext { /// the translation of , or null if /// none is found // The default implementation essentially does (String)Table[msgid]. - // Here we also catch the plural form case. + // Here we support using the Table from this class, and also catch the + // plural form case. public override String GetString (String msgid) { Object value = GetObject(msgid); if (value == null || value is String) @@ -490,7 +533,8 @@ namespace GNU.Gettext { /// the translation of , or null if /// none is found // The default implementation essentially does (String)Table[msgid]. - // Here we also catch the plural form case. + // Here we support using the Table from this class, and also catch the + // plural form case. public override String GetString (String msgid, bool ignoreCase) { Object value = GetObject(msgid, ignoreCase); if (value == null || value is String) @@ -535,13 +579,29 @@ namespace GNU.Gettext { return (n == 1 ? 0 : 1); } + // The keys of the (internal) table of the base class. + private ArrayList _baseKeys; + /// /// Returns the keys of this resource set, i.e. the strings for which /// GetObject() can return a non-null value. /// public virtual ICollection Keys { get { - return Table.Keys; + if (Table != null) + // An instance which uses the Table from this class. + return Table.Keys; + else { + // An instance which behaves like the superclass. + if (_baseKeys == null) { + ArrayList keys = new ArrayList(); + for (IDictionaryEnumerator enumerator = base.GetEnumerator(); enumerator.MoveNext(); ) { + keys.Add(enumerator.Key); + } + _baseKeys = keys; + } + return _baseKeys; + } } } diff --git a/gettext-tools/tests/lang-csharp b/gettext-tools/tests/lang-csharp index a365bb6a5..55879abfa 100755 --- a/gettext-tools/tests/lang-csharp +++ b/gettext-tools/tests/lang-csharp @@ -32,17 +32,35 @@ test "${TESTCSHARP}" = yes || { } cat <<\EOF > program.cs -using System; -using GNU.Gettext; +using System; /* Console */ +using System.IO; /* StreamWriter */ +using System.Text; /* UTF8Encoding */ +using System.Runtime.InteropServices; /* RuntimeInformation, OSPlatform */ +using GNU.Gettext; /* GettextResourceManager */ class Program { static void Main (String[] args) { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + // Change the Console to produce UTF-8 output with Unix end-of-lines. + Console.SetOut( + new StreamWriter(Console.OpenStandardOutput(), + new UTF8Encoding(false)) { + NewLine = "\n", + AutoFlush = true + }); + } #if __MonoCS__ - // Some systems don't set CurrentCulture and CurrentUICulture as specified - // by LC_ALL. So set it by hand. - System.Threading.Thread.CurrentThread.CurrentCulture = - System.Threading.Thread.CurrentThread.CurrentUICulture = - new System.Globalization.CultureInfo("fr-FR"); + if (true) + #else + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) #endif + { + // Some systems don't set CurrentCulture and CurrentUICulture as + // specified by LC_ALL. So set it by hand. + System.Threading.Thread.CurrentThread.CurrentCulture = + System.Threading.Thread.CurrentThread.CurrentUICulture = + new System.Globalization.CultureInfo("fr-FR"); + } int n = Int32.Parse(args[0]); GettextResourceManager catalog = new GettextResourceManager("prog"); Console.WriteLine(catalog.GetString("'Your command, please?', asked the waiter."));