Skip to content

Commit

Permalink
Test, fix & enhance language fallback
Browse files Browse the repository at this point in the history
  • Loading branch information
jim-parry committed Dec 14, 2018
1 parent e714a7c commit 981383d
Show file tree
Hide file tree
Showing 8 changed files with 133 additions and 5 deletions.
18 changes: 16 additions & 2 deletions system/Language/Language.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php namespace CodeIgniter\Language;
<?php
namespace CodeIgniter\Language;

/**
* CodeIgniter
Expand Down Expand Up @@ -132,6 +133,12 @@ public function getLocale(): string
*/
public function getLine(string $line, array $args = [])
{
// ignore requests with no file specified
if (! strpos($line, '.'))
{
return $line;
}

// Parse out the file name and the actual alias.
// Will load the language file and strings.
[
Expand All @@ -153,6 +160,13 @@ public function getLine(string $line, array $args = [])
$output = $this->language[$locale][$file][$parsedLine] ?? null;
}

// if still not found, try English
if (empty($output))
{
$this->parseLine($line, 'en');
$output = $this->language['en'][$file][$parsedLine] ?? null;
}

$output = $output ?? $line;

if (! empty($args))
Expand Down Expand Up @@ -278,7 +292,7 @@ protected function load(string $file, string $locale, bool $return = false)
$this->loadedFiles[$locale][] = $file;

// Merge our string
$this->language[$this->locale][$file] = $lang;
$this->language[$locale][$file] = $lang;
}

//--------------------------------------------------------------------
Expand Down
8 changes: 8 additions & 0 deletions tests/_support/Language/ab-CD/Allin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php
// seven wonders of the ancient world
return [
'one' => 'Pyramid of Giza',
'tre' => 'Colossus of Rhodes',
'fiv' => 'Temple of Artemis',
'sev' => 'Hanging Gardens of Babylon',
];
8 changes: 8 additions & 0 deletions tests/_support/Language/ab/Allin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php
// seven deadly sins
return [
'two' => 'gluttony',
'tre' => 'greed',
'six' => 'envy',
'sev' => 'pride',
];
6 changes: 6 additions & 0 deletions tests/_support/Language/en-ZZ/More.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php
return [
'strongForce' => 'These are not the droids you are looking for',
'notaMoon' => "It's made of cheese",
'wisdom' => 'There is no try',
];
8 changes: 8 additions & 0 deletions tests/_support/Language/en/Allin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php
// 12 days of Christmas
return [
'for' => 'four calling birds',
'fiv' => 'five golden rings',
'six' => 'six geese a laying',
'sev' => 'seven swans a swimming',
];
5 changes: 5 additions & 0 deletions tests/_support/Language/ru/Language.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php

return [
'languageGetLineInvalidArgumentException' => 'Whatever this would be, translated',
];
52 changes: 49 additions & 3 deletions tests/system/Language/LanguageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ public function testLangAllowsOtherLocales()
$str2 = lang('Language.languageGetLineInvalidArgumentException', [], 'ru');

$this->assertEquals('Get line must be a string or array of strings.', $str1);
$this->assertEquals('Language.languageGetLineInvalidArgumentException', $str2);
$this->assertEquals('Whatever this would be, translated', $str2);
}

//--------------------------------------------------------------------
Expand All @@ -155,7 +155,7 @@ public function testLangDoesntFormat()

public function testLanguageDuplicateKey()
{
$lang = new Language('en');
$lang = new Language('en', false);
$this->assertEquals('These are not the droids you are looking for', $lang->getLine('More.strongForce', []));
$this->assertEquals('I have a very bad feeling about this', $lang->getLine('More.cannotMove', []));
$this->assertEquals('Could not move file {0} to {1} ({2})', $lang->getLine('Files.cannotMove', []));
Expand Down Expand Up @@ -223,7 +223,7 @@ public function testPrioritizedLocator()
$message = lang('Number.trillion', [], 'en');
$this->assertEquals(' lots', $message);
// and we should have our new message too
$this->assertEquals(' bazillions', lang('Number.bazillion', [], 'en'));
$this->assertEquals(' bazillion', lang('Number.bazillion', [], 'en'));
}

//--------------------------------------------------------------------
Expand Down Expand Up @@ -268,4 +268,50 @@ public function testBundleUniqueKeys($bundle)
$this->assertGreaterThan(0, count($messages));
}

//--------------------------------------------------------------------
// Testing base locale vs variants

public function testBaseFallbacks()
{
$language = Services::language('en-ZZ', false);
// key is in both base and variant; should pick variant
$this->assertEquals("It's made of cheese", $language->getLine('More.notaMoon'));

// key is in base but not variant; should pick base
$this->assertEquals('I have a very bad feeling about this', $language->getLine('More.cannotMove'));

// key is in variant but not base; should pick variant
$this->assertEquals('There is no try', $language->getLine('More.wisdom'));

// key isn't in either base or variant; should return bad key
$this->assertEquals('More.shootMe', $language->getLine('More.shootMe'));
}

//--------------------------------------------------------------------
/**
* Testing base locale vs variants, with fallback to English.
*
* Key en ab ac-CD
* none N N N
* one N N Y
* two N Y N
* tre N Y Y
* for Y N N
* fiv Y N Y
* six Y Y N
* sev Y Y Y
*/
public function testAllTheWayFallbacks()
{
$language = Services::language('ab-CD', false);
$this->assertEquals('Allin.none', $language->getLine('Allin.none'));
$this->assertEquals('Pyramid of Giza', $language->getLine('Allin.one'));
$this->assertEquals('gluttony', $language->getLine('Allin.two'));
$this->assertEquals('Colossus of Rhodes', $language->getLine('Allin.tre'));
$this->assertEquals('four calling birds', $language->getLine('Allin.for'));
$this->assertEquals('Temple of Artemis', $language->getLine('Allin.fiv'));
$this->assertEquals('envy', $language->getLine('Allin.six'));
$this->assertEquals('Hanging Gardens of Babylon', $language->getLine('Allin.sev'));
}

}
33 changes: 33 additions & 0 deletions user_guide_src/source/outgoing/localization.rst
Original file line number Diff line number Diff line change
Expand Up @@ -263,3 +263,36 @@ Language files also allow nested arrays to make working with lists, etc... easie

// Displays "Apples, Bananas, Grapes, Lemons, Oranges, Strawberries"
echo implode(', ', lang('Fruit.list'));

Language Fallback
=================

If you have a set of messages for a given locale, for instance
``Language/en/app.php``, you can add language variants for that locale,
each in its own folder, for instance ``Language/en-US/app.php``.

You only need to provide values for those messages that would be
localized differently for that locale variant. Any missing message
definitions will be automatically pulled from the main locale settings.

It gets better - the localization can fall all the way back to English,
in case new messages are added to the framework and you haven't had
a chance to translate them yet for your locale.

So, if you are using the locale ``fr-CA``, then a localized
message will first be sought in ``Language/fr/CA``, then in
``Language/fr``, and finally in ``Language/en``.

Message Translations
====================

We have an "official" set of translations in their
`own repository <https://github.com/codeigniter4/translations>`_.

You can download that repository, and copy its ``Language`` folder
into your ``app``. The incorporated translations will be automatically
picked up because the ``App`` namespace is mapped to your ``app`` folder.

Alternately, you could use ``composer install codeigniter4/translations``
inside your project, and the translated messages will be automatically picked
up because the ``Translations`` namespace gets mapped appropriately.

0 comments on commit 981383d

Please sign in to comment.