diff --git a/README.md b/README.md
index 5a7acfa..6bfc24f 100644
--- a/README.md
+++ b/README.md
@@ -273,6 +273,10 @@ Use the [github issue tool](https://github.com/potsky/laravel-localization-helpe
## 5. Upgrade notices
+### From `v2.x.1` to `v2.x.2`
+
+- Parameter `obsolete_array_key` has been added in the [configuration file](https://github.com/potsky/laravel-localization-helpers/tree/master/src/config). Add it in your configuration file.
+
### From `v1.x.x` to `v2.x.x`
- First you need to update your composer file to set the correct version
@@ -280,6 +284,11 @@ Use the [github issue tool](https://github.com/potsky/laravel-localization-helpe
## 6. Change Log
+### v2.x.2
+
+- show obsolete lemma when it is in array ([#21](https://github.com/potsky/laravel-localization-helpers/issues/21))
+- fix a bug when using obsolete option ([#22](https://github.com/potsky/laravel-localization-helpers/issues/22))
+
### v2.x.1
- fix a bug when using backup files and when a dot is in your laravel installation path ([#20](https://github.com/potsky/laravel-localization-helpers/issues/20))
diff --git a/src/Potsky/LaravelLocalizationHelpers/Command/LocalizationAbstract.php b/src/Potsky/LaravelLocalizationHelpers/Command/LocalizationAbstract.php
index bbe3ff7..a6764a5 100644
--- a/src/Potsky/LaravelLocalizationHelpers/Command/LocalizationAbstract.php
+++ b/src/Potsky/LaravelLocalizationHelpers/Command/LocalizationAbstract.php
@@ -12,20 +12,24 @@ abstract class LocalizationAbstract extends Command implements MessageBagInterfa
const SUCCESS = 0;
const ERROR = 1;
+ /**
+ * Init log file for first log
+ *
+ * @var boolean
+ */
+ protected static $logInFileFirst = true;
/**
* Config repository.
*
* @var \Illuminate\Config\Repository
*/
protected $configRepository;
-
/**
* The localization manager
*
* @var Localization
*/
protected $manager;
-
/**
* Should commands display something
*
@@ -122,4 +126,34 @@ public function writeError( $s )
parent::error( $s );
}
}
+
+ /**
+ * Log in a file for debug purpose only
+ *
+ * @param mixed $txt
+ * @param string $logFile
+ *
+ * @codeCoverageIgnore
+ */
+ protected function logInFile( $txt = '' , $logFile = '/tmp/llh.log' )
+ {
+ if ( ! is_string( $txt ) )
+ {
+ $txt = print_r( $txt , true );
+ }
+
+ $txt = '==> ' . date( 'Y/m/d H:i:s' ) . ' ==> ' . $txt . "\n";
+
+ if ( self::$logInFileFirst === true )
+ {
+ file_put_contents( $logFile , $txt );
+
+ self::$logInFileFirst = false;
+ }
+ else
+ {
+ file_put_contents( $logFile , $txt , FILE_APPEND );
+ }
+ }
+
}
diff --git a/src/Potsky/LaravelLocalizationHelpers/Command/LocalizationMissing.php b/src/Potsky/LaravelLocalizationHelpers/Command/LocalizationMissing.php
index 9955fdd..833bced 100644
--- a/src/Potsky/LaravelLocalizationHelpers/Command/LocalizationMissing.php
+++ b/src/Potsky/LaravelLocalizationHelpers/Command/LocalizationMissing.php
@@ -82,6 +82,15 @@ class LocalizationMissing extends LocalizationAbstract
*/
protected $code_style_level = null;
+ /**
+ * The obsolete lemma array key in which to store obsolete lemma
+ *
+ * @var string
+ *
+ * @since 2.x.2
+ */
+ protected $obsolete_array_key = 'LLH:obsolete';
+
/**
* Create a new command instance.
*
@@ -99,6 +108,14 @@ public function __construct( Repository $configRepository )
$this->editor = Config::get( Localization::PREFIX_LARAVEL_CONFIG . 'editor_command_line' );
$this->code_style_fixers = Config::get( Localization::PREFIX_LARAVEL_CONFIG . 'code_style.fixers' );
$this->code_style_level = Config::get( Localization::PREFIX_LARAVEL_CONFIG . 'code_style.level' );
+
+ // @since 2.x.2
+ // Users who have not upgraded their configuration file must have a default
+ // but users may want to set it to null to keep the old buggy behaviour
+ if ( Config::has( Localization::PREFIX_LARAVEL_CONFIG . 'obsolete_array_key' ) )
+ {
+ $this->obsolete_array_key = Config::get( Localization::PREFIX_LARAVEL_CONFIG . 'obsolete_array_key' );
+ }
}
/**
@@ -108,9 +125,10 @@ public function __construct( Repository $configRepository )
*/
public function fire()
{
- $folders = $this->manager->getPath( $this->folders );
- $this->display = ! $this->option( 'silent' );
- $extension = $this->option( 'php-file-extension' );
+ $folders = $this->manager->getPath( $this->folders );
+ $this->display = ! $this->option( 'silent' );
+ $extension = $this->option( 'php-file-extension' );
+ $obsolete_prefix = ( empty( $this->obsolete_array_key ) ) ? '' : $this->obsolete_array_key . '.';
//////////////////////////////////////////////////
// Display where translations are searched in //
@@ -195,6 +213,7 @@ public function fire()
{
switch ( $e->getCode() )
{
+ //@codeCoverageIgnoreStart
case Localization::NO_LANG_FOLDER_FOUND_IN_THESE_PATHS:
$this->writeError( "No lang folder found in these paths:" );
foreach ( $e->getParameter() as $path )
@@ -202,6 +221,7 @@ public function fire()
$this->writeError( "- " . $path );
}
break;
+ //@codeCoverageIgnoreEnd
case Localization::NO_LANG_FOLDER_FOUND_IN_YOUR_CUSTOM_PATH:
$this->writeError( 'No lang folder found in your custom path: "' . $e->getParameter() . '"' );
@@ -241,6 +261,7 @@ public function fire()
{
$this->writeLine( '' );
}
+
$this->writeLine( ' ' . $this->manager->getShortPath( $file_lang_path ) );
if ( ! is_writable( dirname( $file_lang_path ) ) )
@@ -287,16 +308,37 @@ public function fire()
}
/** @noinspection PhpIncludeInspection */
- $a = include( $file_lang_path );
- $old_lemmas = ( is_array( $a ) ) ? array_dot( $a ) : array();
- $new_lemmas = array_dot( $array );
- $final_lemmas = array();
- $display_already_comment = false;
- $something_to_do = false;
- $i = 0;
- $obsolete_lemmas = array_diff_key( $old_lemmas , $new_lemmas );
- $welcome_lemmas = array_diff_key( $new_lemmas , $old_lemmas );
- $already_lemmas = array_intersect_key( $old_lemmas , $new_lemmas );
+ $a = include( $file_lang_path );
+ $old_lemmas_with_obsolete = ( is_array( $a ) ) ? array_dot( $a ) : array();
+ $new_lemmas = array_dot( $array );
+ $final_lemmas = array();
+ $display_already_comment = false;
+ $something_to_do = false;
+ $i = 0;
+
+ // Remove the obsolete prefix key
+ $old_lemmas = array();
+ $obsolete_prefix_length = strlen( $obsolete_prefix );
+ foreach ( $old_lemmas_with_obsolete as $key => $value )
+ {
+ if ( starts_with( $key , $obsolete_prefix ) )
+ {
+ $key = substr( $key , $obsolete_prefix_length );
+ if ( ! isset( $old_lemmas[ $key ] ) )
+ {
+ $old_lemmas[ $key ] = $value;
+ }
+ }
+ else
+ {
+ $old_lemmas[ $key ] = $value;
+ }
+ }
+
+ $obsolete_lemmas = array_diff_key( $old_lemmas , $new_lemmas );
+ $welcome_lemmas = array_diff_key( $new_lemmas , $old_lemmas );
+ $already_lemmas = array_intersect_key( $old_lemmas , $new_lemmas );
+
ksort( $obsolete_lemmas );
ksort( $welcome_lemmas );
ksort( $already_lemmas );
@@ -306,12 +348,13 @@ public function fire()
//////////////////////////
if ( count( $welcome_lemmas ) > 0 )
{
- $display_already_comment = true;
- $something_to_do = true;
- $there_are_new = true;
- $this->writeInfo( " " . count( $welcome_lemmas ) . " new strings to translate" );
+ $display_already_comment = true;
+ $something_to_do = true;
+ $there_are_new = true;
$final_lemmas[ "POTSKY___NEW___POTSKY" ] = "POTSKY___NEW___POTSKY";
+ $this->writeInfo( ' ' . ( $c = count( $welcome_lemmas ) ) . ' new string' . Tools::getPlural( $c ) . ' to translate' );
+
foreach ( $welcome_lemmas as $key => $value )
{
if ( $this->option( 'verbose' ) )
@@ -348,7 +391,7 @@ public function fire()
{
if ( $this->option( 'verbose' ) )
{
- $this->writeLine( " " . count( $already_lemmas ) . " already translated strings" );
+ $this->writeLine( ' ' . ( $c = count( $already_lemmas ) ) . ' already translated string' . Tools::getPlural( $c ) );
}
$final_lemmas[ "POTSKY___OLD___POTSKY" ] = "POTSKY___OLD___POTSKY";
@@ -364,6 +407,8 @@ public function fire()
///////////////////////////////
if ( count( $obsolete_lemmas ) > 0 )
{
+ $protected_already_included = false;
+
// Remove all dynamic fields
foreach ( $obsolete_lemmas as $key => $value )
{
@@ -371,31 +416,53 @@ public function fire()
{
if ( ( strpos( $key , '.' . $remove . '.' ) !== false ) || starts_with( $key , $remove . '.' ) )
{
+ if ( $this->option( 'verbose' ) )
+ {
+ $this->writeLine( " " . $key . " is protected as a dynamic lemma" );
+ }
+
unset( $obsolete_lemmas[ $key ] );
+
+ if ( $protected_already_included === false )
+ {
+ $final_lemmas[ "POTSKY___PROTECTED___POTSKY" ] = "POTSKY___PROTECTED___POTSKY";
+ $protected_already_included = true;
+ }
+
+ // Given that this lemma is never obsolete, we need to send it back to the final lemma array
+ array_set( $final_lemmas , $key , $value );
}
}
}
}
+
+ /////////////////////////////////////
+ // Fill the final lemmas array now //
+ /////////////////////////////////////
if ( count( $obsolete_lemmas ) > 0 )
{
$display_already_comment = true;
$something_to_do = true;
- $this->writeComment( $this->option( 'no-obsolete' )
- ? " " . count( $obsolete_lemmas ) . " obsolete strings (will be deleted)"
- : " " . count( $obsolete_lemmas ) . " obsolete strings (can be deleted manually in the generated file)"
- );
- $final_lemmas[ "POTSKY___OBSOLETE___POTSKY" ] = "POTSKY___OBSOLETE___POTSKY";
- foreach ( $obsolete_lemmas as $key => $value )
+ if ( $this->option( 'no-obsolete' ) )
{
- if ( $this->option( 'verbose' ) )
- {
- $this->writeLine( " " . $key . "" );
- }
- if ( ! $this->option( 'no-obsolete' ) )
+ $this->writeComment( " " . ( $c = count( $obsolete_lemmas ) ) . ' obsolete string' . Tools::getPlural( $c ) . ' (will be deleted)' );
+ }
+ else
+ {
+ $this->writeComment( " " . ( $c = count( $obsolete_lemmas ) ) . ' obsolete string' . Tools::getPlural( $c ) . ' (can be deleted manually in the generated file)' );
+
+ $final_lemmas[ "POTSKY___OBSOLETE___POTSKY" ] = "POTSKY___OBSOLETE___POTSKY";
+
+ foreach ( $obsolete_lemmas as $key => $value )
{
- array_set( $final_lemmas , $key , $value );
+ if ( $this->option( 'verbose' ) )
+ {
+ $this->writeLine( " " . $key . "" );
+ }
+
+ array_set( $final_lemmas , $obsolete_prefix . $key , $value );
}
}
}
@@ -414,11 +481,13 @@ public function fire()
array(
"'POTSKY___NEW___POTSKY' => 'POTSKY___NEW___POTSKY'," ,
"'POTSKY___OLD___POTSKY' => 'POTSKY___OLD___POTSKY'," ,
+ "'POTSKY___PROTECTED___POTSKY' => 'POTSKY___PROTECTED___POTSKY'," ,
"'POTSKY___OBSOLETE___POTSKY' => 'POTSKY___OBSOLETE___POTSKY'," ,
) ,
array(
'//============================== New strings to translate ==============================//' ,
( $display_already_comment === true ) ? '//==================================== Translations ====================================//' : '' ,
+ '//============================== Dynamic protected strings =============================//' ,
'//================================== Obsolete strings ==================================//' ,
) ,
$content
diff --git a/src/Potsky/LaravelLocalizationHelpers/Factory/Localization.php b/src/Potsky/LaravelLocalizationHelpers/Factory/Localization.php
index a564801..3bd79b4 100644
--- a/src/Potsky/LaravelLocalizationHelpers/Factory/Localization.php
+++ b/src/Potsky/LaravelLocalizationHelpers/Factory/Localization.php
@@ -158,12 +158,14 @@ public function getLangPath( $lang_folder_path = null )
if ( file_exists( $path ) )
{
return $path;
+ //@codeCoverageIgnoreStart
}
}
$e = new Exception( '' , self::NO_LANG_FOLDER_FOUND_IN_THESE_PATHS );
$e->setParameter( $paths );
throw $e;
+ //@codeCoverageIgnoreEnd
}
else
{
@@ -450,6 +452,7 @@ public function deleteBackupFiles( $lang_folder_path , $days = 0 , $dryRun = fal
{
switch ( $e->getCode() )
{
+ //@codeCoverageIgnoreStart
case self::NO_LANG_FOLDER_FOUND_IN_THESE_PATHS:
$this->messageBag->writeError( "No lang folder found in these paths:" );
foreach ( $e->getParameter() as $path )
@@ -457,6 +460,7 @@ public function deleteBackupFiles( $lang_folder_path , $days = 0 , $dryRun = fal
$this->messageBag->writeError( "- " . $path );
}
break;
+ //@codeCoverageIgnoreEnd
case self::NO_LANG_FOLDER_FOUND_IN_YOUR_CUSTOM_PATH:
$this->messageBag->writeError( 'No lang folder found in your custom path: "' . $e->getParameter() . '"' );
diff --git a/src/config/config-laravel5.php b/src/config/config-laravel5.php
index 0b13ad9..ba47134 100644
--- a/src/config/config-laravel5.php
+++ b/src/config/config-laravel5.php
@@ -118,6 +118,31 @@
) ,
+ /*
+ |--------------------------------------------------------------------------
+ | Obsolete lemma prefix
+ |--------------------------------------------------------------------------
+ |
+ | If you want to keep obsolete lemma in your lang file, they will be stored
+ | in a sub-array. If not stored in a sub-array, LLH will not be able to
+ | separate child lemma.
+ |
+ | eg : message.section.dog is used
+ | message.section.cat is not used anymore
+ | then : message.section.dog will be kept
+ | LLH:obsolete.message.section.cat will be generated
+ |
+ | : is used in the key because : is a special char in laravel lang lemma and
+ | : are automatically not scanned by LLH.
+ |
+ | Do not change this parameter between 2 commands launch because LLH will not
+ | be able to find obsolete lemma in the second pass and you will need to
+ | clean up obsolete lemma manually
+ |
+ */
+ 'obsolete_array_key' => 'LLH:obsolete',
+
+
/*
|--------------------------------------------------------------------------
| Editor
diff --git a/src/config/config.php b/src/config/config.php
index e1f1c4f..f573014 100644
--- a/src/config/config.php
+++ b/src/config/config.php
@@ -119,6 +119,31 @@
) ,
+ /*
+ |--------------------------------------------------------------------------
+ | Obsolete lemma prefix
+ |--------------------------------------------------------------------------
+ |
+ | If you want to keep obsolete lemma in your lang file, they will be stored
+ | in a sub-array. If not stored in a sub-array, LLH will not be able to
+ | separate child lemma.
+ |
+ | eg : message.section.dog is used
+ | message.section.cat is not used anymore
+ | then : message.section.dog will be kept
+ | LLH:obsolete.message.section.cat will be generated
+ |
+ | : is used in the key because : is a special char in laravel lang lemma and
+ | : are automatically not scanned by LLH.
+ |
+ | Do not change this parameter between 2 commands launch because LLH will not
+ | be able to find obsolete lemma in the second pass and you will need to
+ | clean up obsolete lemma manually
+ |
+ */
+ 'obsolete_array_key' => 'LLH:obsolete',
+
+
/*
|--------------------------------------------------------------------------
| Editor
diff --git a/tests/fixes/Gh21Tests.php b/tests/fixes/Gh21Tests.php
new file mode 100644
index 0000000..e684d45
--- /dev/null
+++ b/tests/fixes/Gh21Tests.php
@@ -0,0 +1,105 @@
+ array(
+ 1 => array(
+ 'name' => 'First lady',
+ ),
+ 2 => array(
+ 'name' => 'Second to die',
+ ),
+ ),
+);";
+
+ private static $defaultLangWithObsoleteContent = " array (
+ 1 => array (
+ 'name' => 'First lady',
+ ),
+ ),
+ 'LLH:obsolete' => array (
+ 'section' => array (
+ 2 => array (
+ 'name' => 'Second to die',
+ ),
+ ),
+ ),
+);";
+
+
+
+ /**
+ * Setup the test environment.
+ *
+ * - Remove all previous lang files before each test
+ * - Set custom configuration paths
+ */
+ public function setUp()
+ {
+ parent::setUp();
+
+ self::$langFolder = self::MOCK_DIR_PATH . '/gh21/lang';
+ self::$langFile = self::$langFolder . '/en/message.php';
+
+ Config::set( Localization::PREFIX_LARAVEL_CONFIG . 'lang_folder_path' , self::$langFolder );
+
+ // Set content in lang file
+ File::put( self::$langFile , self::$defaultLangContent );
+ }
+
+
+ /**
+ * https://github.com/potsky/laravel-localization-helpers/issues/22
+ */
+ public function testObsoleteSubKeyRemoved()
+ {
+ Config::set( Localization::PREFIX_LARAVEL_CONFIG . 'folders' , self::MOCK_DIR_PATH . '/gh21/code' );
+
+ /** @noinspection PhpVoidFunctionResultUsedInspection */
+ Artisan::call( 'localization:missing' , array(
+ '--no-interaction' => true ,
+ '--no-backup' => true ,
+ '--verbose' => true ,
+ ) );
+
+ $this->assertContains( '1 obsolete string' , Artisan::output() );
+
+ $this->assertArrayHasKey( 'LLH:obsolete' , require( self::$langFile ) );
+ }
+
+
+ /**
+ * https://github.com/potsky/laravel-localization-helpers/issues/22
+ */
+ public function testObsoleteAreKept()
+ {
+ Config::set( Localization::PREFIX_LARAVEL_CONFIG . 'folders' , self::MOCK_DIR_PATH . '/gh21/code' );
+
+ // Set content in lang file with obsolete lemma
+ File::put( self::$langFile , self::$defaultLangWithObsoleteContent );
+
+ /** @noinspection PhpVoidFunctionResultUsedInspection */
+ Artisan::call( 'localization:missing' , array(
+ '--no-interaction' => true ,
+ '--no-backup' => true ,
+ ) );
+
+ $this->assertContains( '1 obsolete string' , Artisan::output() );
+
+ $lemmas = require( self::$langFile );
+
+ $this->assertArrayHasKey( 'LLH:obsolete' , $lemmas );
+ $this->assertArrayNotHasKey( 'LLH:obsolete' , $lemmas['LLH:obsolete'] );
+ }
+
+}
diff --git a/tests/fixes/Gh22Tests.php b/tests/fixes/Gh22Tests.php
new file mode 100644
index 0000000..bcb6d07
--- /dev/null
+++ b/tests/fixes/Gh22Tests.php
@@ -0,0 +1,120 @@
+ 'My dog is rich' ,
+ 'section' => array(
+ 1 => array(
+ 'name' => 'Niania',
+ ),
+ ),
+);";
+
+ /**
+ * Setup the test environment.
+ *
+ * - Remove all previous lang files before each test
+ * - Set custom configuration paths
+ */
+ public function setUp()
+ {
+ parent::setUp();
+
+ self::$langFolder = self::MOCK_DIR_PATH . '/gh22/lang';
+ self::$langFile = self::$langFolder . '/en/message.php';
+
+ Config::set( Localization::PREFIX_LARAVEL_CONFIG . 'lang_folder_path' , self::$langFolder );
+
+ // Set content in lang file
+ File::put( self::$langFile , self::$defaultLangContent );
+ }
+
+
+ /**
+ * https://github.com/potsky/laravel-localization-helpers/issues/22
+ */
+ public function testObsoleteKeyIsNotRemoved()
+ {
+ Config::set( Localization::PREFIX_LARAVEL_CONFIG . 'folders' , self::MOCK_DIR_PATH . '/gh22/phase1' );
+
+ /** @noinspection PhpVoidFunctionResultUsedInspection */
+ Artisan::call( 'localization:missing' , array(
+ '--no-interaction' => true ,
+ '--no-backup' => true ,
+ ) );
+
+ $this->assertContains( '1 obsolete string' , Artisan::output() );
+
+ $lemmas = require( self::$langFile );
+
+ $this->assertArrayHasKey( 'LLH:obsolete' , $lemmas );
+ $this->assertArrayHasKey( 'section' , $lemmas['LLH:obsolete'] );
+ }
+
+
+ /**
+ * https://github.com/potsky/laravel-localization-helpers/issues/22
+ */
+ public function testObsoleteKeyIsRemovedWhenSettingOption()
+ {
+ Config::set( Localization::PREFIX_LARAVEL_CONFIG . 'folders' , self::MOCK_DIR_PATH . '/gh22/phase1' );
+
+ /** @noinspection PhpVoidFunctionResultUsedInspection */
+ Artisan::call( 'localization:missing' , array(
+ '--no-interaction' => true ,
+ '--no-backup' => true ,
+ '--no-obsolete' => true ,
+ ) );
+
+ $this->assertContains( '1 obsolete string' , Artisan::output() );
+
+ $lemmas = require( self::$langFile );
+
+ $this->assertArrayNotHasKey( 'LLH:obsolete' , $lemmas );
+ }
+
+ /**
+ * https://github.com/potsky/laravel-localization-helpers/issues/22
+ */
+ public function testDynamicFieldShouldNotBeObsoleteWhenNotAddingANewLemma()
+ {
+ Config::set( Localization::PREFIX_LARAVEL_CONFIG . 'folders' , self::MOCK_DIR_PATH . '/gh22/phase1' );
+ Config::set( Localization::PREFIX_LARAVEL_CONFIG . 'never_obsolete_keys' , array( 'section' ) );
+
+ /** @noinspection PhpVoidFunctionResultUsedInspection */
+ Artisan::call( 'localization:missing' , array(
+ '--no-interaction' => true ,
+ '--no-backup' => true ,
+ '--verbose' => true ,
+ ) );
+
+ $this->assertEquals( self::$defaultLangContent , File::get( self::$langFile ) );
+ }
+
+ /**
+ * https://github.com/potsky/laravel-localization-helpers/issues/22
+ */
+ public function testDynamicFieldShouldNotBeObsoleteWhenAddingANewLemma()
+ {
+ Config::set( Localization::PREFIX_LARAVEL_CONFIG . 'folders' , self::MOCK_DIR_PATH . '/gh22/phase2' );
+ Config::set( Localization::PREFIX_LARAVEL_CONFIG . 'never_obsolete_keys' , array( 'section' ) );
+
+ /** @noinspection PhpVoidFunctionResultUsedInspection */
+ Artisan::call( 'localization:missing' , array(
+ '--no-interaction' => true ,
+ '--no-backup' => true ,
+ '--verbose' => true ,
+ ) );
+
+ $this->assertArrayHasKey( 'section' , require( self::$langFile ) );
+ }
+
+}
diff --git a/tests/mock/gh21/code/trans.php b/tests/mock/gh21/code/trans.php
new file mode 100644
index 0000000..988f154
--- /dev/null
+++ b/tests/mock/gh21/code/trans.php
@@ -0,0 +1,3 @@
+
+ array (
+ 1 =>
+ array (
+ 'name' => 'First lady',
+ ),
+ ),
+ //================================== Obsolete strings ==================================//
+ 'LLH:obsolete' =>
+ array (
+ 'section' =>
+ array (
+ 2 =>
+ array (
+ 'name' => 'Second to die',
+ ),
+ ),
+ ),
+);
\ No newline at end of file
diff --git a/tests/mock/gh22/lang/en/message.php b/tests/mock/gh22/lang/en/message.php
new file mode 100644
index 0000000..e294802
--- /dev/null
+++ b/tests/mock/gh22/lang/en/message.php
@@ -0,0 +1,20 @@
+ 'TODO: my cat is rich',
+ //==================================== Translations ====================================//
+ 'my dog is rich' => 'My dog is rich',
+ //============================== Dynamic protected strings =============================//
+ 'section' =>
+ array (
+ 1 =>
+ array (
+ 'name' => 'Niania',
+ ),
+ ),
+);
\ No newline at end of file
diff --git a/tests/mock/gh22/phase1/trans.php b/tests/mock/gh22/phase1/trans.php
new file mode 100644
index 0000000..de243f3
--- /dev/null
+++ b/tests/mock/gh22/phase1/trans.php
@@ -0,0 +1,8 @@
+