Encapsulando a API do Deepl em uma Fonte de Dados
1Introdução
No tutorial anterior, vimos como criar uma fonte de dados que encapsula a API do serviço OpenWeatherMap. Agora vamos criar outra fonte de dados, uma que dá acesso à API do serviço de tradução Deepl, que pode ser usada para traduzir textos com facilidade.
2Configuração
No arquivo de configuração etc/temma.php, vamos adicionar a definição de uma fonte de dados um pouco especial. Como não é uma fonte de dados gerenciada nativamente pelo Temma, vamos prefixar o DSN com o nome do objeto a ser usado (entre colchetes).
O DSN terá a forma deepl://API_KEY@DEFAULT_LANG
sendo API_KEY a chave de API fornecida pelo Deepl, e DEFAULT_LANG o
idioma padrão para o qual os textos serão traduzidos.
Exemplo de configuração:
<?php
return [
"application" => [
"dataSources" => [
"transl" => '[\Deepl\Translate]deepl://0123456789abcdef0123456789abcdef@EN'
]
]
];
3Código-fonte
Aqui está o código da nossa fonte de dados, que vamos salvar no arquivo lib/Deepl/Translate.php:
<?php
namespace Deepl;
class Translate extends \Temma\Base\Datasource {
/** Constante: prefixo do DSN. */
const DSN_SCHEME = 'deepl://';
/** Constante: URL da API do Deepl. */
const API_URL = 'https://api-free.deepl.com/v2/translate';
/** Chave de acesso à API. */
private string $_key;
/** Idioma padrão de tradução. */
private string $_lang;
/**
* Fábrica. Cria uma instância do objeto a partir de um DSN.
* @param string $dsn String de configuração.
* @return \Deepl\Translate O objeto instanciado.
* @throws \Exception Se o DSN estiver incorreto.
*/
static public function factory(string $dsn) : \Deepl\Translate {
// interpretação do DSN
$parts = parse_url($dsn);
$scheme = $parts['scheme'] ?? null;
$key = $parts['user'] ?? null;
$lang = $parts['host'] ?? null;
// verificações
if ($scheme != self::DSN_SCHEME || !$key || !$lang) {
throw new \Exception("Invalid Deepl DSN '$dsn'.");
}
return (new self($key, $lang));
}
/**
* Construtor.
* @param string $key Chave de acesso à API.
* @param string $lang Idioma padrão de tradução.
*/
public function __construct(string $key, string $lang) {
$this->_key = $key;
$this->_lang = $lang;
}
/**
* Tradução de um texto para o idioma padrão.
* @param string $text Texto a ser traduzido.
* @param mixed $default Parâmetro não utilizado (necessário por motivos de herança).
* @param mixed $options Parâmetro não utilizado (necessário por motivos de herança).
* @return mixed O texto traduzido.
* @throws \Exception Se ocorreu um erro.
*/
public function get(string $text, mixed $default=null, mixed $options=null) : mixed {
$this->translate($text, $this->_lang);
}
/**
* Traduz um texto para um idioma específico.
* @param string $text Texto a ser traduzido
* @param string $lang Idioma de tradução.
* @param ?string $sourceLang (opcional) Idioma do texto a ser traduzido.
* Por padrão, o Deepl o detecta automaticamente.
* @return string A tradução do texto, ou uma string vazia se o texto não pôde ser traduzido.
* @throws \Exception Se ocorreu um erro.
*/
public function translate(string $text, string $lang, ?string $sourceLang=null) : string {
// preparação dos dados a serem enviados
$data = [
'text' => [$text],
'target_lang' => $lang,
];
if ($sourceLang) {
$data['source_lang'] = $sourceLang;
}
$data = json_encode($data);
// chamada à API
$curl = curl_init(self::API_URL);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 3);
curl_setopt($curl, CURLOPT_HTTPHEADER, [
'Authorization: DeepL-Auth-Key ' . $this->_key,
'Content-Type: application/json',
]);
$result = curl_exec($curl);
if ($result === false)
throw new \Exception(curl_error($curl));
curl_close($curl);
// recuperação do resultado
$result = json_decode($result, true);
return ($result['translations'][0]['text'] ?? '');
}
}
- Linhas 21 a 32: método factory(), chamado pelo Temma quando a fonte de dados é criada. Esse método interpreta o DSN e chama o construtor.
- Linhas 38 a 41: construtor, usado para criar uma instância do objeto diretamente.
- Linhas 50 a 52: método get(), que sobrescreve o do objeto pai \Temma\Base\Datasource, e chama o método translate() do objeto. Esse método pode ser usado diretamente, mas também é chamado automaticamente quando o objeto é lido como um array.
- Linhas 62 a 93: método translate(), que se conecta à API do Deepl para realizar uma tradução. Esse método recebe como parâmetros o texto a ser traduzido e o idioma de tradução. Ele também pode receber o idioma de origem, caso você queira traduzir um texto em um idioma diferente do padrão definido na configuração.
- Linhas 64 a 71: criação da tabela de dados a ser enviada à API do Deepl, depois de ser serializada em JSON.
- Linhas 74 a 88: conexão com a API do Deepl, envio dos dados e recuperação do retorno.
- Linhas 91 e 92: desserialização dos dados recuperados e retorno do método.
4Uso
Em um controlador, a fonte de dados chamada "transl" no arquivo de configuração está
disponível nos controladores escrevendo $this->transl. Um texto pode ser traduzido
para o idioma padrão definido na configuração chamando o método get() ou usando-a como um array:
// usando o método get()
$englishText = $this->transl->get('Bonjour, comment allez-vous ?');
// escrita como array
$englishText = $this->transl['Bonjour, comment allez-vous ?'];
Para definir um idioma de tradução diferente, ou para definir o idioma de origem, use o método translate():
$germanText = $this->transl->translate('Hi, how are you?', 'DE', 'EN');
Fora dos controladores, você deve usar o componente de injeção de dependências:
$englishText = $this->_loader->dataSources->transl->get('Bonjour, comment allez-vous ?');
$englishText = $this->_loader->dataSources->transl['Bonjour, comment allez-vous ?'];
$germanText = $this->_loader->dataSources->transl->translate('Hi, how are you?', 'DE', 'EN');