PHP-Foundation icon indicating copy to clipboard operation
PHP-Foundation copied to clipboard

Problem with Internationalization (I18N)

Open daebak74 opened this issue 5 years ago • 11 comments

I don't understand why but I can't get the i18n to work.

my .env

I18N_SUPPORTED_LOCALES=en-US,es-ES

in locale there are 2 folders:

en_US -> LC_MESSAGES
es_ES -> LC_MESSAGES

I purged the cache and rebuild the templates

$ sudo -u www-data php ./index.php clear-template-cache
$ sudo -u www-data php ./index.php precompile-templates

I extracted all translatable strings

$ bash ./i18n.sh en-US

Extracting and updating translations
 * Creating PO (Portable Object) file for “en-US”
Created locale/en-US/LC_MESSAGES/messages.po.
 * Creating MO (Machine Object) file for “en-US”
Done

$ bash ./i18n.sh es-ES

Extracting and updating translations
 * Creating PO (Portable Object) file for “es-ES”
Created locale/es-ES/LC_MESSAGES/messages.po.
 * Creating MO (Machine Object) file for “es-ES”
Done

NOTE -> After this operations in locale created me other 2 folders

en-US -> LC_MESSAGES -> messages.mo, messages.po
es-ES -> LC_MESSAGES -> messages.mo, messages.po

1 QUESTION: Why we have to create folder in locale en_US instead en-US maybe the documentation is wrong ?

https://github.com/delight-im/PHP-I18N#directory-and-file-names-for-translation-files

en-US messages.po

#
msgid ""
msgstr ""
"Language: en-US\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

msgid "Add"
msgstr ""

es-ES messages.po

#
msgid ""
msgstr ""
"Language: es-ES\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

msgid "Add"
msgstr ""

I translated es-ES po

#
msgid ""
msgstr ""
"Language: es-ES\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

msgid "Add"
msgstr "Añadir"

I updated the translations

$ bash ./i18n.sh es-ES

Extracting and updating translations
 * Creating PO (Portable Object) file for “es-ES”
......................................................................................................................................................... done.
 * Creating MO (Machine Object) file for “es-ES”
Done

Now in a file I tested

$app->i18n()->setLocaleManually('es-ES');

echo ('LANG: '. $app->i18n()->getLocale() .'<br>');

echo(_('Add'));

RESULT

LANG: es-ES Add -> INSTEAD -> Añadir

Hope that my process is clear and find the solution.

Thanks.

daebak74 avatar Jan 25 '20 12:01 daebak74

Your I18N_SUPPORTED_LOCALES looks fine. Purging the template cache and re-building it was a good idea as well.

Don’t create the language folders yourself. Maybe the documentation needs to be improved here.

When running the script, it should generate these for you, doesn’t it?

As for dash and underscore, just use what the script generates. If the translations are not picked up, try copying the folders to variants with the other symbol. But make sure these two are copies. The content of the dash variant must not be different from the content of the underscore variant.

ocram avatar Jan 26 '20 17:01 ocram

Yes I tried to purge the template and rebuild after translation and I try to change the symbol too - _ I duplicate the directory. Anything seems work. I don't know what kind of debug I can make because don't give me any message just show always me the word in the principal language. :(

When running the script, it should generate these for you, doesn’t it?

What is strange is ... if Exist a directory as en_US the script generate the folder en-US but it's strange. If you check the i18n.sh file if the directory doesn't exist should to give error. And what happen if don't exist the folder en_US.

daebak74 avatar Jan 26 '20 18:01 daebak74

Well, you should follow some clearly defined steps and make sure to exclude all other possible reasons by resetting the translations:

  1. Remove the directories en-US, en_US, es-ES and es_ES
  2. Do not generate any of these directories manually again
  3. Use i18n.sh en-US and i18n.sh es-ES inside WSL to extract the strings and generate these folders (and the files inside)
  4. Fill in msgstr "" where it’s empty and leave msgid "…" as it is everywhere
  5. Use i18n.sh en-US and i18n.sh es-ES inside WSL again to compile the translations
  6. Perhaps reload your web server or restart your machine
  7. Check if the translations show up
  8. Copy en-US to en_US and es-ES to es_ES (or the other way round)
  9. Repeat steps 6 and 7

ocram avatar Jan 28 '20 10:01 ocram

I make all the test that you wrote but nothing.

I tried to put as default en and es for don't have problem with score and underscore because something wrong with score and underscore there is but the same show always default word.

I said that there is something wrong with score and underscore because if you make a test and run the bash command with score the po generated is

msgid "add"
msgstr ""

Wrong because the default language should has both value

if you make with the underscore the result is

Correct

msgid "add"
msgstr "add"

Anyway later I'll try to make a new installation and just test the language because other idea over than to debug the i18n module I don't have.

daebak74 avatar Jan 28 '20 11:01 daebak74

Why do you think that

msgid "add"
msgstr ""

is wrong and

msgid "add"
msgstr "add"

is correct?

That would only be the case if you filled in the msgstr value already. Gettext doesn’t know about your default locale and shouldn’t automatically fill in translations after extracting strings. This is not the basis that we should evaluate the tool on.

It’s easy with the steps above: After step 3, please report the directory and file structure and the contents of the .po files. After step 5, please do the same.

ocram avatar Jan 28 '20 15:01 ocram

Do you mean that I have to send you the zip of the folder en-US and es-ES after step 3 and after step 5 ?

daebak74 avatar Jan 28 '20 16:01 daebak74

The folder structure can be listed here in text form.

As for the files, you can either do that, or show small excerpts from the files here, e.g. with only the first two strings/translations.

ocram avatar Jan 28 '20 17:01 ocram

Asked because at my first post already I show the file. Anyway this is the directory structure:

locale
- en-US
-- LC_MESSAGES
---- messages.mo
---- messages.po

- es-ES
-- LC_MESSAGES
---- messages.mo
---- messages.PO

- .gitignore

file en-US messages.po

#
msgid ""
msgstr ""
"Language: en-US\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

msgid "%"
msgstr ""

msgid "100"
msgstr ""

msgid "200"
msgstr ""

msgid "Add"
msgstr ""

file es-ES messages.po

#
msgid ""
msgstr ""
"Language: es-ES\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

msgid "%"
msgstr ""

msgid "100"
msgstr ""

msgid "200"
msgstr ""

msgid "Add"
msgstr ""

AFTER STEP 4

file en-US messages.po

#
msgid ""
msgstr ""
"Language: en-US\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

msgid "%"
msgstr ""

msgid "100"
msgstr ""

msgid "200"
msgstr ""

msgid "Add"
msgstr ""

file es-ES messages.po

#
msgid ""
msgstr ""
"Language: es-ES\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

msgid "%"
msgstr ""

msgid "100"
msgstr ""

msgid "200"
msgstr ""

msgid "Add"
msgstr "añadir"

Hope that I got your point and thanks.

daebak74 avatar Jan 28 '20 17:01 daebak74

The structure and the files look good after step 3. I’m just wondering why there aren’t any plural rules, as in the following example:

"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

If en-US is your default locale, you don’t have to create (empty) translation files for it. Just leave it without its own folder. It will pick up the defaults from your code.

After step 4, the translation for msgid "Add" in es-ES is the only translation you’ve added, right?

So you didn’t share the file contents after step 5, which I asked for (and which is a little more interesting), but I guess it’s the same as after step 4.

Further, you may copy the *-* folders to *_*, but that shouldn’t make any difference if you’re on a Windows server.

After that, the only way to find out if everything is working is obviously switching your site to Spanish and checking whether “Add” is translated or not. Is it?

Next, as said above, and as the README states:

Translations are usually cached, so it may be necessary to restart the web server for any changes to take effect.

Finally, you should place the following code in a PHP file after having enabled the I18N component, ideally next to the echo(_('Add')); call:

\var_dump($app->i18n()->getLocale());
\var_dump($app->i18n()->getSystemLocale());
\var_dump($app->i18n()->getLocaleName());
\var_dump($app->i18n()->getLanguageName());
\var_dump($app->i18n()->getLocaleName('fr-BE'));
\var_dump($app->i18n()->getLanguageName('fr-BE'));

What’s the output?

ocram avatar Jan 28 '20 23:01 ocram

Ok, I decided to make a new installation and just write this:

index.php

<?php

$i18n = new \Delight\I18n\I18n([
    \Delight\I18n\Codes::EN,
    \Delight\I18n\Codes::ES,
    \Delight\I18n\Codes::IT
]);

$app->i18n()->setLocaleManually('en');

$app->get('/', [ '\App\HomeController', 'getIndex' ]);

Controller

<?php

namespace App;

use Delight\Foundation\App;

class HomeController {

	public static function getIndex(App $app) {
		
		$name = _('Hallo');
		
		\var_dump($app->i18n()->getLocale());
		\var_dump($app->i18n()->getSystemLocale());
		\var_dump($app->i18n()->getLocaleName());
		\var_dump($app->i18n()->getLanguageName());
		\var_dump($app->i18n()->getLocaleName('fr-BE'));
		\var_dump($app->i18n()->getLanguageName('fr-BE'));
		
		// and return a view
		echo $app->view('welcome.html.twig', [
			'users' => $name
		]);
	}

}

template

{% include 'includes/header.html.twig' %}

<h1>{{_('Hello world')}}</h1>
{{users}}
{% include 'includes/footer.html.twig' %}

If I change in italian clean the cache and restart the web server work. BUT

If I change again in en clean the cache and restart the web server doesn't work and this is the result

Z:\wamp\www\phpfoundation\app\HomeController.php:13:string 'en' (length=2) Z:\wamp\www\phpfoundation\app\HomeController.php:14:string 'en.utf8' (length=7) Z:\wamp\www\phpfoundation\app\HomeController.php:15:string 'inglese' (length=7) Z:\wamp\www\phpfoundation\app\HomeController.php:16:string 'inglese' (length=7) Z:\wamp\www\phpfoundation\app\HomeController.php:17:string 'francese (Belgio)' (length=17) Z:\wamp\www\phpfoundation\app\HomeController.php:18:string 'francese' (length=8) Ciao Mondo Ciao

For let come back in english I need to delete in "it" folder the 2 file .mo and .po clear the cache and restart the web server.

I am frustrated :(

daebak74 avatar Feb 05 '20 19:02 daebak74

Thanks for doing the additional testing!

Don’t worry, I think we’re almost there, and after these initial setup problems on Windows, Gettext is an excellent system.

  1. Don’t throw away and restart your projects anymore, please. The code and setup you have looks fine. This should be suitable for testing, and the problem is probably somewhere else, not in your code or setup.

  2. Since you’re on Windows, can you please double check that you’re using the “Non Thread Safe (NTS)” version of PHP, and not the other one? Could you check your detailed PHP version? Since your version was probably bundled with WAMP, it’s highly likely that it’s the wrong one. This answer might help to install the correct one, which must use FastCGI instead of mod_php.

  3. Please replace setLocaleManually('en') in your code with setLocaleAutomatically() and pass the language you want via GET parameters, e.g. lang=en or lang=it, which is easier during testing and avoids potential caching issues.

  4. Are you using the I18N component in that test setup with or without the framework? If using without the framework, using that constructor is fine. If using with the framework, you should define the supported languages in the configuration in I18N_SUPPORTED_LOCALES instead.

  5. If using it with the framework, please make sure that both I18N_SESSION_FIELD and I18N_COOKIE_NAME are empty. For easier testing, the language should only depend on your supplied GET parameter.

  6. As soon as a language has shown up successfully once (especially with its strings in the templates), there’s no need to clear and re-generate the template cache anymore.

  7. In WSL, where you also extract the strings from code and templates, can you run

    $ sudo locale-gen xx_XX
    $ sudo locale-gen xx_XX.UTF-8
    $ sudo update-locale
    

    once for every language (xx_XX, e.g. it_IT) that you intend to support?

ocram avatar Feb 06 '20 15:02 ocram