From 5a0e1f2212ba07c7f1926240efc5228d2cbd2453 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Tue, 3 Dec 2019 19:41:09 -0800 Subject: [PATCH 1/2] Added Portuguese grammar and abbreviations --- CHANGELOG.md | 1 + languages.js | 6 +++ languages/abbreviations/pt.json | 31 ++++++++++++++ languages/grammar/pt.json | 48 +++++++++++++++++++++ languages/overrides/pt.js | 34 +++++++++++++++ scripts/transifex.js | 6 +++ test/grammar_test.js | 74 +++++++++++++++++++++++++++++++++ 7 files changed, 200 insertions(+) create mode 100644 languages/abbreviations/pt.json create mode 100644 languages/grammar/pt.json create mode 100644 languages/overrides/pt.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 81861d184..ece1133d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file. For change - Update Japanese localization, add named intersections. [#290](https://github.com/Project-OSRM/osrm-text-instructions/pull/290) - Corrected various Portuguese translations. [#283](https://github.com/Project-OSRM/osrm-text-instructions/pull/283) +- Added Portuguese abbreviations and grammar to choose the right preposition-article contraction before certain names. [#294](https://github.com/Project-OSRM/osrm-text-instructions/pull/294) ## 0.13.4 2019-09-16 diff --git a/languages.js b/languages.js index 04c9e9337..6bdea9942 100755 --- a/languages.js +++ b/languages.js @@ -35,6 +35,7 @@ var instructionsZhHans = require('./languages/translations/zh-Hans.json'); var grammarDa = require('./languages/grammar/da.json'); var grammarFr = require('./languages/grammar/fr.json'); var grammarHu = require('./languages/grammar/hu.json'); +var grammarPt = require('./languages/grammar/pt.json'); var grammarRu = require('./languages/grammar/ru.json'); // Load all abbreviations files @@ -50,6 +51,7 @@ var abbreviationsHu = require('./languages/abbreviations/hu.json'); var abbreviationsLt = require('./languages/abbreviations/lt.json'); var abbreviationsNl = require('./languages/abbreviations/nl.json'); var abbreviationsRu = require('./languages/abbreviations/ru.json'); +var abbreviationsPt = require('./languages/abbreviations/pt.json'); var abbreviationsSl = require('./languages/abbreviations/sl.json'); var abbreviationsSv = require('./languages/abbreviations/sv.json'); var abbreviationsUk = require('./languages/abbreviations/uk.json'); @@ -94,6 +96,8 @@ var grammars = { 'da': grammarDa, 'fr': grammarFr, 'hu': grammarHu, + 'pt-BR': grammarPt, + 'pt-PT': grammarPt, 'ru': grammarRu }; @@ -110,6 +114,8 @@ var abbreviations = { 'hu': abbreviationsHu, 'lt': abbreviationsLt, 'nl': abbreviationsNl, + 'pt-BR': abbreviationsPt, + 'pt-PT': abbreviationsPt, 'ru': abbreviationsRu, 'sl': abbreviationsSl, 'sv': abbreviationsSv, diff --git a/languages/abbreviations/pt.json b/languages/abbreviations/pt.json new file mode 100644 index 000000000..05c513579 --- /dev/null +++ b/languages/abbreviations/pt.json @@ -0,0 +1,31 @@ +{ + "abbreviations": { + "quadra": "Qd", + "vila": "Vil" + }, + "classifications": { + "avenida": "Av", + "caminho": "Cam", + "estrada": "Estr", + "rua": "R", + "travessa": "Tv" + }, + "directions": { + "lés-nordeste": "ENE", + "nordeste": "NE", + "oeste": "O", + "sudeste": "SE", + "lés-sudeste": "ESE", + "nor-nordeste": "NNE", + "sul": "S", + "nor-noroeste": "NNO", + "noroeste": "NO", + "norte": "N", + "oés-sudoeste": "OSO", + "oés-noroeste": "ONO", + "sudoeste": "SO", + "sul-sudeste": "SSE", + "su-sudoeste": "SSO", + "leste": "L" + } +} diff --git a/languages/grammar/pt.json b/languages/grammar/pt.json new file mode 100644 index 000000000..fcd3c34fa --- /dev/null +++ b/languages/grammar/pt.json @@ -0,0 +1,48 @@ +{ + "meta": { + "regExpFlags": "gi" + }, + "v5": { + "em": [ + ["^ A(s?) ", " na$1 "], + ["^ O(s?) ", " no$1 "], + + ["^ (Marginal|Parte|Passagem|Ponte|Radial|Rede|Servidão) ", " na $1 "], + ["^ (Anel|Bosque|Boulevard|Cais|Canal|Caracol|Casal|Catete|Coronel|Duque|Fim|General|Impasse|Jardim|Juiz|Lote|Marechal|Mirante|Oriente|Parque|Professor|Setor|Tenente|Terminal|Túnel) ", " no $1 "], + + ["^ ([^\\- ]+dade)(s?) ", " na$2 $1$2 "], + ["^ ([^\\- ]+z) ", " na $1 "], + ["^ ([^\\- ]+z)es ", " nas $1es "], + ["^ ([^\\- ]+[çz]ão) ", " na $1 "], + ["^ ([^\\- ]+[çz]ões) ", " nas $1 "], + + ["^ ([^\\- ]+dor) ", " no $1 "], + ["^ ([^\\- ]+dor)es ", " nos $1es "], + + ["^ (?!n[ao]s? )([^\\- ]+)([ao]s?) ", " n$2 $1$2 "], + + ["^ (?!n[ao]s? )(\\S)", " em $1"] + ], + "a": [ + ["^ A(s?) ", " à$1 "], + ["^ O(s?) ", " ao$1 "], + + ["^ (Marginal|Parte|Passagem|Ponte|Radial|Rede|Servidão) ", " à $1 "], + ["^ (Anel|Bosque|Boulevard|Cais|Canal|Caracol|Casal|Catete|Coronel|Duque|Fim|General|Impasse|Jardim|Juiz|Lote|Marechal|Mirante|Oriente|Parque|Professor|Setor|Tenente|Terminal|Túnel) ", " ao $1 "], + + ["^ ([^\\- ]+dade)(s?) ", " à$2 $1$2 "], + ["^ ([^\\- ]+z) ", " à $1 "], + ["^ ([^\\- ]+z)es ", " às $1es "], + ["^ ([^\\- ]+[çz]ão) ", " à $1 "], + ["^ ([^\\- ]+[çz]ões) ", " às $1 "], + + ["^ ([^\\- ]+dor) ", " ao $1 "], + ["^ ([^\\- ]+dor)es ", " aos $1es "], + + ["^ ([^\\- ]+)a(s?) ", " à$2 $1a$2 "], + ["^ (?!aos? )([^\\- ]+)o(s?) ", " ao$2 $1o$2 "], + + ["^ (?!aos? |às? )(\\S)", " a $1"] + ] + } +} diff --git a/languages/overrides/pt.js b/languages/overrides/pt.js new file mode 100644 index 000000000..daf864925 --- /dev/null +++ b/languages/overrides/pt.js @@ -0,0 +1,34 @@ +// Add grammar option to {way_name} depending on phrase context + +var replaces = [ + [' (n[ao] +)?\{(destination|junction_name|way_name|waypoint_name)\}', ' {$1:em}'], // eslint-disable-line no-useless-escape + [' (ao +|à +)?\{(destination|junction_name|way_name|waypoint_name)\}', ' {$1:a}'] // eslint-disable-line no-useless-escape +]; + +function optionize(phrase) { + var result = phrase; + replaces.forEach(function(pattern) { + var re = new RegExp(pattern[0], 'gi'); + result = result.replace(re, pattern[1]); + }); + + return result; +} + +function iterate(values) { + Object.keys(values).forEach(function (key) { + var value = values[key]; + if (typeof value === 'string') { + values[key] = optionize(value); + } else if (typeof value === 'object') { + iterate(value); + } + }); +} + +module.exports = function(content) { + // Iterate all content string values recursively + iterate(content.v5); + + return content; +}; diff --git a/scripts/transifex.js b/scripts/transifex.js index 8a1f2754f..26d097db5 100644 --- a/scripts/transifex.js +++ b/scripts/transifex.js @@ -36,6 +36,12 @@ languages.supportedCodes.forEach((code) => { var override = `${__dirname}/../languages/overrides/${code}.js`; if (fs.existsSync(override)) { content = require(override)(content); + } else { + var language = code.split('-')[0]; + override = `${__dirname}/../languages/overrides/${language}.js`; + if (fs.existsSync(override)) { + content = require(override)(content); + } } // Write language file diff --git a/test/grammar_test.js b/test/grammar_test.js index 8e30e0978..237da8a71 100644 --- a/test/grammar_test.js +++ b/test/grammar_test.js @@ -472,6 +472,80 @@ const grammarTests = { ['Приморское шоссе', 'dative', 'Приморскому шоссе'], ['Приморское шоссе', 'genitive', 'Приморского шоссе'], ['Приморское шоссе', 'prepositional', 'Приморском шоссе'] + ], + 'pt-PT': [ + ['Anel Viário Prefeito Pedro Ernesto', 'a', 'ao Anel Viário Prefeito Pedro Ernesto'], + ['Anel Viário Prefeito Pedro Ernesto', 'em', 'no Anel Viário Prefeito Pedro Ernesto'], + ['Boqueirão da Ponte da Lama', 'a', 'ao Boqueirão da Ponte da Lama'], + ['Boqueirão da Ponte da Lama', 'em', 'no Boqueirão da Ponte da Lama'], + ['Bosque Marapendi Expresso', 'a', 'ao Bosque Marapendi Expresso'], + ['Bosque Marapendi Expresso', 'em', 'no Bosque Marapendi Expresso'], + ['Boulevard 28 de Setembro', 'a', 'ao Boulevard 28 de Setembro'], + ['Boulevard 28 de Setembro', 'em', 'no Boulevard 28 de Setembro'], + ['Cais de Costas', 'a', 'ao Cais de Costas'], + ['Cais de Costas', 'em', 'no Cais de Costas'], + ['Canal do Cunha', 'a', 'ao Canal do Cunha'], + ['Canal do Cunha', 'em', 'no Canal do Cunha'], + ['Circular Norte do Bairro da Encarnação', 'a', 'a Circular Norte do Bairro da Encarnação'], + ['Circular Norte do Bairro da Encarnação', 'em', 'em Circular Norte do Bairro da Encarnação'], + ['Comunidade do Quiabo', 'a', 'à Comunidade do Quiabo'], + ['Comunidade do Quiabo', 'em', 'na Comunidade do Quiabo'], + ['Coronel Correa Lima', 'a', 'ao Coronel Correa Lima'], + ['Coronel Correa Lima', 'em', 'no Coronel Correa Lima'], + ['Corredor Verde Monsanto-Parque Eduardo VII', 'a', 'ao Corredor Verde Monsanto-Parque Eduardo VII'], + ['Corredor Verde Monsanto-Parque Eduardo VII', 'em', 'no Corredor Verde Monsanto-Parque Eduardo VII'], + ['Cruz das Oliveiras', 'a', 'à Cruz das Oliveiras'], + ['Cruz das Oliveiras', 'em', 'na Cruz das Oliveiras'], + ['Cruzes da Sé', 'a', 'às Cruzes da Sé'], + ['Cruzes da Sé', 'em', 'nas Cruzes da Sé'], + ['Duque de Loulé', 'a', 'ao Duque de Loulé'], + ['Duque de Loulé', 'em', 'no Duque de Loulé'], + ['Elevador de Santa Justa', 'a', 'ao Elevador de Santa Justa'], + ['Elevador de Santa Justa', 'em', 'no Elevador de Santa Justa'], + ['Fim da Trilha do Pico da Tijuca', 'a', 'ao Fim da Trilha do Pico da Tijuca'], + ['Fim da Trilha do Pico da Tijuca', 'em', 'no Fim da Trilha do Pico da Tijuca'], + ['Impasse Rua Padre Américo', 'a', 'ao Impasse Rua Padre Américo'], + ['Impasse Rua Padre Américo', 'em', 'no Impasse Rua Padre Américo'], + ['Jardim de Alah', 'a', 'ao Jardim de Alah'], + ['Jardim de Alah', 'em', 'no Jardim de Alah'], + ['Juiz de Fora', 'a', 'ao Juiz de Fora'], + ['Juiz de Fora', 'em', 'no Juiz de Fora'], + ['Ligação Vista Chinesa Mesa do Imperador', 'a', 'à Ligação Vista Chinesa Mesa do Imperador'], + ['Ligação Vista Chinesa Mesa do Imperador', 'em', 'na Ligação Vista Chinesa Mesa do Imperador'], + ['Marechal Hermes', 'a', 'ao Marechal Hermes'], + ['Marechal Hermes', 'em', 'no Marechal Hermes'], + ['Marginal Avenida Brasil', 'a', 'à Marginal Avenida Brasil'], + ['Marginal Avenida Brasil', 'em', 'na Marginal Avenida Brasil'], + ['Mirante do Urubu', 'a', 'ao Mirante do Urubu'], + ['Mirante do Urubu', 'em', 'no Mirante do Urubu'], + ['Oriente Estacionamento', 'a', 'ao Oriente Estacionamento'], + ['Oriente Estacionamento', 'em', 'no Oriente Estacionamento'], + ['Parque Civil', 'a', 'ao Parque Civil'], + ['Parque Civil', 'em', 'no Parque Civil'], + ['Parte do Circuito da Pedreira', 'a', 'à Parte do Circuito da Pedreira'], + ['Parte do Circuito da Pedreira', 'em', 'na Parte do Circuito da Pedreira'], + ['Passagem Paulo Roberto Lopes Lima', 'a', 'à Passagem Paulo Roberto Lopes Lima'], + ['Passagem Paulo Roberto Lopes Lima', 'em', 'na Passagem Paulo Roberto Lopes Lima'], + ['Ponte Antiga', 'a', 'à Ponte Antiga'], + ['Ponte Antiga', 'em', 'na Ponte Antiga'], + ['Professor Honório Silvestre', 'a', 'ao Professor Honório Silvestre'], + ['Professor Honório Silvestre', 'em', 'no Professor Honório Silvestre'], + ['Radial de Benfica', 'a', 'à Radial de Benfica'], + ['Radial de Benfica', 'em', 'na Radial de Benfica'], + ['Rede Sarah', 'a', 'à Rede Sarah'], + ['Rede Sarah', 'em', 'na Rede Sarah'], + ['Servidão Sete de Setembro', 'a', 'à Servidão Sete de Setembro'], + ['Servidão Sete de Setembro', 'em', 'na Servidão Sete de Setembro'], + ['Setor Alemanha', 'a', 'ao Setor Alemanha'], + ['Setor Alemanha', 'em', 'no Setor Alemanha'], + ['São Paulo', 'a', 'ao São Paulo'], + ['São Paulo', 'em', 'no São Paulo'], + ['Tenente Cerqueira Leite', 'a', 'ao Tenente Cerqueira Leite'], + ['Tenente Cerqueira Leite', 'em', 'no Tenente Cerqueira Leite'], + ['Terminal Aroldo Melodia', 'a', 'ao Terminal Aroldo Melodia'], + ['Terminal Aroldo Melodia', 'em', 'no Terminal Aroldo Melodia'], + ['Túnel Acústico Rafael Mascarenhas', 'a', 'ao Túnel Acústico Rafael Mascarenhas'], + ['Túnel Acústico Rafael Mascarenhas', 'em', 'no Túnel Acústico Rafael Mascarenhas'] ] // TODO add your language grammar tests to call grammarize() and check result }; From eb724e69d4200ab504de0148dfd662e39ced662a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Wed, 4 Dec 2019 12:46:37 -0800 Subject: [PATCH 2/2] Ignore diacritics when matching Portuguese word endings --- languages/grammar/pt.json | 16 ++++++++-------- test/grammar_test.js | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/languages/grammar/pt.json b/languages/grammar/pt.json index fcd3c34fa..1d351b819 100644 --- a/languages/grammar/pt.json +++ b/languages/grammar/pt.json @@ -7,14 +7,14 @@ ["^ A(s?) ", " na$1 "], ["^ O(s?) ", " no$1 "], - ["^ (Marginal|Parte|Passagem|Ponte|Radial|Rede|Servidão) ", " na $1 "], - ["^ (Anel|Bosque|Boulevard|Cais|Canal|Caracol|Casal|Catete|Coronel|Duque|Fim|General|Impasse|Jardim|Juiz|Lote|Marechal|Mirante|Oriente|Parque|Professor|Setor|Tenente|Terminal|Túnel) ", " no $1 "], + ["^ (Marginal|Parte|Passagem|Ponte|Radial|Rede|Servid[aã]o) ", " na $1 "], + ["^ (Anel|Bosque|Boulevard|Cais|Canal|Caracol|Casal|Catete|Coronel|Duque|Fim|General|Impasse|Jardim|Juiz|Lote|Marechal|Mirante|Oriente|Parque|Professor|Setor|Tenente|Terminal|T[uú]nel) ", " no $1 "], ["^ ([^\\- ]+dade)(s?) ", " na$2 $1$2 "], ["^ ([^\\- ]+z) ", " na $1 "], ["^ ([^\\- ]+z)es ", " nas $1es "], - ["^ ([^\\- ]+[çz]ão) ", " na $1 "], - ["^ ([^\\- ]+[çz]ões) ", " nas $1 "], + ["^ ([^\\- ]+[cçz][aã]o) ", " na $1 "], + ["^ ([^\\- ]+[cçz][oõ]es) ", " nas $1 "], ["^ ([^\\- ]+dor) ", " no $1 "], ["^ ([^\\- ]+dor)es ", " nos $1es "], @@ -27,14 +27,14 @@ ["^ A(s?) ", " à$1 "], ["^ O(s?) ", " ao$1 "], - ["^ (Marginal|Parte|Passagem|Ponte|Radial|Rede|Servidão) ", " à $1 "], - ["^ (Anel|Bosque|Boulevard|Cais|Canal|Caracol|Casal|Catete|Coronel|Duque|Fim|General|Impasse|Jardim|Juiz|Lote|Marechal|Mirante|Oriente|Parque|Professor|Setor|Tenente|Terminal|Túnel) ", " ao $1 "], + ["^ (Marginal|Parte|Passagem|Ponte|Radial|Rede|Servid[aã]o) ", " à $1 "], + ["^ (Anel|Bosque|Boulevard|Cais|Canal|Caracol|Casal|Catete|Coronel|Duque|Fim|General|Impasse|Jardim|Juiz|Lote|Marechal|Mirante|Oriente|Parque|Professor|Setor|Tenente|Terminal|T[uú]nel) ", " ao $1 "], ["^ ([^\\- ]+dade)(s?) ", " à$2 $1$2 "], ["^ ([^\\- ]+z) ", " à $1 "], ["^ ([^\\- ]+z)es ", " às $1es "], - ["^ ([^\\- ]+[çz]ão) ", " à $1 "], - ["^ ([^\\- ]+[çz]ões) ", " às $1 "], + ["^ ([^\\- ]+[cçz][aã]o) ", " à $1 "], + ["^ ([^\\- ]+[cçz][oõ]es) ", " às $1 "], ["^ ([^\\- ]+dor) ", " ao $1 "], ["^ ([^\\- ]+dor)es ", " aos $1es "], diff --git a/test/grammar_test.js b/test/grammar_test.js index 237da8a71..364dc0ab2 100644 --- a/test/grammar_test.js +++ b/test/grammar_test.js @@ -476,6 +476,8 @@ const grammarTests = { 'pt-PT': [ ['Anel Viário Prefeito Pedro Ernesto', 'a', 'ao Anel Viário Prefeito Pedro Ernesto'], ['Anel Viário Prefeito Pedro Ernesto', 'em', 'no Anel Viário Prefeito Pedro Ernesto'], + ['Boqueirao da Ponte da Lama', 'a', 'ao Boqueirao da Ponte da Lama'], + ['Boqueirao da Ponte da Lama', 'em', 'no Boqueirao da Ponte da Lama'], ['Boqueirão da Ponte da Lama', 'a', 'ao Boqueirão da Ponte da Lama'], ['Boqueirão da Ponte da Lama', 'em', 'no Boqueirão da Ponte da Lama'], ['Bosque Marapendi Expresso', 'a', 'ao Bosque Marapendi Expresso'], @@ -510,6 +512,12 @@ const grammarTests = { ['Jardim de Alah', 'em', 'no Jardim de Alah'], ['Juiz de Fora', 'a', 'ao Juiz de Fora'], ['Juiz de Fora', 'em', 'no Juiz de Fora'], + ['Ligacao Vista Chinesa Mesa do Imperador', 'a', 'à Ligacao Vista Chinesa Mesa do Imperador'], + ['Ligacao Vista Chinesa Mesa do Imperador', 'em', 'na Ligacao Vista Chinesa Mesa do Imperador'], + ['Ligacão Vista Chinesa Mesa do Imperador', 'a', 'à Ligacão Vista Chinesa Mesa do Imperador'], + ['Ligacão Vista Chinesa Mesa do Imperador', 'em', 'na Ligacão Vista Chinesa Mesa do Imperador'], + ['Ligaçao Vista Chinesa Mesa do Imperador', 'a', 'à Ligaçao Vista Chinesa Mesa do Imperador'], + ['Ligaçao Vista Chinesa Mesa do Imperador', 'em', 'na Ligaçao Vista Chinesa Mesa do Imperador'], ['Ligação Vista Chinesa Mesa do Imperador', 'a', 'à Ligação Vista Chinesa Mesa do Imperador'], ['Ligação Vista Chinesa Mesa do Imperador', 'em', 'na Ligação Vista Chinesa Mesa do Imperador'], ['Marechal Hermes', 'a', 'ao Marechal Hermes'], @@ -534,6 +542,10 @@ const grammarTests = { ['Radial de Benfica', 'em', 'na Radial de Benfica'], ['Rede Sarah', 'a', 'à Rede Sarah'], ['Rede Sarah', 'em', 'na Rede Sarah'], + ['Sao Paulo', 'a', 'ao Sao Paulo'], + ['Sao Paulo', 'em', 'no Sao Paulo'], + ['Servidao Sete de Setembro', 'a', 'à Servidao Sete de Setembro'], + ['Servidao Sete de Setembro', 'em', 'na Servidao Sete de Setembro'], ['Servidão Sete de Setembro', 'a', 'à Servidão Sete de Setembro'], ['Servidão Sete de Setembro', 'em', 'na Servidão Sete de Setembro'], ['Setor Alemanha', 'a', 'ao Setor Alemanha'], @@ -544,6 +556,8 @@ const grammarTests = { ['Tenente Cerqueira Leite', 'em', 'no Tenente Cerqueira Leite'], ['Terminal Aroldo Melodia', 'a', 'ao Terminal Aroldo Melodia'], ['Terminal Aroldo Melodia', 'em', 'no Terminal Aroldo Melodia'], + ['Tunel Acústico Rafael Mascarenhas', 'a', 'ao Tunel Acústico Rafael Mascarenhas'], + ['Tunel Acústico Rafael Mascarenhas', 'em', 'no Tunel Acústico Rafael Mascarenhas'], ['Túnel Acústico Rafael Mascarenhas', 'a', 'ao Túnel Acústico Rafael Mascarenhas'], ['Túnel Acústico Rafael Mascarenhas', 'em', 'no Túnel Acústico Rafael Mascarenhas'] ]