'Goedemorgen, café-eigenaar', 'German' => 'Grüß Gott, Straße', 'French' => 'Ça va, Zoë ? Très bien', 'Greek' => 'Καλημέρα', 'Russian' => 'Здравствуйте', 'Arabic' => 'مرحبا', 'Hebrew' => 'שלום', 'Hindi' => 'नमस्ते', 'Japanese' => 'こんにちは', 'Chinese' => '你好', 'Korean' => '안녕하세요', 'Symbols' => '€ £ ¥ ₹ ≤ ≥ ∞ ✓', 'Emoji' => '👋🌍🐘', ]; // 1. strlen() counts bytes; mb_strlen() (the mbstring extension) counts characters. foreach ($greetings as $language => $text) { printf("%-9s %s (%d characters, %d bytes)\n", $language, $text, mb_strlen($text), strlen($text)); } // 2. strtoupper() only changes ASCII letters; mb_strtoupper() handles the rest. echo strtoupper('café'), ' / ', mb_strtoupper('café'), "\n"; // 3. Byte functions can cut a character in half; mb_substr() can't. echo bin2hex(substr('é', 0, 1)), ' / ', mb_substr('Ελληνικά', 0, 4), "\n"; // 4. json_encode() escapes non-ASCII as \\uXXXX unless told not to. echo json_encode(['city' => 'Zürich']), ' / ', json_encode(['city' => 'Zürich'], JSON_UNESCAPED_UNICODE), "\n"; // 5. Normalisation needs the intl extension, which not every host has. if (class_exists(Normalizer::class)) { $decomposed = "e\u{0301}"; var_dump($decomposed === 'é', Normalizer::normalize($decomposed) === 'é'); } else { echo "intl extension not installed: skipping normalisation\n"; }