Skip to content

Configuration

Vladimir Schneider edited this page May 17, 2016 · 47 revisions

The config file config/laravel-translation-manager.php has comments that provide a description for each option. Note that when admin_enabled is set to false then translation management is limited to editing existing translations all other operations have to be done through the command line. Ideally, this option needs to be dynamic based on user privileges so that translators cannot delete translations or administer translations but admins can. See Installation: step 8.

By default the primary locale is en. The primary locale determines what language is used for the source text for the translate button in the edit pop-up and can be changed in the web interface for the current session. When editing the text for the primary locale a button in the edit pop-up allows you to convert the text of the key to a default value (change . - _ to spaces, capitalize first letter of each word) that way you can generate descent placeholder text to continue development and replace it with more meaningful value later.

By default the configuration will load all translations found in the standard Laravel locations. Below {vendor}, {package}, {locale}, {group} are placeholders for their corresponding values referring to vendor name, package name, locale string and translation group. The translation group will consist of optional sub-directory tree and the file name, allowing you to organize your translation files.

/resources/lang/{locale}/{group}.php : Standard project translation files

/resources/lang/vendor/{package}/{locale}/{group} : Package translation override files.

/workbench/{vendor}/{package}/resources/lang/{locale}/{group} : Translation files for packages that you are developing in the current project. Laravel 4.2 style but the directory layout updated to version 5 standard. These will have a group prefix of wbn: in the database and web interface to distinguish them from the standard Laravel package namespaces.

/vendor/{vendor}/{package}/resources/lang/{locale}/{group} : Translation files for packages that are dependents of your project. By default no translation files are loaded from this section. You will need to edit the configuration file for the 'vendor' section and list the packages you want to include in the 'include' array in the form 'vendor/package'. These will have a group prefix of vnd: in the database and web interface to distinguish them from the standard Laravel package namespaces

The default configuration file also has entries for two packages whose translation files' location and naming convention does not follow Laravel conventions and require more tweaking to allow import/export of their language files. These non-standard layouts can only be included in the wbn: or vnd: prefixed namespaces.

Modifying the default Views

If you published the views to your project in Installation: step 11 then you can customize them to your liking. The package view directory also contains a layouts/master.blade.php file for a default layout. The intent is for you to provide your own master layout that the index.blade.php will extend so it can match your site's style.

Enabling per locale user access control

Admin users, Auth::user()->can('ltm-admin-translations') returns true, can modify, delete, create translation in all locales.

By default, users who are not administrators, ie. Auth::user()->can('ltm-admin-translations') returns false, can modify translations for all locales.

To enable per locale access control for these users you need to set user_locales_enabled in the configuration file to true and configure per user locales in the ltm_user_locales table. The user locales are indexed by currently logged in user's id.

You will need to provide the ltm-list-editors ability, in addition to the other ltm- prefixed abilities:

  • ltm-admin-translations true/false if user can administer translations

  • ltm-bypass-lottery true/false if user bypasses the missing key lottery and all missing keys are displayed for the user.

  • ltm-list-editors true/false if user can manage per locale user list. This the ability function takes 3 parameters:

    1. $user - the currently logged in user

    2. $connection_name - current connection name, '' or null means default

    3. &$user_list - reference in which to return the list of users that can be managed by the currently logged in user.

      This should only return a list of users that have access to the translation manager web UI. Please keep in mind that by default a user can modify any locale if there is no entry for this user in the ltm_user_locales table or if the entry is null or empty. By this measure the table contains entries for users wih limited access. Any user that has access to translation manager web UI and no entry in the ltm_user_locales table will be able to edit translations in any locale. If you don't want a user to access any locales then they should not have access to the LTM web UI through the Laravel middleware authorization mechanism.

These abilities should be defined in the app's AuthServiceProvider::boot function. Here is an example:

$gate->define('ltm-admin-translations', function ($user) {
    /* @var $user \App\User */
    // modify the code below to return true for users that can administer translations
    return $user && $user->is_admin;
});

$gate->define('ltm-bypass-lottery', function ($user) {
    /* @var $user \App\User */
    // modify the code below to return true for users that can administer translations
    // or edit translation so that missing keys will be logged for all sessions of
    // these users instead of one out of N sessions as given by random lottery result 
    return $user && ($user->is_admin || $user->is_editor);
});

$gate->define('ltm-list-editors', function ($user, $connection_name, &$user_list) {
    /* @var $connection_name string */
    /* @var $user \App\User */
    /* @var $query  \Illuminate\Database\Query\Builder */
    $query = $user->on($connection_name)->getQuery();

    // modify the query to return only users that can edit translations and can be
    // managed by $user if you have a an editor scope defined on your user model
    // you can use it to filter only translation editors
    $user_list = $query->orderby('id')->get(['id', 'email']);

    // if the returned list is empty then no per locale admin will be shown for
    // the current user.
    return $user_list;
});

NOTE If the user id is not found in the table or if the locales list is null or empty then the user will have access to all locales.

Column Type Description
user_id unsigned integer value returned by Auth::id()
locales text comma separated list of locales the user is allowed to modify. null or an empty string means can modify any locale.

Users who do not have access to a locale will not be allowed to modify its translations. They will see these translations as text instead of a link that opens the edit pop-up.

Changing the database name

If you have your translation table(s) in a database other than the default used by the default connection you will need to define another database connection that has this database as the default and define a default connection to use the for translation manager database access. By default this is will be the default database connection defined in your Laravel database config file.

Laravel 5 does not handle changing the connection's database consistently. Previous attempts to allow overriding the database name via the config file produced inconsistent results.

    /**
     * used to provide an alternate default connection name for translation
     * tables
     *
     * @type string     connection name to use for the default connection
     *
     * if blank, null or not defined then default connection will be used.
     *
     */

    'default_connection' => 'mysql_laravel5',

Setting up alternate database connections

If you want to be able to access multiple databases for the translation manager from one set of language files you can configure the db_connections option in the config file. Here is what I use to access the production server's translations from my local development environment:

    /**
     * @type array      list of alternate database connections and their properties indexed by app()->environment() value,
     *                  default connection settings are taken from config, so only add alternate connections
     *
     *                  If user_list_connection is missing, null or empty then the connection will also be used
     *                  to obtain the user list for user locale management
     *
     *                  description is used to display the connection name, default connection is displayed as 'default' in
     *                  the web interface.
     *
     *                  indatabase_publish of:
     *                  0 - means use files only and publish to files.
     *                  1 - means use cache for publishing modifications. No files are written out
     *                  2 - means use cache for publishing modifications but also write out the files.
     *                      useful for publishing to files while leaving all flags in the database as
     *                      they would be after publishing only to cache.
     */
    'db_connections' => array(
        'local' => array(
            'mysql_prd' => array(
                'description' => 'production',
                'indatabase_publish' => 2,
                //'user_list_connection' => '',
            ),
        ),
    ),

The option is an array of environment names which in turn contain database connection names which list the options to use for that connection.

description : the string to use in the web interface combo box to represent this connection. If the description is empty or missing then the connection name will be used.

indatabase_publish : the setting for indatabase_publish to use for this connection. If this option is missing then the global configuration indatabase_publish will be used. Setting this value to 2, will write to the local translation files but leave the database in a state to serve changed translations from the cache. Note that with indatabase_publish set to 1 or 2 publishing will not reset the changed flag for translations and these will continue to show up in the dashboard as changed.

- 0: use files only and publish to files.
- 1: use cache for publishing modifications. No files are written out
- 2: use cache for publishing modifications but also write out the files. Useful for
  publishing to files while leaving all flags in the database as they would be after
  publishing only to cache.

user_list_connection : the connection name to use for this connection when retrieving the user list for user access admin. If this entry is missing, null or an empty string then the connection name used for translation manager tables will be used for user list retrieval. Only used if user_locales_enabled is true.

  • After updating the remote translations you need to go into translations page on the remote server and do a publish all so that either the files or the cache is updated with new translations.

  • After deploying a new version of the application, with updated translation files on the servers, you should do an Import with Only add new translations. This will import any new translations and reset the cache.

Markdown to HTML conversion

By default the markdown_key_suffix option is disabled. Enabling it would require that you also install a package that does the HTML conversion. The code currently assumes that this conversion is done via the Markdown facade using the \Markdown::convertToHtml($markdown) call. GrahamCampbell/Laravel-Markdown serves this purpose well. You will need to install this package or implement the facade to use another markdown to HTML converter, if you want to enable this option.

This option is for now experimental. ie. Evolving. There are a few limitations:

  • With this option set to a suffix string, all keys that end in this suffix, will have their text converted to HTML. The resulting HTML text will be saved in a key, with the suffix removed. For example, with the suffix set to '-md', a translation for the key license.email-body-md will be converted to HTML and the resulting text saved for the license.email-body.

  • This conversion is ONLY done when the translation for the markdown key is modified via the web UI. Keys already in the translation files or in the database are assumed to be properly converted.

  • A new button will appear in the edit pop-up for markdown keys: Screen Shot edit clean markdown

    This button removes unnecessary line breaks in the translation text or a selected part of it. Uses very rudimentary string manipulation and not proper markdown parsing. No checking is done for code fences, tables or verbatim blocks.

  • Set this to a reasonable suffix that will not conflict with normal keys in your application , with laravel translation key convention and LTM package operation. Some options that work are: '-md', '--md', '-md-'

  • Do not use:

    • '.md' or anything with a period. It denotes a nested array key for translations.
    • multi-byte characters in the suffix. non-multi-byte string operations are used in manipulating the key.
    • keys that will cause issues in jQuery because keys are used to create jQueries with keys assumed to be valid element id's
    • colons : since these are used to delimit package translation groups
    • any suffix with +, @ these fail in the JavaScript code used in the web UI.

    You get the picture. Try a suffix out and if it works for you great. If not try another one or if you are up to it, fix the code to handle the failing suffix and post a PR.

Enabling Edit In-Place on Site Pages

Edit in place mode allows editing of translations right in the page where they are located. Sometimes it is more convenient to fix a translation where you see it instead of trying to find the key that is used for the display string.

To allow this mode on your pages will require some support code in your views:

  1. You will need to add a link button that will toggle this mode via a call to:

    \Lang::inPlaceEditing(\Lang::inPlaceEditing());

    This can be done by adding a get handler to your HomeController and corresponding entry in routes.php and a link to the route you defined for this purpose. For example:

    In routes.php add:

    Route::get('/edit_in_place', 'HomeController@getEditInPlace');

    In HomeController.php add:

    public
    function getEditInPlace()
    {
        if (\Auth::check() && (\Auth::user()->is_admin || \Auth::user()->is_editor)) {
            \Lang::inPlaceEditing(!\Lang::inPlaceEditing());
            if (\App::runningUnitTests()) return \Redirect::to('/');
        }
        return !is_null(\Request::header('referer')) ? \Redirect::back() : \Redirect::to('/');
    }

    You will want to modify the check validating that the currently logged in user has translation admin or edit rights to suit your user model.

    Then somewhere on the page, probably in the site's menu, you will need to add a link that will toggle this mode:

    <a href="/edit_in_place"><?= noEditTrans('laravel-translation-manager::messages.in-place-edit') ?></a>    
  2. You will need to add supporting stylesheets and JS to you pages when in-place-edit mode is turned on:

    In the page head:

    @if(Lang::inPlaceEditing())
        <link href="//cdnjs.cloudflare.com/ajax/libs/x-editable/1.5.1/bootstrap3-editable/css/bootstrap-editable.css" rel="stylesheet"/>
        <link href="/vendor/laravel-translation-manager/css/translations.css" rel="stylesheet">
    @endif

    And at the bottom of the body with the rest of the scripts:

    @if(Lang::inPlaceEditing())
        <script src="https://cdnjs.cloudflare.com/ajax/libs/x-editable/1.5.1/bootstrap3-editable/js/bootstrap-editable.min.js"></script>
        <script src="/vendor/laravel-translation-manager/js/inflection.js"></script>
        <script src="/vendor/laravel-translation-manager/js/translations.js"></script>
    @endif
  3. All links that contain translations and need to support the in place edit need to be changed since the in-place-edit mode changes the translation string to a link that opens the edit pop-up. A link cannot contain another link so the following changes need to be made:

    From:

    <a href="/some-link">@lang('group.key')</a> 

    To (or its blade equivalent, make sure to use {!! ifEditTrans(...) !!} so as not to escape the HTML returned by this function):

    <?=ifEditTrans('group.key')?> 
    <a href="/some-link"><?=noEditTrans('group.key')?></a> 

    Similarly, you don't want links to be embedded in buttons and should use the noEditTrans() for translating button labels and using ifEditTrans() to generate a link beside the button for editing the button label's translation. This way the UI can still be navigated while in-place-edit mode is on and the translation can be edited.

    The noEditTrans() function will always return the translation string regardless of the in-place-edit mode. So all links in pages that can have this mode turned on should use this function instead of @lang()

    The ifEditTrans() function is only needed for those translations that you wish to be editable within the page. By default the function will return a link wrapped in <br>[] so it is identifiable as a translation link when in-place-edit is turned on and an empty string when it is not.

    You can include multiple ifEditTrans() with different parameters for all strings that you will want to edit in the pages. This is also useful for translations that are not visible in the page but you want to expose for editing.

    The ifEditTrans() takes the same parameters as \Lang::trans() with the addition of an extra $noWrap boolean, which if true will not wrap the returned edit link in <br>[]. The function is defined as:

    /**
     * @param       $key
     * @param array $parameters
     * @param null  $locale
     * @param null  $useDB
     * @param null  $noWrap
     *
     * @return mixed
     */
    function ifEditTrans($key, $parameters = null, $locale = null, $useDB = null, $noWrap = null)
    {
        $trans = App::make('translator');
        if ($trans->inPlaceEditing()) {
            /* @var $trans Translator */
            $text = $trans->getInPlaceEditLink($key, $parameters ?: [], $locale, $useDB);
            return $noWrap ? $text : "<br>[$text]";
        }
        return '';
    }
  4. Pop-up or drop-down menus can also have editable links but editing them will require two clicks. First click to open the drop-down and click on the edit link. This will open the pop-up but close the drop down menu. Second click to open the drop down will show the menu with the edit pop up opened.

  5. After a translation is edited the group will need to be published before it will display in the page, the same as if it was edited in the LTM Web UI.

    LTM Edit In Place

Clone this wiki locally