Kdyby\Translation uložení nepřeložené message do databáze

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
serten
Člen | 55
+
0
-

Zdravím,

řeším aktuálně situaci, kdy využívám pro překlad aplikace Kdyby\Translation a používám databázový loader pro Doctrine. Vše jede jak má, jen se v tuto chvíli snažím nepřeložené message nějak automaticky vložit do databáze. Pokaždé, kdy by se zjistilo, že daná message není v databázi, nebyl by tam záznam a nebo by záznam nebyl přeložený, tak by se vytvořil nový pro danou zprávu v konkrétním jazyce. Chci tím následně umožnit uživateli/administrátorovi překládat si aplikaci a navíc abych nemusel každou zprávu a text ručně zapisovat do databáze. Bohužel jsem nepřišel na způsob, jak přepsat nebo rozšířit tento Translator. Dokázal by jste mi někdo poradit, jak toto provést? Děkuji za jakoukoliv radu.

Azathoth
Člen | 495
+
+3
-

Ahoj,
z Kdyby/Translation jde vytáhnout všechny překlady (např. pro češtinu a angličtinu) tímhle

	$catalogueCs = $this->translator->getCatalogue('cs');
	$catalogueEn = $this->translator->getCatalogue('en');

s tím, že $this->translator je, podle očekávání, Kdyby\Translation\Translator, a $catalogueCs a $catalogueEn jsou katalogy, zapouzřující překlady do daného jazyka.
Takže pokud vím, že mám všechny překlady v češtině a chci je doplnit prázdný string do chybějících překladů v angličtině, udělám to takhle

		$allCsTranslations = $catalogueCs->all();	//tím vyytáhneš překlady do češtiny jako 2D pole
		foreach ($allCsTranslations as $domain => $translations) {
			foreach ($translations as $key => $value) {
				if (!$catalogueEn->defines($key, $domain)) {	//chybí překlad do angličtiny
					$defautValue = '';
					$catalogueEn->set($key, $defautValue, $domain);	//doplním defaultní text
				}
			}
		}

a uložit do databáze to můžeš pak přes Writer ze Symfony\Translation, na kterém Kdyby\Translation stojí, takhle

		$this->writer->writeTranslations($catalogueCs, 'database');
		$this->writer->writeTranslations($catalogueEn, 'database');

a writer se o všechno postará.
$this->writer získáš pomocí DI v presenteru takhle (do modelu si to pochopitelně injectuj přes konstruktor):

	/** @var \Symfony\Component\Translation\Writer\TranslationWriter @inject */
	public $writer;

Takže pokud bude někdo přidávat text do jednoho jazyka, pomocí té defines metody u katalogu pro jiný jazyk si můžeš ověřit, jestli v tom jazyku ten překlad je a pokud není, tak tam doplníš ten defaultní a je to.

Snad jsem pomohl, kdyby to nezabralo, ptej se.
Tohle je bohužel strašně špatně zdokumentované i u Symfony, tu práci s katalogem a writerem jsem objevil tak nějak metodou pokus, omyl.

A tohle je obecné pro Kdyby\Translation, takže je jedno, jaké tam máš úložiště překladů, poradí si to se vším, co má načtený Loader a Dumper.
A to, kam se to uloží, řídíš tím stringem ‚database‘. Kdybys to chtěl uložit jinam, třeba do neonu, yamlu nebo jinam, tak to stačí udělat takhle:

$this->writer->writeTranslations($catalogueEn, 'neon');
$this->writer->writeTranslations($catalogueEn, 'yaml');

Tyhle modifikace jsem zkoušel pouze u ukládání do souborů, u databáze jsem, myslím, tu modifikaci překladů na produkci ještě nezkoušel, ale pokud by se nenačítaly nové překlady a zobrazovaly by se pořád ty staré, tak to je tím, že se špatně invaliduje cache v Kdyby\Translation.
Cache v Kdyby\Translation vypneš takhle:
Nejdřív si injectuješ catalogueCompiler

	/** @var \dyby\Translation\CatalogueCompiler @inject */
	public $catalogueCompiler;	//injectuješ si třídu zodpovědnou za tvorbu překladové cache

a pak mu nastavíš debug mode, kdy se nepoužívá cache

		$this->catalogueCompiler->enableDebugMode();
serten
Člen | 55
+
0
-

Super, díky za pomoc. Vypadá to dobře. Jen mě teď napadlo, jde nějak zautomatizovat tady to ukládání do databáze? V případě že to ten klíč v databázi nenajde, tak ho tam rovnou uloží. Abych při přidání nějakého nového klíče nebo jazyka nemusel všechny klíče k danému jazyku zdlouhavě přidávat do databáze.

martin.knor
Člen | 17
+
+1
-

Ahoj, zrovna jsem to resil, tak pridavam moje reseni. Potreboval jsem, aby kdyz se najde text, ktery neni v katalogu, tak se hodi do databaze – nebo kamkoliv jinam :)

Zaklad je prepsat translator tak, aby kdyz nema preklad, tak je hodi do katalogu:

<?php

namespace Makr\Translation;

use App\Model\Entity\Translation;
use App\Model\Entity\Translations;
use Kdyby\Doctrine\EntityManager;
use Kdyby\Translation\Helpers;

class Translator extends \Kdyby\Translation\Translator {

	/** @var \Kdyby\Doctrine\EntityManager */
	private $em;

	public function __construct(\Kdyby\Translation\IUserLocaleResolver $localeResolver,
								\Symfony\Component\Translation\MessageSelector $selector,
								\Kdyby\Translation\CatalogueCompiler $catalogueCompiler,
								\Kdyby\Translation\FallbackResolver $fallbackResolver,
								\Kdyby\Translation\IResourceLoader $loader,
								EntityManager $em
	)
	{
		parent::__construct($localeResolver, $selector, $catalogueCompiler, $fallbackResolver, $loader);

		$this->em = $em;
	}

	/**
	 * {@inheritdoc}
	 */
	public function translate($message, $count = null, $parameters = [], $domain = null, $locale = null)
	{
		$catalogue = $this->getCatalogue($locale);
		if ($domain === null) {
			list($domain, $message) = Helpers::extractMessageDomain($message);
		}

		if (!$catalogue->has($message, $domain)) {

			$translation = new Translation();
			$translation->setKey($domain . '.' . $message)->setLocale($locale ?: $this->getLocale());
			$this->em->safePersist($translation);
		}

		return parent::translate($message, $count, $parameters, $domain, $locale);
	}

}

Pak je potreba zaregistrovat ho v neonu – resp. prepsat puvodni

translation.default:
        class: Makr\Translation\Translator(@translation.userLocaleResolver)

Editoval martin.knor (5. 11. 2016 12:06)