A
A
Alastor2015-06-23 03:45:21
PHP
Alastor, 2015-06-23 03:45:21

How to push translations to database in CakePHP?

According to the documentation, we wrap the text that we want to translate in the future in __() and then generate .pot files through the console
book.cakephp.org/3.0/en/core-libraries/internation...
And my site is developing dynamically. And several translators will work on it. Therefore, after each phrase added by the command to the template, it is not an option to start generating files for translation, combine them with the old ones and give them to translators.
As I see it, the solution to this issue is to create some kind of __perevod() method of your own and translate everything through it. But suddenly there are more elegant solutions?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
Alastor, 2015-07-02
@Alastor

in general , this plugin simply unloads translations from the table. but you still have to put them in by hand.
What my solution does:
a) Rewrites the standard __ and __d functions. There are a few more translation functions, but I don't need them yet.
b) Automatically writes to the database all translations wrapped in the above functions. Moreover, the recording takes place in all languages ​​at once. And then the translator enters the admin panel and translates (there are 7 languages ​​on the site)
c) Eliminates pot. files. How they annoy me, who would know.
d) Supports arguments. I did not reinvent the wheel and used the standard method provided by I18n
What is not in my solution:
a) Full support for translation domains. Now everything is written in one array.
If there is the same text in the default domain and, say, cake in the domain, then one will be overwritten by the other. Those that will be taken from the base earlier. Then I'll finish it.
What else is there:
a) In the admin panel where they translate, there is a button to update the cache. That is, the translator finished the translation, clicked update, and all the translations appeared on the site.
Dump from Postgres (you need to specify primary keys (id) and do auto-increments)
Table with languages

CREATE TABLE languages (
    id integer NOT NULL,
    created timestamp with time zone,
    modified timestamp with time zone,
    user_id integer NOT NULL,
    priority integer NOT NULL,
    name character varying(16) NOT NULL,
    enabled boolean DEFAULT false NOT NULL,
    translations integer DEFAULT 0 NOT NULL,
    locale character varying(5) NOT NULL,
    code character varying(3) NOT NULL,
    deleted boolean DEFAULT false NOT NULL
);

translations - the number of translations for this language (just for the information of the translator), code - the code in the site link, say site.com/en/page, deleted - the marker is the language is deleted or not. I don't delete the data in some tables and just put a mark that they are deleted. And sometimes users delete something and need to be restored. Do not climb into backups. priority - language priority when displayed in the list on the site. locale - language code for translations. It is possible to use code for this purpose, but I need locale .
Table for language phrases. Why such a structure can be read in the CakePHP documentation
CREATE TABLE i18n_messages (
    id integer NOT NULL,
    domain character varying(100),
    locale character varying(5),
    singular character varying(255),
    plural character varying(255),
    context character varying(50),
    value_0 character varying(255),
    value_1 character varying(255),
    value_2 character varying(255),
    created timestamp with time zone,
    modified timestamp with time zone
);
ALTER TABLE ONLY i18n_messages
    ADD CONSTRAINT i18n_messages_domain_locale_singular_key UNIQUE (domain, locale, singular);
ALTER TABLE ONLY i18n_messages
    ADD CONSTRAINT i18n_messages_pkey PRIMARY KEY (id);
ALTER TABLE ONLY i18n_messages
    ADD CONSTRAINT i18n_messages_locale_fkey FOREIGN KEY (locale) REFERENCES languages(locale) ON UPDATE RESTRICT ON DELETE RESTRICT;

I placed my cache for translations in config/app.php. I am using APC.
'Cache' => [
        'translations' => [
            'className' => 'Apc',
            'path' => CACHE,
            'duration' => '+2 days'
        ],
]

In config/bootstrap.php posted
Declared the $translations variable so that each time not to access the cache.
// указать в начале файла
use Cake\I18n\I18n;
use Cake\ORM\TableRegistry;

$translations = Cache::read('translations', 'translations');

// Custom localization
function __loadTranslations() {
    $languages = [];
    $translations = [];
    $languageList = TableRegistry::get('languages')->find('all', ['fields' => ['locale']])->hydrate(false)->toArray();

    foreach($languageList as $language) {
        $languages[$language['locale']] = TableRegistry::get('i18n_messages')->find('list', ['keyField' => 'singular', 'valueField' => 'value_0'])->where(['locale' => $language['locale']])->order('singular')->hydrate(false)->toArray();   
    }
    foreach($languages['rus'] as $key=>$value) {
        foreach($languageList as $language) { 
            if ($language['locale'] !== 'rus') {
                $translations[$key][$language['locale']] = $languages[$language['locale']][$key];
            }
        }
    }
    Cache::write('translations', $translations, 'translations');
    unset($languages, $translations, $languageList);
}




function __($text = null, $args = null) {
    global $translations;
    $phrase = isset($translations[$text]) ? $translations[$text][Locale::getDefault()] : false; 

    if ($phrase === false) { 
        $messagesTable = TableRegistry::get('i18n_messages');
        $languages = TableRegistry::get('languages')->find('all', ['fields' => ['locale']])->hydrate(false)->toArray();

        foreach($languages as $language) {
            $exists = $messagesTable->find('all', ['fields' => ['id']])->where(['domain' => 'default', 'singular' => $text, 'locale' => $language['locale']])->hydrate(false)->toArray();

            if (empty($exists)) {
                $message = $messagesTable->newEntity();
                $message->domain = 'default';
                $message->singular = $text;
                $message->locale = $language['locale'];

                $messagesTable->save($message);
            }
        }
        return empty($args) ? $text : I18n::translator()->translate($text, $args);
    } else {
        return empty($args) ? (is_null($phrase) ? $text : $phrase) : I18n::translator()->translate(is_null($phrase) ? $text : $phrase, $args);
    }
}

function __d($domain = null, $text = null, $args = null) {
    global $translations;

    $args   = func_num_args() === 3 ? (array) $args : array_slice(func_get_args(), 2);
    $phrase = isset($translations[$text]) ? $translations[$text][Locale::getDefault()] : false; 
    $domain = is_null($domain) ? 'default' : $domain;

    if ($phrase === false) {
        $messagesTable = TableRegistry::get('i18n_messages');
        $languages = TableRegistry::get('languages')->find('all', ['fields' => ['locale']])->hydrate(false)->toArray();

        foreach($languages as $language) {
            $exists = $messagesTable->find('all', ['fields' => ['id']])->where(['domain' => $domain, 'singular' => $text, 'locale' => $language['locale']])->hydrate(false)->toArray();

            if (empty($exists)) {
                $message = $messagesTable->newEntity();
                $message->domain = $domain;
                $message->singular = $text;
                $message->locale = $language['locale'];

                $messagesTable->save($message);
            }
        }
        return empty($args) ? $text : I18n::translator($domain)->translate($text, $args);
    } else {
        return empty($args) ? (is_null($phrase) ? $text : $phrase) : I18n::translator($domain)->translate(is_null($phrase) ? $text : $phrase, $args);
    }
}
if ($translations === false) {
    __loadTranslations();
}

I set the language of the site using the I18n::locale
method. I will be glad to comments, can you tell me what is wrong or how to improve it.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question