Skip to content

Commit 161ae62

Browse files
authored
Added proper pluralization support for localized strings (#125)
1 parent 5f56643 commit 161ae62

20 files changed

Lines changed: 139 additions & 73 deletions

File tree

src/Platforms/SecureFolderFS.Maui/Platforms/Android/ServiceImplementation/VaultForegroundService.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,7 @@ private void UpdateNotification()
103103
var title = count switch
104104
{
105105
0 => "VaultUnlocked".ToLocalized(),
106-
1 => "OneVaultIsUnlocked".ToLocalized(),
107-
_ => "MultipleVaultsAreUnlocked".ToLocalized(count)
106+
_ => "VaultsUnlockedPlural".ToLocalized(count)
108107
};
109108

110109
// Tapping the notification brings the app back to foreground

src/Platforms/SecureFolderFS.Maui/UserControls/Browser/BrowserControl.DragDrop.xaml.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ await transferViewModel.TransferAsync(itemsToProcess, async (item, reporter, tok
461461
new FileViewModel(createdFile, browserViewModel, destinationViewModel),
462462
browserViewModel.Layouts.GetSorter());
463463
}
464-
}, cts.Token);
464+
}, x => x.Name, cts.Token);
465465
}
466466
catch (Exception ex) when (ex is TaskCanceledException or OperationCanceledException)
467467
{

src/Platforms/SecureFolderFS.Maui/UserControls/Browser/TransferControl.xaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
<uc:AnimatedRevealLayout.MainContent>
5757
<Label
5858
FontSize="16"
59+
LineBreakMode="TailTruncation"
5960
Text="{Binding Title, Mode=OneWay}"
6061
VerticalOptions="Center" />
6162
</uc:AnimatedRevealLayout.MainContent>

src/Platforms/SecureFolderFS.Maui/Views/Vault/BrowserPage.xaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
FontSize="18"
5151
HorizontalOptions="Center"
5252
IsVisible="{Binding ViewModel.IsSelecting, Mode=OneWay}"
53-
Text="{Binding ViewModel.CurrentFolder.SelectedItems.Count, Mode=OneWay, Converter={StaticResource CountToStringConverter}, ConverterParameter='(0:LOCALIZE|SelectItems)|(>0:LOCALIZE|ItemsSelected)'}"
53+
Text="{Binding ViewModel.CurrentFolder.SelectedItems.Count, Mode=OneWay, Converter={StaticResource CountToStringConverter}, ConverterParameter='(0:LOCALIZE|SelectItems)|(>0:LOCALIZE|ItemsSelectedPlural)'}"
5454
TextColor="#FFFFFF"
5555
VerticalOptions="Center" />
5656
<VerticalStackLayout IsVisible="{Binding ViewModel.IsSelecting, Mode=OneWay, Converter={StaticResource BoolInvertConverter}}" VerticalOptions="Center">
@@ -62,7 +62,7 @@
6262
<Label
6363
FontSize="12"
6464
Opacity="0.6"
65-
Text="{Binding ViewModel.CurrentFolder.Items.Count, Mode=OneWay, Converter={StaticResource CountToStringConverter}, ConverterParameter='(>=0:LOCALIZE|ElementsCount)'}"
65+
Text="{Binding ViewModel.CurrentFolder.Items.Count, Mode=OneWay, Converter={StaticResource CountToStringConverter}, ConverterParameter='(>=0:LOCALIZE|ElementsCountPlural)'}"
6666
TextColor="#FFFFFF" />
6767
</VerticalStackLayout>
6868
</Grid>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
SmartFormat
2+
https://github.com/axuno/SmartFormat/blob/main/LICENSE.md
3+
MIT
4+
https://github.com/axuno/SmartFormat
5+
6+
The MIT License (MIT)
7+
=====================
8+
9+
Copyright © 2011-2022 SmartFormat Project maintainers and contributors.
10+
11+
All rights reserved.
12+
13+
* Project founder: Scott Rippey
14+
* Project owner: axuno gGmbH
15+
16+
Permission is hereby granted, free of charge, to any person
17+
obtaining a copy of this software and associated documentation
18+
files (the “Software”), to deal in the Software without
19+
restriction, including without limitation the rights to use,
20+
copy, modify, merge, publish, distribute, sublicense, and/or sell
21+
copies of the Software, and to permit persons to whom the
22+
Software is furnished to do so, subject to the following
23+
conditions:
24+
25+
The above copyright notice and this permission notice shall be
26+
included in all copies or substantial portions of the Software.
27+
28+
THE SOFTWARE IS PROVIDED ìAS “IS”, WITHOUT WARRANTY OF ANY KIND,
29+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
30+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
32+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
33+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
34+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
35+
OTHER DEALINGS IN THE SOFTWARE.
36+
37+
---
38+
39+
The bundled project *SmartFormat.ZString* is Copyright © Cysharp, Inc. [Their software](https://github.com/Cysharp/ZString)
40+
is licensed under [The MIT License (MIT)](src/SmartFormat.ZString/repo/LICENSE).
41+
Their conversion methods under the `ZString/Number` directory
42+
is Copyright © .NET Foundation and Contributors und is licensed
43+
under [The MIT License (MIT)](https://github.com/dotnet/runtime/blob/master/LICENSE.TXT).

src/Platforms/SecureFolderFS.UI/Strings/en-US/Resources.resx

Lines changed: 29 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -620,9 +620,6 @@
620620
<data name="DateToday" xml:space="preserve">
621621
<value>Today, {0}</value>
622622
</data>
623-
<data name="DateAgo" xml:space="preserve">
624-
<value>{0} ago</value>
625-
</data>
626623
<data name="ErrorOccurred" xml:space="preserve">
627624
<value>An error occurred</value>
628625
</data>
@@ -1043,11 +1040,11 @@
10431040
<data name="DateYesterday" xml:space="preserve">
10441041
<value>Yesterday, {0}</value>
10451042
</data>
1046-
<data name="DateWeekAgo" xml:space="preserve">
1047-
<value>Last week</value>
1043+
<data name="DateWeekAgoPlural" xml:space="preserve">
1044+
<value>{0:plural:Last week|{} weeks ago|{} weeks ago}</value>
10481045
</data>
1049-
<data name="DateDaysAgo" xml:space="preserve">
1050-
<value>{0} days ago</value>
1046+
<data name="DateDaysAgoPlural" xml:space="preserve">
1047+
<value>{0:plural:{} day ago|{} days ago|{} days ago}</value>
10511048
</data>
10521049
<data name="VaultUnlocked" xml:space="preserve">
10531050
<value>Vault is unlocked</value>
@@ -1085,8 +1082,8 @@
10851082
<data name="FileHasCorruptedChunks" xml:space="preserve">
10861083
<value>Parts of the file are corrupted and will be reset</value>
10871084
</data>
1088-
<data name="CorruptedChunks" xml:space="preserve">
1089-
<value>{0} corrupted region(s)</value>
1085+
<data name="CorruptedChunksPlural" xml:space="preserve">
1086+
<value>{0:plural:{} corrupted region|{} corrupted regions|{} corrupted regions}</value>
10901087
</data>
10911088
<data name="DataLossImminent" xml:space="preserve">
10921089
<value>Data loss unpreventable</value>
@@ -1178,26 +1175,26 @@
11781175
<data name="ClearSelection" xml:space="preserve">
11791176
<value>Clear selection</value>
11801177
</data>
1181-
<data name="CopyingItems" xml:space="preserve">
1182-
<value>Copying {0} item(s)</value>
1178+
<data name="CopyingItemsPlural" xml:space="preserve">
1179+
<value>Copying {Total:choose(0):{Achieved} {Achieved:plural:item|items|items}|{Total:choose(1):{State}|{Achieved}/{Total} {Total:plural:item|items|items}}}</value>
11831180
</data>
1184-
<data name="MovingItems" xml:space="preserve">
1185-
<value>Moving {0} item(s)</value>
1181+
<data name="MovingItemsPlural" xml:space="preserve">
1182+
<value>Moving {Total:choose(0):{Achieved} {Achieved:plural:item|items|items}|{Total:choose(1):{State}|{Achieved}/{Total} {Total:plural:item|items|items}}}</value>
11861183
</data>
1187-
<data name="DeletingItems" xml:space="preserve">
1188-
<value>Deleting {0} item(s)</value>
1184+
<data name="DeletingItemsPlural" xml:space="preserve">
1185+
<value>Deleting {Total:choose(0):{Achieved} {Achieved:plural:item|items|items}|{Total:choose(1):{State}|{Achieved}/{Total} {Total:plural:item|items|items}}}</value>
11891186
</data>
11901187
<data name="NotEnoughSpace" xml:space="preserve">
11911188
<value>Not enough space</value>
11921189
</data>
11931190
<data name="ItemDeletionTitle" xml:space="preserve">
11941191
<value>Deleting item(s)</value>
11951192
</data>
1196-
<data name="ItemDeletionDescription" xml:space="preserve">
1197-
<value>Are you sure you want to permanently delete {0} item(s)?</value>
1193+
<data name="ItemDeletionDescriptionPlural" xml:space="preserve">
1194+
<value>Are you sure you want to permanently delete {0:plural:one item|{} items|{} items}?</value>
11981195
</data>
1199-
<data name="ItemsExceedRecycleBinSize" xml:space="preserve">
1200-
<value>The deleted items exceed the available space in the recycle bin. Do you want to permanently delete {0} item(s) instead?</value>
1196+
<data name="ItemsExceedRecycleBinSizePlural" xml:space="preserve">
1197+
<value>The deleted {0:plural:item exceeds|{} items exceed} the available space in the recycle bin. Do you want to permanently delete {0:plural:this item|{} items} instead?</value>
12011198
</data>
12021199
<data name="IntroPrefix" xml:space="preserve">
12031200
<value>By continuing, you agree to our </value>
@@ -1229,14 +1226,14 @@
12291226
<data name="EnableDeviceLink" xml:space="preserve">
12301227
<value>Enable Device Link</value>
12311228
</data>
1232-
<data name="ItemsSelected" xml:space="preserve">
1233-
<value>{0} item(s) selected</value>
1229+
<data name="ItemsSelectedPlural" xml:space="preserve">
1230+
<value>{0:plural:One item|{} items|{} items} selected</value>
12341231
</data>
1235-
<data name="ElementsCount" xml:space="preserve">
1236-
<value>{0} element(s)</value>
1232+
<data name="ElementsCountPlural" xml:space="preserve">
1233+
<value>{0:plural:{} element|{} elements}</value>
12371234
</data>
1238-
<data name="FoundIssuesCount" xml:space="preserve">
1239-
<value>Found {0} issue(s)</value>
1235+
<data name="FoundIssuesCountPlural" xml:space="preserve">
1236+
<value>Found {0:plural:one issue|{} issues}</value>
12401237
</data>
12411238
<data name="AvailableWidgets" xml:space="preserve">
12421239
<value>Available widgets</value>
@@ -1256,8 +1253,8 @@
12561253
<data name="ArchiveFormatNotSupported" xml:space="preserve">
12571254
<value>This archive format is not supported for extraction</value>
12581255
</data>
1259-
<data name="ExtractingItems" xml:space="preserve">
1260-
<value>Extracting {0} items</value>
1256+
<data name="ExtractingItemsPlural" xml:space="preserve">
1257+
<value>Extracting {Total:choose(0):{Achieved} {Achieved:plural:item|items|items}|{Total:choose(1):{State}|{Achieved}/{Total} {Total:plural:item|items|items}}}</value>
12611258
</data>
12621259
<data name="Extracting" xml:space="preserve">
12631260
<value>Extracting...</value>
@@ -1332,7 +1329,7 @@
13321329
<value>Manual certificate fingerprint (SHA-256)</value>
13331330
</data>
13341331
<data name="SearchIn" xml:space="preserve">
1335-
<value>Search in: {0}</value>
1332+
<value>Search in: '{0}'</value>
13361333
</data>
13371334
<data name="RootFolder" xml:space="preserve">
13381335
<value>Root folder</value>
@@ -1346,8 +1343,8 @@
13461343
<data name="CollectingItemsCount" xml:space="preserve">
13471344
<value>Collecting items ({0})</value>
13481345
</data>
1349-
<data name="CollectedCountItems" xml:space="preserve">
1350-
<value>Collected {0} items</value>
1346+
<data name="CollectedItemsPlural" xml:space="preserve">
1347+
<value>Collected {0:plural:{} item|{} items|{} items}</value>
13511348
</data>
13521349
<data name="ScanCompleted" xml:space="preserve">
13531350
<value>Scan completed</value>
@@ -1421,11 +1418,8 @@
14211418
<data name="TapToLockAll" xml:space="preserve">
14221419
<value>Tap to lock all vaults</value>
14231420
</data>
1424-
<data name="OneVaultIsUnlocked" xml:space="preserve">
1425-
<value>One vault is unlocked</value>
1426-
</data>
1427-
<data name="MultipleVaultsAreUnlocked" xml:space="preserve">
1428-
<value>{0} vaults are unlocked</value>
1421+
<data name="VaultsUnlockedPlural" xml:space="preserve">
1422+
<value>{0:plural:One vault is|{} vaults are|{} vaults are} unlocked</value>
14291423
</data>
14301424
<data name="ViewInApp" xml:space="preserve">
14311425
<value>View in app</value>

src/Platforms/SecureFolderFS.UI/ValueConverters/BaseDateTimeToStringConverter.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using SecureFolderFS.Sdk.Extensions;
33
using SecureFolderFS.Sdk.Services;
44
using SecureFolderFS.Shared;
5-
using SecureFolderFS.Shared.Helpers;
65

76
namespace SecureFolderFS.UI.ValueConverters
87
{
@@ -19,7 +18,7 @@ public abstract class BaseDateTimeToStringConverter : BaseConverter
1918
if (parameter is string formatString)
2019
{
2120
var split = formatString.Split('|');
22-
if (split[0] == "LOCALIZE")
21+
if (split[0].Equals("localize", StringComparison.OrdinalIgnoreCase))
2322
return string.Format(split[1].ToLocalized(), dateString);
2423
else
2524
return string.Format(split[1], dateString);

src/Platforms/SecureFolderFS.UI/ViewModels/Health/HealthFileDataIssueViewModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public HealthFileDataIssueViewModel(IStorableChild storable, IResult? result, st
3535
{
3636
Severity = Severity.Critical;
3737
CorruptedChunks = corruptedChunks ?? [];
38-
CorruptedChunksText = !isRecoverable ? string.Empty : "CorruptedChunks".ToLocalized(CorruptedChunks.Count);
38+
CorruptedChunksText = !isRecoverable ? string.Empty : "CorruptedChunksPlural".ToLocalized(CorruptedChunks.Count);
3939
IsRecoverable = isRecoverable;
4040
}
4141
}

src/Platforms/SecureFolderFS.Uno/Views/Vault/VaultHealthPage.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@
264264
</Grid.RowDefinitions>
265265

266266
<InfoBar
267-
Title="{x:Bind ViewModel.HealthViewModel.FoundIssues.Count, Mode=OneWay, Converter={StaticResource CountToStringConverter}, ConverterParameter='(>=0:LOCALIZE|FoundIssuesCount)'}"
267+
Title="{x:Bind ViewModel.HealthViewModel.FoundIssues.Count, Mode=OneWay, Converter={StaticResource CountToStringConverter}, ConverterParameter='(>=0:LOCALIZE|FoundIssuesCountPlural)'}"
268268
Grid.Row="0"
269269
VerticalContentAlignment="Center"
270270
IsClosable="False"

src/Sdk/SecureFolderFS.Sdk/AppModels/Progress.cs renamed to src/Sdk/SecureFolderFS.Sdk/AppModels/TotalProgress.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55
/// </summary>
66
/// <param name="Achieved">The current achieved progress so far.</param>
77
/// <param name="Total">The total progress to achieve.</param>
8-
public readonly record struct TotalProgress(int Achieved, int Total);
8+
/// <param name="State">The additional state of the progress.</param>
9+
public readonly record struct TotalProgress(int Achieved, int Total, object? State = null);
910
}

0 commit comments

Comments
 (0)