Для тех, кому это интересно, кажется, что полная поддержка locales и i18n в PHP наконец-то начинает действовать.
// Set the current locale to the one the user agent wants
$locale = Locale::acceptFromHttp(getenv('HTTP_ACCEPT_LANGUAGE'));
// Default Locale
Locale::setDefault($locale);
setlocale(LC_ALL, $locale . '.UTF-8');
// Default timezone of server
date_default_timezone_set('UTC');
// iconv encoding
iconv_set_encoding("internal_encoding", "UTF-8");
// multibyte encoding
mb_internal_encoding('UTF-8');
Есть несколько вещей, которые нужно перепутать, и важно определить часовой пояс / локаль, а затем использовать ее для правильного анализа и отображения входных и выходных данных. Существует только что выпущенная библиотека PHP I18N , которая содержит таблицы поиска для большей части этой информации.
Обработка Ввод данных пользователем важен для того, чтобы убедиться, что ваше приложение имеет чистые, правильно сформированные строки UTF-8 из любого ввода, введенного пользователем. iconv отлично подходит для этого.
/**
* Convert a string from one encoding to another encoding
* and remove invalid bytes sequences.
*
* @param string $string to convert
* @param string $to encoding you want the string in
* @param string $from encoding that string is in
* @return string
*/
function encode($string, $to = 'UTF-8', $from = 'UTF-8')
{
// ASCII is already valid UTF-8
if($to == 'UTF-8' AND is_ascii($string))
{
return $string;
}
// Convert the string
return @iconv($from, $to . '//TRANSLIT//IGNORE', $string);
}
/**
* Tests whether a string contains only 7bit ASCII characters.
*
* @param string $string to check
* @return bool
*/
function is_ascii($string)
{
return ! preg_match('/[^\x00-\x7F]/S', $string);
}
Затем просто запустите ввод с помощью этих функций.
$utf8_string = normalizer_normalize(encode($_POST['text']), Normalizer::FORM_C);
Переводы
Как сказал Андре, похоже, gettext - это умный выбор по умолчанию для написания приложений, которые можно переводить.
- Gettext использует довольно быстрый бинарный протокол.
- Реализация gettext обычно проще, так как требует только
_('Text to translate')
- Существующие инструменты для использования переводчиками, и они доказали свою эффективность.
Когда вы достигнете размера фейсбука, вы сможете работать над реализацией кэшированных в ОЗУ альтернативных методов, подобных тому, который я упоминал в этом вопросе. Однако ничто не сравнится с «простым, быстрым и работающим» для большинства проектов.
Однако есть и дополнительные вещи, которые gettext не может обработать. Такие вещи, как отображение дат, денег и цифр. Для тех, кому нужна INTL расширение .
/**
* Return an IntlDateFormatter object using the current system locale
*
* @param string $locale string
* @param integer $datetype IntlDateFormatter constant
* @param integer $timetype IntlDateFormatter constant
* @param string $timezone Time zone ID, default is system default
* @return IntlDateFormatter
*/
function __date($locale = NULL, $datetype = IntlDateFormatter::MEDIUM, $timetype = IntlDateFormatter::SHORT, $timezone = NULL)
{
return new IntlDateFormatter($locale ?: setlocale(LC_ALL, 0), $datetype, $timetype, $timezone);
}
$now = new DateTime();
print __date()->format($now);
$time = __date()->parse($string);
Кроме того, вы можете использовать strftime для разбора дат с учетом текущей локали.
Иногда вам нужно, чтобы значения чисел и дат были правильно вставлены в локальные сообщения
/**
* Format the given string using the current system locale
* Basically, it's sprintf on i18n steroids.
*
* @param string $string to parse
* @param array $params to insert
* @return string
*/
function __($string, array $params = NULL)
{
return msgfmt_format_message(setlocale(LC_ALL, 0), $string, $params);
}
// Multiple choices (can also just use ngettext)
print __(_("{1,choice,0#no errors|1#single error|1<{1, number} errors}"), array(4));
// Show time in the correct way
print __(_("It is now {0,time,medium}), time());
Подробнее см. В формате ICU .
База данных
Убедитесь, что ваше соединение с базой данных использует правильную кодировку, чтобы при хранении ничего не прерывалось.
Строковые функции
Вам необходимо понять разницу между строкой , mb_string и функциями графемы .
// 'LATIN SMALL LETTER A WITH RING ABOVE' (U+00E5) normalization form "D"
$char_a_ring_nfd = "a\xCC\x8A";
var_dump(grapheme_strlen($char_a_ring_nfd));
var_dump(mb_strlen($char_a_ring_nfd));
var_dump(strlen($char_a_ring_nfd));
// 'LATIN CAPITAL LETTER A WITH RING ABOVE' (U+00C5)
$char_A_ring = "\xC3\x85";
var_dump(grapheme_strlen($char_A_ring));
var_dump(mb_strlen($char_A_ring));
var_dump(strlen($char_A_ring));
Доменное имя TLD's
Функции IDN из библиотеки INTL - большая помощь при обработке доменных имен, отличных от ascii.