Skip to content

Commit

Permalink
changes to address idiomatic differences between pt-PT and pt-BR (#1498)
Browse files Browse the repository at this point in the history
* fix pt-PT spelling of numbers

* add pt resources for date humanizer

slight differences between pt-PT and pt-BR regarding "date from now" and "date ago": https://ciberduvidas.iscte-iul.pt/consultorio/perguntas/daqui-a-uma-hora-dentro-de-uma-hora-e-numa-hora/36633

* add time to clock notation for pt-PT

slight differences between pt-PT and pt-BR regarding "telling time": https://ciberduvidas.iscte-iul.pt/consultorio/perguntas/sobre-as-horas/20854
  • Loading branch information
zmira committed May 9, 2024
1 parent f0e379d commit b1c2049
Show file tree
Hide file tree
Showing 8 changed files with 855 additions and 73 deletions.
82 changes: 82 additions & 0 deletions src/Humanizer.Tests/Localisation/pt/DateHumanizeTests.cs
@@ -0,0 +1,82 @@
namespace pt;

[UseCulture("pt")]
public class DateHumanizeTests
{
[Theory]
[InlineData(-2, "há 2 segundos")]
[InlineData(-1, "há um segundo")]
public void SecondsAgo(int seconds, string expected) =>
DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past);

[Theory]
[InlineData(1, "daqui a um segundo")]
[InlineData(2, "daqui a 2 segundos")]
public void SecondsFromNow(int seconds, string expected) =>
DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future);

[Theory]
[InlineData(-2, "há 2 minutos")]
[InlineData(-1, "há um minuto")]
[InlineData(60, "há uma hora")]
public void MinutesAgo(int minutes, string expected) =>
DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past);

[Theory]
[InlineData(1, "daqui a um minuto")]
[InlineData(2, "daqui a 2 minutos")]
public void MinutesFromNow(int minutes, string expected) =>
DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future);

[Theory]
[InlineData(-2, "há 2 horas")]
[InlineData(-1, "há uma hora")]
public void HoursAgo(int hours, string expected) =>
DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past);

[Theory]
[InlineData(1, "daqui a uma hora")]
[InlineData(2, "daqui a 2 horas")]
public void HoursFromNow(int hours, string expected) =>
DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future);

[Theory]
[InlineData(-2, "há 2 dias")]
[InlineData(-1, "ontem")]
public void DaysAgo(int days, string expected) =>
DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past);

[Theory]
[InlineData(1, "amanhã")]
[InlineData(2, "daqui a 2 dias")]
public void DaysFromNow(int days, string expected) =>
DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future);

[Theory]
[InlineData(-2, "há 2 meses")]
[InlineData(-1, "há um mês")]
public void MonthsAgo(int months, string expected) =>
DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past);

[Theory]
[InlineData(1, "daqui a um mês")]
[InlineData(2, "daqui a 2 meses")]
public void MonthsFromNow(int months, string expected) =>
DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future);

[Theory]
[InlineData(-2, "há 2 anos")]
[InlineData(-1, "há um ano")]
public void YearsAgo(int years, string expected) =>
DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past);

[Theory]
[InlineData(1, "daqui a um ano")]
[InlineData(2, "daqui a 2 anos")]
public void YearsFromNow(int years, string expected) =>
DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future);

[Fact]
public void Now() =>
DateHumanize.Verify("agora", 0, TimeUnit.Day, Tense.Future);
}
10 changes: 6 additions & 4 deletions src/Humanizer.Tests/Localisation/pt/NumberToWordsTests.cs
@@ -1,9 +1,10 @@
namespace pt;
namespace pt;

[UseCulture("pt")]
public class NumberToWordsTests
{
[Theory]
[InlineData(0, "zero")]
[InlineData(1, "um")]
[InlineData(2, "dois")]
[InlineData(3, "três")]
Expand All @@ -19,10 +20,10 @@ public class NumberToWordsTests
[InlineData(13, "treze")]
[InlineData(14, "quatorze")]
[InlineData(15, "quinze")]
[InlineData(16, "dezesseis")]
[InlineData(17, "dezessete")]
[InlineData(16, "dezasseis")]
[InlineData(17, "dezassete")]
[InlineData(18, "dezoito")]
[InlineData(19, "dezenove")]
[InlineData(19, "dezanove")]
[InlineData(20, "vinte")]
[InlineData(30, "trinta")]
[InlineData(40, "quarenta")]
Expand Down Expand Up @@ -101,6 +102,7 @@ public class NumberToWordsTests
Assert.Equal(expected, number.ToWords());

[Theory]
[InlineData(0, "zero")]
[InlineData(1, "uma")]
[InlineData(2, "duas")]
[InlineData(3, "três")]
Expand Down
57 changes: 57 additions & 0 deletions src/Humanizer.Tests/Localisation/pt/TimeToClockNotationTests.cs
@@ -0,0 +1,57 @@
#if NET6_0_OR_GREATER

namespace pt;

[UseCulture("pt")]
public class TimeToClockNotationTests
{
[Theory]
[InlineData(00, 00, "meia-noite")]
[InlineData(04, 00, "quatro horas")]
[InlineData(05, 01, "cinco e um")]
[InlineData(06, 05, "seis e cinco")]
[InlineData(07, 10, "sete e dez")]
[InlineData(08, 15, "oito e um quarto")]
[InlineData(09, 20, "nove e vinte")]
[InlineData(10, 25, "dez e vinte e cinco")]
[InlineData(11, 30, "onze e meia")]
[InlineData(12, 00, "meio-dia")]
[InlineData(15, 35, "três e trinta e cinco")]
[InlineData(16, 40, "cinco menos vinte")]
[InlineData(17, 45, "seis menos um quarto")]
[InlineData(18, 50, "sete menos dez")]
[InlineData(19, 55, "oito menos cinco")]
[InlineData(20, 59, "oito e cinquenta e nove")]
public void ConvertToClockNotationTimeOnlyStringPtBr(int hours, int minutes, string expectedResult)
{
var actualResult = new TimeOnly(hours, minutes).ToClockNotation();
Assert.Equal(expectedResult, actualResult);
}

[Theory]
[InlineData(00, 00, "meia-noite")]
[InlineData(04, 00, "quatro horas")]
[InlineData(05, 01, "cinco horas")]
[InlineData(06, 05, "seis e cinco")]
[InlineData(07, 10, "sete e dez")]
[InlineData(08, 15, "oito e um quarto")]
[InlineData(09, 20, "nove e vinte")]
[InlineData(10, 25, "dez e vinte e cinco")]
[InlineData(11, 30, "onze e meia")]
[InlineData(12, 00, "meio-dia")]
[InlineData(13, 23, "uma e vinte e cinco")]
[InlineData(14, 32, "duas e meia")]
[InlineData(15, 35, "três e trinta e cinco")]
[InlineData(16, 40, "cinco menos vinte")]
[InlineData(17, 45, "seis menos um quarto")]
[InlineData(18, 50, "sete menos dez")]
[InlineData(19, 55, "oito menos cinco")]
[InlineData(20, 59, "nove horas")]
public void ConvertToRoundedClockNotationTimeOnlyStringPtBr(int hours, int minutes, string expectedResult)
{
var actualResult = new TimeOnly(hours, minutes).ToClockNotation(ClockNotationRounding.NearestFiveMinutes);
Assert.Equal(expectedResult, actualResult);
}
}

#endif
Expand Up @@ -10,6 +10,7 @@ public TimeOnlyToClockNotationConvertersRegistry() : base(new DefaultTimeOnlyToC
Register("fr", new FrTimeOnlyToClockNotationConverter());
Register("es", new EsTimeOnlyToClockNotationConverter());
Register("lb", new LbTimeOnlyToClockNotationConverter());
Register("pt", new PortugueseTimeOnlyToClockNotationConverter());
}
}

Expand Down
Expand Up @@ -2,7 +2,7 @@

class PortugueseNumberToWordsConverter : GenderedNumberToWordsConverter
{
static readonly string[] PortugueseUnitsMap = ["zero", "um", "dois", "três", "quatro", "cinco", "seis", "sete", "oito", "nove", "dez", "onze", "doze", "treze", "quatorze", "quinze", "dezesseis", "dezessete", "dezoito", "dezenove"];
static readonly string[] PortugueseUnitsMap = ["zero", "um", "dois", "três", "quatro", "cinco", "seis", "sete", "oito", "nove", "dez", "onze", "doze", "treze", "quatorze", "quinze", "dezasseis", "dezassete", "dezoito", "dezanove"];
static readonly string[] PortugueseTensMap = ["zero", "dez", "vinte", "trinta", "quarenta", "cinquenta", "sessenta", "setenta", "oitenta", "noventa"];
static readonly string[] PortugueseHundredsMap = ["zero", "cento", "duzentos", "trezentos", "quatrocentos", "quinhentos", "seiscentos", "setecentos", "oitocentos", "novecentos"];

Expand Down
@@ -0,0 +1,37 @@
#if NET6_0_OR_GREATER

namespace Humanizer;

class PortugueseTimeOnlyToClockNotationConverter : ITimeOnlyToClockNotationConverter
{
public string Convert(TimeOnly time, ClockNotationRounding roundToNearestFive)
{
switch (time)
{
case { Hour: 0, Minute: 0 }:
return "meia-noite";
case { Hour: 12, Minute: 0 }:
return "meio-dia";
}

var normalizedHour = time.Hour % 12;
var normalizedMinutes = (int)(roundToNearestFive == ClockNotationRounding.NearestFiveMinutes
? 5 * Math.Round(time.Minute / 5.0)
: time.Minute);

return normalizedMinutes switch
{
00 => $"{normalizedHour.ToWords(GrammaticalGender.Feminine)} horas",
15 => $"{normalizedHour.ToWords(GrammaticalGender.Feminine)} e um quarto",
30 => $"{normalizedHour.ToWords(GrammaticalGender.Feminine)} e meia",
40 => $"{(normalizedHour + 1).ToWords(GrammaticalGender.Feminine)} menos vinte",
45 => $"{(normalizedHour + 1).ToWords(GrammaticalGender.Feminine)} menos um quarto",
50 => $"{(normalizedHour + 1).ToWords(GrammaticalGender.Feminine)} menos dez",
55 => $"{(normalizedHour + 1).ToWords(GrammaticalGender.Feminine)} menos cinco",
60 => $"{(normalizedHour + 1).ToWords(GrammaticalGender.Feminine)} horas",
_ => $"{normalizedHour.ToWords(GrammaticalGender.Feminine)} e {normalizedMinutes.ToWords()}"
};
}
}

#endif

0 comments on commit b1c2049

Please sign in to comment.