ShahiAssist

Internationalization (i18n)

Internationalization (i18n) enables ShahiAssist to be translated into multiple languages, making it accessible to a global audience. This guide covers complete i18n implementation, translation management, and localization best practices.

Text Domain Setup

Plugin Text Domain

`php
// Main plugin file
class ShahiAssist_Plugin {
public function __construct() {
// Load plugin textdomain
addaction(‘init’, [$this, ‘loadtextdomain’]);

// Load textdomain for admin
addaction(‘admininit’, [$this, ‘loadadmintextdomain’]);
}

public function load_textdomain() {
loadplugintextdomain(
‘shahi-assist’,
false,
dirname(plugin_basename(FILE)) . ‘/languages/’
);
}

public function loadadmintextdomain() {
loadplugintextdomain(
‘shahi-assist-admin’,
false,
dirname(plugin_basename(FILE)) . ‘/languages/admin/’
);
}
}

// Instantiate the plugin
new ShahiAssist_Plugin();
`

Text Domain Constants

`php
// Define text domain constants
define(‘SHAHIASSISTTEXT_DOMAIN’, ‘shahi-assist’);
define(‘SHAHIASSISTADMINTEXTDOMAIN’, ‘shahi-assist-admin’);

// Helper functions for consistent text domain usage
function _shahiassist($text) {
return _($text, SHAHIASSISTTEXTDOMAIN);
}

function eshahi_assist($text) {
e($text, SHAHIASSISTTEXTDOMAIN);
}

function nshahi_assist($single, $plural, $number) {
return n($single, $plural, $number, SHAHIASSISTTEXTDOMAIN);
}
`

String Translation

Basic Translation Functions

`php
// Basic translations
echo __(‘Hello World’, ‘shahi-assist’);
echo __(‘Welcome to ShahiAssist’, ‘shahi-assist’);

// With context for disambiguation
echo _x(‘Post’, ‘noun’, ‘shahi-assist’);
echo _x(‘Post’, ‘verb’, ‘shahi-assist’);

// Plural forms
printf(
_n(‘%s ticket’, ‘%s tickets’, $count, ‘shahi-assist’),
numberformati18n($count)
);

// Echo directly
_e(‘Settings saved successfully’, ‘shahi-assist’);
`

Dynamic String Translation

`php
// Translate dynamic content
function getstatuslabel($status) {
$labels = [
‘open’ => __(‘Open’, ‘shahi-assist’),
‘closed’ => __(‘Closed’, ‘shahi-assist’),
‘pending’ => __(‘Pending’, ‘shahi-assist’),
‘resolved’ => __(‘Resolved’, ‘shahi-assist’),
];

return $labels[$status] ?? __(‘Unknown’, ‘shahi-assist’);
}

// Translate with variables
function getwelcomemessage($user_name) {
return sprintf(
__(‘Welcome back, %s!’, ‘shahi-assist’),
eschtml($username)
);
}
`

JavaScript Translation

`php
// Enqueue script with translations
function enqueuefrontendscripts() {
wpenqueuescript(‘shahi-assist-frontend’, plugindirurl(FILE) . ‘js/frontend.js’, [‘jquery’], ‘1.0.0’, true);

// Localize script with translations
wplocalizescript(‘shahi-assist-frontend’, ‘shahiAssistL10n’, [
‘ajaxUrl’ => admin_url(‘admin-ajax.php’),
‘nonce’ => wpcreatenonce(‘shahiassistnonce’),
‘messages’ => [
‘confirmDelete’ => __(‘Are you sure you want to delete this ticket?’, ‘shahi-assist’),
‘saving’ => __(‘Saving…’, ‘shahi-assist’),
‘saved’ => __(‘Changes saved successfully’, ‘shahi-assist’),
‘error’ => __(‘An error occurred’, ‘shahi-assist’),
],
‘labels’ => [
‘priority’ => __(‘Priority’, ‘shahi-assist’),
‘status’ => __(‘Status’, ‘shahi-assist’),
‘category’ => __(‘Category’, ‘shahi-assist’),
]
]);
}
addaction(‘wpenqueuescripts’, ‘enqueuefrontend_scripts’);

// In JavaScript file
jQuery(document).ready(function($) {
$(‘.delete-ticket’).on(‘click’, function() {
if (confirm(shahiAssistL10n.messages.confirmDelete)) {
// Delete ticket
}
});
});
`

POT File Generation

WP-CLI POT Generation

`bash

Generate POT file using WP-CLI

wp i18n make-pot . languages/shahi-assist.pot –domain=shahi-assist

Generate POT for admin strings

wp i18n make-pot . languages/admin/shahi-assist-admin.pot –domain=shahi-assist-admin –include=”admin/”
`

Grunt/Gulp Task for POT Generation

`javascript
// gulpfile.js
const gulp = require(‘gulp’);
const wpPot = require(‘gulp-wp-pot’);

gulp.task(‘pot’, function() {
return gulp.src(‘*/.php’)
.pipe(wpPot({
domain: ‘shahi-assist’,
package: ‘ShahiAssist’,
bugReport: ‘https://example.com’,
lastTranslator: ‘Your Name ‘,
team: ‘Your Team
}))
.pipe(gulp.dest(‘languages/shahi-assist.pot’));
});

gulp.task(‘pot-admin’, function() {
return gulp.src(‘admin/*/.php’)
.pipe(wpPot({
domain: ‘shahi-assist-admin’,
package: ‘ShahiAssist Admin’,
bugReport: ‘https://example.com’,
lastTranslator: ‘Your Name ‘,
team: ‘Your Team
}))
.pipe(gulp.dest(‘languages/admin/shahi-assist-admin.pot’));
});
`

Custom POT Generation Script

`php
// tools/make-pot.php
require_once ‘vendor/autoload.php’;

use Gettext\Translations;
use Gettext\Generator\PoGenerator;

function generatepotfile($sourcedirs, $outputfile, $domain) {
$translations = new Translations();
$translations->setDomain($domain);
$translations->setHeader(‘Language’, ‘en’);
$translations->setHeader(‘Content-Type’, ‘text/plain; charset=UTF-8’);

foreach ($source_dirs as $dir) {
$files = glob($dir . ‘*/.php’);
foreach ($files as $file) {
$content = filegetcontents($file);

// Extract __() calls
pregmatchall(‘/_\(([“\’])(.?)\1\s,\s[“\’]’ . pregquote($domain) . ‘[“\’]\s\)/s’, $content, $matches);
foreach ($matches[2] as $string) {
$translation = $translations->find(null, $string);
if (!$translation) {
$translation = $translations->insert(null, $string);
}
$translation->addReference($file, 0);
}

// Extract _e() calls
pregmatchall(‘/e\(([“\’])(.?)\1\s,\s[“\’]’ . pregquote($domain) . ‘[“\’]\s\)/s’, $content, $matches);
foreach ($matches[2] as $string) {
$translation = $translations->find(null, $string);
if (!$translation) {
$translation = $translations->insert(null, $string);
}
$translation->addReference($file, 0);
}

// Extract _n() calls
pregmatchall(‘/n\(([“\’])(.?)\1\s,\s([“\’])(.?)\3\s,\s[^,]+\s,\s[“\’]’ . pregquote($domain) . ‘[“\’]\s*\)/s’, $content, $matches);
for ($i = 0; $i < count($matches[2]); $i++) { $translation = $translations->find(null, $matches[2][$i]);
if (!$translation) {
$translation = $translations->insert(null, $matches[2][$i]);
$translation->setPlural($matches[4][$i]);
}
$translation->addReference($file, 0);
}
}
}

$generator = new PoGenerator();
$generator->generateFile($translations, $output_file);
}

// Generate main POT file
generatepotfile(
[‘includes/’, ‘public/’, ‘admin/’],
‘languages/shahi-assist.pot’,
‘shahi-assist’
);

// Generate admin POT file
generatepotfile(
[‘admin/’],
‘languages/admin/shahi-assist-admin.pot’,
‘shahi-assist-admin’
);

echo “POT files generated successfully!\n”;
`

Translation File Management

Loading Translation Files

`php
// Load translations for current locale
function loadshahiassist_translations() {
$locale = get_locale();

// Load main translations
$mofile = plugindir_path(FILE) . ‘languages/shahi-assist-‘ . $locale . ‘.mo’;
if (fileexists($mofile)) {
loadtextdomain(‘shahi-assist’, $mofile);
}

// Load admin translations
$adminmofile = plugindirpath(FILE) . ‘languages/admin/shahi-assist-admin-‘ . $locale . ‘.mo’;
if (fileexists($adminmo_file)) {
loadtextdomain(‘shahi-assist-admin’, $adminmo_file);
}
}
addaction(‘init’, ‘loadshahiassisttranslations’);
`

Translation Update Checker

`php
class ShahiAssistTranslationUpdater {
private $api_url = ‘https://api.github.com/repos/your-org/shahi-assist-translations/contents/’;

public function checkforupdates() {
$locale = get_locale();
$remotetranslations = $this->getremote_translations($locale);
$localtranslations = $this->getlocal_translations($locale);

$updates_available = [];

foreach ($remotetranslations as $file => $remotedata) {
$localfile = plugindir_path(FILE) . ‘languages/’ . $file;

if (!fileexists($localfile) ||
filemtime($localfile) < strtotime($remotedata[‘last_modified’])) {
$updates_available[] = $file;
}
}

if (!empty($updates_available)) {
updateoption(‘shahiassisttranslationupdates’, $updates_available);
$this->notifyadminofupdates($updatesavailable);
}
}

private function getremotetranslations($locale) {
$response = wpremoteget($this->api_url . $locale);

if (iswperror($response)) {
return [];
}

$files = jsondecode(wpremoteretrievebody($response), true);
$translations = [];

foreach ($files as $file) {
if (pathinfo($file[‘name’], PATHINFO_EXTENSION) === ‘po’) {
$translations[$file[‘name’]] = [
‘url’ => $file[‘download_url’],
‘lastmodified’ => $file[‘lastmodified’]
];
}
}

return $translations;
}

private function getlocaltranslations($locale) {
$pattern = plugindirpath(FILE) . ‘languages/*-‘ . $locale . ‘.po’;
return glob($pattern);
}

private function notifyadminof_updates($files) {
$adminemail = getoption(‘admin_email’);
$subject = __(‘ShahiAssist Translation Updates Available’, ‘shahi-assist’);
$message = sprintf(
__(‘New translations are available for ShahiAssist: %s’, ‘shahi-assist’),
implode(‘, ‘, $files)
);

wpmail($adminemail, $subject, $message);
}
}
`

Date, Time, and Number Formatting

Localized Date/Time Formatting

`php
// Localized date formatting
function formatticketdate($timestamp) {
$dateformat = getoption(‘date_format’);
$timeformat = getoption(‘time_format’);

return sprintf(
__(‘Created on %s at %s’, ‘shahi-assist’),
datei18n($dateformat, $timestamp),
datei18n($timeformat, $timestamp)
);
}

// Relative time
function getrelativetime($timestamp) {
$timediff = humantimediff($timestamp, currenttime(‘timestamp’));

if ($timestamp > current_time(‘timestamp’)) {
return sprintf(_(‘in %s’, ‘shahi-assist’), $timediff);
} else {
return sprintf(_(‘%s ago’, ‘shahi-assist’), $timediff);
}
}
`

Number Formatting

`php
// Localized number formatting
function formatticketcount($count) {
return sprintf(
_n(‘%s ticket’, ‘%s tickets’, $count, ‘shahi-assist’),
numberformati18n($count)
);
}

// Currency formatting
function format_currency($amount, $currency = ‘USD’) {
$formatted = numberformati18n($amount, 2);

// Add currency symbol based on locale
$locale = get_locale();

switch ($locale) {
case ‘en_US’:
return ‘$’ . $formatted;
case ‘en_GB’:
return ‘£’ . $formatted;
case ‘de_DE’:
return $formatted . ‘ €’;
default:
return $formatted . ‘ ‘ . $currency;
}
}
`

RTL Language Support

RTL Stylesheet

`php
// Enqueue RTL stylesheet
function enqueuertlstyles() {
if (is_rtl()) {
wpenqueuestyle(
‘shahi-assist-rtl’,
plugindirurl(FILE) . ‘css/rtl.css’,
[‘shahi-assist-main’],
‘1.0.0’
);
}
}
addaction(‘wpenqueuescripts’, ‘enqueuertl_styles’);
addaction(‘adminenqueuescripts’, ‘enqueuertl_styles’);
`

RTL CSS Rules

`css
/ css/rtl.css /
body.rtl .ticket-list {
direction: rtl;
}

.rtl .ticket-meta {
text-align: right;
}

.rtl .ticket-actions {
float: left; / In RTL, left becomes right /
}

.rtl .priority-high::before {
content: “\f344”; / Dashicon pointing left in RTL /
margin-left: 5px;
margin-right: 0;
}
`

RTL JavaScript Adjustments

`javascript
// Adjust layout for RTL
jQuery(document).ready(function($) {
if ($(‘body’).hasClass(‘rtl’)) {
// Adjust positioning for RTL
$(‘.ticket-sidebar’).css(‘float’, ‘left’);
$(‘.ticket-content’).css(‘margin-left’, ‘300px’);
$(‘.ticket-content’).css(‘margin-right’, ‘0’);
}
});
`

Translation Contribution

Translation Interface

`php
// Add translation interface to admin
addaction(‘adminmenu’, function() {
addsubmenupage(
‘shahi-assist-settings’,
__(‘Translations’, ‘shahi-assist’),
__(‘Translations’, ‘shahi-assist’),
‘manage_options’,
‘shahi-assist-translations’,
‘shahiassisttranslations_page’
);
});

function shahiassisttranslations_page() {
$locale = get_locale();
$translations = gettranslationsforcurrentlocale(‘shahi-assist’);

?>

‘ . $locale . ‘‘
); ?>

count’] / $translations[‘totalcount’]) * 100)
); ?>

`

Export Translation Template

`php
// Generate translation template for contributors
function exporttranslationtemplate() {
if (!currentusercan(‘manage_options’)) {
return;
}

$locale = sanitizetextfield($_GET[‘locale’] ?? ‘en’);
$potfile = plugindir_path(FILE) . ‘languages/shahi-assist.pot’;

if (!fileexists($potfile)) {
wpdie(_(‘POT file not found’, ‘shahi-assist’));
}

header(‘Content-Type: application/octet-stream’);
header(‘Content-Disposition: attachment; filename=”shahi-assist-‘ . $locale . ‘.po”‘);
header(‘Content-Length: ‘ . filesize($pot_file));

readfile($pot_file);
exit;
}
addaction(‘adminpostexporttranslationtemplate’, ‘exporttranslation_template’);
`

Testing Internationalization

i18n Testing Functions

`php
// Test translation loading
function test_translations() {
$test_strings = [
__(‘Hello World’, ‘shahi-assist’),
__(‘Settings’, ‘shahi-assist’),
_n(‘%s ticket’, ‘%s tickets’, 1, ‘shahi-assist’),
_n(‘%s ticket’, ‘%s tickets’, 5, ‘shahi-assist’),
];

$results = [];
foreach ($test_strings as $string) {
$results[] = [
‘original’ => $string,
‘translated’ => $string !== __(‘Hello World’, ‘shahi-assist’), // Check if different from English
];
}

return $results;
}

// RTL testing
function isrtllanguage() {
$rtl_languages = [‘ar’, ‘he’, ‘fa’, ‘ur’, ‘yi’];
$locale = get_locale();
$language_code = substr($locale, 0, 2);

return inarray($languagecode, $rtl_languages);
}
`

Locale Switching for Testing

`php
// Switch locale for testing
function switchlocalefor_testing($locale) {
global $wp_locale;

switchtolocale($locale);

// Reload text domains
unload_textdomain(‘shahi-assist’);
loadplugintextdomain(‘shahi-assist’, false, dirname(plugin_basename(FILE)) . ‘/languages/’);

// Force reload of admin text domain
unload_textdomain(‘shahi-assist-admin’);
loadplugintextdomain(‘shahi-assist-admin’, false, dirname(plugin_basename(FILE)) . ‘/languages/admin/’);
}

// Test different locales
addaction(‘admininit’, function() {
if (isset($GET[‘testlocale’])) {
$locale = sanitizetextfield($GET[‘testlocale’]);
switchlocalefor_testing($locale);

// Redirect back to remove query param
wpredirect(removequeryarg(‘testlocale’));
exit;
}
});
`

Resources

Share this article

Was this article helpful?

Help us improve our documentation

Still need help?

Our support team is ready to assist you with personalized guidance for your workspace.

Submit a support ticket