Skip to content

Commit 37ada11

Browse files
Move unit abbreviation strings into culture-specific resource files (#1210)
Fixes #1126 Refs #1238 A quick draft to move the unit abbreviations into resource files. I also want to move methods for getting culture-specific abbreviations to the individual quantities. This should: - Reduce initialization time by removing the MapGeneratedLocalizations methods (TODO) - Reduce in-memory footprint by only loading a requested culture - Allow formatting to use methods on the quantities themselves - Which should allow for better extensibility as well - Remove the unit abbreviations cache (deprecate) ### TODOs - [ ] Test fallback to invariant culture `export DOTNET_SYSTEM_GLOBALIZATION_INVARIANT='1'` #1238 --------- Co-authored-by: Andreas Gullberg Larsen <[email protected]>
1 parent 4a02911 commit 37ada11

File tree

282 files changed

+3901
-4652
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

282 files changed

+3901
-4652
lines changed

CodeGen/Generators/UnitsNetGen/QuantityGenerator.cs

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ private void GenerateStaticConstructor()
135135
if (baseUnits == null)
136136
{
137137
Writer.WL($@"
138-
new UnitInfo<{_unitEnumName}>({_unitEnumName}.{unit.SingularName}, ""{unit.PluralName}"", BaseUnits.Undefined),");
138+
new UnitInfo<{_unitEnumName}>({_unitEnumName}.{unit.SingularName}, ""{unit.PluralName}"", BaseUnits.Undefined, ""{_quantity.Name}""),");
139139
}
140140
else
141141
{
@@ -152,7 +152,7 @@ private void GenerateStaticConstructor()
152152
}.Where(str => str != null));
153153

154154
Writer.WL($@"
155-
new UnitInfo<{_unitEnumName}>({_unitEnumName}.{unit.SingularName}, ""{unit.PluralName}"", new BaseUnits({baseUnitsCtorArgs})),");
155+
new UnitInfo<{_unitEnumName}>({_unitEnumName}.{unit.SingularName}, ""{unit.PluralName}"", new BaseUnits({baseUnitsCtorArgs}), ""{_quantity.Name}""),");
156156
}
157157
}
158158

@@ -359,25 +359,6 @@ internal static void RegisterDefaultConversions(UnitConverter unitConverter)
359359
Writer.WL($@"
360360
}}
361361
362-
internal static void MapGeneratedLocalizations(UnitAbbreviationsCache unitAbbreviationsCache)
363-
{{");
364-
foreach(Unit unit in _quantity.Units)
365-
{
366-
foreach(Localization localization in unit.Localization)
367-
{
368-
// All units must have a unit abbreviation, so fallback to "" for units with no abbreviations defined in JSON
369-
var abbreviationParams = localization.Abbreviations.Any() ?
370-
string.Join(", ", localization.Abbreviations.Select(abbr => $@"""{abbr}""")) :
371-
$@"""""";
372-
373-
Writer.WL($@"
374-
unitAbbreviationsCache.PerformAbbreviationMapping({_unitEnumName}.{unit.SingularName}, new CultureInfo(""{localization.Culture}""), false, {unit.AllowAbbreviationLookup.ToString().ToLower()}, new string[]{{{abbreviationParams}}});");
375-
}
376-
}
377-
378-
Writer.WL($@"
379-
}}
380-
381362
/// <summary>
382363
/// Get unit abbreviation string.
383364
/// </summary>

CodeGen/Generators/UnitsNetGen/StaticQuantityGenerator.cs

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ namespace UnitsNet
3030
/// <summary>
3131
/// Dynamically parse or construct quantities when types are only known at runtime.
3232
/// </summary>
33-
public static partial class Quantity
33+
public partial class Quantity
3434
{
3535
/// <summary>
3636
/// All QuantityInfo instances mapped by quantity name that are present in UnitsNet by default.
@@ -63,7 +63,7 @@ public static IQuantity FromQuantityInfo(QuantityInfo quantityInfo, QuantityValu
6363
Writer.WL(@"
6464
_ => throw new ArgumentException($""{quantityInfo.Name} is not a supported quantity."")
6565
};
66-
}
66+
}
6767
6868
/// <summary>
6969
/// Try to dynamically construct a quantity.
@@ -74,26 +74,22 @@ public static IQuantity FromQuantityInfo(QuantityInfo quantityInfo, QuantityValu
7474
/// <returns><c>True</c> if successful with <paramref name=""quantity""/> assigned the value, otherwise <c>false</c>.</returns>
7575
public static bool TryFrom(QuantityValue value, Enum? unit, [NotNullWhen(true)] out IQuantity? quantity)
7676
{
77-
switch (unit)
77+
quantity = unit switch
7878
{");
7979
foreach (var quantity in _quantities)
8080
{
8181
var quantityName = quantity.Name;
8282
var unitTypeName = $"{quantityName}Unit";
8383
var unitValue = unitTypeName.ToCamelCase();
8484
Writer.WL($@"
85-
case {unitTypeName} {unitValue}:
86-
quantity = {quantityName}.From(value, {unitValue});
87-
return true;");
85+
{unitTypeName} {unitValue} => {quantityName}.From(value, {unitValue}),");
8886
}
8987

9088
Writer.WL(@"
91-
default:
92-
{
93-
quantity = default(IQuantity);
94-
return false;
95-
}
96-
}
89+
_ => null
90+
};
91+
92+
return quantity is not null;
9793
}
9894
9995
/// <summary>
@@ -125,7 +121,7 @@ public static bool TryParse(IFormatProvider? formatProvider, Type quantityType,
125121
Writer.WL(@"
126122
_ => false
127123
};
128-
}
124+
}
129125
130126
internal static IEnumerable<Type> GetQuantityTypes()
131127
{");

CodeGen/Generators/UnitsNetGenerator.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed under MIT No Attribution, see LICENSE file at the root.
22
// Copyright 2013 Andreas Gullberg Larsen ([email protected]). Maintained at https://github.com/angularsen/UnitsNet.
33

4+
using System.Collections.Generic;
45
using System.IO;
56
using System.Linq;
67
using CodeGen.Generators.UnitsNetGen;
@@ -71,6 +72,7 @@ public static void Generate(string rootDir, Quantity[] quantities, QuantityNameT
7172
Log.Information("");
7273
GenerateIQuantityTests(quantities, $"{testProjectDir}/GeneratedCode/IQuantityTests.g.cs");
7374
GenerateStaticQuantity(quantities, $"{outputDir}/Quantity.g.cs");
75+
GenerateResourceFiles(quantities, $"{outputDir}/Resources");
7476

7577
var unitCount = quantities.SelectMany(q => q.Units).Count();
7678
Log.Information("");
@@ -130,5 +132,54 @@ private static void GenerateStaticQuantity(Quantity[] quantities, string filePat
130132
File.WriteAllText(filePath, content);
131133
Log.Information("✅ Quantity.g.cs");
132134
}
135+
136+
private static void GenerateResourceFiles(Quantity[] quantities, string resourcesDirectory)
137+
{
138+
foreach(var quantity in quantities)
139+
{
140+
var cultures = new HashSet<string>();
141+
142+
foreach(Unit unit in quantity.Units)
143+
{
144+
foreach(Localization localization in unit.Localization)
145+
{
146+
cultures.Add(localization.Culture);
147+
}
148+
}
149+
150+
foreach(var culture in cultures)
151+
{
152+
var fileName = culture.Equals("en-US", System.StringComparison.InvariantCultureIgnoreCase) ?
153+
$"{resourcesDirectory}/{quantity.Name}.restext" :
154+
$"{resourcesDirectory}/{quantity.Name}.{culture}.restext";
155+
156+
using var writer = File.CreateText(fileName);
157+
158+
foreach(Unit unit in quantity.Units)
159+
{
160+
foreach(Localization localization in unit.Localization)
161+
{
162+
if(localization.Culture == culture)
163+
{
164+
if(localization.Abbreviations.Any())
165+
{
166+
writer.Write($"{unit.PluralName}=");
167+
168+
for(int i = 0; i < localization.Abbreviations.Length; i++)
169+
{
170+
writer.Write($"{localization.Abbreviations[i]}");
171+
172+
if(i != localization.Abbreviations.Length - 1)
173+
writer.Write(",");
174+
}
175+
176+
writer.WriteLine();
177+
}
178+
}
179+
}
180+
}
181+
}
182+
}
183+
}
133184
}
134185
}

UnitsNet/BaseUnits.cs

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -138,21 +138,28 @@ public override int GetHashCode()
138138
/// <inheritdoc />
139139
public override string ToString()
140140
{
141-
var sb = new StringBuilder();
142-
143-
string GetDefaultAbbreviation<TUnitType>(TUnitType? unitOrNull) where TUnitType : struct, Enum => unitOrNull is { } unit
144-
? UnitAbbreviationsCache.Default.GetDefaultAbbreviation(unit)
145-
: "N/A";
146-
147-
sb.AppendFormat("[Length]: {0}, ", GetDefaultAbbreviation(Length));
148-
sb.AppendFormat("[Mass]: {0}, ", GetDefaultAbbreviation(Mass));
149-
sb.AppendFormat("[Time]: {0}, ", GetDefaultAbbreviation(Time));
150-
sb.AppendFormat("[Current]: {0}, ", GetDefaultAbbreviation(Current));
151-
sb.AppendFormat("[Temperature]: {0}, ", GetDefaultAbbreviation(Temperature));
152-
sb.AppendFormat("[Amount]: {0}, ", GetDefaultAbbreviation(Amount));
153-
sb.AppendFormat("[LuminousIntensity]: {0}", GetDefaultAbbreviation(LuminousIntensity));
154-
155-
return sb.ToString();
141+
if(!Equals(Undefined))
142+
{
143+
var sb = new StringBuilder();
144+
145+
string GetDefaultAbbreviation<TUnitType>(TUnitType? unitOrNull) where TUnitType : struct, Enum => unitOrNull is { } unit
146+
? UnitAbbreviationsCache.Default.GetDefaultAbbreviation(unit)
147+
: "N/A";
148+
149+
sb.AppendFormat("[Length]: {0}, ", GetDefaultAbbreviation(Length));
150+
sb.AppendFormat("[Mass]: {0}, ", GetDefaultAbbreviation(Mass));
151+
sb.AppendFormat("[Time]: {0}, ", GetDefaultAbbreviation(Time));
152+
sb.AppendFormat("[Current]: {0}, ", GetDefaultAbbreviation(Current));
153+
sb.AppendFormat("[Temperature]: {0}, ", GetDefaultAbbreviation(Temperature));
154+
sb.AppendFormat("[Amount]: {0}, ", GetDefaultAbbreviation(Amount));
155+
sb.AppendFormat("[LuminousIntensity]: {0}", GetDefaultAbbreviation(LuminousIntensity));
156+
157+
return sb.ToString();
158+
}
159+
else
160+
{
161+
return "Undefined";
162+
}
156163
}
157164

158165
/// <summary>

UnitsNet/CustomCode/Quantities/Length.extra.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,8 @@ public string ToString(IFormatProvider? cultureInfo)
227227
{
228228
cultureInfo = cultureInfo ?? CultureInfo.CurrentCulture;
229229

230-
var footUnit = UnitAbbreviationsCache.Default.GetDefaultAbbreviation(LengthUnit.Foot, cultureInfo);
231-
var inchUnit = UnitAbbreviationsCache.Default.GetDefaultAbbreviation(LengthUnit.Inch, cultureInfo);
230+
var footUnit = Length.GetAbbreviation(LengthUnit.Foot, cultureInfo);
231+
var inchUnit = Length.GetAbbreviation(LengthUnit.Inch, cultureInfo);
232232

233233
// Note that it isn't customary to use fractions - one wouldn't say "I am 5 feet and 4.5 inches".
234234
// So inches are rounded when converting from base units to feet/inches.

UnitsNet/CustomCode/Quantities/Mass.extra.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,8 @@ public string ToString(IFormatProvider? cultureInfo)
156156
{
157157
cultureInfo = cultureInfo ?? CultureInfo.CurrentCulture;
158158

159-
var stoneUnit = UnitAbbreviationsCache.Default.GetDefaultAbbreviation(MassUnit.Stone, cultureInfo);
160-
var poundUnit = UnitAbbreviationsCache.Default.GetDefaultAbbreviation(MassUnit.Pound, cultureInfo);
159+
var stoneUnit = Mass.GetAbbreviation(MassUnit.Stone, cultureInfo);
160+
var poundUnit = Mass.GetAbbreviation(MassUnit.Pound, cultureInfo);
161161

162162
// Note that it isn't customary to use fractions - one wouldn't say "I am 11 stone and 4.5 pounds".
163163
// So pounds are rounded here.

0 commit comments

Comments
 (0)