Browse Source

Add Portuguese from Portugal Language (#7329)

* Good day to deal with people in high places; particularly lonely stewardesses.

* You're currently going through a difficult transition period called "Life."

* You're at the end of the road again.

* Fixes

* Add references to  pt-pt

* Fix order

* Config typos

* Update conf.php

* Fix whitespace

* Update app/i18n/pt-pt/sub.php

---------

Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
Rui Melo 1 year ago
parent
commit
ecb7a836ec

+ 1 - 0
.typos.toml

@@ -33,6 +33,7 @@ extend-exclude = [
 	"app/i18n/oc/",
 	"app/i18n/pl/",
 	"app/i18n/pt-br/",
+	"app/i18n/pt-pt/",
 	"app/i18n/ru/",
 	"app/i18n/sk/",
 	"app/i18n/tr/",

+ 1 - 0
app/i18n/cs/gen.php

@@ -170,6 +170,7 @@ return array(
 		'oc' => 'Occitan',	// IGNORE
 		'pl' => 'Polski',	// IGNORE
 		'pt-br' => 'Português (Brasil)',	// IGNORE
+		'pt-pt' => 'Português (Portugal)',	// IGNORE
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE

+ 1 - 0
app/i18n/de/gen.php

@@ -170,6 +170,7 @@ return array(
 		'oc' => 'Occitan',	// IGNORE
 		'pl' => 'Polski',	// IGNORE
 		'pt-br' => 'Português (Brasil)',	// IGNORE
+		'pt-pt' => 'Português (Portugal)',	// IGNORE
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE

+ 1 - 0
app/i18n/el/gen.php

@@ -170,6 +170,7 @@ return array(
 		'oc' => 'Occitan',	// IGNORE
 		'pl' => 'Polski',	// IGNORE
 		'pt-br' => 'Português (Brasil)',	// IGNORE
+		'pt-pt' => 'Português (Portugal)',	// IGNORE
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE

+ 1 - 0
app/i18n/en-us/gen.php

@@ -170,6 +170,7 @@ return array(
 		'oc' => 'Occitan',	// IGNORE
 		'pl' => 'Polski',	// IGNORE
 		'pt-br' => 'Português (Brasil)',	// IGNORE
+		'pt-pt' => 'Português (Portugal)',	// IGNORE
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE

+ 1 - 0
app/i18n/en/gen.php

@@ -170,6 +170,7 @@ return array(
 		'oc' => 'Occitan',
 		'pl' => 'Polski',
 		'pt-br' => 'Português (Brasil)',
+		'pt-pt' => 'Português (Portugal)',
 		'ru' => 'Русский',
 		'sk' => 'Slovenčina',
 		'tr' => 'Türkçe',

+ 1 - 0
app/i18n/es/gen.php

@@ -170,6 +170,7 @@ return array(
 		'oc' => 'Occitan',	// IGNORE
 		'pl' => 'Polski',	// IGNORE
 		'pt-br' => 'Português (Brasil)',	// IGNORE
+		'pt-pt' => 'Português (Portugal)',	// IGNORE
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE

+ 1 - 0
app/i18n/fa/gen.php

@@ -170,6 +170,7 @@ return array(
 		'oc' => 'Occitan',	// IGNORE
 		'pl' => 'Polski',	// IGNORE
 		'pt-br' => 'Português (Brasil)',	// IGNORE
+		'pt-pt' => 'Português (Portugal)',	// IGNORE
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE

+ 1 - 0
app/i18n/fi/gen.php

@@ -170,6 +170,7 @@ return array(
 		'oc' => 'Occitan',	// IGNORE
 		'pl' => 'Polski',	// IGNORE
 		'pt-br' => 'Português (Brasil)',	// IGNORE
+		'pt-pt' => 'Português (Portugal)',	// IGNORE
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE

+ 1 - 0
app/i18n/fr/gen.php

@@ -170,6 +170,7 @@ return array(
 		'oc' => 'Occitan',	// IGNORE
 		'pl' => 'Polski',	// IGNORE
 		'pt-br' => 'Português (Brasil)',	// IGNORE
+		'pt-pt' => 'Português (Portugal)',	// IGNORE
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE

+ 1 - 0
app/i18n/he/gen.php

@@ -170,6 +170,7 @@ return array(
 		'oc' => 'Occitan',	// IGNORE
 		'pl' => 'Polski',	// IGNORE
 		'pt-br' => 'Português (Brasil)',	// IGNORE
+		'pt-pt' => 'Português (Portugal)',	// IGNORE
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE

+ 1 - 0
app/i18n/hu/gen.php

@@ -170,6 +170,7 @@ return array(
 		'oc' => 'Occitan',	// IGNORE
 		'pl' => 'Polski',	// IGNORE
 		'pt-br' => 'Português (Brasil)',	// IGNORE
+		'pt-pt' => 'Português (Portugal)',	// IGNORE
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE

+ 1 - 0
app/i18n/id/gen.php

@@ -170,6 +170,7 @@ return array(
 		'oc' => 'Occitan',	// IGNORE
 		'pl' => 'Polski',	// IGNORE
 		'pt-br' => 'Português (Brasil)',	// IGNORE
+		'pt-pt' => 'Português (Portugal)',	// IGNORE
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE

+ 1 - 0
app/i18n/it/gen.php

@@ -170,6 +170,7 @@ return array(
 		'oc' => 'Occitan',	// IGNORE
 		'pl' => 'Polski',	// IGNORE
 		'pt-br' => 'Português (Brasil)',	// IGNORE
+		'pt-pt' => 'Português (Portugal)',	// IGNORE
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE

+ 1 - 0
app/i18n/ja/gen.php

@@ -170,6 +170,7 @@ return array(
 		'oc' => 'Occitan',	// IGNORE
 		'pl' => 'Polski',	// IGNORE
 		'pt-br' => 'Português (Brasil)',	// IGNORE
+		'pt-pt' => 'Português (Portugal)',	// IGNORE
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE

+ 1 - 0
app/i18n/ko/gen.php

@@ -170,6 +170,7 @@ return array(
 		'oc' => 'Occitan',	// IGNORE
 		'pl' => 'Polski',	// IGNORE
 		'pt-br' => 'Português (Brasil)',	// IGNORE
+		'pt-pt' => 'Português (Portugal)',	// IGNORE
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE

+ 1 - 0
app/i18n/lv/gen.php

@@ -170,6 +170,7 @@ return array(
 		'oc' => 'Occitan',	// IGNORE
 		'pl' => 'Polski',	// IGNORE
 		'pt-br' => 'Português (Brasil)',	// IGNORE
+		'pt-pt' => 'Português (Portugal)',	// IGNORE
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE

+ 1 - 0
app/i18n/nl/gen.php

@@ -170,6 +170,7 @@ return array(
 		'oc' => 'Occitan',	// IGNORE
 		'pl' => 'Polski',	// IGNORE
 		'pt-br' => 'Português (Brasil)',	// IGNORE
+		'pt-pt' => 'Português (Portugal)',	// IGNORE
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE

+ 1 - 0
app/i18n/oc/gen.php

@@ -170,6 +170,7 @@ return array(
 		'oc' => 'Occitan',	// IGNORE
 		'pl' => 'Polski',	// IGNORE
 		'pt-br' => 'Português (Brasil)',	// IGNORE
+		'pt-pt' => 'Português (Portugal)',	// IGNORE
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE

+ 1 - 0
app/i18n/pl/gen.php

@@ -170,6 +170,7 @@ return array(
 		'oc' => 'Occitan',	// IGNORE
 		'pl' => 'Polski',	// IGNORE
 		'pt-br' => 'Português (Brasil)',	// IGNORE
+		'pt-pt' => 'Português (Portugal)',	// IGNORE
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE

+ 1 - 0
app/i18n/pt-br/gen.php

@@ -170,6 +170,7 @@ return array(
 		'oc' => 'Occitan',	// IGNORE
 		'pl' => 'Polski',	// IGNORE
 		'pt-br' => 'Português (Brasil)',	// IGNORE
+		'pt-pt' => 'Português (Portugal)',	// IGNORE
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE

+ 240 - 0
app/i18n/pt-pt/admin.php

@@ -0,0 +1,240 @@
+<?php
+
+/******************************************************************************/
+/* Each entry of that file can be associated with a comment to indicate its   */
+/* state. When there is no comment, it means the entry is fully translated.   */
+/* The recognized comments are (comment matching is case-insensitive):        */
+/*   + TODO: the entry has never been translated.                             */
+/*   + DIRTY: the entry has been translated but needs to be updated.          */
+/*   + IGNORE: the entry does not need to be translated.                      */
+/* When a comment is not recognized, it is discarded.                         */
+/******************************************************************************/
+
+return array(
+	'auth' => array(
+		'allow_anonymous' => 'Permitir a leitura anônima dos artigos pelo utilizador padrão (%s)',
+		'allow_anonymous_refresh' => 'Permitir atualização anônima dos artigos',
+		'api_enabled' => 'Permitir acesso à <abbr>API</abbr> <small>(É preciso para aplicações móveis e partilha pesquisas personalizadas)</small>',
+		'form' => 'Formulário Web(tradicional, Necessita de JavaScript)',
+		'http' => 'HTTP (advanced: managed by Web server, OIDC, SSO…)',	// TODO
+		'none' => 'Nenhum (Perigoso)',
+		'title' => 'Autenticação',
+		'token' => 'Token de autenticação principal',
+		'token_help' => 'Permite acesso a todos as saídas RSS do utilizador bem como atualização dos feeds sem autenticação:',
+		'type' => 'Método de autenticação',
+		'unsafe_autologin' => 'Permitir login automático inseguro usando o seguinte formato: ',
+	),
+	'check_install' => array(
+		'cache' => array(
+			'nok' => 'Verifique as permissões no diretório <em>./data/cache</em>. O servidor HTTP deve ter direitos para escrever dentro desta pasta.',
+			'ok' => 'Permissões no diretório cache estão corretos.',
+		),
+		'categories' => array(
+			'nok' => 'Tabela Categoria está configurada incorretamente.',
+			'ok' => 'Tabela Categoria está ok.',
+		),
+		'connection' => array(
+			'nok' => 'Ligação ao banco de dados não pode ser estabelecida.',
+			'ok' => 'Ligação ao banco de dados está correcta.',
+		),
+		'ctype' => array(
+			'nok' => 'Não foi possível encontrar uma biblioteca necessária para verificação do tipo de caractere (php-ctype).',
+			'ok' => 'A biblioteca necessária para verificação do tipo de caractere (ctype).Foi Encontrada',
+		),
+		'curl' => array(
+			'nok' => 'Não foi possível encontrar a biblioteca cURL (php-curl).',
+			'ok' => 'Tem a biblioteca cURL.',
+		),
+		'data' => array(
+			'nok' => 'Verifique as permissões no diretório <em>./data</em>. O servidor HTTP deve ter direitos para escrever dentro desta pasta.',
+			'ok' => 'Permissões no diretório data estão corretos.',
+		),
+		'database' => 'Instalação do banco de dados',
+		'dom' => array(
+			'nok' => 'Não foi possível encontrar uma biblioteca necessária para navegar pelo DOM (php-xml).',
+			'ok' => 'Tem a biblioteca necessária para navegar pelo DOM.',
+		),
+		'entries' => array(
+			'nok' => 'Tabela entradas está configurada incorretamente.',
+			'ok' => 'Tabela entradas está correcta.',
+		),
+		'favicons' => array(
+			'nok' => 'Verifique as permissões no diretório <em>./data/favicons</em>. O servidor HTTP deve ter direitos para escrever dentro desta pasta.',
+			'ok' => 'Permissões no diretório favicons estão corretos.',
+		),
+		'feeds' => array(
+			'nok' => 'Tabela Feed está configurada incorretamente.',
+			'ok' => 'Tabela Feed está ok.',
+		),
+		'fileinfo' => array(
+			'nok' => 'Não foi possível encontrar a biblioteca fileinfo do PHP (fileinfo).',
+			'ok' => 'Tem a biblioteca fileinfo.',
+		),
+		'files' => 'Instalação de arquivos',
+		'json' => array(
+			'nok' => 'Não foi possível encontrar JSON (php-json).',
+			'ok' => 'Tem a extensão JSON.',
+		),
+		'mbstring' => array(
+			'nok' => 'Não foi possível encontrar a biblioteca recomendada para Unicode (mbstring).',
+			'ok' => 'Tem a biblioteca recomendada para Unicode (mbstring).',
+		),
+		'pcre' => array(
+			'nok' => 'Não foi possível encontrar uma biblioteca necessário para expressões regulares (php-pcre).',
+			'ok' => 'Tem a biblioteca necessária para expressões regulares (php-pcre).',
+		),
+		'pdo' => array(
+			'nok' => 'Não foi encontrado o PDO ou um dos drivers suportados (pdo_mysql, pdo_sqlite, pdo_pgsql).',
+			'ok' => 'Tem o PDO e ao menos um dos drivers suportados (pdo_mysql, pdo_sqlite, pdo_pgsql).',
+		),
+		'php' => array(
+			'_' => 'Instação do PHP',
+			'nok' => 'A versão do PHP é %s mas FreshRSS requer ao menos a versão %s.',
+			'ok' => 'A versão do PHP é %s, que é compatível com o FreshRSS.',
+		),
+		'tables' => array(
+			'nok' => 'Há uma ou mais tabelas inexistentes no banco de dados.',
+			'ok' => 'As tabelas apropriadas existem no base de dados.',
+		),
+		'title' => 'Verificação de instalação',
+		'tokens' => array(
+			'nok' => 'Verifique as permissões no diretório <em>./data/tokens</em>. O servidor HTTP deve ter direitos para escrever dentro desta pasta.',
+			'ok' => 'Permissões no diretório tokens estão corretos.',
+		),
+		'users' => array(
+			'nok' => 'Verifiquei as permissões no diretório <em>./data/users</em>. O servidor HTTP deve ter direitos para escrever dentro desta pasta.',
+			'ok' => 'Permissões no diretório users estão corretos.',
+		),
+		'zip' => array(
+			'nok' => 'Não foi possível localizar a extensão ZIP (php-zip).',
+			'ok' => 'Tem a extensão ZIP.',
+		),
+	),
+	'extensions' => array(
+		'author' => 'Autor',
+		'community' => 'Extensões da comunidade disponíveis',
+		'description' => 'Descrição',
+		'disabled' => 'Desactivado',
+		'empty_list' => 'Não existem extensões instaladas',
+		'empty_list_help' => 'Check the logs to determine the reason behind the empty extension list.',	// TODO
+		'enabled' => 'Habilitada',
+		'latest' => 'Instalado',
+		'name' => 'Nome',
+		'no_configure_view' => 'Esta extensão não pode ser configurada.',
+		'system' => array(
+			'_' => 'Extensões do sistema',
+			'no_rights' => 'Extensões do sistema (Não tem permissões para isto)',
+		),
+		'title' => 'Extensões',
+		'update' => 'Atualização disponível',
+		'user' => 'Extensões do utilizador',
+		'version' => 'Versão',
+	),
+	'stats' => array(
+		'_' => 'Estatísticas',
+		'all_feeds' => 'Todos os feeds',
+		'category' => 'Categoria',
+		'entry_count' => 'Contagem de entrada',
+		'entry_per_category' => 'Entradas por categoria',
+		'entry_per_day' => 'Entradas por dia (últimos 30 dias)',
+		'entry_per_day_of_week' => 'Por dia da semana(média: %.2f mensagens)',
+		'entry_per_hour' => 'Por hora (média: %.2f mensagens)',
+		'entry_per_month' => 'Por mês(média: %.2f mensagens)',
+		'entry_repartition' => 'Repartição de entradas',
+		'feed' => 'Feed',	// IGNORE
+		'feed_per_category' => 'Feeds por categoria',
+		'idle' => 'Feeds inativos',
+		'main' => 'Estatísticas principais',
+		'main_stream' => 'Stream principal',
+		'no_idle' => 'Não há nenhum feed inativo!',
+		'number_entries' => '%d artigos',
+		'overview' => 'Overview',	// TODO
+		'percent_of_total' => '% do total',
+		'repartition' => 'Repartição de artigos: %s',
+		'status_favorites' => 'Favoritos',
+		'status_read' => 'Lido',
+		'status_total' => 'Total',	// IGNORE
+		'status_unread' => 'Não lidos',
+		'title' => 'Estatísticas',
+		'top_feed' => 'Top10 Feeds',
+	),
+	'system' => array(
+		'_' => 'Configuração do sistema',
+		'auto-update-url' => 'URL do servidor para atualização automática',
+		'base-url' => array(
+			'_' => 'URL Base',
+			'recommendation' => 'Recomendação automática: <kbd>%s</kbd>',
+		),
+		'cookie-duration' => array(
+			'help' => 'em segundos',
+			'number' => 'Manter seção ativa durante',
+		),
+		'force_email_validation' => 'Força verificação do endereço de email',
+		'instance-name' => 'Nome da instância',
+		'max-categories' => 'Limite de categorias por utilizador',
+		'max-feeds' => 'Limite de Feeds por utilizador',
+		'registration' => array(
+			'number' => 'Máximo número de contas',
+			'select' => array(
+				'label' => 'Formulário de Registro',
+				'option' => array(
+					'noform' => 'Desativado: Sem formulário de registro',
+					'nolimit' => 'Ativado: Sem limites de contas',
+					'setaccountsnumber' => 'Definir o máximo número de contas',
+				),
+			),
+			'status' => array(
+				'disabled' => 'Formulário desabilitado',
+				'enabled' => 'Formulário activado',
+			),
+			'title' => 'Formulário de registo de utilizador',
+		),
+		'sensitive-parameter' => 'Parâmetro sensível. Edite manualmente em <kbd>./data/config.php</kbd>',
+		'tos' => array(
+			'disabled' => 'não fornecido',
+			'enabled' => '<a href="./?a=tos">está ativado</a>',
+			'help' => 'Como <a href="https://freshrss.github.io/FreshRSS/en/admins/12_User_management.html#enable-terms-of-service-tos" target="_blank">habilitar os Termos de Serviço</a>',
+		),
+		'websub' => array(
+			'help' => 'Sobre <a href="https://freshrss.github.io/FreshRSS/en/users/WebSub.html" target="_blank">WebSub</a>',
+		),
+	),
+	'update' => array(
+		'_' => 'Atualização do sistema',
+		'apply' => 'Aplicar',
+		'changelog' => 'Registo de alterações',
+		'check' => 'Pesquisar por novas atualizações',
+		'copiedFromURL' => 'update.php copiado de %s para ./data',
+		'current_version' => 'Versão',
+		'last' => 'Última verificação',
+		'loading' => 'A fazer atualização…',
+		'none' => 'Nenhuma atualização disponivel',
+		'releaseChannel' => array(
+			'_' => 'Canal de Release',
+			'edge' => 'Release contínua (“edge”)',
+			'latest' => 'Release estável (“latest”)',
+		),
+		'title' => 'Sistema de atualização',
+		'viaGit' => 'Atualização via git e GitHub.com iniciada',
+	),
+	'user' => array(
+		'admin' => 'Administrador',
+		'article_count' => 'Artigos',
+		'back_to_manage' => '← Voltar para à lista de utilizadores',
+		'create' => 'Criar novo utilizador',
+		'database_size' => 'Tamanho do banco de dados',
+		'email' => 'Endereço de email',
+		'enabled' => 'Activado',
+		'feed_count' => 'Feeds',	// IGNORE
+		'is_admin' => 'É administrador',
+		'language' => 'Idioma',
+		'last_user_activity' => 'Última Atividade do utilizador',
+		'list' => 'Lista de utilizadors',
+		'number' => 'Há %d conta criada',
+		'numbers' => 'Há %d contas criadas',
+		'password_form' => 'Senha<br /><small>(para o login pelo método do formulário)</small>',
+		'password_format' => 'Ao menos 7 caracteres',
+		'title' => 'Gerir utilizadores',
+		'username' => 'utilizador',
+	),
+);

+ 351 - 0
app/i18n/pt-pt/conf.php

@@ -0,0 +1,351 @@
+<?php
+
+/******************************************************************************/
+/* Each entry of that file can be associated with a comment to indicate its   */
+/* state. When there is no comment, it means the entry is fully translated.   */
+/* The recognized comments are (comment matching is case-insensitive):        */
+/*   + TODO: the entry has never been translated.                             */
+/*   + DIRTY: the entry has been translated but needs to be updated.          */
+/*   + IGNORE: the entry does not need to be translated.                      */
+/* When a comment is not recognized, it is discarded.                         */
+/******************************************************************************/
+
+return array(
+	'archiving' => array(
+		'_' => 'Arquivar',
+		'exception' => 'Regras de exceção da limpeza',
+		'help' => 'Mais opções estão disponíveis nas configurações individuais do Feed',
+		'keep_favourites' => 'Nunca apagar os favoritos',
+		'keep_labels' => 'Nunca apagar tags',
+		'keep_max' => 'Número máximo de artigos para manter no feed',
+		'keep_min_by_feed' => 'Número mínimo de artigos para manter no feed',
+		'keep_period' => 'Idade máxima dos artigos a serem mantidos',
+		'keep_unreads' => 'Nunca apagar os não lidos',
+		'maintenance' => 'Manutenção',
+		'optimize' => 'Otimizar banco de dados',
+		'optimize_help' => 'Faça ocasionalmente para reduzir o tamanho do banco de dados',
+		'policy' => 'Política de limpeza',
+		'policy_warning' => 'Se nenhuma política de limpeza for selecionada, todos os artigos serão mantidos.',
+		'purge_now' => 'Limpar agora',
+		'title' => 'Arquivar',
+		'ttl' => 'Não atualize automaticamente mais frequente que',
+	),
+	'display' => array(
+		'_' => 'Exibição',
+		'darkMode' => array(
+			'_' => 'Modo noturno automático',
+			'auto' => 'Automático',
+			'help' => 'For compatible themes only',	// TODO
+			'no' => 'Não',
+		),
+		'icon' => array(
+			'bottom_line' => 'Linha inferior',
+			'display_authors' => 'Autores',
+			'entry' => 'Ícones de artigos',
+			'publication_date' => 'Data da publicação',
+			'related_tags' => 'Tags relacionadas',
+			'sharing' => 'Compartilhar',
+			'summary' => 'Sumário',
+			'top_line' => 'Linha superior',
+		),
+		'language' => 'Idioma',
+		'notif_html5' => array(
+			'seconds' => 'segundos (0 significa sem timeout)',
+			'timeout' => 'Notificação em HTML5 de timeout',
+		),
+		'show_nav_buttons' => 'Mostrar botões de navegação',
+		'theme' => array(
+			'_' => 'Tema',
+			'deprecated' => array(
+				'_' => 'Depreciado',
+				'description' => 'Este tema não é suportado e não estará novamente disponível em <a href="https://freshrss.github.io/FreshRSS/en/users/05_Configuration.html#theme" target="_blank">uma versão futura do FreshRSS</a>',
+			),
+		),
+		'theme_not_available' => 'O tema “%s” não está disponível. Por favor escolha outro tema.',
+		'thumbnail' => array(
+			'label' => 'Miniatura',
+			'landscape' => 'Modo paisagem',
+			'none' => 'Nenhum',
+			'portrait' => 'Modo retrato',
+			'square' => 'Modo quadrado',
+		),
+		'timezone' => 'Fuso horário',
+		'title' => 'Exibição',
+		'website' => array(
+			'full' => 'Ícone e nome',
+			'icon' => 'Apenas ícone',
+			'label' => 'Site',
+			'name' => 'Apenas nome',
+			'none' => 'Nenhum',
+		),
+		'width' => array(
+			'content' => 'Largura do conteúdo',
+			'large' => 'Largo',
+			'medium' => 'Médio',
+			'no_limit' => 'Sem limite',
+			'thin' => 'Fino',
+		),
+	),
+	'logs' => array(
+		'loglist' => array(
+			'level' => 'Nivel de Registro',
+			'message' => 'Mensagem de Registro',
+			'timestamp' => 'Data e Hora',
+		),
+		'pagination' => array(
+			'first' => 'Primeiro',
+			'last' => 'Último',
+			'next' => 'Próximo',
+			'previous' => 'Anterior',
+		),
+	),
+	'privacy' => array(
+		'_' => 'Privacy',	// TODO
+		'retrieve_extension_list' => 'Retrieve extension list',	// TODO
+	),
+	'profile' => array(
+		'_' => 'Gestão de perfil',
+		'api' => array(
+			'_' => 'Administração da API',
+			'check_link' => 'Check API status via: <kbd><a href="../api/" target="_blank">%s</a></kbd>',	// TODO
+			'disabled' => 'The API access is disabled.',	// TODO
+			'documentation_link' => 'See the <a href="https://freshrss.github.io/FreshRSS/en/users/06_Mobile_access.html#access-via-mobile-app" target="_blank">documentation and list of known apps</a>',	// TODO
+			'help' => 'See <a href="http://freshrss.github.io/FreshRSS/en/users/06_Mobile_access.html#access-via-mobile-app" target=_blank>documentation</a>',	// TODO
+		),
+		'delete' => array(
+			'_' => 'Remover conta',
+			'warn' => 'A conta e todos os dados relacionados serão removidos.',
+		),
+		'email' => 'Endereço de e-mail',
+		'password_api' => 'Senha da API<br /><small>(p.s., para aplicativos móveis)</small>',
+		'password_form' => 'Senha<br /><small>(para o método de formulário web)</small>',
+		'password_format' => 'Ao menos 7 caracteres',
+		'title' => 'Perfil',
+	),
+	'query' => array(
+		'_' => 'Consultas do utilizador',
+		'deprecated' => 'Esta não é válida. A categoria ou feed relacionado foi apagado.',
+		'description' => 'Description',	// TODO
+		'filter' => array(
+			'_' => 'Filtro aplicado:',
+			'categories' => 'Mostrar por categoria',
+			'feeds' => 'Mostrar por feed',
+			'order' => 'Ordenar por data',
+			'search' => 'Expressão',
+			'shareOpml' => 'Activa a partilha por OPML de categorias e feeds correspondentes',
+			'shareRss' => 'Activa o partilha por HTML &amp; RSS',
+			'state' => 'Estado',
+			'tags' => 'Mostrar por tag',
+			'type' => 'Tipo',
+		),
+		'get_A' => 'Show all feeds, also those shown in their category',	// TODO
+		'get_Z' => 'Show all feeds, also archived ones',	// TODO
+		'get_all' => 'Mostrar todos os artigos',
+		'get_all_labels' => 'Mostrar artigos com qualquer rótulo',
+		'get_category' => 'Visualizar “%s” categoria',
+		'get_favorite' => 'Visualizar artigos favoritos',
+		'get_feed' => 'Visualizar “%s” feed',
+		'get_important' => 'Mostrar artigos de feeds importantes',
+		'get_label' => 'Mostrar artigos com rótulo “%s”',
+		'help' => 'Ver a <a href="https://freshrss.github.io/FreshRSS/en/users/user_queries.html" target="_blank">documentação para consultas de utilozadoes e partilhas por HTML / RSS / OPML</a>.',
+		'image_url' => 'Image URL',	// TODO
+		'name' => 'Nome',
+		'no_filter' => 'Sem filtro',
+		'no_queries' => array(
+			'_' => 'No user queries are saved yet.',	// TODO
+			'help' => 'See <a href="https://freshrss.github.io/FreshRSS/en/users/user_queries.html" target="_blank">documentation</a>',	// TODO
+		),
+		'number' => 'Consulta n°%d',
+		'order_asc' => 'Mostrar artigos mais antigos primeiro',
+		'order_desc' => 'Mostrar artigos mais novos primeiro',
+		'search' => 'Pesquisa por “%s”',
+		'share' => array(
+			'_' => 'Compartilhar esta consulta por link',
+			'disabled' => array(
+				'_' => 'disabled',	// TODO
+				'title' => 'Sharing',	// TODO
+			),
+			'greader' => 'Shareable link to the GReader JSON',	// TODO
+			'help' => 'Forneça este link se quiser partilhar esta consulta com alguém',
+			'html' => 'Link compartilhável para a página HTML',
+			'opml' => 'Link compartilhável para a lista de feeds OPML',
+			'rss' => 'Link compartilhável para o feed RSS',
+		),
+		'state_0' => 'Mostrar todos os artigos',
+		'state_1' => 'Mostrar artigos lidos',
+		'state_2' => 'Mostrar artigos não lidos',
+		'state_3' => 'Mostrar todos os artigos',
+		'state_4' => 'Mostrar artigos favoritos',
+		'state_5' => 'Mostrar artigos favoritos lidos',
+		'state_6' => 'Mostrar artigos favoritos não lidos',
+		'state_7' => 'Mostrar artigos favoritos',
+		'state_8' => 'Mostrar artigos que não são favoritos',
+		'state_9' => 'Mostrar artigos que não são favoritos lidos',
+		'state_10' => 'Mostrar artigos que não são favoritos não lidos',
+		'state_11' => 'Mostrar artigos que não são favoritos',
+		'state_12' => 'Mostrar todos os artigos',
+		'state_13' => 'Mostrar artigos lidos',
+		'state_14' => 'Mostrar artigos não lidos',
+		'state_15' => 'Mostrar todos os artigos',
+		'title' => 'Consultas de Utilizadores',
+	),
+	'reading' => array(
+		'_' => 'Leitura',
+		'after_onread' => 'Depois de “marcar todos como lido”,',
+		'always_show_favorites' => 'Mostrar todos os artigos nos favoritos por padrão',
+		'apply_to_individual_feed' => 'Applies to feeds individually',	// TODO
+		'article' => array(
+			'authors_date' => array(
+				'_' => 'Autores e Data',
+				'both' => 'No cabeçalho e rodapé',
+				'footer' => 'No rodapé',
+				'header' => 'No cabeçalho',
+				'none' => 'Nenhum',
+			),
+			'feed_name' => array(
+				'above_title' => 'Acima do título/etiqueta',
+				'none' => 'Nenhum',
+				'with_authors' => 'Com autores e data',
+			),
+			'feed_title' => 'Título do Feed',
+			'icons' => array(
+				'_' => 'Article icons position<br /><small>(Reading view only)</small>',	// TODO
+				'above_title' => 'Above title',	// TODO
+				'with_authors' => 'In authors and date row',	// TODO
+			),
+			'tags' => array(
+				'_' => 'Tag',
+				'both' => 'No cabeçalho e rodapé',
+				'footer' => 'No rodapé',
+				'header' => 'No cabeçalho',
+				'none' => 'Nenhum',
+			),
+			'tags_max' => array(
+				'_' => 'Número máximo de tags exibidas',
+				'help' => '0 significa: mostrar todas as tags e não enconde-las',
+			),
+		),
+		'articles_per_page' => 'Número de artigos por página',
+		'auto_load_more' => 'Carregar mais artigos no final da página',
+		'auto_remove_article' => 'Esconder artigos depois de lidos',
+		'confirm_enabled' => 'Mostrar uma caixa de diálogo de confirmação quando acionar “marcar todos como lido”',
+		'display_articles_unfolded' => 'Mostrar artigos abertos por padrão',
+		'display_categories_unfolded' => 'Categorias abertas',
+		'headline' => array(
+			'articles' => 'Artigos: Abrir/Fechar',
+			'articles_header_footer' => 'Artigos: cabeçalho/rodapé',
+			'categories' => 'Navegação à esquerda: Categoria',
+			'mark_as_read' => 'Marcar artigo como lido',
+			'misc' => 'Diversos',
+			'view' => 'Visualização',
+		),
+		'hide_read_feeds' => 'Esconder categorias e feeds com nenhum artigo não lido (não funciona com a configuração “Mostrar todos os artigos”)',
+		'img_with_lazyload' => 'Utilizar o modo <em>lazy load</em> para carregar as imagens',
+		'jump_next' => 'Ir para o próximo não lido',
+		'mark_updated_article_unread' => 'Marcar artigos atualizados como não lidos',
+		'number_divided_when_reader' => 'Dividido por 2 no modo de leitura .',
+		'read' => array(
+			'article_open_on_website' => 'quando o artigo é aberto no site original',
+			'article_viewed' => 'Quando o artigo é visualizado',
+			'focus' => 'quando focado (exceto por feeds importantes)',
+			'keep_max_n_unread' => 'Número máximo de artigos para manter como não lido',
+			'scroll' => 'enquanto faz a passagem (exceto por feeds importantes)',
+			'upon_gone' => 'Quando não estiver mais no feed de notícias principais',
+			'upon_reception' => 'ao receber um artigo',
+			'when' => 'Marcar artigo como lido…',
+			'when_same_title_in_category' => 'if an identical title already exists in the top <i>n</i> newest articles of the category',	// TODO
+			'when_same_title_in_feed' => 'Se um título idêntico já existir nos últimos <i>n</i> artigos mais novos (no feed)',
+		),
+		'show' => array(
+			'_' => 'Artigos para Mostrar',
+			'active_category' => 'Categoria ativa',
+			'adaptive' => 'Show unreads if any, all articles otherwise',	// TODO
+			'all_articles' => 'Mostrar todos os artigos',
+			'all_categories' => 'Mostrar todas as categorias',
+			'no_category' => 'Nenhuma categoria',
+			'remember_categories' => 'lembrar de abrir as categorias',
+			'unread' => 'Mostrar apenas não lido',
+			'unread_or_favorite' => 'Show unreads and favourites',	// TODO
+		),
+		'show_fav_unread_help' => 'Aplicar também nas tags',
+		'sides_close_article' => 'Clicando fora da área do texto do artigo fecha o mesmo',
+		'sort' => array(
+			'_' => 'Ordem de visualização',
+			'newer_first' => 'Novos primeiro',
+			'older_first' => 'Antigos primeiro',
+		),
+		'star' => array(
+			'when' => 'Mark an article as favourite…',	// TODO
+		),
+		'sticky_post' => 'Coloque o artigo no topo quando aberto',
+		'title' => 'Lendo',
+		'view' => array(
+			'default' => 'Visualização padrão',
+			'global' => 'Visualização global',
+			'normal' => 'Visualização normal',
+			'reader' => 'Visualização de leitura',
+		),
+	),
+	'sharing' => array(
+		'_' => 'Partilha',
+		'add' => 'Adicionar um método de partilha',
+		'bluesky' => 'Bluesky',	// TODO
+		'deprecated' => 'Este serviço está obceloeto e será removido do FreshRSS <a href="https://freshrss.github.io/FreshRSS/en/users/08_sharing_services.html" title="Abra este documento para mais informações" target="_blank">em versões futuras</a>.',
+		'diaspora' => 'Diaspora*',	// IGNORE
+		'email' => 'E-mail',
+		'facebook' => 'Facebook',	// IGNORE
+		'more_information' => 'Mais informação',
+		'print' => 'Imprimir',
+		'raindrop' => 'Raindrop.io',	// IGNORE
+		'remove' => 'Remover método de partilha',
+		'shaarli' => 'Shaarli',	// IGNORE
+		'share_name' => 'Nome de visualização para partilhar',
+		'share_url' => 'URL utilizada para partilha',
+		'title' => 'Partilhar',
+		'twitter' => 'Twitter',	// IGNORE
+		'wallabag' => 'wallabag',	// IGNORE
+	),
+	'shortcut' => array(
+		'_' => 'Atalhos',
+		'article_action' => 'Ações no artigo',
+		'auto_share' => 'Partilhar',
+		'auto_share_help' => 'Se há apenas um modo de partilha, ele é usado. Caso contrário, serão acessíveis pelo seu número.',
+		'close_dropdown' => 'Fechar menus',
+		'collapse_article' => 'Fechar',
+		'first_article' => 'Ir para o primeiro artigo',
+		'focus_search' => 'Aceder a caixa de pesquisa',
+		'global_view' => 'Mudar para visualização global',
+		'help' => 'Mostrar documentação',
+		'javascript' => 'JavaScript deve ser activado para utilizar atalhos',
+		'last_article' => 'Ir para o último artigo',
+		'load_more' => 'Carregar mais artigos',
+		'mark_favorite' => 'Marcar como favorito',
+		'mark_read' => 'Marcar como lido',
+		'navigation' => 'Navegação',
+		'navigation_help' => 'Com o modificador <kbd>⇧ Shift</kbd>, atalhos de navegação aplicam aos feeds.<br/>Com o <kbd>Alt ⎇</kbd> modificador, atalhos de navegação aplicam as categorias.',
+		'navigation_no_mod_help' => 'Os seguintes atalhos de navegação não suportam modificadores.',
+		'next_article' => 'Pule para o próximo artigo',
+		'next_unread_article' => 'Abrir o próximo artigo não lido',
+		'non_standard' => 'Algumas teclas (<kbd>%s</kbd>) podem não funcionar como atalhos.',
+		'normal_view' => 'Mudar para a visualização normal',
+		'other_action' => 'Outras ações',
+		'previous_article' => 'Saltar para o artigo anterior',
+		'reading_view' => 'Mudar para o modo de leitura',
+		'rss_view' => 'Abrir como feed RSS ',
+		'see_on_website' => 'Visualize o site original',
+		'shift_for_all_read' => '+ <kbd>Alt ⎇</kbd> para marcar artigos anteriores como lido<br />+ <kbd>⇧ Shift</kbd> para marcar todos os artigos como lido',
+		'skip_next_article' => 'Focar o próximo sem abri-lo',
+		'skip_previous_article' => 'Focar o anterior sem abri-lo',
+		'title' => 'Atalhos',
+		'toggle_media' => 'Reproduzir/pausar mídia',
+		'user_filter' => 'Acesse filtros de utilizador',
+		'user_filter_help' => 'Se há apenas um filtro, ele é utilizado. Caso contrário, os filtros serão acessíveis pelos seus números.',
+		'views' => 'Visualizações',
+	),
+	'user' => array(
+		'articles_and_size' => '%s artigos (%s)',
+		'current' => 'Utilizador atual',
+		'is_admin' => 'é administrador',
+		'users' => 'Utilizadores',
+	),
+);

+ 146 - 0
app/i18n/pt-pt/feedback.php

@@ -0,0 +1,146 @@
+<?php
+
+/******************************************************************************/
+/* Each entry of that file can be associated with a comment to indicate its   */
+/* state. When there is no comment, it means the entry is fully translated.   */
+/* The recognized comments are (comment matching is case-insensitive):        */
+/*   + TODO: the entry has never been translated.                             */
+/*   + DIRTY: the entry has been translated but needs to be updated.          */
+/*   + IGNORE: the entry does not need to be translated.                      */
+/* When a comment is not recognized, it is discarded.                         */
+/******************************************************************************/
+
+return array(
+	'access' => array(
+		'denied' => ' não tem permissão para acessar esta página',
+		'not_found' => ' está a pesquisar por uma página que não existe',
+	),
+	'admin' => array(
+		'optimization_complete' => 'Otimização Completa',
+	),
+	'api' => array(
+		'password' => array(
+			'failed' => 'A senha não pode ser modificada',
+			'updated' => 'A senha foi alterada com sucesso',
+		),
+	),
+	'auth' => array(
+		'login' => array(
+			'invalid' => 'Login está incorreto',
+			'success' => ' está ligado',
+		),
+		'logout' => array(
+			'success' => ' está desligado',
+		),
+	),
+	'conf' => array(
+		'error' => 'Um erro ocorreu durante o salvamento das configurações',
+		'query_created' => 'A Query “%s” foi criada.',
+		'shortcuts_updated' => 'Atalhos foram criados',
+		'updated' => 'Configuração foi atualizada',
+	),
+	'extensions' => array(
+		'already_enabled' => '%s já está activado',
+		'cannot_remove' => '%s não pode ser removido',
+		'disable' => array(
+			'ko' => '%s não pode ser desactivado. <a href="%s">verifique os logs do FreshRSS</a> para detalhes.',
+			'ok' => '%s agora está desactivado',
+		),
+		'enable' => array(
+			'ko' => '%s não pode ser activado. <a href="%s">verifique os logs do FreshRSS</a> para detalhes.',
+			'ok' => '%s agora está activado',
+		),
+		'no_access' => ' não tem acesso ao %s',
+		'not_enabled' => '%s não está habilitado',
+		'not_found' => '%s não existe',
+		'removed' => '%s removido',
+	),
+	'import_export' => array(
+		'export_no_zip_extension' => 'extensão ZIP não está presente em seu servidor. Por favor tente exportar os arquivos um por vez.',
+		'feeds_imported' => 'Seus feeds foram importados e serão atualizados pode clicar no butão<i>atualizar feeds</i>.',
+		'feeds_imported_with_errors' => 'Seus feeds foram importados, mas alguns erros ocorreram Carregue no butão <i>atualizar feeds</i>.',
+		'file_cannot_be_uploaded' => 'Arquivo não pôde ser enviado',
+		'no_zip_extension' => 'extensão ZIP não está presente em seu servidor.',
+		'zip_error' => 'Um erro ocorreu durante a importação do arquivo ZIP.',
+	),
+	'profile' => array(
+		'error' => 'Seu perfil não pode ser editado',
+		'updated' => 'Seu perfil foi editado com sucesso',
+	),
+	'sub' => array(
+		'actualize' => 'A atualizar…',
+		'articles' => array(
+			'marked_read' => 'Os artigos selecionados foram marcados como lidos.',
+			'marked_unread' => 'Os artigos foram marcados como não lidos',
+		),
+		'category' => array(
+			'created' => 'Categoria %s foi criada.',
+			'deleted' => 'Categoria foi apagada.',
+			'emptied' => 'Categoria foi limpa',
+			'error' => 'Categoria não pode ser atualizada',
+			'name_exists' => 'Este nome de categoria já existe.',
+			'no_id' => ' precisa especificar um id para a categoria.',
+			'no_name' => 'Nome da categoria não pode ser vazio.',
+			'not_delete_default' => ' não pode apagar uma categoria vazia!',
+			'not_exist' => 'A categoria não existe!',
+			'over_max' => ' atingiu seu limite de categorias (%d)',
+			'updated' => 'Categoria foi atualizada.',
+		),
+		'feed' => array(
+			'actualized' => '<em>%s</em> foi atualizado',
+			'actualizeds' => 'Os feeds RSS foram atualizados',
+			'added' => 'O feed RSS <em>%s</em> foi adicionado',
+			'already_subscribed' => ' já está inscrito no <em>%s</em>',
+			'cache_cleared' => 'O cache do feed <em>%s</em> foi limpo',
+			'deleted' => 'o feed foi apagado',
+			'error' => 'O feed não pode ser atualizado',
+			'internal_problem' => 'O feed RSS não pôde ser adicionado. <a href="%s">Verifique os logs do FreshRSS</a> para detalhes. Pode forçar a atualização no link <code>#force_feed</code> .',
+			'invalid_url' => 'URL <em>%s</em> é inválida',
+			'n_actualized' => '%d feeds foram atualizados',
+			'n_entries_deleted' => '%d artigos foram apagados',
+			'no_refresh' => 'Não há feed para atualizar…',
+			'not_added' => '<em>%s</em> não pode ser atualizado',
+			'not_found' => 'Não foi possível encontrar o feed',
+			'over_max' => ' atingiu seu limite de feeds (%d)',
+			'reloaded' => 'O feed <em>%s</em> foi recarregado',
+			'selector_preview' => array(
+				'http_error' => 'Falha ao carregar o conteúdo do site.',
+				'no_entries' => 'Não há nenhuma entrada nesse feed.	precisa de pelo menos um artigo para criar uma pré-visualização',
+				'no_feed' => 'Erro interno (nenhum feed para verificar).',
+				'no_result' => 'O seletor não teve correspondência. Por isso foi exibido o texto do feed original.',
+				'selector_empty' => 'O seletor está vazio.	precisa definir um para criar uma pré-visualização.',
+			),
+			'updated' => 'Os feeds foram atualizados',
+		),
+		'purge_completed' => 'Limpeza completa (%d artigos apagados)',
+	),
+	'tag' => array(
+		'created' => 'A Tag “%s” foi criada.',
+		'error' => 'Etiqueta não pode ser atualizada!',
+		'name_exists' => 'O nome da tag já existe.',
+		'renamed' => 'A Tag “%s” foi renomeada para “%s”.',
+		'updated' => 'Etiqueta foi atualizada.',
+	),
+	'update' => array(
+		'can_apply' => 'O FreshRSS será atualizado para a <strong>versão %s</strong>.',
+		'error' => 'O processo de atualização encontrou um erro: %s',
+		'file_is_nok' => 'Nova <strong>versão %s</strong> disponível, mas verifique as permissões no diretório <em>%s</em>. Servidor HTTP deve ter direitos para escrever dentro',
+		'finished' => 'Atualização completa!',
+		'none' => 'Nenhuma atualização para aplicar',
+		'server_not_found' => 'Servidor de atualização não pôde ser localizado. [%s]',
+	),
+	'user' => array(
+		'created' => array(
+			'_' => 'Utilizador %s foi criado',
+			'error' => 'Utilizador %s não pode ser criado',
+		),
+		'deleted' => array(
+			'_' => 'Utilizador %s foi deletado',
+			'error' => 'Utilizador %s não pode ser deletado',
+		),
+		'updated' => array(
+			'_' => 'O Utilizador %s foi atualizado com sucesso',
+			'error' => 'O Utilizador %s não foi atualizado',
+		),
+	),
+);

+ 264 - 0
app/i18n/pt-pt/gen.php

@@ -0,0 +1,264 @@
+<?php
+
+/******************************************************************************/
+/* Each entry of that file can be associated with a comment to indicate its   */
+/* state. When there is no comment, it means the entry is fully translated.   */
+/* The recognized comments are (comment matching is case-insensitive):        */
+/*   + TODO: the entry has never been translated.                             */
+/*   + DIRTY: the entry has been translated but needs to be updated.          */
+/*   + IGNORE: the entry does not need to be translated.                      */
+/* When a comment is not recognized, it is discarded.                         */
+/******************************************************************************/
+
+return array(
+	'action' => array(
+		'actualize' => 'Atualizar feeds',
+		'add' => 'Adicionar',
+		'back_to_rss_feeds' => '← Volte para o seu feeds RSS',
+		'cancel' => 'Cancelar',
+		'close' => 'Close',	// TODO
+		'create' => 'Criar',
+		'delete_all_feeds' => 'Delete all feeds',	// TODO
+		'delete_errored_feeds' => 'Delete feeds with errors',	// TODO
+		'delete_muted_feeds' => 'Excluir feeds silenciados',
+		'demote' => 'Despromover',
+		'disable' => 'Desactivar',
+		'download' => 'Download',	// TODO
+		'empty' => 'Vazio',
+		'enable' => 'Activar',
+		'export' => 'Exportar',
+		'filter' => 'Filtrar',
+		'import' => 'Importar',
+		'load_default_shortcuts' => 'Carregar mais atalhos',
+		'manage' => 'Gerir',
+		'mark_read' => 'Marcar como lido',
+		'menu' => array(
+			'open' => 'Open menu',	// TODO
+		),
+		'nav_buttons' => array(
+			'next' => 'Next article',	// TODO
+			'prev' => 'Previous article',	// TODO
+			'up' => 'Go up',	// TODO
+		),
+		'open_url' => 'Abrir URL',
+		'promote' => 'Promover',
+		'purge' => 'Limpar',
+		'refresh_opml' => 'Atualizar OPML',
+		'remove' => 'Remover',
+		'rename' => 'Renomear',
+		'see_website' => 'Ver o site',
+		'submit' => 'Enviar',
+		'truncate' => 'Apagar todos os artigos',
+		'update' => 'Atualizar',
+	),
+	'auth' => array(
+		'accept_tos' => 'Eu aceito os <a href="%s">Termos de serviço</a>.',
+		'email' => 'Endereço de e-mail',
+		'keep_logged_in' => 'Mantenha-se ligado por <small>(%s days)</small>',
+		'login' => 'Entrar',
+		'logout' => 'Sair',
+		'password' => array(
+			'_' => 'Senha',
+			'format' => '<small>Pelo menos 7 caracteres</small>',
+		),
+		'registration' => array(
+			'_' => 'Nova conta',
+			'ask' => 'Criar novoa conta?',
+			'title' => 'Criação de conta',
+		),
+		'username' => array(
+			'_' => 'Utilizador',
+			'format' => '<small>Máximo 16 caracteres alphanumericos</small>',
+		),
+	),
+	'date' => array(
+		'Apr' => '\\A\\b\\r\\i\\l',
+		'Aug' => '\\A\\g\\o\\s\\t\\o',
+		'Dec' => '\\D\\e\\z\\e\\m\\b\\r\\o',
+		'Feb' => '\\F\\e\\v\\e\\r\\e\\i\\r\\o',
+		'Jan' => '\\J\\a\\n\\e\\i\\r\\o',
+		'Jul' => '\\J\\u\\l\\h\\o',
+		'Jun' => '\\J\\u\\n\\h\\o',
+		'Mar' => '\\M\\a\\r\\ç\\o',
+		'May' => '\\M\\a\\i\\o',
+		'Nov' => '\\N\\o\\v\\e\\m\\b\\r\\o',
+		'Oct' => '\\O\\u\\t\\u\\b\\r\\o',
+		'Sep' => '\\S\\e\\t\\e\\m\\b\\r\\o',
+		'apr' => 'abr',
+		'april' => 'Abr',
+		'aug' => 'ago',
+		'august' => 'Ago',
+		'before_yesterday' => 'Antes de ontem',
+		'dec' => 'dez',
+		'december' => 'Dez',
+		'feb' => 'fev',
+		'february' => 'Fev',
+		'format_date' => 'j \\d\\e %s \\d\\e Y',
+		'format_date_hour' => 'j \\d\\e %s \\d\\e Y\\, H\\:i',
+		'fri' => 'Sex',
+		'jan' => 'jan',
+		'january' => 'Jan',
+		'jul' => 'jul',
+		'july' => 'Jul',
+		'jun' => 'jun',
+		'june' => 'Jun',
+		'last_2_year' => 'Últimos dois anos',
+		'last_3_month' => 'Últimos três meses',
+		'last_3_year' => 'Últimos três anos',
+		'last_5_year' => 'Últimos cinco anos',
+		'last_6_month' => 'Últimos seis meses',
+		'last_month' => 'Últimos mês',
+		'last_week' => 'Última semana',
+		'last_year' => 'Último ano',
+		'mar' => 'mar',
+		'march' => 'Mar',
+		'may' => 'Mai',
+		'may_' => 'Mai',
+		'mon' => 'Seg',
+		'month' => 'meses',
+		'nov' => 'nov',
+		'november' => 'Nov',
+		'oct' => 'out',
+		'october' => 'Out',
+		'sat' => 'Sab',
+		'sep' => 'set',
+		'september' => 'Set',
+		'sun' => 'Dom',
+		'thu' => 'Qui',
+		'today' => 'Hoje',
+		'tue' => 'Ter',
+		'wed' => 'Qua',
+		'yesterday' => 'Ontem',
+	),
+	'dir' => 'ltr',	// IGNORE
+	'freshrss' => array(
+		'_' => 'FreshRSS',	// IGNORE
+		'about' => 'Sobre FreshRSS',
+	),
+	'js' => array(
+		'category_empty' => 'Categoria vazia',
+		'confirm_action' => 'Tem certeza que deseja efetuar esta ação? Ela não poderá ser revertida!',
+		'confirm_action_feed_cat' => 'Tem certeza que deseja efetuar esta ação ? vai perder favoritos e pesquisas personalizadas. Não poderá ser revertida!',
+		'feedback' => array(
+			'body_new_articles' => 'Há %%d novos artigos para ler no FreshRSS.',
+			'body_unread_articles' => '(não lido: %%d)',
+			'request_failed' => 'Uma solicitação falhou, isto pode ter sido causado por problemas de ligação a internet.',
+			'title_new_articles' => 'FreshRSS: novos artigos!',
+		),
+		'labels_empty' => 'No labels',	// TODO
+		'new_article' => 'Há novos artigos disponíveis, clique para atualizar a página.',
+		'should_be_activated' => 'O JavaScript precisa estar ativo',
+	),
+	'lang' => array(
+		'cs' => 'Čeština',	// IGNORE
+		'de' => 'Deutsch',	// IGNORE
+		'el' => 'Ελληνικά',	// IGNORE
+		'en' => 'English',	// IGNORE
+		'en-us' => 'English (United States)',	// IGNORE
+		'es' => 'Español',	// IGNORE
+		'fa' => 'فارسی',	// IGNORE
+		'fi' => 'Suomi',	// IGNORE
+		'fr' => 'Français',	// IGNORE
+		'he' => 'עברית',	// IGNORE
+		'hu' => 'Magyar',	// IGNORE
+		'id' => 'Bahasa Indonesia',	// IGNORE
+		'it' => 'Italiano',	// IGNORE
+		'ja' => '日本語',	// IGNORE
+		'ko' => '한국어',	// IGNORE
+		'lv' => 'Latviešu',	// IGNORE
+		'nl' => 'Nederlands',	// IGNORE
+		'oc' => 'Occitan',	// IGNORE
+		'pl' => 'Polski',	// IGNORE
+		'pt-br' => 'Português (Brasil)',	// IGNORE
+		'pt-pt' => 'Português (Portugal)',	// IGNORE
+		'ru' => 'Русский',	// IGNORE
+		'sk' => 'Slovenčina',	// IGNORE
+		'tr' => 'Türkçe',	// IGNORE
+		'zh-cn' => '简体中文',	// IGNORE
+		'zh-tw' => '正體中文',	// IGNORE
+	),
+	'menu' => array(
+		'about' => 'Sobre',
+		'account' => 'Conta',
+		'admin' => 'Administração',
+		'archiving' => 'Arquivar',
+		'authentication' => 'Autenticação',
+		'check_install' => 'Verificação de instalação',
+		'configuration' => 'Configuração',
+		'display' => 'Visualização',
+		'extensions' => 'Extensões',
+		'logs' => 'Logs',	// IGNORE
+		'privacy' => 'Privacy',	// TODO
+		'queries' => 'Queries de utilizador',
+		'reading' => 'Leitura',
+		'search' => 'Procurar por palavras ou #tags',
+		'search_help' => 'See documentation for advanced <a href="https://freshrss.github.io/FreshRSS/en/users/10_filter.html#with-the-search-field" target="_blank">search parameters</a>',	// TODO
+		'sharing' => 'Partilhar',
+		'shortcuts' => 'Atalhos',
+		'stats' => 'Estatísticas',
+		'system' => 'Configuração do sistema',
+		'update' => 'Atualização',
+		'user_management' => 'Gestão de utilizadores',
+		'user_profile' => 'Perfil',
+	),
+	'period' => array(
+		'days' => 'dias',
+		'hours' => 'horas',
+		'months' => 'meses',
+		'weeks' => 'semanas',
+		'years' => 'anos',
+	),
+	'share' => array(
+		'Known' => 'Sites no Known',
+		'archiveIS' => 'archive.is',	// IGNORE
+		'archiveORG' => 'archive.org',	// IGNORE
+		'archivePH' => 'archive.ph',	// IGNORE
+		'bluesky' => 'Bluesky',	// TODO
+		'buffer' => 'Buffer',	// IGNORE
+		'clipboard' => 'Área de transferência',
+		'diaspora' => 'Diaspora*',	// IGNORE
+		'email' => 'E-mail',
+		'email-webmail-firefox-fix' => 'Email (webmail - correção para o Firefox)',
+		'facebook' => 'Facebook',	// IGNORE
+		'gnusocial' => 'GNU social',	// IGNORE
+		'jdh' => 'Journal du hacker',	// IGNORE
+		'lemmy' => 'Lemmy',	// IGNORE
+		'linkding' => 'Linkding',	// IGNORE
+		'linkedin' => 'LinkedIn',	// IGNORE
+		'mastodon' => 'Mastodon',	// IGNORE
+		'movim' => 'Movim',	// IGNORE
+		'omnivore' => 'Omnivore',	// IGNORE
+		'pinboard' => 'Pinboard',	// IGNORE
+		'pinterest' => 'Pinterest',	// IGNORE
+		'pocket' => 'Pocket',	// IGNORE
+		'print' => 'Imprimir',
+		'raindrop' => 'Raindrop.io',	// IGNORE
+		'reddit' => 'Reddit',	// IGNORE
+		'shaarli' => 'Shaarli',	// IGNORE
+		'telegram' => 'Telegram',	// IGNORE
+		'twitter' => 'Twitter',	// IGNORE
+		'wallabag' => 'wallabag v1',	// IGNORE
+		'wallabagv2' => 'wallabag v2',	// IGNORE
+		'web-sharing-api' => 'Sistemas-compartilhados (API)',
+		'whatsapp' => 'Whatsapp',	// IGNORE
+		'xing' => 'Xing',	// IGNORE
+	),
+	'short' => array(
+		'attention' => 'Atenção!',
+		'blank_to_disable' => 'Deixe em branco para desativar',
+		'by_author' => 'Por:',
+		'by_default' => 'Por padrão',
+		'damn' => 'Buumm!',
+		'default_category' => 'Sem categoria',
+		'no' => 'Não',
+		'not_applicable' => 'Não disponível',
+		'ok' => 'Ok!',	// IGNORE
+		'or' => 'ou',
+		'yes' => 'Sim',
+	),
+	'stream' => array(
+		'load_more' => 'Carregar mais artigos',
+		'mark_all_read' => 'Marcar todos como lidos',
+		'nothing_to_load' => 'Não existem mais artigos',
+	),
+);

+ 103 - 0
app/i18n/pt-pt/index.php

@@ -0,0 +1,103 @@
+<?php
+
+/******************************************************************************/
+/* Each entry of that file can be associated with a comment to indicate its   */
+/* state. When there is no comment, it means the entry is fully translated.   */
+/* The recognized comments are (comment matching is case-insensitive):        */
+/*   + TODO: the entry has never been translated.                             */
+/*   + DIRTY: the entry has been translated but needs to be updated.          */
+/*   + IGNORE: the entry does not need to be translated.                      */
+/* When a comment is not recognized, it is discarded.                         */
+/******************************************************************************/
+
+return array(
+	'about' => array(
+		'_' => 'Sobre',
+		'agpl3' => '<a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL 3</a>',	// IGNORE
+		'bug_reports' => array(
+			'environment_information' => array(
+				'_' => 'System information',	// TODO
+				'browser' => 'Browser',	// TODO
+				'database' => 'Database',	// TODO
+				'server_software' => 'Server software',	// TODO
+				'version_frss' => 'FreshRSS version',	// TODO
+				'version_php' => 'PHP version',	// TODO
+			),
+		),
+		'bugs_reports' => 'Reportar Erros',
+		'credits' => 'Créditos',
+		'credits_content' => 'Alguns elementos de design vieram do <a href="http://twitter.github.io/bootstrap/">Bootstrap</a> Embora FreshRRS não utiliza este framework. <a href="https://gitlab.gnome.org/Archive/gnome-icon-theme-symbolic">Ícones</a> vieram do <a href="https://www.gnome.org/">GNOME project</a>. <em>Open Sans</em> font police foi criada por <a href="https://fonts.google.com/specimen/Open+Sans">Steve Matteson</a>. FreshRSS é baseado no <a href="https://framagit.org/marienfressinaud/MINZ">Minz</a>, um framework PHP.',
+		'documentation' => 'Documentação',
+		'freshrss_description' => 'FreshRSS é um RSS feeds aggregator para um host próprio. É leve e fácil de utilizar enquanto é uma ferramenta poderosa e configurável. ',
+		'github' => '<a href="https://github.com/FreshRSS/FreshRSS/issues">no GitHub</a>',
+		'license' => 'licença',
+		'project_website' => 'Site do projeto',
+		'title' => 'Sobre',
+		'version' => 'Versão',
+	),
+	'feed' => array(
+		'empty' => 'Não há nenhum artigo para mostrar.',
+		'received' => array(
+			'before_yesterday' => 'Received before yesterday',	// TODO
+			'today' => 'Received today',	// TODO
+			'yesterday' => 'Received yesterday',	// TODO
+		),
+		'rss_of' => 'RSS feed do %s',
+		'title' => 'Stream principal',
+		'title_fav' => 'Favoritos',
+		'title_global' => 'Visualização Global',
+	),
+	'log' => array(
+		'_' => 'Logs',	// IGNORE
+		'clear' => 'Limpar logs',
+		'empty' => 'Arquivo de log está vazio',
+		'title' => 'Logs',	// IGNORE
+	),
+	'menu' => array(
+		'about' => 'Sobre o FreshRSS',
+		'before_one_day' => 'Antes de um dia',
+		'before_one_week' => 'Antes de uma semana',
+		'bookmark_query' => 'Salvar pesquisa atual',
+		'favorites' => 'Favoritos (%s)',
+		'global_view' => 'Visualização global',
+		'important' => 'Feeds importantes',
+		'main_stream' => 'Stream principal',
+		'mark_all_read' => 'Marcar todos como lidos',
+		'mark_cat_read' => 'Marcar categoria como lida',
+		'mark_feed_read' => 'Marcar feed com lido',
+		'mark_selection_unread' => 'Marcar seleção como não lida',
+		'mylabels' => 'Minhas etiquetas',
+		'newer_first' => 'Novos primeiro',
+		'non-starred' => 'Mostrar todos, exceto favoritos',
+		'normal_view' => 'visualização normal',
+		'older_first' => 'Antigos primeiro',
+		'queries' => 'Queries do utilizador',
+		'read' => 'Mostrar apenas lidos',
+		'reader_view' => 'Visualização de leitura',
+		'rss_view' => 'Feed RSS',
+		'search_short' => 'Pesquisar',
+		'sort' => array(
+			'_' => 'Sorting criteria',	// TODO
+			'date_asc' => 'Publication date 1→9',	// TODO
+			'date_desc' => 'Publication date 9→1',	// TODO
+			'id_asc' => 'Freshly received last',	// TODO
+			'id_desc' => 'Freshly received first',	// TODO
+			'link_asc' => 'Link A→Z',	// TODO
+			'link_desc' => 'Link Z→A',	// TODO
+			'rand' => 'Random order',	// TODO
+			'title_asc' => 'Title A→Z',	// TODO
+			'title_desc' => 'Title Z→A',	// TODO
+		),
+		'starred' => 'Mostrar apenas os favoritos',
+		'stats' => 'Estatísticas',
+		'subscription' => 'Gestão de inscrições',
+		'unread' => 'Mostrar apenas os não lidos',
+	),
+	'share' => 'Partilhar',
+	'tag' => array(
+		'related' => 'Tags relacionadas',
+	),
+	'tos' => array(
+		'title' => 'Termos do serviço',
+	),
+);

+ 128 - 0
app/i18n/pt-pt/install.php

@@ -0,0 +1,128 @@
+<?php
+
+/******************************************************************************/
+/* Each entry of that file can be associated with a comment to indicate its   */
+/* state. When there is no comment, it means the entry is fully translated.   */
+/* The recognized comments are (comment matching is case-insensitive):        */
+/*   + TODO: the entry has never been translated.                             */
+/*   + DIRTY: the entry has been translated but needs to be updated.          */
+/*   + IGNORE: the entry does not need to be translated.                      */
+/* When a comment is not recognized, it is discarded.                         */
+/******************************************************************************/
+
+return array(
+	'action' => array(
+		'finish' => 'Instalação completa',
+		'fix_errors_before' => 'Por favor resolva os erros antes de ir para o próximo passo.',
+		'keep_install' => 'Mantenha as configurações anteriores',
+		'next_step' => 'Vá para o próximo passo',
+		'reinstall' => 'Reinstale o FreshRSS',
+	),
+	'bdd' => array(
+		'_' => 'base de dados',
+		'conf' => array(
+			'_' => 'Configuração da base de dados',
+			'ko' => 'Verifique as informações do seu base de dados.',
+			'ok' => 'Configurações do base de dados foram salvas.',
+		),
+		'host' => 'Host',	// IGNORE
+		'password' => 'Senha do base de dados',
+		'prefix' => 'Prefixo da tabela',
+		'type' => 'Tipo do base de dados',
+		'username' => 'Utilizador do base de dados',
+	),
+	'check' => array(
+		'_' => 'Verificações',
+		'already_installed' => 'Verificamos que o FreshRSS já está instalado!',
+		'cache' => array(
+			'nok' => 'Verifique as permissões no diretório <em>%s</em>. O servidor HTTP deve ter direitos para escrever dentro desta pasta.',
+			'ok' => 'Permissões no diretório cache estão corretos.',
+		),
+		'ctype' => array(
+			'nok' => 'Não foi possível encontrar uma biblioteca necessária para verificação do tipo de caractere (php-ctype).',
+			'ok' => 'Tem a biblioteca necessária para verificação do tipo de caractere (ctype).',
+		),
+		'curl' => array(
+			'nok' => 'Não foi possível encontrar a biblioteca cURL (php-curl).',
+			'ok' => 'Tem a biblioteca cURL.',
+		),
+		'data' => array(
+			'nok' => 'Verifique as permissões no diretório <em>%s</em>. O servidor HTTP deve ter direitos para escrever dentro desta pasta.',
+			'ok' => 'Permissões no diretório data estão corretos.',
+		),
+		'dom' => array(
+			'nok' => 'Não foi possível encontrar uma biblioteca necessária para navegar pelo DOM (php-xml).',
+			'ok' => 'Tem a biblioteca necessária para navegar pelo DOM.',
+		),
+		'favicons' => array(
+			'nok' => 'Verifique as permissões no diretório <em>%s</em>. O servidor HTTP deve ter direitos para escrever dentro desta pasta.',
+			'ok' => 'Permissões no diretório favicons estão corretos.',
+		),
+		'fileinfo' => array(
+			'nok' => 'Não foi possível encontrar a biblioteca fileinfo do PHP (fileinfo).',
+			'ok' => 'Tem a biblioteca fileinfo.',
+		),
+		'json' => array(
+			'nok' => 'Não foi possível encontrar JSON (php-json).',
+			'ok' => 'Tem a extensão JSON.',
+		),
+		'mbstring' => array(
+			'nok' => 'Não foi possível encontrar a biblioteca recomendada para o Unicode (mbstring).',
+			'ok' => 'Tem a biblioteca recomendada para o Unicode (mbstring).',
+		),
+		'pcre' => array(
+			'nok' => 'Não foi possível encontrar uma biblioteca necessário para expressões regulares (php-pcre).',
+			'ok' => 'Tem a biblioteca necessária para expressões regulares (php-pcre).',
+		),
+		'pdo' => array(
+			'nok' => 'Não foi encontrado o PDO ou um dos drivers suportados (pdo_mysql, pdo_sqlite, pdo_pgsql).',
+			'ok' => 'Tem o PDO e ao menos um dos drivers suportados (pdo_mysql, pdo_sqlite, pdo_pgsql).',
+		),
+		'php' => array(
+			'nok' => 'A versão do PHP é %s mas FreshRSS requer ao menos a versão %s.',
+			'ok' => 'A versão do PHP é %s, que é compatível com o FreshRSS.',
+		),
+		'reload' => 'Verifique novamente',
+		'tmp' => array(
+			'nok' => 'Verifiquei as permissões no diretório <em>%s</em>. O servidor HTTP deve ter direitos para escrever dentro desta pasta.',
+			'ok' => 'As permissões para o diretório temporário estão certas.',
+		),
+		'unknown_process_username' => 'Desconhecido',
+		'users' => array(
+			'nok' => 'Verifiquei as permissões no diretório <em>%s</em>. O servidor HTTP deve ter direitos para escrever dentro desta pasta.',
+			'ok' => 'Permissões no diretório users estão corretos.',
+		),
+		'xml' => array(
+			'nok' => 'Não foi possível encontrar a biblioteca necessária para parse o XML.',
+			'ok' => 'Tem a biblioteca necessária para parse o XML.',
+		),
+	),
+	'conf' => array(
+		'_' => 'Configurações gerais',
+		'ok' => 'Configurações gerais foram salvas.',
+	),
+	'congratulations' => 'Parabéns!',
+	'default_user' => array(
+		'_' => 'Utilizador padrão',
+		'max_char' => 'máximo de 16 caracteres alfanuméricos',
+	),
+	'fix_errors_before' => 'Por favor solucione os erros antes de ir para o próximo passo.',
+	'javascript_is_better' => 'O FreshRSS é mais agradável com o JavaScript ativo',
+	'js' => array(
+		'confirm_reinstall' => 'Vai perder suas configurações anteriores ao reinstalar o FreshRSS. Confirma que pretende continuar?',
+	),
+	'language' => array(
+		'_' => 'Idioma',
+		'choose' => 'Escolha o idioma para o FreshRSS',
+		'defined' => 'O idioma foi definido.',
+	),
+	'missing_applied_migrations' => 'Algo de errado ocorreu; Tem que criar um arquivo vazio <em>%s</em> manualmente.',
+	'ok' => 'O processo de instalação foi um sucesso.',
+	'session' => array(
+		'nok' => 'O servidor parece ter sido configurado incorretamente para os cookies necessários para sessões PHP!',
+	),
+	'step' => 'passo %d',
+	'steps' => 'Passos',
+	'this_is_the_end' => 'Este é o final',
+	'title' => 'Instalação · FreshRSS',
+);

+ 296 - 0
app/i18n/pt-pt/sub.php

@@ -0,0 +1,296 @@
+<?php
+
+/******************************************************************************/
+/* Each entry of that file can be associated with a comment to indicate its   */
+/* state. When there is no comment, it means the entry is fully translated.   */
+/* The recognized comments are (comment matching is case-insensitive):        */
+/*   + TODO: the entry has never been translated.                             */
+/*   + DIRTY: the entry has been translated but needs to be updated.          */
+/*   + IGNORE: the entry does not need to be translated.                      */
+/* When a comment is not recognized, it is discarded.                         */
+/******************************************************************************/
+
+return array(
+	'api' => array(
+		'documentation' => 'Copie a seguinte URL para utilizar com uma ferramenta externa',
+		'title' => 'API',	// IGNORE
+	),
+	'bookmarklet' => array(
+		'documentation' => 'Arraste este botão para sua barra de favoritos ou clique com o botão direito e escolha “Adicionar este link aos favoritos”. Depois clique no no link da barra de favoritos “Inscrever-se” em qualquer página que você queira se inscrever.',
+		'label' => 'Inscrever-se',
+		'title' => 'Bookmarklet',	// IGNORE
+	),
+	'category' => array(
+		'_' => 'Categoria',
+		'add' => 'Adicionar categoria',
+		'archiving' => 'Arquivar',
+		'dynamic_opml' => array(
+			'_' => 'OPML Dinâmico',
+			'help' => 'Forneça uma URL para <a href="http://opml.org/" target="_blank">o arquivo OPML </a> para preencher dinamicamente esta categoria com feeds',
+		),
+		'empty' => 'Categoria vazia',
+		'expand' => 'Expand category',	// TODO
+		'information' => 'Informações',
+		'open' => 'Open category',	// TODO
+		'opml_url' => 'URL de OPML',
+		'position' => 'Posição de visualização',
+		'position_help' => 'Para controlar a ordem de visualização',
+		'title' => 'Título',
+	),
+	'feed' => array(
+		'accept_cookies' => 'Aceitar cookies',
+		'accept_cookies_help' => 'Permitir que o servidor de Feed defina os cookies (sarmazenados na memória apenas durante a solicitação)',
+		'add' => 'Adicionar um feed',
+		'advanced' => 'Avançado',
+		'archiving' => 'Arquivar',
+		'auth' => array(
+			'configuration' => 'Entrar',
+			'help' => 'Permite acesso a feeds RSS protegidos por HTTP',
+			'http' => 'Autenticação HTTP',
+			'password' => 'Senha HTTP',
+			'username' => 'Utilizador HTTP',
+		),
+		'clear_cache' => 'Sempre limpar o cache',
+		'content_action' => array(
+			'_' => 'Ações ao buscar pelo conteúdo de artigos',
+			'append' => 'Adicionar depois conteúdo existente',
+			'prepend' => 'Adicionar antes do conteúdo existente',
+			'replace' => 'Substituir o conteúdo existente',
+		),
+		'content_retrieval' => 'Content retrieval',	// TODO
+		'css_cookie' => 'Usar cookies ao pesquisa pelo conteúdo de artigos',
+		'css_cookie_help' => 'Exemplo: <kbd>foo=bar; gdpr_consent=true; cookie=value</kbd>',
+		'css_help' => 'Retorna RSS feeds truncados (atenção, requer mais tempo!)',
+		'css_path' => 'Caminho do CSS do artigo no site original',
+		'css_path_filter' => array(
+			'_' => 'Seletor CSS dos elementos a serem removidos',
+			'help' => 'O seletor CSS pode ser uma lista com: <kbd>footer, aside, p[data-sanitized-class~="menu"]</kbd>',
+		),
+		'description' => 'Descrição',
+		'empty' => 'Este feed está vazio. Por favor verifique ele ainda é mantido.',
+		'error' => 'Este feed encontra-se com problema. Por favor verifique que ainda está disponível.',
+		'export-as-opml' => array(
+			'download' => 'Download',	// IGNORE
+			'help' => 'Arquivo XML (. <a href="https://freshrss.github.io/FreshRSS/en/developers/OPML.html" target="_blank">Ver documentação</a>)',
+			'label' => 'Exportar como OPML',
+		),
+		'filteractions' => array(
+			'_' => 'Ações do filtro',
+			'help' => 'Escreva um filtro de pesquisa por linha. <a href="https://freshrss.github.io/FreshRSS/en/users/10_filter.html#with-the-search-field" target="_blank">Ver documentação</a>.',
+		),
+		'http_headers' => 'HTTP Headers',	// TODO
+		'http_headers_help' => 'Headers are separated by a newline, and the name and value of a header are separated by a colon (e.g: <kbd><code>Accept: application/atom+xml<br />Authorization: Bearer some-token</code></kbd>).',	// TODO
+		'information' => 'Informações',
+		'keep_min' => 'Número mínimo de artigos para manter',
+		'kind' => array(
+			'_' => 'Tipo de fonte de alimentação do Feed',
+			'html_json' => array(
+				'_' => 'HTML + XPath + JSON dot notation (JSON in HTML)',	// TODO
+				'xpath' => array(
+					'_' => 'XPath for JSON in HTML',	// TODO
+					'help' => 'Example: <code>//script[@type="application/json"]</code>',	// TODO
+				),
+			),
+			'html_xpath' => array(
+				'_' => 'HTML + XPath (Web scraping)',	// IGNORE
+				'feed_title' => array(
+					'_' => 'Título do Feed',
+					'help' => 'Exemplo: <code>//title</code> ou uma string estática: <code>"Meu feed personalizado"</code>',
+				),
+				'help' => '<dfn><a href="https://www.w3.org/TR/xpath-10/" target="_blank">XPath 1.0</a></dfn>é uma linguagem de consulta padrão para usuários avançados e que o FreshRSS suporta para habilitar o Web scraping.',
+				'item' => array(
+					'_' => 'encontrar notícias <strong>items</strong><br /><small>(mais importantes)</small>',
+					'help' => 'Exemplo: <code>//div[@class="news-item"]</code>',
+				),
+				'item_author' => array(
+					'_' => 'Autor do item',
+					'help' => 'Também pode ser uma string estática. Exemplo: <code>"Anônimo"</code>',
+				),
+				'item_categories' => 'Etiquetas do item',
+				'item_content' => array(
+					'_' => 'Conteúdo do item',
+					'help' => 'Exemplo para pegar o item completo: <code>.</code>',
+				),
+				'item_thumbnail' => array(
+					'_' => 'Miniatura do item',
+					'help' => 'Exemplo: <code>descendant::img/@src</code>',
+				),
+				'item_timeFormat' => array(
+					'_' => 'Custom date/time format',	// TODO
+					'help' => 'Optional. A format supported by <a href="https://php.net/datetime.createfromformat" target="_blank"><code>DateTime::createFromFormat()</code></a> such as <code>d-m-Y H:i:s</code>',	// TODO
+				),
+				'item_timestamp' => array(
+					'_' => 'Data do Item',
+					'help' => 'O resultado será parecido com: <a href="https://php.net/strtotime" target="_blank"><code>strtotime()</code></a>',
+				),
+				'item_title' => array(
+					'_' => 'Titulo do Item',
+					'help' => 'Utilize especialmente <a href="https://developer.mozilla.org/docs/Web/XPath/Axes" target="_blank">XPath axis</a> <code>descendant::</code> like <code>descendant::h2</code>',
+				),
+				'item_uid' => array(
+					'_' => 'ID único do item',
+					'help' => 'Opcional. Exemplo: <code>descendant::div/@data-uri</code>',
+				),
+				'item_uri' => array(
+					'_' => 'Link do item (URL)',
+					'help' => 'Exemplo: <code>descendant::a/@href</code>',
+				),
+				'relative' => 'XPath (relativo do item) para:',
+				'xpath' => 'XPath para:',
+			),
+			'json_dotnotation' => array(
+				'_' => 'JSON (notação de ponto)',
+				'feed_title' => array(
+					'_' => 'título do feed',
+					'help' => 'Exemplo: <code>meta.title</code> ou uma string estática: <code>"Meu feed personalizado"</code>',
+				),
+				'help' => 'Um JSON na notação de ponto usa pontos entre os objetos e colchetes para arrays (e.g. <code>data.items[0].title</code>)',
+				'item' => array(
+					'_' => 'encontrando novidades <strong>itens</strong><br /><small>(mais importante)</small>',
+					'help' => 'Caminho do JSON para o array contendo os itens, e.g. <code>$</code> or <code>newsItems</code>',
+				),
+				'item_author' => 'autor do item',
+				'item_categories' => 'tags dos itens',
+				'item_content' => array(
+					'_' => 'conteúdo do item',
+					'help' => 'Chave sob na qual o conteúdo é encontrado, e.g. <code>content</code>',
+				),
+				'item_thumbnail' => array(
+					'_' => 'miniatura do item',
+					'help' => 'Exemplo: <code>image</code>',
+				),
+				'item_timeFormat' => array(
+					'_' => 'Formato de data/hora personalizado',
+					'help' => 'Opcional. Um formato suportado por <a href="https://php.net/datetime.createfromformat" target="_blank"><code>DateTime::createFromFormat()</code></a> assim como <code>d-m-Y H:i:s</code>',
+				),
+				'item_timestamp' => array(
+					'_' => 'data do item',
+					'help' => 'The result will be parsed by <a href="https://php.net/strtotime" target="_blank"><code>strtotime()</code></a>',	// TODO
+				),
+				'item_title' => 'título do item',
+				'item_uid' => 'ID único do item',
+				'item_uri' => array(
+					'_' => 'Link do item (URL)',
+					'help' => 'Exemplo: <code>permalink</code>',
+				),
+				'json' => 'notação de ponto para:',
+				'relative' => 'notação de ponto (relativa ao item) para:',
+			),
+			'jsonfeed' => 'JSON Feed',	// IGNORE
+			'rss' => 'RSS / Atom (padrão)',
+			'xml_xpath' => 'XML + XPath',	// IGNORE
+		),
+		'maintenance' => array(
+			'clear_cache' => 'Limpar o cache',
+			'clear_cache_help' => 'Limpar o cache em disco deste feed',
+			'reload_articles' => 'Recarregar artigos',
+			'reload_articles_help' => 'Recarregar artigos e buscar conteúdo completo',
+			'title' => 'Manutenção',
+		),
+		'max_http_redir' => 'Quantidade máxima de redirecionamentos HTTP',
+		'max_http_redir_help' => 'Defina como 0 ou deixe em branco para desactivar, -1 para redirecionamentos ilimitados',
+		'method' => array(
+			'_' => 'Método HTTP',
+		),
+		'method_help' => 'O conteúdo do POST tem suporte automático para <code>application/x-www-form-urlencoded</code> e <code>application/json</code>',
+		'method_postparams' => 'Conteúdo do POST',
+		'moved_category_deleted' => 'Quando você deleta uma categoria, seus feeds são automaticamente classificados como <em>%s</em>.',
+		'mute' => array(
+			'_' => 'silenciar',
+			'state_is_muted' => 'This feed is muted',	// TODO
+		),
+		'no_selected' => 'Nenhum feed selecionado.',
+		'number_entries' => '%d artigos',
+		'open_feed' => 'Open feed %s',	// TODO
+		'path_entries_conditions' => 'Conditions for content retrieval',	// TODO
+		'priority' => array(
+			'_' => 'Visibilidade',
+			'archived' => 'Não exibir (arquivado)',
+			'category' => 'Mostrar na sua categoria',
+			'important' => 'Mostrar feeds importantes',
+			'main_stream' => 'Mostrar na tela principal',
+		),
+		'proxy' => 'Defina um proxy para buscar esse feed',
+		'proxy_help' => 'Selecione um protocolo (e.g: SOCKS5) e digite o endereço do proxy (e.g: <kbd>127.0.0.1:1080</kbd> or <kbd>username:password@127.0.0.1:1080</kbd>)',
+		'selector_preview' => array(
+			'show_raw' => 'Mostrar fonte',
+			'show_rendered' => 'Mostrar conteúdo',
+		),
+		'show' => array(
+			'all' => 'Mostrar todos os Feeds',
+			'error' => 'Somente mostrar Feeds com erros',
+		),
+		'showing' => array(
+			'error' => 'Exibir apenas os feeds com erros',
+		),
+		'ssl_verify' => 'Verificar segurança SSL',
+		'stats' => 'Estatísticas',
+		'think_to_add' => 'Tem adicionar alguns feeds.',
+		'timeout' => 'Timeout em segundos',
+		'title' => 'Título',
+		'title_add' => 'Adicionar o RSS feed',
+		'ttl' => 'Não atualize automaticamente mais que',
+		'unicityCriteria' => array(
+			'_' => 'Article unicity criteria',	// TODO
+			'forced' => '<span title="Block the unicity criteria, even when the feed has duplicate articles">forced</span>',	// TODO
+			'help' => 'Relevant for invalid feeds.<br />⚠️ Changing the policy will create duplicates.',	// TODO
+			'id' => 'Standard ID (default)',	// TODO
+			'link' => 'Link',	// TODO
+			'sha1:link_published' => 'Link + Date',	// TODO
+			'sha1:link_published_title' => 'Link + Date + Title',	// TODO
+			'sha1:link_published_title_content' => 'Link + Date + Title + Content',	// TODO
+		),
+		'url' => 'URL do Feed',
+		'useragent' => 'Defina um utilizador para pesquisar este feed',
+		'useragent_help' => 'Exemplo: <kbd>Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0)</kbd>',
+		'validator' => 'Verifique a validade do feed',
+		'website' => 'URL do site',
+		'websub' => 'Notificação instantânea com WebSub',
+	),
+	'import_export' => array(
+		'export' => array(
+			'_' => 'Exportar',
+			'sqlite' => 'Download user database as SQLite',	// TODO
+		),
+		'export_labelled' => 'Exportar seus artigos etiquetados',
+		'export_opml' => 'Exporta a lista dos feeds (OPML)',
+		'export_starred' => 'Exportar seus favoritos',
+		'feed_list' => 'Lista dos %s artigos',
+		'file_to_import' => 'Arquivo para importar<br />(OPML, JSON or ZIP)',
+		'file_to_import_no_zip' => 'Arquivo para importar<br />(OPML or JSON)',
+		'import' => 'Importar',
+		'starred_list' => 'Listar artigos favoritos',
+		'title' => 'Importar / exportar',
+	),
+	'menu' => array(
+		'add' => 'Adicionar um feed ou categoria',
+		'import_export' => 'Importar / exportar',
+		'label_management' => 'Gerir etiquetas',
+		'stats' => array(
+			'idle' => 'Feeds inativos',
+			'main' => 'Estatísticas principais',
+			'repartition' => 'Repartição de artigos',
+		),
+		'subscription_management' => 'Gerir de inscrições',
+		'subscription_tools' => 'Ferramentas de inscrição',
+	),
+	'tag' => array(
+		'auto_label' => 'Adicione esta etiqueta para novos artigos',
+		'name' => 'Nome',
+		'new_name' => 'Nome novo',
+		'old_name' => 'Nome antigo',
+	),
+	'title' => array(
+		'_' => 'Gerir inscrições',
+		'add' => 'Adicionar um feed ou categoria',
+		'add_category' => 'Adicionar uma categoria',
+		'add_dynamic_opml' => 'Adicionar OPML dinâmico',
+		'add_feed' => 'Adicionar um feed',
+		'add_label' => 'Adicionar uma etiqueta',
+		'add_opml_category' => 'OPML category name',	// TODO
+		'delete_label' => 'Apagar uma etiqueta',
+		'feed_management' => 'Gerir dos RSS feeds',
+		'rename_label' => 'Renomear uma etiqueta',
+		'subscription_tools' => 'Ferramentas de inscrição',
+	),
+);

+ 54 - 0
app/i18n/pt-pt/user.php

@@ -0,0 +1,54 @@
+<?php
+
+/******************************************************************************/
+/* Each entry of that file can be associated with a comment to indicate its   */
+/* state. When there is no comment, it means the entry is fully translated.   */
+/* The recognized comments are (comment matching is case-insensitive):        */
+/*   + TODO: the entry has never been translated.                             */
+/*   + DIRTY: the entry has been translated but needs to be updated.          */
+/*   + IGNORE: the entry does not need to be translated.                      */
+/* When a comment is not recognized, it is discarded.                         */
+/******************************************************************************/
+
+return array(
+	'email' => array(
+		'feedback' => array(
+			'invalid' => 'Endereço de email inválido',
+			'required' => 'O endereço de email é necessário',
+		),
+		'validation' => array(
+			'change_email' => 'Pode mudar seu endereço de email <a href="%s">na página do perfil</a>.',
+			'email_sent_to' => 'Enviamos um email para <strong>%s</strong>. Por favor, siga as instruções contidas nele para verificar sua conta.',
+			'feedback' => array(
+				'email_failed' => 'Não foi possível enviar um email devido a um erro de configuração no servidor.',
+				'email_sent' => 'Um email foi enviado para o seu endereço',
+				'error' => 'Falha na verificação do endereço de email',
+				'ok' => 'O endereço de email foi verificado com sucesso.',
+				'unnecessary' => 'Esse endereço de email já foi verificado.',
+				'wrong_token' => 'A verificação do endereço de email falhou por causa do token incorreto.',
+			),
+			'need_to' => 'Para poder utilizar o %s, deve verificar seu endereço de email.',
+			'resend_email' => 'Reenviar o email',
+			'title' => 'Validação do endereço de email',
+		),
+	),
+	'mailer' => array(
+		'email_need_validation' => array(
+			'body' => 'Registrou no %s. Mas ainda é necessário verificar seu endereço de email. Para isso, basta seguir o link:',
+			'title' => 'Precisa verificar a conta',
+			'welcome' => 'Bem vindo %s,',
+		),
+	),
+	'password' => array(
+		'invalid' => 'Senha incorreta',
+	),
+	'tos' => array(
+		'feedback' => array(
+			'invalid' => 'Para se registrar, tem que aceitar os Termos do serviço.',
+		),
+	),
+	'username' => array(
+		'invalid' => 'Nome de utilizador inválido.',
+		'taken' => 'O nome de utilizador %s já está sendo utilizado',
+	),
+);

+ 1 - 0
app/i18n/ru/gen.php

@@ -170,6 +170,7 @@ return array(
 		'oc' => 'Occitan',	// IGNORE
 		'pl' => 'Polski',	// IGNORE
 		'pt-br' => 'Português (Brasil)',	// IGNORE
+		'pt-pt' => 'Português (Portugal)',	// IGNORE
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE

+ 1 - 0
app/i18n/sk/gen.php

@@ -170,6 +170,7 @@ return array(
 		'oc' => 'Occitan',	// IGNORE
 		'pl' => 'Polski',	// IGNORE
 		'pt-br' => 'Português (Brasil)',	// IGNORE
+		'pt-pt' => 'Português (Portugal)',	// IGNORE
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE

+ 1 - 0
app/i18n/tr/gen.php

@@ -170,6 +170,7 @@ return array(
 		'oc' => 'Occitan',	// IGNORE
 		'pl' => 'Polski',	// IGNORE
 		'pt-br' => 'Português (Brasil)',	// IGNORE
+		'pt-pt' => 'Português (Portugal)',	// IGNORE
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE

+ 1 - 0
app/i18n/zh-cn/gen.php

@@ -170,6 +170,7 @@ return array(
 		'oc' => 'Occitan',	// IGNORE
 		'pl' => 'Polski',	// IGNORE
 		'pt-br' => 'Português (Brasil)',	// IGNORE
+		'pt-pt' => 'Português (Portugal)',	// IGNORE
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE

+ 1 - 0
app/i18n/zh-tw/gen.php

@@ -170,6 +170,7 @@ return array(
 		'oc' => 'Occitan',	// IGNORE
 		'pl' => 'Polski',	// IGNORE
 		'pt-br' => 'Português (Brasil)',	// IGNORE
+		'pt-pt' => 'Português (Portugal)',	// IGNORE
 		'ru' => 'Русский',	// IGNORE
 		'sk' => 'Slovenčina',	// IGNORE
 		'tr' => 'Türkçe',	// IGNORE