In PHP, is there a way to detect the language of a string? Suppose the string is in UTF-8 format.
In PHP, is there a way to detect the language of a string? Suppose the string is in UTF-8 format.
Text_LanguageDetect pear package produced terrible results: "luxury apartments downtown" is detected as Portuguese...
Google API is still the best solution, they give 300$ free credit and warn before charging you anything
Below is a super simple function that uses file_get_contents to download the lang detected by the API, so no need to download or install libraries etc.
function guess_lang($str) {
$str = str_replace(" ", "%20", $str);
$content = file_get_contents("https://translation.googleapis.com/language/translate/v2/detect?key=YOUR_API_KEY&q=".$str);
$lang = (json_decode($content, true));
if(isset($lang))
return $lang["data"]["detections"][0][0]["language"];
}
Execute:
echo guess_lang("luxury apartments downtown montreal"); // returns "en"
You can get your Google Translate API key here: https://console.cloud.google.com/apis/library/translate.googleapis.com/
This is a simple example for short phrases to get you going. For more complex applications you'll want to restrict your API key and use the library obviously.
I have had good results with https://github.com/patrickschur/language-detection and am using it in production:
My usage: I am analyzing emails for a CRM system to know what language an email was written in, so sending the text to a third party service was not an option. Even though the Universal Declaration of Human Rights is probably not the best basis to categorize the language of emails (as emails often have formulaic parts like greetings, which are not part of the Human Rights Declaration) it identifies the correct language in like 99% of cases, if there are at least 5 words in it.
Update: I managed to improve language recognition in emails to basically 100% when using the language-detection library with the following methods:
These do make the library a bit slower, so I would suggest to use them in an async way if possible and measure the performance. In my case it is more than fast enough and much more accurate.
I used this method to check for non- english, spanish, french chars using strictly PHP without any extra language API or Classes as of PHP 5.1. The language scripts list comes from: https://www.php.net/manual/en/regexp.reference.unicode.php See below
An improvement would be to add a function to PHP that lists all supported script languages so that you dont have to fill in the array by hand.
The usecase was for blocking non-latin posts to a form to improve it's spam blocking as the form was receiving a lot of russian, chinese, and arabic spam posts. Since this was implemented, its gone from 40000/week to less than 5, with none in the last 3 weeks. Google Re-Captcha was in use but it was being defeated easily. #satisfied
<?php
$non_latin_text = "This is NOT english, spanish, or french (which are latin languages) because it has this char in it: и";
$latin_text = "1234567890-=\][poiuytrewqasdfghjkl;'/.,mnbvcxz!@#$%^&*()_+|}{:\"?><QWERTYUIOPLKJHGFDSAZXCVBNM";
print_r(is_non_latin($non_latin_text)); //Returns TRUE
print_r(is_non_latin($latin_text)); //Returns FALSE
function is_non_latin($text)
{
$text_script_languages = get_language_scripts($text);
//All Latin characters and numbers which are Common and Latin.
if (count($text_script_languages) == 2 && in_array('Common', $text_script_languages) && in_array('Latin', $text_script_languages))
{
return FALSE;
}
if (count($text_script_languages) == 1 && (in_array('Common', $text_script_languages) || in_array('Latin', $text_script_languages)))
{
return FALSE;
}
//If we are here, then the text had other language scripts in it.
return TRUE;
}
function get_language_scripts($text)
{
$scripts = array('Arabic', 'Armenian', 'Avestan', 'Balinese', 'Bamum', 'Batak', 'Bengali', 'Bopomofo', 'Brahmi', 'Braille', 'Buginese', 'Buhid', 'Canadian_Aboriginal', 'Carian', 'Chakma', 'Cham', 'Cherokee', 'Common', 'Coptic', 'Cuneiform', 'Cypriot', 'Cyrillic', 'Deseret', 'Devanagari', 'Egyptian_Hieroglyphs', 'Ethiopic', 'Georgian', 'Glagolitic', 'Gothic', 'Greek', 'Gujarati', 'Gurmukhi', 'Han', 'Hangul', 'Hanunoo', 'Hebrew', 'Hiragana', 'Imperial_Aramaic', 'Inherited', 'Inscriptional_Pahlavi', 'Inscriptional_Parthian', 'Javanese', 'Kaithi', 'Kannada', 'Katakana', 'Kayah_Li', 'Kharoshthi', 'Khmer', 'Lao', 'Latin', 'Lepcha', 'Limbu', 'Linear_B', 'Lisu', 'Lycian', 'Lydian', 'Malayalam', 'Mandaic', 'Meetei_Mayek', 'Meroitic_Cursive', 'Meroitic_Hieroglyphs', 'Miao', 'Mongolian', 'Myanmar', 'New_Tai_Lue', 'Nko', 'Ogham', 'Old_Italic', 'Old_Persian', 'Old_South_Arabian', 'Old_Turkic', 'Ol_Chiki', 'Oriya', 'Osmanya', 'Phags_Pa', 'Phoenician', 'Rejang', 'Runic', 'Samaritan', 'Saurashtra', 'Sharada', 'Shavian', 'Sinhala', 'Sora_Sompeng', 'Sundanese', 'Syloti_Nagri', 'Syriac', 'Tagalog', 'Tagbanwa', 'Tai_Le', 'Tai_Tham', 'Tai_Viet', 'Takri', 'Tamil', 'Telugu', 'Thaana', 'Thai', 'Tibetan', 'Tifinagh', 'Ugaritic', 'Vai', 'Yi');
$found_scripts = array();
foreach ($scripts AS $key => $script)
{
if (!empty($script))
{
if (preg_match( '/[\p{'.$script.'}]/u', $text))
{
$found_scripts[] = $script;
}
}
}
return $found_scripts;
}
Additional words for French and Spanish to Swiss Mister's answer:
// Franch word list
// from https://1000mostcommonwords.com/1000-most-common-french-words/
$wordList['fr'] = array ('comme', 'que', 'était', 'pour', 'sur', 'sont', 'avec',
'être', 'à', 'un', 'ce', 'par', 'mais', 'que', 'est',
'il', 'eu', 'la', 'et', 'dans');
// Spanish word list
// from https://spanishforyourjob.com/commonwords/
$wordList['es'] = array ('que', 'no', 'a', 'la', 'el', 'es', 'y',
'en', 'lo', 'un', 'por', 'qué', 'si', 'una',
'los', 'con', 'para', 'está', 'eso', 'las');
My answer is for specific case. Here is what I wrote to find if string is in specific language, but there is one condition - different languages have different alphabets. In my case the word(s) can be in 3 languages - english, bulgarian and greek (each with different alphabet). And I need to find if a text is in bulgarian, so later translate it to greek.
class Language {
protected $bgSymbols = array(
'а', 'б', 'в', 'г', 'д', 'е', 'ж', 'з', 'и', 'й', 'к', 'л', 'м', 'н', 'о', 'п', 'р', 'с', 'т', 'у', 'ф', 'х', 'ц', 'ъ', 'ь', 'ч', 'щ', 'ш', 'ю', 'я',
'А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ж', 'З', 'И', 'Й', 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф', 'Х', 'Ц', 'Ъ', 'Ь', 'Ч', 'Щ', 'Ш', 'Ю', 'Я'
);
public function checkIfForTranslate($string) {
$result = false;
$stringArray = array();
preg_match_all('/./u', $string, $matches);
if(isset($matches[0])) {
$stringArray = $matches[0];
}
foreach($this->bgSymbols as $symbol) {
$found = array_search($symbol, $stringArray);
if($found !== false) {
$result = true;
break;
}
}
return $result;
}
}
Hope this help someone with similar case to mine.