Sage: Translation tools aren't picking up strings in templates

Created on 7 Apr 2017  路  24Comments  路  Source: roots/sage

it looks like translatable strings, such as https://github.com/roots/sage/blob/bea1b34322d38c04a16f373170154051244c4982/resources/views/index.blade.php#L8, aren't been picked up by translation tools

if you swap {{ }} with <?php ?> then the strings are detected

- {{ __('Sorry, no results were found.', 'sage') }}
+ <?php __('Sorry, no results were found.', 'sage'); ?>

discourse thread: https://discourse.roots.io/t/localization-of-blade-templates/9331

tools:

Most helpful comment

Ok this one seems to work! Hooray :) So here's the workflow:

  1. Add strings in blade files like __('string', 'domain')
  2. In the terminal, go to the theme root folder & execute the command above (don't forget to replace two terms as mentioned)
  3. I recommend placing all localization (.pot .mo .po) files in THEME_FOLDER/lang (they're easily found by Wordpress here).
  4. Open the generated .pot file with PoEdit, select "create new translation", and save .mo & .po files in the lang folder with the correct name syntax, eg. fr_FR or en_US.
  5. Translate some strings and save, .mo files should be generated automatically by PoEdit.
  6. When adding/removing translations in templates, run the command again, then in PoEdit go to "Catalog > Update from a POT file" and select the .pot file.

If you're using WPML, in the "Theme & plugin localization" tab, you should see the table for each lang with the corresponding "The file exists" in front of it:

capture-d ecran-2017-05-31-a-14 50 30

You can also add the terminal command to your package.json file and then run yarn run pot:

json { "name": "sage", ... "scripts": { ... "pot": "find ./templates -iname \"*.php\" | xargs xgettext --language=Python --add-comments=TRANSLATORS --force-po --from-code=UTF-8 --default-domain=<domain> -k__ -k_e -k_n -k_x -k_ex -k_nx -kesc_attr__ -kesc_attr_e -kesc_attr_x -kesc_html__ -kesc_html_e -kesc_html_x -k_n_noop -k_nx_noop -o ./lang/<domain>.pot" }, }

Many thanks.

All 24 comments

For PoEdit (1.x and 2.x) following this guide should work.
http://framework.themosis.com/docs/master/blade/

I do not think this issue should be resolved on Sage level but rather on the translation tools themselves.

Thanks, but PoEdit still can't find any string if not within a <?php ?> block:

php // wp-content/themes/sage/templates/test.blade.php <?php __('test'); ?> // works {{__('test2')}} // doesn't work @php(_e('test3')) // doesn't work

I also tried these tools:

without luck, the generated .pot files are always empty. Too bad because it could be great to have a command to generate .pot files, like yarn run localize.

Just stumbled upon a PHP solution, https://github.com/xinax/laravel-gettext. Did anyone tried to integrate something like this?

By the way, looks like the WPML team doesn't plan to do anything more to support Blade templates: https://wpml.org/forums/topic/string-translation-in-blade-template-engine/

Thanks.

@nicooprat I'm using PoEdit, WPML and Sage 9 Bladeand following the guide above it works.

EDIT: Have you added the keywords?

_e
_x
esc_html__
esc_html_e
_n
_nx
_n_noop
_nx_noop
_ex

Thanks for your feedback. Here's my config:

capture d ecran 2017-04-11 a 14 26 18
capture d ecran 2017-04-11 a 09 58 32
capture d ecran 2017-04-11 a 09 59 42
capture d ecran 2017-04-11 a 09 58 39

(Btw, I agree that's not sth to be managed by Sage theme, but its tooling, either with PHP or JS)

I'm using the exact same config and it works.
I only have a slight difference, I'm using the theme root folder and I've added exclusions for vendor/node_modules/(...)

Currently I'm on PoEdit 2.0, but the same config worked on previous versions.

Try removing the *.scout.php, leave only *.blade.php

Unfortunately removing *.scout.php didn't solve it.

Also tried the configuration you recommend, no change.

I just did it all over again, by creating a fresh new .po file in the theme root directory with PoEdit, no luck either. :(

Do we agree that the goal is to avoid using <?php ?> blocks, like in my screenshot above?

When you say that it's working with WPML, do you mean that you scan the theme with PoEdit, leave translations empty, and then fill them with the WPML String Translation plugin?

Thanks for your time.

I'm using Poedit 2 (macOS) with the Blade extractor settings in a Multilingual Press (multisite) setup. Poedit works like a charm with the {{ __('String','namespace') }} definitions. I've created a .pot file first.

Make sure you include the load textdomain method and define your lang folder.

Update:
This works:
<h1>{{ __('Always free','sage') }}</h1>

But attributes don't seem to work:
<div data-readmore="{{ __('Show more', 'sage') }}">

It seems I'm only able to make this work for either php or blade, not both at once.

Is it possible to ship a config file for PoEdit bundled with Sage?

I think it works well with xgettext on the command line using this in the theme folder (replace \

$ find ./resources ./app -iname "*.php" | xargs xgettext --language=Python --add-comments=TRANSLATORS --force-po --from-code=UTF-8 --default-domain=<textdomain> -k__ -k_e -k_n -k_x -k_ex -k_nx -kesc_attr__ -kesc_attr_e -kesc_attr_x -kesc_html__ -kesc_html_e -kesc_html_x -k_n_noop -k_nx_noop -o resources/languages/<theme>.pot

Ok this one seems to work! Hooray :) So here's the workflow:

  1. Add strings in blade files like __('string', 'domain')
  2. In the terminal, go to the theme root folder & execute the command above (don't forget to replace two terms as mentioned)
  3. I recommend placing all localization (.pot .mo .po) files in THEME_FOLDER/lang (they're easily found by Wordpress here).
  4. Open the generated .pot file with PoEdit, select "create new translation", and save .mo & .po files in the lang folder with the correct name syntax, eg. fr_FR or en_US.
  5. Translate some strings and save, .mo files should be generated automatically by PoEdit.
  6. When adding/removing translations in templates, run the command again, then in PoEdit go to "Catalog > Update from a POT file" and select the .pot file.

If you're using WPML, in the "Theme & plugin localization" tab, you should see the table for each lang with the corresponding "The file exists" in front of it:

capture-d ecran-2017-05-31-a-14 50 30

You can also add the terminal command to your package.json file and then run yarn run pot:

json { "name": "sage", ... "scripts": { ... "pot": "find ./templates -iname \"*.php\" | xargs xgettext --language=Python --add-comments=TRANSLATORS --force-po --from-code=UTF-8 --default-domain=<domain> -k__ -k_e -k_n -k_x -k_ex -k_nx -kesc_attr__ -kesc_attr_e -kesc_attr_x -kesc_html__ -kesc_html_e -kesc_html_x -k_n_noop -k_nx_noop -o ./lang/<domain>.pot" }, }

Many thanks.

Closing this since it's now a documentation issue.

I believe this is still an issue as it won't pick __() between quotes (in HTML attributes)
So @lekkerduidelijk comment is still valid from what i tested.
See https://stackoverflow.com/a/34249157/632487

So best solution seems to compile blade templates and run xgettext on it.
To do this i guess https://github.com/alwaysblank/blade-generate would help!

Thanks @nicooprat麓s! I've modified the terminal command to match the current directory structure and parsing .php and .blade.php in separate commands, since it gave me warnings on php files:

{
  "name": "sage",
  ...
  "scripts": {
    ...
    "pot": "mkdir -p ./resources/lang && find ./resources ./app -iname \"*.php\" | xargs xgettext --add-comments=TRANSLATORS --force-po --from-code=UTF-8 --default-domain=de_DE -k__ -k_e -k_n:1,2 -k_x:1,2c -k_ex:1,2c -k_nx:4c,12 -kesc_attr__ -kesc_attr_e -kesc_attr_x:1,2c -kesc_html__ -kesc_html_e -kesc_html_x:1,2c -k_n_noop:1,2 -k_nx_noop:3c,1,2, -k__ngettext_noop:1,2 -o resources/lang/sage.pot && find ./resources -iname '*.blade.php' | xargs xgettext --language=Python --add-comments=TRANSLATORS --force-po --from-code=UTF-8 --default-domain=de_DE -k__ -k_e -k_n:1,2 -k_x:1,2c -k_ex:1,2c -k_nx:4c,12 -kesc_attr__ -kesc_attr_e -kesc_attr_x:1,2c -kesc_html__ -kesc_html_e -kesc_html_x:1,2c -k_n_noop:1,2 -k_nx_noop:3c,1,2, -k__ngettext_noop:1,2 -j -o resources/lang/sage.pot"
  },
}

I was getting an error when the pot file wasn't exist. Fixed by adding

touch ./resources/lang/sage.pot

@dsturm I cannot seem to make your command work.

Am I missing anything?

@apintocr Hmmm - do you get any error message? What system are you using? Any files created?

@dsturm I'm using Windows and Ubuntu. Obviously it is not working on Windows ;)

On ubuntu, it returns:
xgettext: no input file given

But the file is there.

Hi,

For all Polylang (Pro) users: I am using this plugin for theme translation: https://wordpress.org/plugins/theme-translation-for-polylang/

I've used it before for Timber/Twig projects and now for the first time for a Sage/Laravel project. You can use {{ pll__('String to translate') }} (note the missing text domain, the plugin will add it for you) and your strings will automatically appear in Languages > String translation. No need to worry about .po, .mo or .pot files.

Edit:
I just noticed this plugin will only pick up string from /resources, not from /app. I'm looking into a solution for that.

Edit 2:
This might not be the prettiest way to do it, but if it works it ain't stupid:

if (class_exists('Polylang_Theme_Translation')) {

    class Sage_Polylang_Theme_Translation extends Polylang_Theme_Translation
    {
        /**
         * Constructor.
         */
        public function __construct()
        {
            parent::__construct();
            $this->run_sage_theme_scanner();
        }

        /**
         * Find strings in /theme/app folder.
         */
        protected function run_sage_theme_scanner()
        {
            $themes = wp_get_themes();

            if (!empty($themes)) {
                foreach ($themes as $name => $theme) {
                    if ($name === 'YOUR_THEME_NAME/resources') {
                        $theme_path = $theme->theme_root . DIRECTORY_SEPARATOR . $name;
                        $app_path = str_replace('resources', 'app', $theme_path);
                        $app_controllers_path = "{$app_path}/controllers";

                        $app_files = $this->get_files_from_dir($app_path);
                        $app_controllers_files = $this->get_files_from_dir($app_controllers_path);

                        $app_strings = $this->file_scanner($app_files);
                        $app_controllers_strings = $this->file_scanner($app_controllers_files);

                        $strings = array_merge($app_strings, $app_controllers_strings);

                        $this->add_to_polylang_register($strings, $name);
                    }
                }
            }
        }

    }

    new Sage_Polylang_Theme_Translation();

}

for anyone coming here in the future: https://roots.io/sage/docs/theme-localization/

for updates/improvements, please submit a PR to the docs or open a discussion on roots discourse

@dsturm @apintocr
Got an error too:

$ yarn pot
yarn run v1.5.1
$ mkdir -p ./resources/lang && find ./resources ./app -iname "*.php" | xargs xgettext --add-comments=TRANSLATORS --force-po --from-code=UTF-8 --default-domain=de_DE -k__ -k_e -k_n:1,2 -k_x:1,2c -k_ex:1,2c -k_nx:4c,12 -kesc_attr__ -kesc_attr_e -kesc_attr_x:1,2c -kesc_html__ -kesc_html_e -kesc_html_x:1,2c -k_n_noop:1,2 -k_nx_noop:3c,1,2, -k__ngettext_noop:1,2 -o resources/lang/sage.pot && find ./resources -iname '*.blade.php' | xargs xgettext --language=Python --add-comments=TRANSLATORS --force-po --from-code=UTF-8 --default-domain=de_DE -k__ -k_e -k_n:1,2 -k_x:1,2c -k_ex:1,2c -k_nx:4c,12 -kesc_attr__ -kesc_attr_e -kesc_attr_x:1,2c -kesc_html__ -kesc_html_e -kesc_html_x:1,2c -k_n_noop:1,2 -k_nx_noop:3c,1,2, -k__ngettext_noop:1,2 -j -o resources/lang/sage.pot
xargs: xgettext: No such file or directory
error An unexpected error occurred: "Command failed.
Exit code: 127
Command: sh
Arguments: -c mkdir -p ./resources/lang && find ./resources ./app -iname \"*.php\" | xargs xgettext --add-comments=TRANSLATORS --force-po --from-code=UTF-8 --default-domain=de_DE -k__ -k_e -k_n:1,2 -k_x:1,2c -k_ex:1,2c -k_nx:4c,12 -kesc_attr__ -kesc_attr_e -kesc_attr_x:1,2c -kesc_html__ -kesc_html_e -kesc_html_x:1,2c -k_n_noop:1,2 -k_nx_noop:3c,1,2, -k__ngettext_noop:1,2 -o resources/lang/sage.pot && find ./resources -iname '*.blade.php' | xargs xgettext --language=Python --add-comments=TRANSLATORS --force-po --from-code=UTF-8 --default-domain=de_DE -k__ -k_e -k_n:1,2 -k_x:1,2c -k_ex:1,2c -k_nx:4c,12 -kesc_attr__ -kesc_attr_e -kesc_attr_x:1,2c -kesc_html__ -kesc_html_e -kesc_html_x:1,2c -k_n_noop:1,2 -k_nx_noop:3c,1,2, -k__ngettext_noop:1,2 -j -o resources/lang/sage.pot
Directory: /Users/sandro/Sites/Hostpoint/madbox.ch/web/app/themes/madbox
Output:
".
info If you think this is a bug, please open a bug report with the information provided in "/Users/sandro/Sites/Hostpoint/madbox.ch/web/app/themes/madbox/yarn-error.log".
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

@retlehs
In your docs, the Part

... app -iname "*.php" | xargs ...
should be
... app -iname \"*.php\" | xargs ...

right? But as i wrote in the comment before, for me it doesn't work.

please read the error message you provided:

xargs: xgettext: No such file or directory

i'm locking this because we prefer to use roots discourse for conversations & support. every reply on here notifies everyone who is watching the repo

Was this page helpful?
0 / 5 - 0 ratings

Related issues

williamscotholmes picture williamscotholmes  路  4Comments

mquellhorst picture mquellhorst  路  3Comments

nicooprat picture nicooprat  路  5Comments

Geczy picture Geczy  路  5Comments

jlariza picture jlariza  路  5Comments