diff --git a/se5/BrazilianToEuropeanPortuguese.Tests/AutomaticGrammarTests.cs b/se5/BrazilianToEuropeanPortuguese.Tests/AutomaticGrammarTests.cs index b796c091..6b461e82 100644 --- a/se5/BrazilianToEuropeanPortuguese.Tests/AutomaticGrammarTests.cs +++ b/se5/BrazilianToEuropeanPortuguese.Tests/AutomaticGrammarTests.cs @@ -49,7 +49,7 @@ public void ReviewedGrammarWarningsBecomeCorrections(string source, string expec [InlineData("É difícil dizer que foi pelo o que aconteceu.", "É difícil dizer que foi pelo que aconteceu.")] [InlineData("Tenho um ideia melhor.", "Tenho uma ideia melhor.")] [InlineData("Faz todo sentido.", "Faz todo o sentido.")] - [InlineData("Dei a ela todo dinheiro.", "Dei a ela todo o dinheiro.")] + [InlineData("Dei a ela todo dinheiro.", "Dei-lhe todo o dinheiro.")] public void RepeatedMissedEpisodeFamiliesBecomeSelectableChanges(string source, string expected) => Converts(source, expected); [Theory] diff --git a/se5/BrazilianToEuropeanPortuguese.Tests/BigCompareObjectTests.cs b/se5/BrazilianToEuropeanPortuguese.Tests/BigCompareObjectTests.cs new file mode 100644 index 00000000..ab6256c9 --- /dev/null +++ b/se5/BrazilianToEuropeanPortuguese.Tests/BigCompareObjectTests.cs @@ -0,0 +1,594 @@ +using SubtitleEdit.Plugins.BrazilianToEuropeanPortuguese; + +namespace BrazilianToEuropeanPortuguese.Tests; + +public sealed class BigCompareObjectTests +{ + private static void AssertConverts(string input, string expected) + { + var converter = new PortugueseConverter(); + Assert.Equal(expected, converter.Convert(input)); + Assert.Equal(expected, converter.Convert(expected)); + } + + [Theory] + [InlineData("Adorei ele!", "Adorei-o!")] + [InlineData("Eu tirei ela de lá.", "Eu tirei-a de lá.")] + [InlineData("Ela queria você.", "Ela queria-te.")] + [InlineData("e isso inclui você.", "e isso inclui-te.")] + [InlineData("Se alguém investigasse você,", "Se alguém te investigasse,")] + [InlineData("Tudo porque deixou que usassem você.", "Tudo porque deixou que te usassem.")] + [InlineData("Não estou evitando você.", "Não estou a evitar-te.")] + [InlineData("Está estudando ela?", "Estás a estudá-la?")] + [InlineData("Está procurando você.", "Está a procurar-te.")] + [InlineData("Citando você, Graça:", "Citando-te, Graça:")] + [InlineData("Eu não mereço você.", "Eu não te mereço.")] + [InlineData("Ele ferrou você.", "Ele lixou-te.")] + [InlineData("Constrangi você?", "Constrangi-te?")] + [InlineData("Porque agora eu tenho você.", "Porque agora eu tenho-te.")] + [InlineData("Joguem ele no carro!", "Joguem-no no carro!")] + [InlineData("Tragam ele, façam ele falar.", "Tragam-no, façam-no falar.")] + [InlineData("Ele confundiu você com outra.", "Ele confundiu-te com outra.")] + [InlineData("Ela stressava ele muito.", "Ela stressava-o muito.")] + public void ObjectPronounsAfterPastGerundAndSubjunctiveForms(string input, string expected) + => AssertConverts(input, expected); + + [Theory] + [InlineData("Mas por que alguém mataria ele?", "Mas porque alguém o mataria?")] + [InlineData("Eu aceitaria ela.", "Eu aceitá-la-ia.")] + [InlineData("Não aceitariam ele?", "Não o aceitariam?")] + [InlineData("O Bob e a Carol não salvariam ela.", "O Bob e a Carol não a salvariam.")] + public void ConditionalObjectsUseProclisisOrMesoclisis(string input, string expected) + => AssertConverts(input, expected); + + [Theory] + [InlineData("Espero que tenha visto ele.", "Espero que o tenha visto.")] + [InlineData("Queria ter encontrado você antes.", "Queria ter-te encontrado antes.")] + [InlineData("Lamento ter trazido você aqui.", "Lamento ter-te trazido aqui.")] + [InlineData("Tinha visto ele ontem.", "Tinha-o visto ontem.")] + [InlineData("Não tinha visto ela.", "Não a tinha visto.")] + [InlineData("Eu teria matado ele.", "Eu tê-lo-ia matado.")] + [InlineData("Ele tem ajudado você muito.", "Ele tem-te ajudado muito.")] + [InlineData("Por ter salvado ela, ganhou.", "Por tê-la salvado, ganhou.")] + [InlineData("Ninguém tinha avisado você.", "Ninguém te tinha avisado.")] + public void CompoundTenseObjectsAttachToTheAuxiliary(string input, string expected) + => AssertConverts(input, expected); + + [Theory] + [InlineData("Escolhe você.", "Escolhe tu.")] + [InlineData("Tente você.", "Tenta tu.")] + [InlineData("Atire você.", "Atira tu.")] + [InlineData("E acho que conheço ele também.", "E acho que conheço ele também.")] + [InlineData("Tem ele aqui?", "Tem ele aqui?")] + [InlineData("O que tinha feito ele?", "O que tinha feito ele?")] + [InlineData("Eu tinha ido lá.", "Eu tinha ido lá.")] + [InlineData("Eu esperei você me pedir.", "Eu esperei pedires-me.")] + [InlineData("Mas adorei você estar aqui.", "Mas adorei estares aqui.")] + [InlineData("Convenci você a ir.", "Convenci-te a ir.")] + [InlineData("Eu fiz você chorar.", "Eu fiz-te chorar.")] + [InlineData("Não ouço você fazer comentários.", "Não te ouço fazer comentários.")] + [InlineData("só eu mandando você se foder.", "só eu a mandar-te se foder.")] + [InlineData("só eu mandando ele embora.", "só eu a mandá-lo embora.")] + [InlineData("- Ajudando você!", "- Ajudando-te!")] + [InlineData("Foda-se.", "Foda-se.")] + [InlineData("eu nem sequer tenho visto ela.", "eu nem sequer a tenho visto.")] + [InlineData("deve ter feito eles pirarem.", "deve ter feito eles pirarem.")] + public void SubjectsAndIntransitiveCompoundsAreKept(string input, string expected) + => AssertConverts(input, expected); + + [Theory] + [InlineData("Ela é intensa e esquentada.", "Ela é intensa e esquentada.")] + [InlineData("Esquentei a sopa.", "Aqueci a sopa.")] + [InlineData("Nem esquente a cabeça com isso.", "Não te preocupes com isso.")] + [InlineData("Chispa daqui!", "Desaparece daqui!")] + [InlineData("Chispem daqui!", "Desapareçam daqui!")] + [InlineData("Cantava uma canção de ninar.", "Cantava uma canção de embalar.")] + [InlineData("Vai ser na marra.", "Vai ser à força.")] + [InlineData("Não tem água encanada.", "Não tem água canalizada.")] + public void BigCompareVocabulary(string input, string expected) + => AssertConverts(input, expected); + + [Theory] + [InlineData("Você deixou que usassem você.", "Deixaste-te usar.")] + [InlineData("Não deixe que usem você.", "Não te deixes usar.")] + [InlineData("Deixa que ajudem você.", "Deixa-te ajudar.")] + [InlineData("Você deixou que te vissem.", "Deixaste-te ver.")] + [InlineData("Você deixou eles usarem você.", "Deixaste-os usar-te.")] + [InlineData("Você fez eles pararem.", "Fizeste-os parar.")] + [InlineData("Ele deixou que usassem você.", "Ele deixou que te usassem.")] + [InlineData("Não deixe que façam isso.", "Não deixes que façam isso.")] + public void LetYourselfUsesReflexiveDeixarWithInfinitive(string input, string expected) + => AssertConverts(input, expected); + + [Fact] + public void DroppedSubjectLetYourselfNeedsEnglishEvidence() + { + const string source = "Tudo porque deixou que usassem você."; + Assert.Equal("Tudo porque te deixaste usar.", new PortugueseConverter() + .Convert(source, reference: ReferenceHint.FromText("All because you let yourself get used."))); + Assert.Equal("Tudo porque deixou que te usassem.", new PortugueseConverter() + .Convert(source, reference: ReferenceHint.FromText("All because he let them use you."))); + } + + [Theory] + [InlineData("Para eles usarem você.", "Para eles te usarem.")] + [InlineData("Para eles usarem ele.", "Para eles o usarem.")] + [InlineData("Sem eles verem você.", "Sem eles te verem.")] + [InlineData("Antes de eles encontrarem você.", "Antes de eles te encontrarem.")] + [InlineData("Até eles acharem você.", "Até eles te acharem.")] + [InlineData("Para o Jack ver você.", "Para o Jack te ver.")] + [InlineData("Para os polícias encontrarem você.", "Para os polícias te encontrarem.")] + [InlineData("Para a polícia prender ele.", "Para a polícia o prender.")] + [InlineData("para eles usarem-te.", "para eles te usarem.")] + [InlineData("É melhor eles ajudarem você.", "É melhor eles ajudarem-te.")] + [InlineData("Para eles irem embora.", "Para eles irem embora.")] + public void PrepositionWithInfinitiveSubjectAttractsTheClitic(string input, string expected) + => AssertConverts(input, expected); + + [Theory] + [InlineData("Para você usar ele.", "Para o usares.")] + [InlineData("Sem você ver ele.", "Sem o veres.")] + [InlineData("Até você encontrar ela.", "Até a encontrares.")] + [InlineData("Para a gente ajudar você.", "Para te ajudarmos.")] + [InlineData("Para a gente encontrar eles.", "Para os encontrarmos.")] + [InlineData("Para você usá-lo.", "Para o usares.")] + [InlineData("Para você fazê-lo.", "Para o fazeres.")] + [InlineData("Antes de você pô-lo lá.", "Antes de o pores lá.")] + [InlineData("Sem você ajudar-me.", "Sem me ajudares.")] + [InlineData("Pagaram para matarem ele.", "Pagaram para o matarem.")] + [InlineData("Para ganharem ele treinou muito.", "Para ganharem ele treinou muito.")] + [InlineData("Para tu o usares.", "Para tu o usares.")] + public void PersonalInfinitiveEndingAttractsTheCliticWithoutSubject(string input, string expected) + => AssertConverts(input, expected); + + [Theory] + [InlineData("Nunca vi você também.", "Nunca te vi também.")] + [InlineData("Amo você também.", "Amo-te também.")] + [InlineData("Você também.", "Tu também.")] + [InlineData("E você também vai.", "E tu também vais.")] + [InlineData("Isso vale para você também.", "Isso vale para ti também.")] + [InlineData("Era você também?", "Eras tu também?")] + public void YouAlsoAfterTransitiveVerbIsTheObject(string input, string expected) + => AssertConverts(input, expected); + + [Theory] + [InlineData("Ele só quer faturar um pouco de Molly.", "Ele só quer comprar um pouco de Molly.")] + [InlineData("Ele faturou cocaína no bar.", "Ele comprou cocaína no bar.")] + [InlineData("A empresa faturou milhões.", "A empresa faturou milhões.")] + [InlineData("Vamos faturar o cliente.", "Vamos faturar o cliente.")] + public void ScoringDrugsIsBuying(string input, string expected) + => AssertConverts(input, expected); + + [Fact] + public void ScoringNeedsDrugOrEnglishEvidence() + { + Assert.Equal("Fui comprar um pouco.", new PortugueseConverter() + .Convert("Fui faturar um pouco.", reference: ReferenceHint.FromText("I went to score some."))); + Assert.Equal("Fui faturar um pouco.", new PortugueseConverter().Convert("Fui faturar um pouco.")); + } + + [Theory] + [InlineData("Calma.\nQuanto quer faturar?", "Chill out. How much you looking to score?", "Calma.\nQuanto quer comprar?")] + [InlineData("Ele foi faturar no bairro.", "He went to score in the neighborhood.", "Ele foi comprar no bairro.")] + [InlineData("É onde eu costumava faturar.", "That's where I used to score.", "É onde eu costumava comprar.")] + [InlineData("Ele tentou faturar dele.", "He tried to score from him.", "Ele tentou comprar dele.")] + [InlineData("Faturou ontem à noite?", "Did you score last night?", "Comprou ontem à noite?")] + [InlineData("Ele faturou!", "He scored a goal!", "Ele marcou!")] + [InlineData("O time precisa faturar.", "The team needs to score.", "A equipa precisa de marcar.")] + [InlineData("Ele faturou no segundo tempo.", "He scored in the second half.", "Ele marcou na segunda parte.")] + [InlineData("Ele quer faturar alto.", "He wants to score big.", "Ele quer faturar alto.")] + [InlineData("Vamos faturar.", "Let's settle the score.", "Vamos faturar.")] + [InlineData("Ele vai faturar milhões.", "He's going to score millions.", "Ele vai faturar milhões.")] + [InlineData("Ele faturou dois gols.", "", "Ele marcou dois golos.")] + [InlineData("Faturei o primeiro gol.", "", "Marquei o primeiro golo.")] + [InlineData("Eles faturaram pontos com o chefe.", "", "Eles marcaram pontos com o chefe.")] + [InlineData("Nós faturamos três cestas.", "", "Nós marcamos três cestas.")] + [InlineData("A loja faturou milhões.", "The store made millions.", "A loja faturou milhões.")] + public void IntransitiveDrugScoringIsBuying(string input, string english, string expected) + { + Assert.Equal(expected, new PortugueseConverter().Convert(input, reference: ReferenceHint.FromText(english))); + } + + [Theory] + [InlineData("Presta atenção nisto.", "Presta atenção a isto.")] + [InlineData("Presta atenção no que eu digo.", "Presta atenção ao que eu digo.")] + [InlineData("Ninguém prestou atenção nela.", "Ninguém prestou atenção a ela.")] + [InlineData("Não dês atenção naquilo.", "Não dês atenção àquilo.")] + [InlineData("Prestem mais atenção nos detalhes.", "Prestem mais atenção aos detalhes.")] + [InlineData("Presta atenção em mim.", "Presta atenção a mim.")] + [InlineData("A atenção no caso é grande.", "A atenção no caso é grande.")] + [InlineData("Ela prestava atenção\nem sua conversa.", "Ela prestava atenção\nà sua conversa.")] + [InlineData("Presta atenção em teus filhos.", "Presta atenção aos teus filhos.")] + [InlineData("Presta atenção na tua mulher\ntanto quanto na tua colega.", "Presta atenção à tua mulher\ntanto quanto à tua colega.")] + [InlineData("Presta atenção no jogo. Como no outro dia.", "Presta atenção ao jogo. Como no outro dia.")] + public void PayingAttentionTakesA(string input, string expected) + => AssertConverts(input, expected); + + [Fact] + public void AttentionToThoseKeepsTheEnglishDistance() + { + Assert.Equal("Não prestes atenção a esses.", new PortugueseConverter() + .Convert("Não preste atenção nestes.", reference: ReferenceHint.FromText("Oh, don't pay any attention to those."))); + Assert.Equal("Não prestes atenção a estes.", new PortugueseConverter().Convert("Não preste atenção nestes.")); + } + + [Theory] + [InlineData("Não preste atenção nestes.", "Oh, don't pay any attention to those.", "Não preste atenção a esses.")] + [InlineData("Não preste atenção a estes.", "Oh, don't pay any attention to those.", "Não preste atenção a esses.")] + [InlineData("Não preste atenção nestas.", "This is important. Pay attention to those.", "Não preste atenção a essas.")] + [InlineData("Não preste atenção nestes.", "Those are old. Pay attention to these.", "Não preste atenção a estes.")] + [InlineData("Não preste atenção nestes.", null, "Não preste atenção a estes.")] + public void AttentionDistanceUsesItsAlignedEnglishTarget(string input, string? english, string expected) + { + var converter = new PortugueseConverter(new ConversionOptions(YouToTu: false)); + var reference = ReferenceHint.FromText(english); + Assert.Equal(expected, converter.Convert(input, reference: reference)); + Assert.Equal(expected, converter.Convert(expected, reference: reference)); + } + + [Theory] + [InlineData("Acho que talvez ele esqueceu\nde tirar o lixo.", "Acho que talvez ele se tenha esquecido\nde tirar o lixo.")] + [InlineData("Talvez é verdade.", "Talvez seja verdade.")] + [InlineData("Talvez ele está certo.", "Talvez ele esteja certo.")] + [InlineData("Talvez você tem razão.", "Talvez tenhas razão.")] + [InlineData("Talvez ela estava com medo.", "Talvez ela estivesse com medo.")] + [InlineData("Talvez ele foi embora.", "Talvez ele tenha ido embora.")] + [InlineData("Talvez foi um acidente.", "Talvez tenha sido um acidente.")] + [InlineData("Talvez eles viram você.", "Talvez eles te tenham visto.")] + [InlineData("Talvez você esqueceu.", "Talvez te tenhas esquecido.")] + [InlineData("Talvez ele precisa de ajuda.", "Talvez ele precise de ajuda.")] + [InlineData("Talvez o pai sabe.", "Talvez o pai saiba.")] + [InlineData("Talvez Jamie ligou para ela.", "Talvez Jamie lhe tenha ligado.")] + [InlineData("Talvez ele não quer falar.", "Talvez ele não queira falar.")] + [InlineData("Talvez ele me viu.", "Talvez ele me tenha visto.")] + [InlineData("Talvez você podia ajudar.", "Talvez pudesses ajudar.")] + [InlineData("Talvez para amanhã.", "Talvez para amanhã.")] + [InlineData("Talvez há dois anos.", "Talvez há dois anos.")] + [InlineData("Talvez há um problema.", "Talvez haja um problema.")] + [InlineData("Hematomas, talvez marcas de agulha.", "Hematomas, talvez marcas de agulha.")] + [InlineData("Algo que você tenha esquecido, ignorado.", "Algo que tenhas esquecido, ignorado.")] + [InlineData("Talvez nada.", "Talvez nada.")] + [InlineData("Ele esqueceu, talvez.", "Ele esqueceu-se, talvez.")] + [InlineData("Talvez porque ele sabe.", "Talvez porque ele sabe.")] + [InlineData("Talvez parte disso seja verdade.", "Talvez parte disso seja verdade.")] + [InlineData("Espero que ele tenha esquecido o nome.", "Espero que ele tenha esquecido o nome.")] + [InlineData("Espero que você não tenha esquecido de mim.", "Espero que não te tenhas esquecido de mim.")] + [InlineData("É possível que ele tenha-lhe mentido.", "É possível que ele lhe tenha mentido.")] + public void MaybeBeforeTheVerbTakesTheSubjunctive(string input, string expected) + => AssertConverts(input, expected); + + [Theory] + [InlineData("Mãos onde podemos vê-las!", "", "Mãos onde possamos vê-las!")] + [InlineData("Mãos onde eu posso ver!", "", "Mãos onde eu possa ver!")] + [InlineData("As mãos no ar, onde podemos vê-las!", "", "As mãos no ar, onde possamos vê-las!")] + [InlineData("Põe as mãos onde eu posso vê-las!", "", "Põe as mãos onde eu possa vê-las!")] + [InlineData("- Coloque-as onde posso ver!\n- Não se mexa!", "", "- Põe-nas onde possa ver!\n- Não te mexas!")] + [InlineData("Coloque-as mãos onde posso ver!", "", "Põe as mãos onde possa ver!")] + [InlineData("Ponha as mãos para fora\nonde eu posso vê-las!", "And put your hands out the window\nwhere I can see 'em!", "Põe as mãos para fora\nonde eu possa vê-las!")] + [InlineData("Fique onde a gente pode te ver.", "", "Fica onde possamos ver-te.")] + [InlineData("Fica onde estás.", "", "Fica onde estás.")] + [InlineData("Sabes onde posso encontrar o David?", "You know where I can find David?", "Sabes onde posso encontrar o David?")] + [InlineData("Não me diga onde posso e não posso ir.", "Don't tell me where I can and cannot go.", "Não me digas onde posso e não posso ir.")] + [InlineData("Há uma cama onde posso dormir.", "", "Há uma cama onde posso dormir.")] + [InlineData("Põe-no onde ele pode ser visto.", "", "Põe-no onde ele possa ser visto.")] + [InlineData("Mostra-me onde posso estacionar.", "", "Mostra-me onde posso estacionar.")] + [InlineData("Leva o carro para onde ele pode ser visto.", "", "Leva o carro para onde ele pode ser visto.")] + public void WhereClauseGivingTheCommandPurposeTakesTheSubjunctive(string input, string english, string expected) + { + var reference = english.Length == 0 ? null : ReferenceHint.FromText(english); + var actual = new PortugueseConverter().Convert(input, reference: reference); + Assert.Equal(expected, actual); + Assert.Equal(expected, new PortugueseConverter().Convert(expected, reference: reference)); + } + + [Theory] + [InlineData("No segundo tempo, ele marcou dois gols.", "", "Na segunda parte, ele marcou dois golos.")] + [InlineData("Ele faturou no segundo tempo.", "", "Ele marcou na segunda parte.")] + [InlineData("Trocou de caddie aos 45 do segundo tempo.", "", "Trocou de caddie aos 45 da segunda parte.")] + [InlineData("Segundo tempo! Vamos!", "", "Segunda parte! Vamos!")] + [InlineData("Todo o primeiro tempo foi horrível.", "", "Toda a primeira parte foi horrível.")] + [InlineData("O 2º tempo começa já.", "", "A 2ª parte começa já.")] + [InlineData("Pelo segundo tempo seguido, perderam.", "", "Pela segunda parte seguida, perderam.")] + [InlineData("Num segundo tempo, vamos falar disso.", "", "Num segundo tempo, vamos falar disso.")] + [InlineData("O segundo tempo verbal.", "", "O segundo tempo verbal.")] + [InlineData("Segundo, tempo é dinheiro.", "", "Segundo, tempo é dinheiro.")] + [InlineData("Qual o tempo?", "cut it out.\nWhat quarter?", "Qual o quarto?")] + [InlineData("Estamos no terceiro período.", "We're in the third quarter.", "Estamos no terceiro quarto.")] + [InlineData("Marcou no 3º período.", "He scored in the 3rd quarter.", "Marcou no 3º quarto.")] + [InlineData("Perdemos os dois últimos tempos.", "We lost the last two quarters.", "Perdemos os dois últimos quartos.")] + [InlineData("No último período, viraram o jogo.", "In the final quarter, they turned it around.", "No último quarto, viraram o jogo.")] + [InlineData("Estamos no terceiro período.", "", "Estamos no terceiro período.")] + [InlineData("No primeiro período tive boas notas.", "In the first term I got good grades.", "No primeiro período tive boas notas.")] + [InlineData("O jogo foi para a prorrogação.", "The game went into overtime.", "O jogo foi para o prolongamento.")] + [InlineData("Ganharam na prorrogação.", "They won it in overtime.", "Ganharam no prolongamento.")] + [InlineData("Pedimos uma prorrogação do prazo.", "We asked for an extension.", "Pedimos uma prorrogação do prazo.")] + [InlineData("Ele faz prorrogação.", "He works overtime.", "Ele faz prorrogação.")] + public void MatchPeriodsUsePortugueseNames(string input, string english, string expected) + { + var reference = english.Length == 0 ? null : ReferenceHint.FromText(english); + Assert.Equal(expected, new PortugueseConverter().Convert(input, reference: reference)); + Assert.Equal(expected, new PortugueseConverter().Convert(expected, reference: reference)); + } + + [Theory] + [InlineData("Talvez eu lembrei errado.", "Talvez eu me tenha lembrado mal.")] + [InlineData("Acho que lembrei errado.", "Acho que me lembrei mal.")] + [InlineData("O que deu errado?", "O que correu mal?")] + [InlineData("Se der errado lá, o que fazes?", "Se correr mal lá, o que fazes?")] + [InlineData("As coisas podem dar errado.", "As coisas podem correr mal.")] + [InlineData("Deu tudo errado.", "Correu tudo mal.")] + [InlineData("Vai dar tudo errado.", "Vai correr tudo mal.")] + [InlineData("Ele deu errado o troco.", "Ele deu errado o troco.")] + [InlineData("Você entendeu tudo errado.", "Percebeste tudo mal.")] + [InlineData("Calculei errado o açúcar.", "Calculei mal o açúcar.")] + [InlineData("Você me ouviu errado.", "Ouviste-me mal.")] + [InlineData("Eu fiz tudo errado.", "Eu fiz tudo mal.")] + [InlineData("Você leu errado.", "Leste mal.")] + [InlineData("Ele está errado.", "Ele está errado.")] + [InlineData("Acho errado.", "Acho errado.")] + [InlineData("Esse é o jogo errado.", "Esse é o jogo errado.")] + [InlineData("Escolheu o programa errado.", "Escolheu o programa errado.")] + [InlineData("Usaram o dado errado.", "Usaram o dado errado.")] + [InlineData("Ele tinha esquecido de ligar.", "Ele tinha-se esquecido de ligar.")] + [InlineData("Eu tinha esquecido do nome dela.", "Eu tinha-me esquecido do nome dela.")] + [InlineData("Você tinha esquecido de mim?", "Tinhas-te esquecido de mim?")] + [InlineData("Ela teria esquecido de tudo.", "Ela ter-se-ia esquecido de tudo.")] + [InlineData("Ele tinha esquecido o nome.", "Ele tinha esquecido o nome.")] + [InlineData("Achei que ele tinha esquecido de mim.", "Achei que ele se tinha esquecido de mim.")] + [InlineData("O que ele tinha esquecido?", "O que ele tinha esquecido?")] + [InlineData("Eles tinham esquecido de trancar a porta.", "Eles tinham-se esquecido de trancar a porta.")] + [InlineData("Nós tínhamos lembrado disso.", "Nós tínhamo-nos lembrado disso.")] + [InlineData("Para você ver você mesmo.", "Para veres por ti mesmo.")] + [InlineData("Veja você mesmo.", "Vê por ti mesmo.")] + [InlineData("Vejam vocês mesmos.", "Vejam por vocês mesmos.")] + [InlineData("Senhor, veja você mesmo.", "Senhor, veja por si mesmo.")] + [InlineData("Faça você mesmo.", "Faz tu mesmo.")] + [InlineData("-Deu errado.\n-Não sabemos que deu errado.", "-Correu mal.\n-Não sabemos que correu mal.")] + public void WrongAsMannerAdverbAndReflexiveCompoundsUseEuropeanForms(string input, string expected) + { + Assert.Equal(expected, new PortugueseConverter().Convert(input)); + Assert.Equal(expected, new PortugueseConverter().Convert(expected)); + } + + [Fact] + public void WhatWentWrongKeepsTheImpersonalSubject() + { + var reference = ReferenceHint.FromText("But unless you can articulate what went wrong, we're done."); + Assert.Equal("Mas, se não disseres\no que correu mal, é isso.", + new PortugueseConverter().Convert("Mas, se não disser\no que deu errado, é isso.", reference: reference)); + } + + [Theory] + [InlineData("-Tinha muita gente neste andar.", "-Havia muita gente neste andar.")] + [InlineData("Não tinha ninguém em casa.", "Não havia ninguém em casa.")] + [InlineData("Tinha um cão quando era miúdo.", "Tinha um cão quando era miúdo.")] + [InlineData("Desculpa por fazer vocês esperarem.", "Desculpem por fazer-vos esperar.")] + [InlineData("Ele nunca fez vocês esperarem.", "Ele nunca vos fez esperar.")] + [InlineData("Não quero deixar vocês irem sozinhos.", "Não quero deixar-vos ir sozinhos.")] + [InlineData("Não foi o que Linda disse-lhe?", "Não foi o que Linda lhe disse?")] + [InlineData("Sei que a Linda disse-lhe tudo.", "Sei que a Linda lhe disse tudo.")] + [InlineData("Quando o Frank viu-me, fugiu.", "Quando o Frank me viu, fugiu.")] + [InlineData("Não disse-lhe nada.", "Não lhe disse nada.")] + [InlineData("Ninguém disse-me nada.", "Ninguém me disse nada.")] + [InlineData("Ele disse-lhe tudo.", "Ele disse-lhe tudo.")] + [InlineData("Não, disse-lhe tudo.", "Não, disse-lhe tudo.")] + [InlineData("Não vou fazê-lo.", "Não vou fazê-lo.")] + [InlineData("Uma das crianças pode ter pego.", "Uma das crianças pode ter pegado.")] + [InlineData("Eu tinha chego tarde.", "Eu tinha chegado tarde.")] + [InlineData("Tenham certeza.", "Tenham a certeza.")] + [InlineData("O único jeito de resolver.", "A única forma de resolver.")] + [InlineData("Ele tem jeito para isso.", "Ele tem jeito para isso.")] + [InlineData("Ela nunca devia ter pego o caso.", "Ela nunca devia ter pegado no caso.")] + [InlineData("Só lembre-se de mim.", "Só lembra-te de mim.")] + [InlineData("Só lembra-te de quem enfrentas.", "Só lembra-te de quem enfrentas.")] + [InlineData("Ele só lembrou-se de mim.", "Ele só se lembrou de mim.")] + [InlineData("Já disse-te a verdade.", "Já te disse a verdade.")] + public void BlueBloodsLeftoversUseEuropeanConstructions(string input, string expected) + { + Assert.Equal(expected, new PortugueseConverter().Convert(input)); + Assert.Equal(expected, new PortugueseConverter().Convert(expected)); + } + + [Theory] + [InlineData("Se não puder, apoie-se na sua família.", "Se não puderes, apoia-te na tua família.")] + [InlineData("Quando chegar, ligue-me.", "Quando chegares, liga-me.")] + [InlineData("Se se sentir mal, deite-se.", "Se te sentires mal, deita-te.")] + [InlineData("Caso precise, chame a polícia.", "Caso precises, chama a polícia.")] + [InlineData("Se ele ligar, avise-me.", "Se ele ligar, avisa-me.")] + [InlineData("Se puder, ligo-te amanhã.", "Se puder, ligo-te amanhã.")] + [InlineData("Senhor, se puder, sente-se.", "Senhor, se puder, sente-se.")] + [InlineData("Desculpe por fazer vocês esperarem.", "Desculpem por fazer-vos esperar.")] + [InlineData("Desculpe pelo vosso carro.", "Desculpem pelo vosso carro.")] + [InlineData("Desculpa, pessoal.", "Desculpem, pessoal.")] + [InlineData("Desculpe pelo atraso.", "Desculpa pelo atraso.")] + [InlineData("Desculpe, Frank.", "Desculpa, Frank.")] + [InlineData("Frank tinha esquecido de ligar.", "Frank tinha-se esquecido de ligar.")] + [InlineData("Ontem tinha esquecido de ligar.", "Ontem tinha esquecido de ligar.")] + [InlineData("Tinhas entendido mal.", "Tinhas percebido mal.")] + [InlineData("Eu tinha entendido tudo.", "Eu tinha percebido tudo.")] + [InlineData("Entendido.", "Entendido.")] + [InlineData("Tudo bem, fique aqui.", "Tudo bem, fica aqui.")] + [InlineData("Se correr mal, chame reforço.", "Se correr mal, chama reforço.")] + [InlineData("Se é o que quer, empreste-me dez mil.", "Se é o que queres, empresta-me dez mil.")] + [InlineData("Quando é seguido, fique parado.", "Quando és seguido, fica parado.")] + [InlineData("Se é proibido, saia.", "Se é proibido, sai.")] + [InlineData("Se for preciso, ligue.", "Se for preciso, liga.")] + [InlineData("Se ele lembrar-se de algo útil, avise-me.", "Se ele se lembrar de algo útil, avisa-me.")] + [InlineData("Se está cansado, durma.", "Se estás cansado, dorme.")] + [InlineData("És bom e ganha sempre.", "És bom e ganhas sempre.")] + [InlineData("Só não ferva minhas bolas de novo.", "Só não fervas as minhas bolas de novo.")] + [InlineData("Não toque minhas bolas.", "Não toques nas minhas bolas.")] + [InlineData("Não toque a minha mão.", "Não toques na minha mão.")] + [InlineData("Ele tocou sua música.", "Ele tocou a sua música.")] + [InlineData("Não corte a corda.", "Não cortes a corda.")] + [InlineData("O corte foi fundo.", "O corte foi fundo.")] + [InlineData("Desculpa fazer vocês celebrarem do meu jeito.", "Desculpem fazer-vos celebrar à minha maneira.")] + [InlineData("Faz do teu jeito.", "Faz à tua maneira.")] + [InlineData("Fiz do jeito dele.", "Fiz à maneira dele.")] + [InlineData("Do jeito que está, não dá.", "Como está, não dá.")] + [InlineData("Não atenda se não quiser falar.", "Não atendas se não quiseres falar.")] + [InlineData("Não cometa o crime,\nse não puder cumprir a pena.", "Não cometas o crime,\nse não puderes cumprir a pena.")] + [InlineData("Não venda a casa.", "Não vendas a casa.")] + [InlineData("Liga-me quando puder.", "Liga-me quando puderes.")] + [InlineData("Sente-se aí.", "Senta-te aí.")] + [InlineData("Não se sente aí.", "Não te sentes aí.")] + [InlineData("Se sentirá diferente amanhã.", "Sentir-se-á diferente amanhã.")] + [InlineData("Se fará justiça.", "Far-se-á justiça.")] + [InlineData("Sinto o meu útero se rasgando ao meio.", "Sinto o meu útero a rasgar-se ao meio.")] + [InlineData("Estás a cuidar de si mesmo.", "Estás a cuidar de ti mesmo.")] + [InlineData("Você devia se livrar dessa gente, não se juntar a eles.", "Devias livrar-te dessa gente, não te juntar a eles.")] + [InlineData("Devias se livrar dela.", "Devias livrar-te dela.")] + [InlineData("Provável demoremos aqui.", "É provável que demoremos aqui.")] + [InlineData("Impossível que ele saiba.", "É impossível que ele saiba.")] + [InlineData("Nunca me retornou sobre o negócio.", "Nunca me respondeu sobre o negócio.")] + [InlineData("Ele me retornou o dinheiro.", "Ele devolveu-me o dinheiro.")] + [InlineData("Vou retornar a ligação.", "Vou devolver a chamada.")] + [InlineData("Vou retornar para casa.", "Vou retornar para casa.")] + [InlineData("Porque você nunca sentava quando vinha aqui.", "Porque nunca te sentavas quando vinhas aqui.")] + [InlineData("Sentamos na mesa.", "Sentamo-nos na mesa.")] + [InlineData("Quando ele sentou, começou.", "Quando ele se sentou, começou.")] + [InlineData("Você sentou ali.", "Sentaste-te ali.")] + [InlineData("Ela sentou o bebé na cadeira.", "Ela sentou o bebé na cadeira.")] + [InlineData("Mentiste para o Lugo.", "Mentiste ao Lugo.")] + [InlineData("Perguntei para a minha mãe.", "Perguntei à minha mãe.")] + [InlineData("Pergunta para o pai vir.", "Pergunta para o pai vir.")] + [InlineData("Tu ligaste quando chegou?", "Tu ligaste quando chegaste?")] + [InlineData("Viste o homem quando chegou?", "Viste o homem quando chegou?")] + [InlineData("Tu choravas quando era tarde.", "Tu choravas quando era tarde.")] + [InlineData("Você bem que podia ajudar.", "Bem que podias ajudar.")] + [InlineData("Ele bem que podia ajudar.", "Ele bem que podia ajudar.")] + [InlineData("Para de se mexer.", "Para de te mexer.")] + [InlineData("Tenta não se machucar.", "Tenta não te magoar.")] + [InlineData("Vem e se junte a nós.", "Vem e junta-te a nós.")] + [InlineData("Vem se sentar aqui.", "Vem sentar-te aqui.")] + [InlineData("Ela adora se divertir.", "Ela adora divertir-se.")] + [InlineData("Cubra o cabelo.", "Cobre o cabelo.")] + [InlineData("Eu te retorno.", "Eu respondo-te.")] + [InlineData("Possível ataque no porto.", "Possível ataque no porto.")] + [InlineData("Tenho perguntas pro papai.", "Tenho perguntas para o pai.")] + [InlineData("Fica quieto e me ligue.", "Fica quieto e liga-me.")] + [InlineData("Respeite isso, entendeu?", "Respeita isso, percebeste?")] + [InlineData("Olhe, ele é bom amigo, mas quando se trata de mulheres, não presta.", "Olha, ele é bom amigo, mas quando se trata de mulheres, não presta.")] + [InlineData("Vamos sair domingo a noite.", "Vamos sair domingo à noite.")] + [InlineData("Saí ontem a noite.", "Saí ontem à noite.")] + [InlineData("Passei sábado a noite toda a ler.", "Passei sábado a noite toda a ler.")] + [InlineData("Vemos-nos amanhã.", "Vemo-nos amanhã.")] + [InlineData("Ouça, não vai contar à minha mãe, certo?", "Ouça, não vai contar à minha mãe, certo?")] + [InlineData("Você adora se abrir demais.", "Adoras abrir-te demais.")] + [InlineData("Você tenta se esconder.", "Tentas esconder-te.")] + [InlineData("Tu precisas de acalmar-se.", "Tu precisas de acalmar-te.")] + [InlineData("Ele deixou-o se vestir.", "Ele deixou-o vestir-se.")] + [InlineData("Ela mandou-nos se sentar.", "Ela mandou-nos sentar.")] + [InlineData("Ele deixa a menina se vestir.", "Ele deixa a menina vestir-se.")] + [InlineData("Eu vi o homem se afogar.", "Eu vi o homem afogar-se.")] + [InlineData("Ela faz as crianças se deitarem cedo.", "Ela faz as crianças deitarem-se cedo.")] + [InlineData("Você viu ele se jogar?", "Viste-o jogar-se?")] + [InlineData("Ele deixa o carro se ganhar.", "Ele deixa o carro se ganhar.")] + [InlineData("Que papo é esse?", "Que conversa é essa?")] + [InlineData("Que papo era aquele?", "Que conversa era aquela?")] + [InlineData("Se faz você se sentir melhor, já me vinguei dele.", "Se te faz sentir melhor, já me vinguei dele.")] + [InlineData("Eu mandei você se calar.", "Eu mandei-te calar.")] + [InlineData("Não que estar certo te ajude.", "Não que estar certo te ajude.")] + [InlineData("O problema é que estar sozinho me assusta.", "O problema é que estar sozinho me assusta.")] + [InlineData("O que você andou fazendo?", "O que andaste a fazer?")] + [InlineData("Eu via você se afastar\nquando eu me aproximava demais", "Eu via-te afastar\nquando eu me aproximava demais")] + [InlineData("Que cara de bunda é essa?", "Que cara de rabo é essa?")] + [InlineData("Mas eu acho você chique demais.", "Mas eu acho-te muito chique.")] + [InlineData("Não acho você bonita.", "Não te acho bonita.")] + [InlineData("Sempre achei você muito inteligente, sabia?", "Sempre te achei muito inteligente, sabia?")] + [InlineData("Ela acha você engraçado e simpático.", "Ela acha-te engraçado e simpático.")] + public void RemainingAddressAndReflexiveGapsUseEuropeanForms(string input, string expected) + => Assert.Equal(expected, new PortugueseConverter().Convert(input)); + + [Theory] + [InlineData("Mandy, como se sentiu\nquando encontrou sua mãe assim?", "Mandy, how did you feel when you found your mother this way?", + "Mandy, como te sentiste\nquando encontraste a tua mãe assim?")] + [InlineData("você só aparece quando precisa de algo,\nnunca me retornou sobre o negócio,", "You only appear when you need something,\nyou never got back to me about the thing,", + "só apareces quando precisas de algo,\nnunca me respondeste sobre o negócio,")] + [InlineData("Pergunte ao Bobby\nquando fizer a oferta.", "You'll have to ask Bobby when you make the offer.", + "Pergunta ao Bobby\nquando fizeres a oferta.")] + [InlineData("Venha me procurar\nquando tiver mais.", "You need to find me... when you have more.", + "Vem procurar-me\nquando tiveres mais.")] + [InlineData("Se sentirá diferente\nquando socar pessoas.", "You might feel differently when you start punching people.", + "Sentir-te-ás diferente\nquando socares pessoas.")] + [InlineData("Serei honesta, Reagan,\nquando mentiu para o Lugo", "I'll be honest with you, Reagan, when you lied to Lugo", + "Serei honesta, Reagan,\nquando mentiste ao Lugo")] + [InlineData("Você podia se beneficiar ao pegar\ndinheiro de Bobby Glass, mas recusou.", "You were offered the benefits\nof taking Bobby Glass's money, but you refused.", + "Podias beneficiar-te ao pegar\ndinheiro de Bobby Glass, mas recusaste.")] + [InlineData("Então, quando ganhar hoje,\nvocê bem que podia me beijar.", "So when you win today, you could kiss me.", + "Então, quando ganhares hoje,\nbem que me podias beijar.")] + [InlineData("Caramba, Eddie,\npor que pergunta se já sabe?", "Jeez, Eddie, why do you ask if you already know?", + "Caramba, Eddie,\nporque perguntas se já sabes?")] + [InlineData("Não pode fazer isso\nse não estiver cuidando de si mesmo.", "You can't really do that if you're not taking care of yourself then.", + "Não podes fazer isso\nse não estiveres a cuidar de ti mesmo.")] + [InlineData("O que está acontecendo?", "What are you doing?", "O que está a acontecer?")] + [InlineData("Por que quer mesmo\ndesistir do seu distintivo?", "Why do you really want to hang up your shield?", + "Porque queres mesmo\ndesistir do teu distintivo?")] + [InlineData("Porque se você não está falhando,\nnão está tentando,", "Because if you aren't failing, you aren't trying,", + "Porque se não estás a falhar,\nnão estás a tentar,")] + [InlineData("Quando você era pequena,\nnão conseguia dormir.", "Yeah, when you were little, you couldn't sleep.", + "Quando eras pequena,\nnão conseguias dormir.")] + [InlineData("O que aconteceu? Do que se lembra?", "Tell me what happened. What do you remember?", + "O que aconteceu? Do que te lembras?")] + [InlineData("Se você acha que é fácil, esquece.", "If you think it's easy, forget it.", + "Se achas que é fácil, esquece.")] + [InlineData("O que se passou?", "What happened to you?", "O que se passou?")] + [InlineData("que lutou para salvar quando\nestava na Comissão Histórica.", "you fought to save when you were on the landmark commission.", + "que lutaste para salvar quando\nestavas na Comissão Histórica.")] + [InlineData("Não faça perguntas\npara as quais não quer a resposta.", "Look, don't ask questions you don't want to know the answer to.", + "Não faças perguntas\npara as quais não queres a resposta.")] + [InlineData("Você mostrou o livro que estava na mesa.", "You showed the book that was on the table.", + "Mostraste o livro que estava na mesa.")] + [InlineData("Desculpe, por que vai apreender?", "Excuse me, why are you taking this?", + "Desculpa, porque vais apreender?")] + [InlineData("Desculpe, mas o senhor vai sair?", "Excuse me, sir, are you leaving?", + "Desculpe, mas o senhor vai sair?")] + [InlineData("Ele quer sair com você\ndomingo a noite, se puder.", "He wants to take you out Sunday night if you're free.", + "Ele quer sair contigo\ndomingo à noite, se puderes.")] + [InlineData("Ele vai te ajudar se puder.", "He'll help you if he can.", "Ele vai ajudar-te se puder.")] + [InlineData("Respeite isso, entendeu?", "You need to respect that, understand?", "Respeita isso, percebeste?")] + [InlineData("Você, fique com a avó, está bem?", "You stay with grandma, okay?", "Tu, fica com a avó, está bem?")] + [InlineData("Você precisa se acalmar.", "You need to calm down.", "Precisas de te acalmar.")] + [InlineData("E você, me viu\nou falou comigo depois do café?", "And you, did you see me or talk to me since breakfast?", + "E tu, viste-me\nou falaste comigo depois do café?")] + [InlineData("Depois que você sabe, não tem volta.", "Once you know, you can't unknow.", "Depois que sabes, não tem volta.")] + [InlineData("Depois que terminou seu aperitivo,\npassou para a entrada.", "After you finished your appetizer, you moved on to the entree.", + "Depois que terminaste o teu aperitivo,\npassaste para a entrada.")] + [InlineData("Tenha modos, porra.", "You watch your manners.", "Tem modos, porra.")] + [InlineData("Saia daqui!", "Get out!", "Sai daqui!")] + [InlineData("Espere aqui, amigo.", "You wait here, pal.", "Espera aqui, amigo.")] + [InlineData("Explique como essa mulher", "Now, you explain to me how this woman", "Explica como esta mulher")] + [InlineData("Avise que o disfarce dele já era.", "You've gotta call him and tell him his cover's blown.", "Avisa que o disfarce dele já era.")] + [InlineData("Você sabe que não.", "You know it's not.", "Sabes que não.")] + [InlineData("Por que decidiu nos ajudar?", "Why did you decide to help us?", "Porque decidiste ajudar-nos?")] + [InlineData("Por que nos ajudou?", "Why did you help us?", "Porque nos ajudaste?")] + [InlineData("Onde o deixou?", "Where did you leave him?", "Onde o deixaste?")] + [InlineData("Onde deixou isso?", "Where did you leave it?", "Onde deixaste isso?")] + [InlineData("Onde colocou a arma?", "Where did you put the gun?", "Onde puseste a arma?")] + [InlineData("Quando chegou a carta?", "When did you get the letter?", "Quando chegou a carta?")] + [InlineData("Por que ele nos ajudou?", "Why did you think he helped us?", "Porque ele nos ajudou?")] + [InlineData("Como ele te achou?", "How did he find you?", "Como ele te achou?")] + [InlineData("Tem o meu número.", "You have my number.\nGive me a call when you get a bead on that kid.", "Tens o meu número.")] + [InlineData("Pode ir aproveitar seu fim de semana.", "You go have your little weekend.", "Podes ir aproveitar o teu fim de semana.")] + [InlineData("Lembra do meu noivo, David.", "You remember my fiancé, David.", "Lembras-te do meu noivo, David.")] + [InlineData("Que papo é esse? Como pode ter certeza?", "What the hell? Um, how... How are you sure though?", "Que conversa é essa? Como podes ter a certeza?")] + [InlineData("Pode pegar um caderninho\nque está na minha bolsa?", "Can you reach into my purse and hand me my tiny notebook?", "Pode pegar num caderninho\nque está na minha bolsa?")] + [InlineData("De que merda está falando?", "What the fuck are you talkin' about?", "De que merda estás a falar?")] + [InlineData("Para que arma se só vai bater na porta?", "Why are you takin' a gun if you just have to knock on the door?", "Para que arma se só vais bater à porta?")] + [InlineData("Isso vai a julgamento mês que vem.", "Would you mind if I take a look? This is going to trial next month.", "Isto vai a julgamento mês que vem.")] + [InlineData("O que andou fazendo?", "what have you been up to?", "O que andaste a fazer?")] + [InlineData("É a última vez que esvaziou isso?", "When was the last time you emptied these?", "É a última vez que esvaziaste isto?")] + [InlineData("E na próxima vez que precisar de ajuda", "And next time you need help", "E na próxima vez que precisares de ajuda")] + [InlineData("para que aprenda com seus erros?", "so that you can learn from your mistake?", "para que aprendas com os teus erros?")] + [InlineData("com que ia nos dizer, Joe?", "what you were gonna tell us, Joe?", "com que nos ias dizer, Joe?")] + [InlineData("Com que vai estourar o balão\ndessa vez?", "What are you gonna pop the balloon with this time?", "Com que vais estourar o balão\ndesta vez?")] + [InlineData("Que teve um problema ruim.", "but you got a bad problem.", "Que tiveste um problema mau.")] + [InlineData("- Que paga muito mais.\n- Pai, você ama seu trabalho.", "A much higher paying job.\nBut Dad, you love your job.", "- Que paga muito mais.\n- Pai, amas o teu trabalho.")] + [InlineData("Para que serve isso?", "What is it for? You know.", "Para que serve isso?")] + [InlineData("Que sorte!", "You are so lucky.", "Que sorte!")] + [InlineData("Que drama é esse com a noite livre?", "You're making way too much of this night off.", "Que drama é esse com a noite livre?")] + [InlineData("Que porra é essa?", "What the fuck is this?", "Que porra é esta?")] + [InlineData("mas eu te acho chique demais.", "but I think you're very chic.", "mas eu acho-te muito chique.")] + public void ReferenceConfirmedSecondPersonClausesUseTu(string input, string english, string expected) + => Assert.Equal(expected, new PortugueseConverter().Convert(input, null, ReferenceHint.FromText(english))); +} diff --git a/se5/BrazilianToEuropeanPortuguese.Tests/ClauseAgreementAnalysisTests.cs b/se5/BrazilianToEuropeanPortuguese.Tests/ClauseAgreementAnalysisTests.cs new file mode 100644 index 00000000..ebc37018 --- /dev/null +++ b/se5/BrazilianToEuropeanPortuguese.Tests/ClauseAgreementAnalysisTests.cs @@ -0,0 +1,141 @@ +using SubtitleEdit.Plugins.BrazilianToEuropeanPortuguese; +using SubtitleEdit.Plugins.Shared; + +namespace BrazilianToEuropeanPortuguese.Tests; + +public sealed class ClauseAgreementAnalysisTests +{ + [Theory] + [InlineData("Certeza?", "Certeza", "NominalUse")] + [InlineData("Ajuda financeira.", "Ajuda", "NominalUse")] + [InlineData("Ela precisa de ajuda.", "precisa", "OtherSubject")] + [InlineData("Maria trabalha aqui.", "trabalha", "OtherSubject")] + [InlineData("É necessário sair.", "É", "Impersonal")] + [InlineData("A pessoa que tu achas que precisa de ajuda.", "precisa", "RelativeSubject")] + [InlineData("A médica que tu pensas que trabalha aqui.", "trabalha", "RelativeSubject")] + [InlineData("Não tens o que fazer.", "fazer", "NonFiniteUse")] + [InlineData("Que miúda esperta tens.", "miúda", "NominalUse")] + public void StructuralReasonsBlockUnsafeAgreement(string text, string verb, string reason) + { + var decision = new ClauseAgreementAnalysis(text).Decide(text.IndexOf(verb, StringComparison.Ordinal), + ReferenceHint.FromText("You think this works.")); + Assert.False(decision.Allowed); + Assert.Equal(reason, decision.Block.ToString()); + } + + [Theory] + [InlineData("Precisa de ajuda.", "Precisa")] + [InlineData("Se não precisar de ajuda.", "precisar")] + [InlineData("Tu sabes que precisa de ajuda.", "precisa")] + [InlineData("Ela saiu. Precisa de ajuda.", "Precisa")] + [InlineData("Ela saiu… Precisa de ajuda.", "Precisa")] + [InlineData("Ela saiu;\nprecisa de ajuda.", "precisa")] + [InlineData("-Ela saiu.\n-Precisa de ajuda.", "Precisa")] + [InlineData("Precisa de ajuda.", "Precisa")] + [InlineData("E está certo.", "está")] + [InlineData("Eu gostaria que confirmasse comigo.", "confirmasse")] + [InlineData("Disseste que sairia.", "sairia")] + [InlineData("Se mentir, é um crime.", "mentir")] + [InlineData("A pessoa que tu achas que você precisa de ajuda.", "precisa")] + public void BoundariesDoNotLeakAnUnrelatedSubject(string text, string verb) + { + var decision = new ClauseAgreementAnalysis(text).Decide(text.IndexOf(verb, StringComparison.Ordinal), + ReferenceHint.FromText("You need help.")); + Assert.True(decision.Allowed); + } + + [Theory] + [InlineData("Ajuda financeira.", "You help financially.", "Ajuda financeira.")] + [InlineData("Conta própria.", "You count on yourself.", "Conta própria.")] + [InlineData("É necessário sair.", "You need to leave.", "É necessário sair.")] + [InlineData("Era possível sair.", "You could leave.", "Era possível sair.")] + [InlineData("É possível.", "You can do it.", "É possível.")] + [InlineData("A médica que você pensa que precisa de ajuda.", "The doctor you think needs help.", + "A médica que pensas que precisa de ajuda.")] + [InlineData("Está falando com um cara que costumava pesar 65kg.", + "You're talking to a guy that used to weigh a buck 45 soaking wet.", + "Estás a falar com um tipo que costumava pesar 65kg.")] + [InlineData("Estamos atrás do cara que comanda o jogo de pôquer.", + "That'll get you killed, all right. The guy we're looking at runs the poker game.", + "Estamos atrás do tipo que comanda o jogo de póquer.")] + [InlineData("Que garota esperta você tem.", "Smart kid you got there.", "Que miúda esperta tens.")] + [InlineData("Não tem o que fazer.", "You have nothing to do.", "Não tens o que fazer.")] + [InlineData("O que significa que Reid terá acabado com dois policiais.", + "And you'll go to jail. Which means Reid takes out two cops.", + "O que significa que Reid terá acabado com dois polícias.")] + public void ReviewedNegativeCasesDoNotChangeMeaning(string source, string english, string expected) => + Assert.Equal(expected, new PortugueseConverter().Convert(source, reference: ReferenceHint.FromText(english))); + + [Theory] + [InlineData("Precisa de ajuda.", "You need help.", "Precisas de ajuda.")] + [InlineData("Se precisar de ajuda.", "If you need help.", "Se precisares de ajuda.")] + [InlineData("Você pensa que precisa de ajuda.", "You think you need help.", "Pensas que precisas de ajuda.")] + [InlineData("Você trabalha aqui e mora perto.", "You work here and you live nearby.", "Trabalhas aqui e vives perto.")] + [InlineData("Então soube que chegou.", "Then I learned you arrived.", "Então soube que chegaste.")] + [InlineData("É possível que ajude.", "You might help.", "É possível que ajudes.")] + [InlineData("E está certo.", "And you'd be right.", "E estás certo.")] + [InlineData("Eu gostaria que confirmasse comigo.", "I wish you would check in with me.", + "Eu gostaria que confirmasses comigo.")] + [InlineData("Você disse que sairia daqui.", "You said you would be out of here.", + "Disseste que sairias daqui.")] + [InlineData("Se mentir, é um crime.", "If you lie, it is a felony.", "Se mentires, é um crime.")] + [InlineData("O serviço que comanda?", "Why don't you tell us about the service you're running?", "O serviço que comandas?")] + [InlineData("O livro que quer ler.", "The book you want to read.", "O livro que queres ler.")] + public void ReviewedPositiveCasesKeepRequiredConversions(string source, string english, string expected) => + Assert.Equal(expected, new PortugueseConverter().Convert(source, reference: ReferenceHint.FromText(english))); + + [Fact] + public void CandidatesRetainMorphologicalAmbiguity() + { + Assert.True(ClauseAgreementAnalysis.Candidates("ajuda").HasFlag(VerbCandidate.ThirdPerson)); + Assert.True(ClauseAgreementAnalysis.Candidates("ajuda").HasFlag(VerbCandidate.NominalHomograph)); + Assert.True(ClauseAgreementAnalysis.Candidates("ajudas").HasFlag(VerbCandidate.SecondPerson)); + Assert.False(ClauseAgreementAnalysis.Candidates("certeza").HasFlag(VerbCandidate.ThirdPerson)); + } + + [Theory] + [InlineData("O que está fazendo?", "What the hell are you doing?", "O que estás a fazer?")] + [InlineData("Pode fazer o que quiser.", "You can do whatever you want.", "Podes fazer o que quiseres.")] + [InlineData("Tem certeza que está pronta?", "You sure you're up for this?", "Tens a certeza que estás pronta?")] + [InlineData("Você lê o que está nos rótulos.", "You read what's on the labels.", + "Lês o que está nos rótulos.")] + [InlineData("É tudo que pode fazer.", "That's all you can do.", "É tudo o que podes fazer.")] + [InlineData("Estou preocupada com o que está fazendo.", + "Are you worried I don't know what I'm doing? I'm worried about what you are doing.", + "Estou preocupada com o que estás a fazer.")] + [InlineData("Dou o tempo que precisar.", "I'll give you as much time as you need.", + "Dou o tempo que precisares.")] + [InlineData("O que sabe da testemunha que desapareceu?", + "What do you know about the witness that disappeared?", + "O que sabes da testemunha que desapareceu?")] + public void ComplementAndObjectRelativeSubjectsRemainDistinct(string source, string english, string expected) => + Assert.Equal(expected, new PortugueseConverter().Convert(source, reference: ReferenceHint.FromText(english))); + + [Fact] + public void FormalAndDisabledAddressStayUnchanged() + { + const string source = "Precisa de ajuda."; + var reference = ReferenceHint.FromText("You need help.")!; + Assert.Equal(source, new PortugueseConverter().Convert(source, reference: reference with { FormalAddress = true })); + Assert.Equal(source, new PortugueseConverter(new ConversionOptions(YouToTu: false)).Convert(source, reference: reference)); + Assert.Equal(source, new PortugueseConverter(new ConversionOptions(DisabledRules: "address")).Convert(source, reference: reference)); + } + + [Fact] + public void SharedPipelinePreservesSelectionOriginalsAndTiming() + { + var blocks = SubRipParser.Parse("1\n00:00:01,000 --> 00:00:02,000\nÉ necessário sair.\n\n" + + "2\n00:00:02,100 --> 00:00:03,000\nPrecisa de ajuda.\n\n"); + var result = SubtitleConversion.Convert(blocks, new ConversionOptions(), + english: new string?[] { "You need to leave.", "You need help." }, selected: new HashSet { 0 }); + Assert.Equal("É necessário sair.", result[0].Text); + Assert.Equal("Precisa de ajuda.", result[1].Text); + Assert.Equal("É necessário sair.", blocks[0].Text); + Assert.Equal(3000L, blocks[1].EndMs); + var selected = SubtitleConversion.Convert(blocks, new ConversionOptions(), + english: new string?[] { "You need to leave.", "You need help." }, selected: new HashSet { 1 }); + Assert.Equal("Precisas de ajuda.", selected[1].Text); + Assert.Equal(2100L, blocks[1].StartMs); + Assert.Equal("Precisa de ajuda.", blocks[1].Text); + } +} diff --git a/se5/BrazilianToEuropeanPortuguese.Tests/ConflictVocabularyTests.cs b/se5/BrazilianToEuropeanPortuguese.Tests/ConflictVocabularyTests.cs new file mode 100644 index 00000000..7adf2660 --- /dev/null +++ b/se5/BrazilianToEuropeanPortuguese.Tests/ConflictVocabularyTests.cs @@ -0,0 +1,147 @@ +using SubtitleEdit.Plugins.BrazilianToEuropeanPortuguese; +using SubtitleEdit.Plugins.Shared; + +namespace BrazilianToEuropeanPortuguese.Tests; + +public sealed class ConflictVocabularyTests +{ + [Theory] + [InlineData("A briga estourou\nfaz 20 minutos.", "Fighting broke out\n20 minutes ago.", + "A luta estourou\nfaz 20 minutos.")] + [InlineData("As brigas terminaram.", "The physical fights ended.", "As lutas terminaram.")] + [InlineData("Uma briga violenta.", "A violent brawl.", "Uma rixa violenta.")] + [InlineData("As brigas violentas.", "The violent brawls.", "As rixas violentas.")] + [InlineData("Uma briga.", "A physical scuffle.", "Uma rixa.")] + [InlineData("A briga foi por dinheiro.", "The argument was about money.", "A discussão foi por dinheiro.")] + [InlineData("As brigas foram por dinheiro.", "The arguments were about money.", "As discussões foram por dinheiro.")] + [InlineData("A briga pela propriedade.", "The dispute over the property.", "A disputa pela propriedade.")] + [InlineData("A briga pelo título.", null, "A luta pelo título.")] + [InlineData("Uma briga de rua.", null, "Uma luta de rua.")] + [InlineData("Uma briga de faca.", null, "Uma luta de faca.")] + [InlineData("Uma briga corpo a corpo.", null, "Uma luta corpo a corpo.")] + [InlineData("A briga contra o câncer.", null, "A luta contra o cancro.")] + [InlineData("A briga verbal.", null, "A discussão verbal.")] + [InlineData("A BRIGA ESTOUROU.", "Fighting broke out.", "A LUTA ESTOUROU.")] + [InlineData("A briga estourou.", "Fighting broke out.", "A luta estourou.")] + [InlineData("Um bate-boca acalorado.", "A heated argument.", "Uma discussão acalorada.")] + [InlineData("Os bate-bocas acalorados.", "The heated arguments.", "As discussões acaloradas.")] + [InlineData("Um bate-boca.", "A chat.", "Uma conversa.")] + [InlineData("Um bate-boca.", "An uproar.", "Uma algazarra.")] + [InlineData("Eles brigaram.", "They fought with their fists.", "Eles lutaram.")] + [InlineData("Ele brigou.", "He fought in battle.", "Ele lutou.")] + [InlineData("Eles estavam brigando.", "They were fighting with their fists.", "Eles estavam a lutar.")] + [InlineData("Ele vai brigar.", "He will fight in battle.", "Ele vai lutar.")] + [InlineData("Se eles brigarem.", "If they fight with their fists.", "Se eles lutarem.")] + [InlineData("Eles brigaram a socos.", null, "Eles lutaram a socos.")] + [InlineData("Eles brigam pela liberdade.", null, "Eles lutam pela liberdade.")] + [InlineData("Ele briga.", "He fights with his fists.", "Ele luta.")] + [InlineData("Tu brigas.", "You fight with your fists.", "Tu lutas.")] + [InlineData("Ele briga por dinheiro.", "He argues about money.", "Ele discute por dinheiro.")] + public void ContextDistinguishesCombatArgumentsAndDisputes(string source, string? english, string expected) => + Assert.Equal(expected, new PortugueseConverter().Convert(source, reference: ReferenceHint.FromText(english))); + + [Theory] + [InlineData("Uma briga.", null, "Uma zanga.")] + [InlineData("Eles brigaram.", null, "Eles discutiram.")] + [InlineData("Eles brigaram.", "They argued about dinner.", "Eles discutiram.")] + [InlineData("Eles brigaram.", "They fight about money.", "Eles discutiram.")] + [InlineData("Estamos brigados.", "We had a fight.", "Estamos brigados.")] + [InlineData("Uma briga de palavras.", "A physical fight.", "Uma zanga de palavras.")] + [InlineData("A luta terminou.", "The argument ended.", "A luta terminou.")] + [InlineData("A zanga terminou.", "The fighting ended.", "A zanga terminou.")] + [InlineData("Obrigado, brigada.", "The fighting ended.", "Obrigado, brigada.")] + [InlineData("Uma briga e uma briga.", "A fight and an argument.", "Uma zanga e uma zanga.")] + [InlineData("Uma pancadaria.", "A brawl.", "Uma pancadaria.")] + [InlineData("Um barraco.", "A small shack.", "Um barraco.")] + [InlineData("Briga começou.", "Fighting started.", "Briga começou.")] + [InlineData("Brigas violentas.", "Violent fights.", "Brigas violentas.")] + [InlineData("Uma briga.", "A fight and an argument.", "Uma zanga.")] + [InlineData("Eles brigaram.", "They argued, then fought.", "Eles discutiram.")] + [InlineData("Eles brigavam como um velho casal.", "They would fight like an old married couple.", + "Eles discutiam como um velho casal.")] + [InlineData("Uma briga doméstica.", "A domestic dispute.", "Uma discussão doméstica.")] + [InlineData("Uma briga.", "A fight.", "Uma zanga.")] + [InlineData("Eles brigaram.", "They fought.", "Eles discutiram.")] + [InlineData("Uma briga.", "A battle of words.", "Uma discussão.")] + [InlineData("Um bate-boca.", "A physical fight.", "Uma discussão.")] + [InlineData("Eles brigaram com o NCIS.", "They got into a scuffle with NCIS over a theory.", + "Eles discutiram com o NCIS.")] + [InlineData("brigue com o NCIS por um palpite\nde que a Força Quds está", + "get into a scuffle with NCIS over some harebrained notion\nthat Quds Force is picking off SEALs", + "discuta com o NCIS por um palpite\nde que a Força Quds está")] + public void AmbiguousAndAlreadyEuropeanReadingsAreNotRewritten(string source, string? english, string expected) => + Assert.Equal(expected, new PortugueseConverter().Convert(source, reference: ReferenceHint.FromText(english))); + + [Fact] + public void SeparateClausesKeepTheirOwnConflictSense() + { + const string source = "A briga acabou. A briga começou."; + var hint = ReferenceHint.FromText("The physical fight ended. The argument started."); + Assert.Equal("A luta acabou. A discussão começou.", new PortugueseConverter().Convert(source, reference: hint)); + Assert.Equal("- Uma luta.\n- Uma discussão.", new PortugueseConverter().Convert("- Uma briga.\n- Uma briga.", + reference: ReferenceHint.FromText("- A physical fight.\n- An argument."))); + } + + [Fact] + public void EveryUnambiguousGeneratedVerbFormRetainsTenseAndPerson() + { + var entry = new VerbEntry("brigar", "discutir", null, null, + new[] { "brigado", "brigada", "brigados", "brigadas" }, new[] { "briga", "brigas" }); + var verbs = new VerbVocabulary(new[] { entry }, _ => false, _ => false); + Assert.True(VerbConjugator.TryConjugate("brigar", out var source)); + Assert.True(VerbConjugator.TryConjugate("lutar", out var combat)); + Assert.True(VerbConjugator.TryConjugate("discutir", out var argument)); + var checkedForms = 0; + foreach (var group in source.Select((form, index) => (form, index)).GroupBy(pair => pair.form)) + { + if (entry.Skip.Contains(group.Key) || group.Select(pair => argument[pair.index]).Distinct().Count() != 1 || + group.Select(pair => combat[pair.index]).Distinct().Count() != 1) continue; + var index = group.First().index; + Assert.Equal("Eles " + combat[index], verbs.Apply("Eles " + group.Key, ReferenceHint.FromText("They fought with their fists."))); + Assert.Equal("Eles " + argument[index], verbs.Apply("Eles " + group.Key, ReferenceHint.FromText("They argued."))); + checkedForms++; + } + Assert.True(checkedForms >= 30, $"Only {checkedForms} inflections checked."); + } + + [Fact] + public void ExistingControlsAndLocalEntriesTakePrecedence() + { + var hint = ReferenceHint.FromText("Fighting broke out.")!; + const string source = "A briga estourou."; + Assert.Equal(source, new PortugueseConverter(new ConversionOptions(Vocabulary: false)).Convert(source, reference: hint)); + Assert.Equal(source, new PortugueseConverter(new ConversionOptions(DisabledRules: "word-list")).Convert(source, reference: hint)); + var ignored = new PortugueseLocalWordList(); + ignored.Ignored.Add("briga"); + Assert.Equal(source, new PortugueseConverter(localWordList: ignored).Convert(source, reference: hint)); + var local = new PortugueseLocalWordList(); + local.Words.Add(("briga", "contenda")); + Assert.Equal("A contenda estourou.", new PortugueseConverter(localWordList: local).Convert(source, reference: hint)); + Assert.Equal("Eles brigaram.", new PortugueseConverter(new ConversionOptions(DisabledRules: "verb-vocabulary")) + .Convert("Eles brigaram.", reference: ReferenceHint.FromText("They fought."))); + var ignoredVerb = new PortugueseLocalWordList(); + ignoredVerb.Ignored.Add("brigar"); + Assert.Equal("Eles brigaram.", new PortugueseConverter(localWordList: ignoredVerb) + .Convert("Eles brigaram.", reference: ReferenceHint.FromText("They fought."))); + var nounOverride = new PortugueseLocalWordList(); + nounOverride.Words.Add(("briga", "disputa")); + Assert.Equal("Ele disputa.", new PortugueseConverter(localWordList: nounOverride) + .Convert("Ele briga.", reference: ReferenceHint.FromText("He fights."))); + } + + [Fact] + public void BatchPipelinePreservesOriginalsTimingsAndRepeatedOutput() + { + const string source = "A briga estourou\nfaz 20 minutos."; + var blocks = new List { new() { StartMs = 1045145, EndMs = 1046574, Text = source } }; + var results = SubtitleConversion.Convert(blocks, new ConversionOptions(), + english: new string?[] { "Fighting broke out\n20 minutes ago." }); + Assert.Equal("A luta estourou\nfaz 20 minutos.", results[0].Text); + Assert.Equal(source, blocks[0].Text); + Assert.Equal(1045145, blocks[0].StartMs); + Assert.Equal(1046574, blocks[0].EndMs); + Assert.Contains(results[0].Rules, r => r.Id == "word-list"); + Assert.Equal(results[0].Text, new PortugueseConverter().Convert(results[0].Text, + reference: ReferenceHint.FromText("Fighting broke out\n20 minutes ago."))); + } +} diff --git a/se5/BrazilianToEuropeanPortuguese.Tests/ConverterTests.cs b/se5/BrazilianToEuropeanPortuguese.Tests/ConverterTests.cs index 3eabc1c4..ca782f0b 100644 --- a/se5/BrazilianToEuropeanPortuguese.Tests/ConverterTests.cs +++ b/se5/BrazilianToEuropeanPortuguese.Tests/ConverterTests.cs @@ -827,7 +827,7 @@ public void ConvertingAgainChangesNothingForAllRegressionExamples() [InlineData("Se afaste.", "Afasta-te.")] [InlineData("Se afastem da porta!", "Afastem-se da porta!")] [InlineData("Se aproxime.", "Aproxima-te.")] - [InlineData("Se sente.", "Sente-se.")] + [InlineData("Se sente.", "Senta-te.")] [InlineData("Se levante!", "Levanta-te!")] [InlineData("Se prepare para sair.", "Prepara-te para sair.")] [InlineData("Se proteja.", "Protege-te.")] @@ -841,7 +841,7 @@ public void ConvertingAgainChangesNothingForAllRegressionExamples() [InlineData("Talvez se afaste.", "Talvez se afaste.")] [InlineData("Se afaste o perigo, ficamos aqui.", "Se afaste o perigo, ficamos aqui.")] [InlineData("Se afaste ele, esperamos.", "Se afaste ele, esperamos.")] - [InlineData("Se sente dor, fale.", "Se sente dor, fale.")] + [InlineData("Se sente dor, fale.", "Se sentes dor, fala.")] [InlineData("Se sente dor.", "Se sente dor.")] public void ReflexiveImperativePlacement(string br, string pt) => AssertConverts(br, pt); @@ -1665,6 +1665,20 @@ public void OwnWordListEntryWinsOverGeneratedForms() Assert.Equal("Vou pôr aqui. Botei ali.", converter.Convert("Vou botar aqui. Botei ali.")); } + [Theory] + [InlineData("Brigas são como uma caixa de chocolates.")] + [InlineData("BRIGAS SÃO COMO UMA CAIXA DE CHOCOLATES.")] + public void BuiltInNounEntriesDoNotLeaveUnmappedVerbMatches(string text) => + Assert.Equal(text, Converter.Convert(text)); + + [Fact] + public void LocalNounEntryWinsOverGeneratedHomograph() + { + var local = new PortugueseLocalWordList(); + local.Words.Add(("bota", "calçado")); + Assert.Equal("Calçado aqui.", new PortugueseConverter(ConversionOptions.Default, local).Convert("Bota aqui.")); + } + [Fact] public void ConjugatorKeepsTheConsonantSound() { @@ -1872,6 +1886,10 @@ public sealed class SlangTests [InlineData("Digo, a justiça ir atrás desse\ncara, por causa do porte.", "Digo, a justiça ir atrás desse\ntipo, por causa do porte.")] [InlineData("- Oi.\nCara, que susto.", "- Olá.\nMeu, que susto.")] [InlineData("Ele é um cara legal.", "Ele é um tipo fixe.")] + [InlineData("desobedece uma ordem legal.", "desobedece uma ordem legal.")] + [InlineData("As ordens legais são válidas.", "As ordens legais são válidas.")] + [InlineData("UMA ORDEM LEGAL.", "UMA ORDEM LEGAL.")] + [InlineData("É legal dar ordens.", "É fixe dar ordens.")] public void BrazilianSlangBecomesEuropean(string text, string expected) => Assert.Equal(expected, Converter.Convert(text)); [Theory] diff --git a/se5/BrazilianToEuropeanPortuguese.Tests/CorpusConstructionTests.cs b/se5/BrazilianToEuropeanPortuguese.Tests/CorpusConstructionTests.cs new file mode 100644 index 00000000..0ce71744 --- /dev/null +++ b/se5/BrazilianToEuropeanPortuguese.Tests/CorpusConstructionTests.cs @@ -0,0 +1,91 @@ +using SubtitleEdit.Plugins.BrazilianToEuropeanPortuguese; +using SubtitleEdit.Plugins.Shared; + +namespace BrazilianToEuropeanPortuguese.Tests; + +public sealed class CorpusConstructionTests +{ + [Theory] + [InlineData("Alguém que você acha que é calmo.", "Someone you think is calm.", "Alguém que achas que é calmo.")] + [InlineData("O homem que você pensa que trabalha aqui.", "The man you think works here.", "O homem que pensas que trabalha aqui.")] + [InlineData("Uma pessoa que você acredita que pode ajudar.", "A person you believe can help.", "Uma pessoa que acreditas que pode ajudar.")] + [InlineData("Alguém que pensa que você é esperto.", "Someone who thinks you're smart.", "Alguém que pensa que és esperto.")] + [InlineData("Você acha que é calmo.", "You think you are calm.", "Achas que és calmo.")] + [InlineData("Diz.", "But you say your experience tells you it's a gun. It does.", "Diz.")] + [InlineData("Sabe.", "You know. He does.", "Sabe.")] + [InlineData("Diz.", "You say.", "Dizes.")] + [InlineData("Continue fazendo isso.", "You keep doing that.", "Continua a fazer isso.")] + [InlineData("Continues fazendo isso.", "I hope you keep doing that.", "Continues a fazer isso.")] + [InlineData("Começa a ganhar dinheiro.", "You start making money.", "Começas a ganhar dinheiro.")] + public void ReferenceAgreementPreservesEmbeddedSubjectsAndCommands(string source, string english, string expected) + { + var converter = new PortugueseConverter(); + var reference = ReferenceHint.FromText(english); + Assert.Equal(expected, converter.Convert(source, reference: reference)); + Assert.Equal(expected, converter.Convert(expected, reference: reference)); + } + + [Theory] + [InlineData("Espero não ter deixado você esperando.", "I hope I didn't keep you waiting.", "Espero não te ter deixado à espera.")] + [InlineData("Tenho deixado você esperando.", "I have kept you waiting.", "Tenho-te deixado à espera.")] + [InlineData("Nunca tinha deixado você esperando.", "I had never kept you waiting.", "Nunca te tinha deixado à espera.")] + [InlineData("Espero não ter deixado você esperando.", "I hope I didn't keep you waiting.", "Espero não te ter deixado à espera.")] + public void KeptWaitingUsesTheExistingAuxiliaryAndCliticRules(string source, string english, string expected) + { + var converter = new PortugueseConverter(); + var reference = ReferenceHint.FromText(english); + Assert.Equal(expected, converter.Convert(source, reference: reference)); + Assert.Equal(expected, converter.Convert(expected, reference: reference)); + } + + [Theory] + [InlineData("e a música ainda tocando?", "e a música ainda a tocar?")] + [InlineData("As pessoas ainda esperando.", "As pessoas ainda a esperar.")] + [InlineData("A DCO na minha casa, tirando fotos.", "A DCO na minha casa, a tirar fotos.")] + [InlineData("A DCO na minha casa tirando fotos.", "A DCO na minha casa a tirar fotos.")] + [InlineData("Na rua correndo.", "Na rua a correr.")] + [InlineData("Na casa Fernando.", "Na casa Fernando.")] + [InlineData("A música é linda.", "A música é linda.")] + [InlineData("A pessoa ainda linda.", "A pessoa ainda linda.")] + [InlineData("Na sala de comando.", "Na sala de comando.")] + [InlineData("Na minha casa, pensando nisso.", "Na minha casa, pensando nisso.")] + [InlineData("Num caso envolvendo apostas.", "Num caso envolvendo apostas.")] + [InlineData("Num contrato incluindo despesas.", "Num contrato incluindo despesas.")] + [InlineData("Num documento contendo dados.", "Num documento contendo dados.")] + public void ProgressiveComplementsPreserveNonverbalAndPunctuatedUses(string source, string expected) + { + var converter = new PortugueseConverter(); + Assert.Equal(expected, converter.Convert(source)); + Assert.Equal(expected, converter.Convert(expected)); + } + + [Fact] + public void OptionsAndIgnoredTextKeepPriority() + { + const string source = "Espero não ter deixado você esperando."; + var reference = ReferenceHint.FromText("I hope I didn't keep you waiting.")!; + Assert.Equal(source, new PortugueseConverter().Convert(source, reference: reference with { FormalAddress = true })); + Assert.Equal(source, new PortugueseConverter(new ConversionOptions(Progressive: false)).Convert(source, reference: reference)); + Assert.Equal(source, new PortugueseConverter(new ConversionOptions(Pronouns: false)).Convert(source, reference: reference)); + Assert.Equal(source, new PortugueseConverter(new ConversionOptions(DisabledRules: "waiting-complements")).Convert(source, reference: reference)); + var list = new PortugueseLocalWordList(); + list.Ignored.Add("deixado você esperando"); + Assert.Equal(source, new PortugueseConverter(localWordList: list).Convert(source, reference: reference)); + Assert.Equal("Espero não ter deixado você esperando.", new PortugueseConverter().Convert(source)); + Assert.Equal("e a música ainda tocando?", new PortugueseConverter(new ConversionOptions(Progressive: false)).Convert("e a música ainda tocando?")); + } + + [Fact] + public void ShortRepliesAndWaitingComplementsPreserveCueTimes() + { + var blocks = SubRipParser.Parse("1\n00:00:01,000 --> 00:00:03,000\nEspero não ter deixado\nvocê esperando.\n\n" + + "2\n00:00:03,100 --> 00:00:04,100\nDiz.\n\n"); + var results = SubtitleConversion.Convert(blocks, new ConversionOptions(), + english: new string?[] { "I hope I didn't keep you waiting.", "You say it. It does." }); + Assert.Equal("Espero não te ter deixado à espera.", string.Join(" ", results[0].Text.Split('\n'))); + Assert.Equal("Diz.", results[1].Text); + Assert.Equal(1000L, blocks[0].StartMs); + Assert.Equal(4100L, blocks[1].EndMs); + Assert.Equal("Espero não ter deixado\nvocê esperando.", blocks[0].Text); + } +} diff --git a/se5/BrazilianToEuropeanPortuguese.Tests/DativeRecipientTests.cs b/se5/BrazilianToEuropeanPortuguese.Tests/DativeRecipientTests.cs new file mode 100644 index 00000000..0caadb18 --- /dev/null +++ b/se5/BrazilianToEuropeanPortuguese.Tests/DativeRecipientTests.cs @@ -0,0 +1,113 @@ +using SubtitleEdit.Plugins.BrazilianToEuropeanPortuguese; +using SubtitleEdit.Plugins.Shared; + +namespace BrazilianToEuropeanPortuguese.Tests; + +public sealed class DativeRecipientTests +{ + [Theory] + [InlineData("Não contou a ela?", "Não lhe contou?")] + [InlineData("Não contou a ele?", "Não lhe contou?")] + [InlineData("Não contou a elas?", "Não lhes contou?")] + [InlineData("Não contou a mim?", "Não me contou?")] + [InlineData("Não contou a ti?", "Não te contou?")] + [InlineData("Não contou a nós?", "Não nos contou?")] + [InlineData("Nunca contei a eles.", "Nunca lhes contei.")] + [InlineData("Contei a ela.", "Contei-lhe.")] + [InlineData("Ele explicou a elas.", "Ele explicou-lhes.")] + [InlineData("Eu perguntei a ele.", "Eu perguntei-lhe.")] + [InlineData("Ela respondeu a mim.", "Ela respondeu-me.")] + [InlineData("Ele escreveu a ti.", "Ele escreveu-te.")] + [InlineData("Ela telefonou a nós.", "Ela telefonou-nos.")] + [InlineData("Eu paguei a ela.", "Eu paguei-lhe.")] + [InlineData("Ela mentiu a ele.", "Ela mentiu-lhe.")] + [InlineData("Ele enviou a elas.", "Ele enviou-lhes.")] + [InlineData("Disse a ela a verdade.", "Disse-lhe a verdade.")] + [InlineData("Dei a ela tudo.", "Dei-lhe tudo.")] + [InlineData("Não entregou a ela?", "Não lhe entregou?")] + [InlineData("Ela emprestou a ele.", "Ela emprestou-lhe.")] + [InlineData("Contava a ela.", "Contava-lhe.")] + [InlineData("Contámos a ela.", "Contámos-lhe.")] + [InlineData("Se contássemos a ela.", "Se lhe contássemos.")] + [InlineData("Se déssemos a ela.", "Se lhe déssemos.")] + [InlineData("Se dermos a ela.", "Se lhe dermos.")] + [InlineData("Não daríamos a elas.", "Não lhes daríamos.")] + [InlineData("Se respondermos a eles.", "Se lhes respondermos.")] + [InlineData("Se contar a ela.", "Se lhe contar.")] + [InlineData("Se contasse a ela.", "Se lhe contasse.")] + [InlineData("Contarei a ela.", "Contar-lhe-ei.")] + [InlineData("Contaria a elas.", "Contar-lhes-ia.")] + [InlineData("Não contaria a ela.", "Não lhe contaria.")] + [InlineData("Vou contar a ela.", "Vou contar-lhe.")] + [InlineData("Pedi a ela para sair.", "Pedi-lhe para sair.")] + [InlineData("Sei que a Maria contou a ela.", "Sei que a Maria lhe contou.")] + [InlineData("Não contou isso a ela?", "Não lhe contou isso?")] + [InlineData("Contou tudo a eles.", "Contou-lhes tudo.")] + [InlineData("Ele deu o livro a ela.", "Ele deu-lhe o livro.")] + [InlineData("Não mostrou a casa a ele.", "Não lhe mostrou a casa.")] + [InlineData("Contei a verdade a ela.", "Contei-lhe a verdade.")] + [InlineData("Não contou\na ela?", "Não\nlhe contou?")] + [InlineData("Não contou para ela?", "Não lhe contou?")] + [InlineData("Não contou isso para ela?", "Não lhe contou isso?")] + [InlineData("Contou a ela e saiu.", "Contou-lhe e saiu.")] + [InlineData("Ele lhe contou a ela.", "Ele contou-lhe a ela.")] + [InlineData("NÃO CONTOU A ELA?", "NÃO LHE CONTOU?")] + [InlineData("Não contou a ela?", "Não lhe contou?")] + public void NeutralRecipientsUseDativeClitics(string source, string expected) + { + var converter = new PortugueseConverter(); + Assert.Equal(expected, converter.Convert(source)); + Assert.Equal(expected, converter.Convert(expected)); + } + + [Theory] + [InlineData("Contou a ela mesma.")] + [InlineData("Contou para ela mesma.")] + [InlineData("Contou a ela própria.")] + [InlineData("Contei a ELA.")] + [InlineData("Não contou a ela nem a ele.")] + [InlineData("Contou a ela, mas não a ele.")] + [InlineData("Contou a ela e à mãe.")] + [InlineData("Contou a ela e a mim.")] + [InlineData("Contou a ela ou a ele.")] + [InlineData("Contou a ela e ele.")] + [InlineData("Contou a ela, não a ele.")] + [InlineData("Contou isso a ela e a ele.")] + [InlineData("Contou a verdade a ela mesma.")] + [InlineData("Ele contou-lhe a ela.")] + [InlineData("Contou apenas a ela.")] + [InlineData("Isso não conta para ela.")] + [InlineData("Isso dá para ela.")] + [InlineData("A conta a ela pertence.")] + [InlineData("Ela voltou a ele.")] + [InlineData("Ela pensou a respeito.")] + [InlineData("Vou comprar um presente a ela.")] + [InlineData("Telefonei para ela saber.")] + public void EmphasisCoordinationAndNonDativeUsesArePreserved(string source) => + Assert.Equal(source, new PortugueseConverter().Convert(source)); + + [Fact] + public void PronounOptionsAndDisabledStageAreRespected() + { + foreach (var options in new[] + { + new ConversionOptions(Pronouns: false), + new ConversionOptions(DisabledRules: "pronouns"), + }) + Assert.Equal("Não contou a ela?", new PortugueseConverter(options).Convert("Não contou a ela?")); + } + + [Fact] + public void ReportedCueKeepsItsTenseAndTimingInFormalAndDefaultConversion() + { + foreach (var options in new[] { ConversionOptions.Default, new ConversionOptions(Address: AddressMode.Formal) }) + { + var cue = new SrtBlock { StartMs = 1934133, EndMs = 1936092, Text = "Não contou a ela?" }; + var converted = Assert.Single(SubtitleConversion.Convert(new[] { cue }, options, + english: new string?[] { "What, you didn't tell her?" })); + Assert.Equal("Não lhe contou?", converted.Text); + Assert.Equal(1934133, cue.StartMs); + Assert.Equal(1936092, cue.EndMs); + } + } +} diff --git a/se5/BrazilianToEuropeanPortuguese.Tests/DialogueReplyTests.cs b/se5/BrazilianToEuropeanPortuguese.Tests/DialogueReplyTests.cs index 4a881563..8437e9c2 100644 --- a/se5/BrazilianToEuropeanPortuguese.Tests/DialogueReplyTests.cs +++ b/se5/BrazilianToEuropeanPortuguese.Tests/DialogueReplyTests.cs @@ -30,7 +30,8 @@ public void ReplyAndReportedClauseUseConfirmedSubjects(string source, string eng [Theory] [InlineData("Ligue para João?", "Call John?", "Ligo para o João?")] - [InlineData("Ligue para Jamie?", "Call Jamie?", "Ligo para o Jamie?")] + [InlineData("Ligue para Kevin?", "Call Kevin?", "Ligo para o Kevin?")] + [InlineData("Ligue para Jamie?", "Call Jamie?", "Ligo para Jamie?")] [InlineData("Telefone para Maria?", "Phone Maria?", "Telefono para a Maria?")] [InlineData("Pergunte ao João?", "Ask John?", "Pergunto ao João?")] [InlineData("Espere aqui?", "Wait here?", "Espero aqui?")] diff --git a/se5/BrazilianToEuropeanPortuguese.Tests/FerrarSlangTests.cs b/se5/BrazilianToEuropeanPortuguese.Tests/FerrarSlangTests.cs new file mode 100644 index 00000000..26938a1e --- /dev/null +++ b/se5/BrazilianToEuropeanPortuguese.Tests/FerrarSlangTests.cs @@ -0,0 +1,77 @@ +using SubtitleEdit.Plugins.BrazilianToEuropeanPortuguese; +using SubtitleEdit.Plugins.Shared; + +namespace BrazilianToEuropeanPortuguese.Tests; + +public sealed class FerrarSlangTests +{ + [Theory] + [InlineData("Ferrei tudo,", "Lixei tudo,")] + [InlineData("Ferraste tudo.", "Lixaste tudo.")] + [InlineData("Ela ferrou o negócio.", "Ela lixou o negócio.")] + [InlineData("Ferramos tudo.", "Lixamos tudo.")] + [InlineData("Ferrámos tudo.", "Lixámos tudo.")] + [InlineData("Ferraram a minha vida.", "Lixaram a minha vida.")] + [InlineData("Estou ferrado.", "Estou lixado.")] + [InlineData("Estou completamente ferrado.", "Estou completamente lixado.")] + [InlineData("Ferrei com tudo.", "Lixei tudo.")] + [InlineData("Estamos ferradas.", "Estamos lixadas.")] + [InlineData("Eu me ferrei.", "Eu lixei-me.")] + [InlineData("Não se ferre.", "Não te lixes.")] + [InlineData("Ferrar tudo.", "Lixar tudo.")] + [InlineData("FERREI TUDO!", "LIXEI TUDO!")] + [InlineData("Ferrei tudo.", "Lixei tudo.")] + [InlineData("-Ferrei tudo.", "-Lixei tudo.")] + [InlineData("Ele ferrou você.", "Ele lixou-te.")] + [InlineData("Não me ferres.", "Não me lixes.")] + [InlineData("Vou ferrar-me.", "Vou lixar-me.")] + [InlineData("Ferraria tudo.", "Lixaria tudo.")] + [InlineData("Se ferrasse tudo.", "Se lixasse tudo.")] + [InlineData("Ela está ferrando tudo.", "Ela está a lixar tudo.")] + [InlineData("Vou ferrá-lo.", "Vou ferrá-lo.")] + public void QualifiedSlangUsesLixarAcrossInflections(string source, string expected) + { + var converter = new PortugueseConverter(); + Assert.Equal(expected, converter.Convert(source)); + Assert.Equal(expected, converter.Convert(expected)); + } + + [Theory] + [InlineData("Eu ferrei a viagem.", "I screwed up the trip.", "Eu lixei a viagem.")] + [InlineData("Ele ferrou o cliente.", "He screwed the client over.", "Ele lixou o cliente.")] + [InlineData("Ela ferrou.", "She screwed up.", "Ela lixou.")] + public void EnglishSlangCanResolveOtherObjects(string source, string english, string expected) => + Assert.Equal(expected, new PortugueseConverter().Convert(source, reference: ReferenceHint.FromText(english))); + + [Theory] + [InlineData("Ferrei o cavalo.")] + [InlineData("Ele ferrou o gado.")] + [InlineData("O gato ferrou as unhas.")] + [InlineData("Ela ferrou no sono.")] + [InlineData("Ferrou-lhe uma reprimenda.")] + [InlineData("Ela ferrou.")] + [InlineData("Ele ferrou-se a trabalhar.")] + [InlineData("Ela ferrou-se a uma ideia.")] + [InlineData("Ele ferrou-a pelo braço.")] + [InlineData("Ferraram-se a dormir.")] + public void LiteralAndUnresolvedUsesArePreserved(string source) => + Assert.Equal(source, new PortugueseConverter().Convert(source)); + + [Theory] + [InlineData("Ferrei tudo.", "Lixei tudo.")] + [InlineData("Não se ferre.", "Não se lixe.")] + public void FormalAddressDoesNotDisableVocabulary(string source, string expected) => + Assert.Equal(expected, Assert.Single(SubtitleConversion.Convert( + new[] { new SrtBlock { StartMs = 1000, EndMs = 2000, Text = source } }, + new ConversionOptions(Address: AddressMode.Formal))).Text); + + [Fact] + public void OptionsStageAndLocalOverrideAreRespected() + { + Assert.Equal("Ferrei tudo.", new PortugueseConverter(new ConversionOptions(Vocabulary: false)).Convert("Ferrei tudo.")); + Assert.Equal("Ferrei tudo.", new PortugueseConverter(new ConversionOptions(DisabledRules: "construction-vocabulary")).Convert("Ferrei tudo.")); + var words = new PortugueseLocalWordList(); + words.Ignored.Add("ferrar"); + Assert.Equal("Ferrei tudo.", new PortugueseConverter(localWordList: words).Convert("Ferrei tudo.")); + } +} diff --git a/se5/BrazilianToEuropeanPortuguese.Tests/FirstPluralCliticTests.cs b/se5/BrazilianToEuropeanPortuguese.Tests/FirstPluralCliticTests.cs new file mode 100644 index 00000000..5f7bf953 --- /dev/null +++ b/se5/BrazilianToEuropeanPortuguese.Tests/FirstPluralCliticTests.cs @@ -0,0 +1,71 @@ +using SubtitleEdit.Plugins.BrazilianToEuropeanPortuguese; +using SubtitleEdit.Plugins.Shared; + +namespace BrazilianToEuropeanPortuguese.Tests; + +public sealed class FirstPluralCliticTests +{ + [Theory] + [InlineData("-Ryan Young.\n-Nós o viramos.", "Ryan Young.\nWe flipped him.", "-Ryan Young.\n-Nós virámo-lo.")] + [InlineData("Nós o viramos.", "We flipped him.", "Nós virámo-lo.")] + [InlineData("Nós a compramos.", "We bought it.", "Nós comprámo-la.")] + [InlineData("Nós os chamamos.", "We called them.", "Nós chamámo-los.")] + [InlineData("Nós as encontramos.", "We found them.", "Nós encontrámo-las.")] + [InlineData("Nós o viramos.", "We turn him.", "Nós viramo-lo.")] + [InlineData("Nós o viramos.", null, "Nós viramo-lo.")] + [InlineData("Nós o virámos.", null, "Nós virámo-lo.")] + [InlineData("Nós o vimos.", "We saw him.", "Nós vimo-lo.")] + [InlineData("Nós o encontramos.", "We will find him.", "Nós encontramo-lo.")] + [InlineData("NÓS O VIRAMOS.", "We flipped him.", "NÓS VIRÁMO-LO.")] + [InlineData("Nós os abraçamos.", "We hugged them yesterday.", "Nós abraçámo-los.")] + [InlineData("Nós o viramos.", "We wanted to flip him.", "Nós viramo-lo.")] + [InlineData("Nós o viramos.", "We were told to flip him.", "Nós viramo-lo.")] + [InlineData("Nós o viramos.", "We turn him. They found it.", "Nós viramo-lo.")] + [InlineData("Nós o viramos.", "We helped him. We turned him.", "Nós viramo-lo.")] + [InlineData("Nós não o viramos.", "We didn't turn him.", "Nós não o viramos.")] + [InlineData("Ela disse que nós o viramos.", "She said that we turned him.", "Ela disse que nós o viramos.")] + public void FirstPluralObjectCliticsRespectTenseAndAttraction(string source, string? english, string expected) + { + var converter = new PortugueseConverter(); + var reference = ReferenceHint.FromText(english); + Assert.Equal(expected, converter.Convert(source, reference: reference)); + Assert.Equal(expected, converter.Convert(expected, reference: reference)); + } + + [Fact] + public void CliticConversionCanBeDisabled() + { + var converter = new PortugueseConverter(new ConversionOptions(Pronouns: false)); + Assert.Equal("Nós o viramos.", converter.Convert("Nós o viramos.", + reference: ReferenceHint.FromText("We flipped him."))); + } + + [Fact] + public void CliticStageCanBeDisabled() + { + var converter = new PortugueseConverter(new ConversionOptions(DisabledRules: "pronouns")); + Assert.Equal("Nós o viramos.", converter.Convert("Nós o viramos.", + reference: ReferenceHint.FromText("We flipped him."))); + } + + [Fact] + public void TimingAlignedReferencesResolveBothReportedCases() + { + var source = new[] + { + new SrtBlock { StartMs = 1000, EndMs = 2500, Text = "-Ryan Young.\n-Nós o viramos." }, + new SrtBlock { StartMs = 4000, EndMs = 6000, Text = "Não preste atenção nestes." }, + }; + var english = new[] + { + new SrtBlock { StartMs = 950, EndMs = 1600, Text = "Ryan Young." }, + new SrtBlock { StartMs = 1601, EndMs = 2600, Text = "We flipped him." }, + new SrtBlock { StartMs = 4000, EndMs = 6000, Text = "Oh, don't pay any attention\nto those." }, + }; + var alignment = ReferenceAligner.AlignByTiming(source, english); + var result = SubtitleConversion.Convert(source, new ConversionOptions(YouToTu: false), english: alignment.Texts); + Assert.Equal("-Ryan Young.\n-Nós virámo-lo.", result[0].Text); + Assert.Equal("Não preste atenção a esses.", result[1].Text); + Assert.Equal("Não preste atenção nestes.", source[1].Text); + } +} diff --git a/se5/BrazilianToEuropeanPortuguese.Tests/InformalPredicateTests.cs b/se5/BrazilianToEuropeanPortuguese.Tests/InformalPredicateTests.cs index 13aa65ee..aa9f8b3b 100644 --- a/se5/BrazilianToEuropeanPortuguese.Tests/InformalPredicateTests.cs +++ b/se5/BrazilianToEuropeanPortuguese.Tests/InformalPredicateTests.cs @@ -5,6 +5,34 @@ namespace BrazilianToEuropeanPortuguese.Tests; public sealed class InformalPredicateTests { + [Theory] + [InlineData("Desculpa.", "You took my seat. I'm sorry.", "Desculpa.")] + [InlineData("Certeza?", "You sure?", "Certeza?")] + [InlineData("Não faz sentido.", "You know, it just doesn't make sense.", "Não faz sentido.")] + [InlineData("Não está certo, cara.", "You know, it's not right, bro.", "Não está certo, meu.")] + [InlineData("Não é assustador.", "You're starting to scare me. That's not scary.", "Não é assustador.")] + [InlineData("Não é catastrófico?", "You consider that catastrophic?", "Não é catastrófico?")] + [InlineData("Não é egoísta.", "You're not selfish.", "Não és egoísta.")] + [InlineData("Não abriu.", "You never opened it.", "Não abriste.")] + [InlineData("Sabe.", "You know.", "Sabes.")] + [InlineData("Será adulto.", "You'll be an adult.", "Serás adulto.")] + [InlineData("Seria adulto.", "You'd be an adult.", "Serias adulto.")] + [InlineData("Não faz sentido.", "You know, that doesn't make sense.", "Não faz sentido.")] + [InlineData("Anda dizendo que sou corrupto.", "You're telling people I'm corrupt. I'm not your friend.", + "Andas a dizer que sou corrupto.")] + [InlineData("Roubou a minha frase.", "You stole my line. I'm sorry.", "Roubaste a minha frase.")] + [InlineData("É adulto.", "You are an adult. I agree.", "És adulto.")] + [InlineData("É policial?", "You a cop?", "És polícia?")] + [InlineData("Acho que precisa de ajuda.", "You know, John needs help.", "Acho que precisa de ajuda.")] + [InlineData("Sei que precisa de ajuda.", "You know, you need help.", "Sei que precisas de ajuda.")] + public void ReferenceHeadsDoNotInventNominalOrImpersonalSubjects(string source, string english, string expected) + { + var converter = new PortugueseConverter(); + var reference = ReferenceHint.FromText(english); + Assert.Equal(expected, converter.Convert(source, reference: reference)); + Assert.Equal(expected, converter.Convert(expected, reference: reference)); + } + [Theory] [InlineData("no que Maria diria se\ncontasse que iria parar.", "what Maria would say if you told her you were gonna quit.", diff --git a/se5/BrazilianToEuropeanPortuguese.Tests/NounSubjectDirectCliticTests.cs b/se5/BrazilianToEuropeanPortuguese.Tests/NounSubjectDirectCliticTests.cs new file mode 100644 index 00000000..d53ffb67 --- /dev/null +++ b/se5/BrazilianToEuropeanPortuguese.Tests/NounSubjectDirectCliticTests.cs @@ -0,0 +1,53 @@ +using SubtitleEdit.Plugins.BrazilianToEuropeanPortuguese; + +namespace BrazilianToEuropeanPortuguese.Tests; + +public sealed class NounSubjectDirectCliticTests +{ + [Theory] + [InlineData("A família a registrou\nno acampamento,", "A família registou-a\nno acampamento,")] + [InlineData("A família a registou no acampamento.", "A família registou-a no acampamento.")] + [InlineData("A família o registou.", "A família registou-o.")] + [InlineData("A família os registou.", "A família registou-os.")] + [InlineData("A família as registou.", "A família registou-as.")] + [InlineData("A minha família a registou.", "A minha família registou-a.")] + [InlineData("Maria a viu.", "Maria viu-a.")] + [InlineData("O professor o ouviu.", "O professor ouviu-o.")] + [InlineData("O professor a vê.", "O professor vê-a.")] + [InlineData("Os pais a encontraram.", "Os pais encontraram-na.")] + [InlineData("A FAMÍLIA A REGISTOU.", "A FAMÍLIA REGISTOU-A.")] + [InlineData("A família a registou.", "A família registou-a.")] + public void NounSubjectsPlaceDirectObjectsAfterValidatedFiniteVerbs(string source, string expected) + { + var converter = new PortugueseConverter(); + Assert.Equal(expected, converter.Convert(source)); + Assert.Equal(expected, converter.Convert(expected)); + } + + [Theory] + [InlineData("A família não a registou.")] + [InlineData("A família já a registou.")] + [InlineData("Se a família a registou.")] + [InlineData("Disse que a família a registou.")] + [InlineData("Quem a registou?")] + [InlineData("A família a registará.")] + [InlineData("A família a registaria.")] + [InlineData("A família a casa.")] + [InlineData("Maria a ajuda financeira.")] + [InlineData("É bom o ver.")] + [InlineData("Ele aparafusou a peça.")] + [InlineData("Esse é o jogo errado.")] + [InlineData("Sinto o cheiro.")] + [InlineData("venceu o teste de ADN?")] + [InlineData("venceram o teste de ADN?")] + public void ArticlesAttractorsAndNonFiniteOrFutureUsesStayUnchanged(string source) => + Assert.Equal(source, new PortugueseConverter().Convert(source)); + + [Fact] + public void PronounOptionAndStageControlTheRule() + { + const string source = "A família a registou."; + Assert.Equal(source, new PortugueseConverter(new ConversionOptions(Pronouns: false)).Convert(source)); + Assert.Equal(source, new PortugueseConverter(new ConversionOptions(DisabledRules: "pronouns")).Convert(source)); + } +} diff --git a/se5/BrazilianToEuropeanPortuguese.Tests/NounSubjectReflexiveTests.cs b/se5/BrazilianToEuropeanPortuguese.Tests/NounSubjectReflexiveTests.cs new file mode 100644 index 00000000..bd3a6201 --- /dev/null +++ b/se5/BrazilianToEuropeanPortuguese.Tests/NounSubjectReflexiveTests.cs @@ -0,0 +1,47 @@ +using SubtitleEdit.Plugins.BrazilianToEuropeanPortuguese; + +namespace BrazilianToEuropeanPortuguese.Tests; + +public sealed class NounSubjectReflexiveTests +{ + [Theory] + [InlineData("A revolta se espalhou para\noutro bloco de celas.", "A revolta espalhou-se para\noutro bloco de celas.")] + [InlineData("A notícia se espalhou.", "A notícia espalhou-se.")] + [InlineData("A família se reuniu.", "A família reuniu-se.")] + [InlineData("O rapaz se levantou.", "O rapaz levantou-se.")] + [InlineData("Maria se levantou.", "Maria levantou-se.")] + [InlineData("Os alunos se levantaram.", "Os alunos levantaram-se.")] + [InlineData("A REVOLTA SE ESPALHOU.", "A REVOLTA ESPALHOU-SE.")] + [InlineData("A revolta se espalhou.", "A revolta espalhou-se.")] + public void NounSubjectsAlsoSupportReflexiveSe(string source, string expected) + { + var converter = new PortugueseConverter(); + Assert.Equal(expected, converter.Convert(source)); + Assert.Equal(expected, converter.Convert(expected)); + } + + [Theory] + [InlineData("A revolta não se espalhou.")] + [InlineData("A revolta já se espalhou.")] + [InlineData("Disse que a revolta se espalhou.")] + [InlineData("Se a revolta se espalhou.")] + [InlineData("A revolta se espalhar.")] + [InlineData("A revolta se espalhará.")] + [InlineData("A revolta se espalharia.")] + [InlineData("Pergunta se conhece Maria.")] + [InlineData("Não sei se precisa.")] + public void AttractorsNonFiniteUsesAndConditionalSeArePreserved(string source) => + Assert.Equal(source, new PortugueseConverter().Convert(source)); + + [Fact] + public void OptionAndStageAreRespected() + { + const string source = "A revolta se espalhou."; + Assert.Equal(source, new PortugueseConverter(new ConversionOptions(Pronouns: false)).Convert(source)); + Assert.Equal(source, new PortugueseConverter(new ConversionOptions(DisabledRules: "pronouns")).Convert(source)); + } + + [Fact] + public void CoordinatedCommandsKeepInformalReflexives() => + Assert.Equal("Vem e junta-te a nós.", new PortugueseConverter().Convert("Vem e se junte a nós.")); +} diff --git a/se5/BrazilianToEuropeanPortuguese.Tests/OrthographyTests.cs b/se5/BrazilianToEuropeanPortuguese.Tests/OrthographyTests.cs index dff7bddc..b5b7dce5 100644 --- a/se5/BrazilianToEuropeanPortuguese.Tests/OrthographyTests.cs +++ b/se5/BrazilianToEuropeanPortuguese.Tests/OrthographyTests.cs @@ -13,6 +13,30 @@ namespace BrazilianToEuropeanPortuguese.Tests; public sealed class OrthographyTests { + [Theory] + [InlineData("depois da meia noite.", "depois da meia-noite.")] + [InlineData("Meia noite de domingo.", "Meia-noite de domingo.")] + [InlineData("À MEIA NOITE.", "À MEIA-NOITE.")] + [InlineData("meia noite", "meia-noite")] + [InlineData("meia-noite", "meia-noite")] + [InlineData("meia noite inteira", "meia-noite inteira")] + public void MidnightIsHyphenatedInBothOrthographies(string source, string expected) + { + foreach (var postAgreement in new[] { false, true }) + Assert.Equal(expected, new PortugueseConverter(new ConversionOptions(PostAgreement: postAgreement)).Convert(source)); + } + + [Fact] + public void MidnightSpellingRespectsOptionsAndIgnoredText() + { + const string source = "meia noite"; + Assert.Equal(source, new PortugueseConverter(new ConversionOptions(Spelling: false)).Convert(source)); + Assert.Equal(source, new PortugueseConverter(new ConversionOptions(DisabledRules: "orthography")).Convert(source)); + var list = new PortugueseLocalWordList(); + list.Ignored.Add(source); + Assert.Equal(source, new PortugueseConverter(localWordList: list).Convert(source)); + } + [Theory] [InlineData("Baseada em que?", "Baseada em quê?")] [InlineData("Estão a falar de que?", "Estão a falar de quê?")] diff --git a/se5/BrazilianToEuropeanPortuguese.Tests/PersonalNameArticlesTests.cs b/se5/BrazilianToEuropeanPortuguese.Tests/PersonalNameArticlesTests.cs new file mode 100644 index 00000000..2ef35663 --- /dev/null +++ b/se5/BrazilianToEuropeanPortuguese.Tests/PersonalNameArticlesTests.cs @@ -0,0 +1,135 @@ +using SubtitleEdit.Plugins.BrazilianToEuropeanPortuguese; +using SubtitleEdit.Plugins.Shared; +using System.Text.Json; + +namespace BrazilianToEuropeanPortuguese.Tests; + +public sealed class PersonalNameArticlesTests +{ + [Fact] + public void UnresolvedNamesAreCollectedOnlyAtSupportedArticleDecisions() + { + var unresolved = new HashSet(StringComparer.OrdinalIgnoreCase); + var converter = new PortugueseConverter(unresolvedNameArticles: unresolved); + converter.Convert("Jamie chegou."); + converter.Convert("pensar em João e em Maria."); + converter.Convert("pensar em soluções."); + converter.Convert("pensar em Jamie e em Jamie."); + Assert.Equal(new[] { "Jamie" }, unresolved); + unresolved.Clear(); + converter.Convert("Ligue para Alex?", reference: ReferenceHint.FromText("Should I call Alex?")); + Assert.Equal(new[] { "Alex" }, unresolved); + unresolved.Clear(); + converter.Convert("Sobre o que você e Xanthe discutiram?", + reference: ReferenceHint.FromText("What did you and Xanthe fight about?")); + Assert.Equal(new[] { "Xanthe" }, unresolved); + } + + [Fact] + public void SavedChoicesAndDisabledStagesDoNotReportNames() + { + var unresolved = new HashSet(); + var options = new ConversionOptions(NameArticles: "Jamie = none\nAlex = a"); + new PortugueseConverter(options, unresolvedNameArticles: unresolved).Convert("pensar em Jamie e em Alex."); + Assert.Empty(unresolved); + options = new ConversionOptions(DisabledRules: "personal-name-complements,action-questions,natural-word-order"); + var converter = new PortugueseConverter(options, unresolvedNameArticles: unresolved); + converter.Convert("pensar em Jamie."); + converter.Convert("Ligue para Alex?", reference: ReferenceHint.FromText("Should I call Alex?")); + converter.Convert("Sobre o que você e Xanthe discutiram?", + reference: ReferenceHint.FromText("What did you and Xanthe fight about?")); + Assert.Empty(unresolved); + new PortugueseConverter(new ConversionOptions(Pronouns: false), unresolvedNameArticles: unresolved) + .Convert("pensar em Jamie."); + Assert.Empty(unresolved); + } + + [Fact] + public void SelectionLimitsNameQuestionsAndSettingsRememberOptOut() + { + var unresolved = new HashSet(); + var blocks = new List + { + new() { StartMs = 1000, EndMs = 2000, Text = "pensar em Jamie." }, + new() { StartMs = 3000, EndMs = 4000, Text = "pensar em Alex." }, + }; + SubtitleConversion.Convert(blocks, ConversionOptions.Default, selected: new HashSet { 1 }, + unresolvedNameArticles: unresolved); + Assert.Equal(new[] { "Alex" }, unresolved); + Assert.True(ConversionOptions.Load(new PluginRequest()).AskNameArticles); + var options = new ConversionOptions(AskNameArticles: false); + Assert.False(ConversionOptions.Load(new PluginRequest + { SettingsVersion = ConversionOptions.Version, Settings = options.ToJson() }).AskNameArticles); + } + + [Theory] + [InlineData("Jamie = o", "pensar em Jamie.", "pensar no Jamie.", "Ligo para o Jamie?")] + [InlineData("jamie = a", "pensar em Jamie.", "pensar na Jamie.", "Ligo para a Jamie?")] + [InlineData("Maria = o", "pensar em Maria.", "pensar no Maria.", "Ligo para o Maria?")] + [InlineData("Maria = none", "pensar em Maria.", "pensar em Maria.", "Ligo para Maria?")] + public void ChoicesApplyToSupportedRules(string list, string source, string expected, string question) + { + var name = source.Split(' ').Last().TrimEnd('.'); + var converter = new PortugueseConverter(new ConversionOptions(NameArticles: list)); + Assert.Equal(expected, converter.Convert(source)); + Assert.Equal(question, converter.Convert($"Ligue para {name}?", reference: ReferenceHint.FromText("Should I call them?"))); + Assert.Equal(expected, converter.Convert(expected)); + } + + [Fact] + public void ChoicesRespectRuleOptionsAndDoNotTurnLowercaseWordsIntoNames() + { + var options = new ConversionOptions(NameArticles: "rosa = o", Pronouns: false); + Assert.Equal("pensar em Rosa.", new PortugueseConverter(options).Convert("pensar em Rosa.")); + Assert.Equal("pensar em rosa.", new PortugueseConverter(options with { Pronouns = true }).Convert("pensar em rosa.")); + Assert.Equal("pensar em Rosa.", new PortugueseConverter(options with + { Pronouns = true, DisabledRules = "personal-name-complements" }).Convert("pensar em Rosa.")); + } + + [Theory] + [InlineData("Jamie = a", "Tu e a Jamie discutiram sobre o quê?")] + [InlineData("Jamie = o", "Tu e o Jamie discutiram sobre o quê?")] + [InlineData("Jamie = none", "Você e Jamie discutiram sobre o quê?")] + public void ChoicesAlsoApplyToNaturalWordOrder(string list, string expected) + { + var converter = new PortugueseConverter(new ConversionOptions(NameArticles: list)); + Assert.Equal(expected, converter.Convert("Sobre o que você e Jamie discutiram?", + reference: ReferenceHint.FromText("What did you and Jamie fight about?"))); + } + + [Fact] + public void SettingsRoundTripAndApplyToSeparateBatchFiles() + { + var configured = BatchMode.BuildConfigureResponse(new ConversionOptions(NameArticles: "Jamie = a\nAlex = o")); + Assert.Equal(PluginStatus.Ok, configured.Status); + var request = new PluginRequest + { + RequestType = PluginRequestType.Batch, + SettingsVersion = configured.SettingsVersion, + Settings = configured.Settings, + }; + Assert.Equal("Jamie = a\nAlex = o", ConversionOptions.Load(request).NameArticles); + var path = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"), "words.xml"); + foreach (var (source, expected) in new[] { ("pensar em Jamie.", "pensar na Jamie."), ("pensar em Alex.", "pensar no Alex.") }) + { + request.Subtitle = new PluginSubtitle { Format = "SubRip", SubRip = $"1\n00:00:01,000 --> 00:00:02,000\n{source}\n\n" }; + var response = BatchMode.BuildBatchResponse(request, path, new EmbeddingSettings(CheckMeaning: false)); + Assert.Equal(PluginStatus.Ok, response.Status); + Assert.Equal(expected, Assert.Single(SubRipParser.Parse(response.Subtitle!.Native)).Text); + } + Assert.Equal("", ConversionOptions.Load(new PluginRequest()).NameArticles); + } + + [Theory] + [InlineData("Jamie")] + [InlineData("Jamie = x")] + [InlineData("Jamie = o\nJAMIE = a")] + [InlineData("Jamie Smith = o")] + public void InvalidListsFailExplicitly(string list) + { + Assert.Throws(() => new PortugueseConverter(new ConversionOptions(NameArticles: list))); + var request = new PluginRequest { SettingsVersion = ConversionOptions.Version, + Settings = JsonSerializer.SerializeToElement(new { nameArticles = list }) }; + Assert.Throws(() => ConversionOptions.Load(request)); + } +} diff --git a/se5/BrazilianToEuropeanPortuguese.Tests/PersonalObjectTests.cs b/se5/BrazilianToEuropeanPortuguese.Tests/PersonalObjectTests.cs new file mode 100644 index 00000000..3fbfc08b --- /dev/null +++ b/se5/BrazilianToEuropeanPortuguese.Tests/PersonalObjectTests.cs @@ -0,0 +1,84 @@ +using SubtitleEdit.Plugins.BrazilianToEuropeanPortuguese; +using SubtitleEdit.Plugins.Shared; + +namespace BrazilianToEuropeanPortuguese.Tests; + +public sealed class PersonalObjectTests +{ + [Theory] + [InlineData("Seu pai bateu você.", "O teu pai bateu-te.")] + [InlineData("Ele bate você.", "Ele bate-te.")] + [InlineData("Ele batia você.", "Ele batia-te.")] + [InlineData("Ele vai bater você.", "Ele vai bater-te.")] + [InlineData("Ele não bateu você.", "Ele não te bateu.")] + [InlineData("O homem que bateu você.", "O homem que te bateu.")] + [InlineData("Sei que o teu pai bateu você.", "Sei que o teu pai te bateu.")] + [InlineData("Ele bateu ele.", "Ele bateu-o.")] + [InlineData("Ele bateu ela.", "Ele bateu-a.")] + [InlineData("Não bateu eles.", "Não os bateu.")] + [InlineData("Ele bateu em você e na sua mãe.", "Ele bateu em ti e na sua mãe.")] + [InlineData("Bateu em ti.", "Bateu em ti.")] + [InlineData("Ele bateu à porta.", "Ele bateu à porta.")] + [InlineData("Ele bateu o recorde.", "Ele bateu o recorde.")] + [InlineData("Você bateu à porta.", "Bateste à porta.")] + [InlineData("Bateu você mesmo?", "Bateu tu mesmo?")] + [InlineData("Seu pai bateu você.", "O teu pai bateu-te.")] + public void PersonalObjectsPreserveGovernmentAndOtherSenses(string source, string expected) + { + var converter = new PortugueseConverter(); + Assert.Equal(expected, converter.Convert(source)); + Assert.Equal(expected, converter.Convert(expected)); + } + + [Fact] + public void ReportedCuePreservesOriginalAndTiming() + { + var blocks = SubRipParser.Parse("1\n00:18:30,310 --> 00:18:31,452\nSeu pai bateu você.\n\n" + + "2\n00:18:31,464 --> 00:18:33,139\nBateu em você\ne na sua mãe,\n\n"); + var results = SubtitleConversion.Convert(blocks, new ConversionOptions(), + english: new string?[] { "Your dad beat you.", "He beat you and your mother," }); + Assert.Equal("O teu pai bateu-te.", results[0].Text); + Assert.Equal("Bateu em ti\ne na tua mãe,", results[1].Text); + Assert.Equal("Seu pai bateu você.", blocks[0].Text); + Assert.Equal(1110310L, blocks[0].StartMs); + Assert.Equal(1113139L, blocks[1].EndMs); + } + + [Theory] + [InlineData("Ele atingiu você.", "Ele atingiu-te.")] + [InlineData("Ele surrou você.", "Ele surrou-te.")] + [InlineData("Ele livrou você do perigo.", "Ele livrou-te do perigo.")] + [InlineData("Ele liberou você.", "Ele liberou-te.")] + [InlineData("Ele fichou você.", "Ele fichou-te.")] + [InlineData("Ele não recusou você.", "Ele não te recusou.")] + [InlineData("Ele considerou você inocente.", "Ele considerou-te inocente.")] + [InlineData("Ele honrou você.", "Ele honrou-te.")] + [InlineData("Ele contactou você.", "Ele contactou-te.")] + [InlineData("Eu aguento você.", "Eu aguento-te.")] + [InlineData("Ele espancou você.", "Ele espancou-te.")] + [InlineData("Ele socou você.", "Ele socou-te.")] + [InlineData("Ele feriu você.", "Ele feriu-te.")] + [InlineData("Ele bateu em você.", "Ele bateu em ti.")] + [InlineData("Ele levou você para casa.", "Ele levou-te para casa.")] + [InlineData("Ele surrou você como vingança.", "Ele surrou-te como vingança.")] + [InlineData("Ele lida com você.", "Ele lida contigo.")] + [InlineData("Ele suspeita de você.", "Ele suspeita de ti.")] + public void DictionaryReviewedPersonalVerbsUseExistingCliticPlacement(string source, string expected) + { + var converter = new PortugueseConverter(); + Assert.Equal(expected, converter.Convert(source)); + Assert.Equal(expected, converter.Convert(expected)); + } + + [Fact] + public void OptionsAndIgnoredFormsKeepPriority() + { + const string source = "Seu pai bateu você."; + Assert.Equal("O seu pai bateu você.", new PortugueseConverter(new ConversionOptions(YouToTu: false)).Convert(source)); + Assert.Equal("O seu pai bateu você.", new PortugueseConverter().Convert(source, + reference: ReferenceHint.FromText("Your dad beat you.")! with { FormalAddress = true })); + var local = new PortugueseLocalWordList(); + local.Ignored.Add("bateu você"); + Assert.Equal("Teu pai bateu você.", new PortugueseConverter(localWordList: local).Convert(source)); + } +} diff --git a/se5/BrazilianToEuropeanPortuguese.Tests/PoliceNounTests.cs b/se5/BrazilianToEuropeanPortuguese.Tests/PoliceNounTests.cs new file mode 100644 index 00000000..94cf96c9 --- /dev/null +++ b/se5/BrazilianToEuropeanPortuguese.Tests/PoliceNounTests.cs @@ -0,0 +1,37 @@ +using SubtitleEdit.Plugins.BrazilianToEuropeanPortuguese; + +namespace BrazilianToEuropeanPortuguese.Tests; + +public sealed class PoliceNounTests +{ + [Theory] + [InlineData("Sem isso, haveria muito\nmais policiais", "Sem isso, haveria muito\nmais polícias")] + [InlineData("Precisamos de mais policiais.", "Precisamos de mais polícias.")] + [InlineData("Há menos policiais.", "Há menos polícias.")] + [InlineData("Chegaram 20 policiais.", "Chegaram 20 polícias.")] + [InlineData("MAIS POLICIAIS.", "MAIS POLÍCIAS.")] + [InlineData("As operações policiais.", "As operações policiais.")] + [InlineData("Mais operações policiais.", "Mais operações policiais.")] + [InlineData("Há muitos carros policiais.", "Há muitos carros policiais.")] + public void QuantifiersIdentifyPersonnelWithoutChangingAdjectives(string source, string expected) + { + var converter = new PortugueseConverter(); + Assert.Equal(expected, converter.Convert(source)); + Assert.Equal(expected, converter.Convert(expected)); + } + + [Fact] + public void ReferenceAndUserOptionsRemainEffective() + { + const string source = "Há mais policiais."; + Assert.Equal("Há mais polícias.", new PortugueseConverter().Convert(source, + reference: ReferenceHint.FromText("There are more cops."))); + Assert.Equal("Há mais agentes.", new PortugueseConverter().Convert(source, + reference: ReferenceHint.FromText("There are more officers."))); + Assert.Equal(source, new PortugueseConverter(new ConversionOptions(Vocabulary: false)).Convert(source)); + Assert.Equal(source, new PortugueseConverter(new ConversionOptions(DisabledRules: "police-nouns")).Convert(source)); + var words = new PortugueseLocalWordList(); + words.Ignored.Add("mais policiais"); + Assert.Equal(source, new PortugueseConverter(localWordList: words).Convert(source)); + } +} diff --git a/se5/BrazilianToEuropeanPortuguese.Tests/ReferenceInitialAdverbTests.cs b/se5/BrazilianToEuropeanPortuguese.Tests/ReferenceInitialAdverbTests.cs new file mode 100644 index 00000000..8412bd8b --- /dev/null +++ b/se5/BrazilianToEuropeanPortuguese.Tests/ReferenceInitialAdverbTests.cs @@ -0,0 +1,81 @@ +using SubtitleEdit.Plugins.BrazilianToEuropeanPortuguese; +using SubtitleEdit.Plugins.Shared; + +namespace BrazilianToEuropeanPortuguese.Tests; + +public sealed class ReferenceInitialAdverbTests +{ + [Theory] + [InlineData("Realmente gosta\ndesse cara, hein?", "You really dig this guy, huh?", "Realmente gostas\ndesse tipo, não?")] + [InlineData("Realmente gosta dele.", "You really like him.", "Realmente gostas dele.")] + [InlineData("Simplesmente gosta dele.", "You just like him.", "Simplesmente gostas dele.")] + [InlineData("Sempre gosta dele.", "You always like him.", "Sempre gostas dele.")] + [InlineData("Jamais gosta disso.", "You never like that.", "Jamais gostas disso.")] + [InlineData("Quase entende tudo.", "You almost understand everything.", "Quase percebes tudo.")] + [InlineData("Realmente não gosta dele.", "You really don't like him.", "Realmente não gostas dele.")] + [InlineData("Realmente já sabe disso.", "You really already know that.", "Realmente já sabes disso.")] + [InlineData("REALMENTE GOSTA DELE.", "You really like him.", "REALMENTE GOSTAS DELE.")] + [InlineData("Realmente gosta dele.", "You really like him.", "Realmente gostas dele.")] + public void InitialAdverbsDoNotHideTheReferenceConfirmedAddressee(string source, string english, string expected) + { + var hint = ReferenceHint.FromText(english)!; + Assert.True(hint.StartsWithSecondPersonSubject); + var converter = new PortugueseConverter(); + Assert.Equal(expected, converter.Convert(source, reference: hint)); + Assert.Equal(expected, converter.Convert(expected, reference: hint)); + } + + [Theory] + [InlineData("Realmente gosta dele.", null)] + [InlineData("Realmente gosta dele.", "He really likes him.")] + [InlineData("Realmente gosta dele.", "What happened to you?")] + [InlineData("Realmente ele gosta de ti.", "You really think he likes you.")] + [InlineData("Realmente Maria gosta de ti.", "You really think Maria likes you.")] + [InlineData("Realmente a ajuda é necessária.", "You really need help.")] + [InlineData("Realmente é impossível esperar.", "You really cannot wait.")] + public void OtherSubjectsAndNominalOrImpersonalUsesStayUnchanged(string source, string? english) => + Assert.Equal(source, new PortugueseConverter().Convert(source, reference: ReferenceHint.FromText(english))); + + [Fact] + public void AddressOptionAndDisabledStageAreRespected() + { + var source = "Realmente gosta dele."; + var hint = ReferenceHint.FromText("You really like him.")!; + foreach (var options in new[] + { + new ConversionOptions(YouToTu: false), + new ConversionOptions(Address: AddressMode.Formal), + new ConversionOptions(DisabledRules: "address"), + }) + { + var blocks = new[] { new SrtBlock { StartMs = 1000, EndMs = 2000, Text = source } }; + Assert.Equal(source, Assert.Single(SubtitleConversion.Convert(blocks, options, + english: new string?[] { hint.EnglishText })).Text); + } + } + + [Fact] + public void TimingAlignedCueUsesItsOwnEnglishSubject() + { + var blocks = new[] + { + new SrtBlock { StartMs = 23469, EndMs = 24974, Text = "Realmente gosta\ndesse cara, hein?" }, + new SrtBlock { StartMs = 25126, EndMs = 28555, Text = "Sim, verdadeiro, sim.\nPode parar de falar agora?" }, + }; + var english = new[] + { + new SrtBlock { StartMs = 23291, EndMs = 25159, Text = "You really dig\nthis guy, huh?" }, + new SrtBlock { StartMs = 25193, EndMs = 26327, Text = "Yeah, he's\nthe real deal, yeah." }, + new SrtBlock { StartMs = 26360, EndMs = 28662, Text = "Will you just...\njust stop talking now?" }, + }; + var aligned = ReferenceAligner.AlignByTiming(blocks, english); + var conversions = SubtitleConversion.Convert(blocks, ConversionOptions.Default, english: aligned.Texts); + Assert.Equal("Realmente gostas\ndesse tipo, não?", conversions[0].Text); + Assert.Contains(conversions[0].Rules, rule => rule.Id == "address"); + Assert.StartsWith("Sim, verdadeiro, sim.", conversions[1].Text); + var response = BatchMode.BuildOkResponse(blocks.ToList(), conversions.Select((cue, i) => (cue, i)) + .ToDictionary(item => item.i, item => item.cue.Text), ConversionOptions.Default); + var output = SubRipParser.Parse(response.Subtitle!.Native); + Assert.Equal(blocks.Select(b => (b.StartMs, b.EndMs)), output.Select(b => (b.StartMs, b.EndMs))); + } +} diff --git a/se5/BrazilianToEuropeanPortuguese.Tests/ReferenceTests.cs b/se5/BrazilianToEuropeanPortuguese.Tests/ReferenceTests.cs index 184b16ac..1f90fa3c 100644 --- a/se5/BrazilianToEuropeanPortuguese.Tests/ReferenceTests.cs +++ b/se5/BrazilianToEuropeanPortuguese.Tests/ReferenceTests.cs @@ -819,6 +819,149 @@ void LocalText(string name, string text) Assert.Equal("teste", Assert.Single(PortugueseLocalWordList.Load(refreshPath).Ignored)); batchConfig.Close(); + var namesConfig = new MainWindow(new PluginRequest { RequestType = PluginRequestType.Configure }, refreshPath); + namesConfig.Show(); + namesConfig.FindControl