问题
I want to display a list of values from an array, and have it be translatable. My translation method of choice is gettext. An example of what I am trying to do is to turn a variable-length array like:
$array = ('apple', 'plum', 'watermelon', [...]);
into a string like apple, plum and watermelon
.
Doing it only in English would not be a problem, but making it translatable is, because other languages may not necessarily use a comma to separate values and/or may not have the word "and" without a comma between the second last and last values. If I knew that the array always had 3 values, I could easily just do:
sprintf(gettext("%s, %s and %s"), $array[0], $array[1], $array[2]);
The problem is that the array can vary in length. How can I make a translatable list from a variable-length array?
Edit:
Perhaps I didn't make myself clear, but other languages may handle lists differently. For example a language might display the list like 1 and 2, 3, 4
, another one might display it like 1, 2, 3, 4
, another might have extra things before and after the list, etc.
回答1:
This might help but as far as pre know which type of separator and glue to use it might be having a list and being able to send the language as a reference of which one of these to use?
<?php
/**
* @author - Sephedo
* @for - Mike @ Stackoverflow
* @question - http://stackoverflow.com/questions/18751650/making-a-variable-length-list-translatable
*/
echo arr2str( array('apple', 'banana', 'peach', 'pear', 'orange') );
// This function will convert the array to a formatted string.
function arr2str( array $array, $separator = ', ', $glue = ' and ' )
{
if( count( $array ) == 1 ) return (string) $array; // If there is only one item return the item.
$last = array_pop( $array ); // get the last element of the array and remove from the array.
return implode( $separator, $array ) . "$glue$last"; // implode the array by the seperator and add the last element.
}
?>
This will return
string 'apple, banana, peach, pear and orange' (length=38)
回答2:
You can do the following:
- Loop through your array and
- Check if the iteration is the last one
- If it is, then prepend an
and
to the variable
Code:
function makeTrans($array)
{
$str = '';
for ($i=0; $i < count($array); $i++) {
if($i == count($array) - 1) {
$str .= "and ".$array[$i];
}
else {
$str .= $array[$i]." ";
}
}
return $str;
}
Usage:
$array = array('apple', 'plum', 'watermelon', 'foo', 'bar', 'baz', 'baq');
echo makeTrans($array);
Output:
apple plum watermelon foo bar baz and baq
See it in action!
回答3:
If you are wanting to change the position of the separator try this modified version
<?php
/**
* @author - Sephedo
* @for - Mike @ Stackoverflow
* @question - http://stackoverflow.com/questions/18751650/making-a-variable-length-list-translatable
*/
var_dump( arr2str( array('apple', 'banana', 'peach', 'pear', 'orange') ) );
var_dump( arr2str( array('apple', 'banana', 'peach', 'pear', 'orange'), 1 ) );
var_dump( arr2str( array('apple', 'banana', 'peach', 'pear', 'orange'), 3 ) );
var_dump( arr2str( array('apple', 'banana', 'peach', 'pear', 'orange'), 4 ) );
// @array - the array to parse
// @pos - the position to put the glue
// @separator - aka the comma separator
// @glue - aka the and word
function arr2str( array $array, $pos=null, $separator = ', ', $glue = ' and ' )
{
if( count( $array ) == 1 ) return (string) $array; // If there is only one item return the item.
if( is_null( $pos ) ) $pos = count( $array ) - 1; // get the default and position aka last.
$start = array_slice( $array, 0, $pos ); $end = array_slice( $array, $pos, count( $array ) + 1 );
return implode( $separator, $start ) . $glue . implode( $separator, $end );
}
?>
This will result with
string 'apple, banana, peach, pear and orange' (length=37)
string 'apple and banana, peach, pear, orange' (length=37)
string 'apple, banana, peach and pear, orange' (length=37)
string 'apple, banana, peach, pear and orange' (length=37)
回答4:
One way I thought of doing this would be like this:
function array_to_str($array) {
$two_values = _("%s and %s");
$three_values = _("%s, %s and %s");
$separator = _(", ");
if (count($array) == 1) {
return $array[0];
}
if (count($array) == 2) {
return sprintf($two_values, $array[0], $array[1]);
}
$prev = '';
for ($i = 0; $i < count($array) - 2; $i++) {
$prev .= $array[$i];
if ($i < count($array) - 3) {
$prev .= $separator;
}
}
return sprintf(
$three_values,
$prev,
$array[count($array) - 2],
$array[count($array) - 1]
);
}
$arrays[] = array('apple');
$arrays[] = array('apple', 'plum');
$arrays[] = array('apple', 'plum', 'watermelon');
$arrays[] = array('apple', 'plum', 'watermelon', 'lemon');
foreach ($arrays as $array) {
echo array_to_str($array) . PHP_EOL;
}
This will output:
apple
apple and plum
apple, plum and watermelon
apple, plum, watermelon and lemon
If the language uses the list format 1 and 2, 3, 4, 5, 6
, the translator could then overcome this by translating
$three_values = "%3$s and %2$s, %1$s";
Unfortunately doing it like this, the list will be out of order. The string would output 6 and 5, 1, 2, 3, 4
.
However, going through the languages currently defined in Google Translate, there are none that change the position of the "and" to be anything but the second last position. The right-to-left languages put it after the first element when reading left to right, but since it is right to left, it is actually in the correct (penultimate) position.
Using this method would also allow you to overcome languages that display their lists in a non standard way:
(Korean) 1, 2, 3, 4 <-- only commas are used
(Italian) 1, 2, 3 e 4, <-- extra comma at the end
(Chinese) 1,2,3和4的 <-- extra 的 at the end
(Hungarian) Az 1., 2., 3. és 4. <-- extra A at the beginning for 2 numbers, Az at the beginning for 3 or more numbers
The last of these could be done using the above function like this:
$two_values = "A %s és %s";
$three_values = "Az %s, %s és %s";
$separator = ", ";
Assuming your numbers are formatted correctly, this will output:
A 1. és 2.
Az 1., 2. és 3.
Az 1., 2., 3. és 4.
来源:https://stackoverflow.com/questions/18751650/making-a-variable-length-list-translatable