Can I customize the prompt for each post?
For my translations, there are some inconsistencies in articles that refer to female artists. The issue is that some paragraphs refer to the artist in the feminine, while others revert to the masculine, even though the entire article is about the same person.
I believe this is because by translating each block separately, the overall context is lost, and when the AI can’t determine gender, it defaults to masculine.
So I need to add more instructions to the prompt to keep the gender consistent. And I need to do this selectively for each post. How can I do that?
You must first configure the plugin to translate each post in its own request to the API.
Then, you must add hooks to store the post IDs being translated, and then override the prompt based on the translated post.
This PHP code provides an example:
<?php
// Occurs when a translation process is starting
add_action("gatompl:query_execution_start", "my_gato_query_execution_start", 10, 2);
// Occurs when a translation process is ending
add_action("gatompl:query_execution_end", "my_gato_query_execution_end");
// Customize the prompt
add_filter('gatompl:prompt', "my_gato_custom_prompt", 10, 9);
/**
* The translation process starts here
*
* @param array<string,mixed> $queryVariables
*/
function my_gato_query_execution_start (
string $querySlug,
array $queryVariables
): void {
if ( 'translate-customposts' !== $querySlug ) {
return;
}
/** @var string */
$customPostType = $queryVariables['customPostType'];
if ( 'post' !== $customPostType ) {
return;
}
$a_post_ids = [];
$new_ids = [];
// If customPostId is defined and is an integer
if (isset($queryVariables['customPostId']) && is_int($queryVariables['customPostId'])) {
$new_ids[] = $queryVariables['customPostId'];
}
// If customPostIds is defined and is an array
if (isset($queryVariables['customPostIds']) && is_array($queryVariables['customPostIds'])) {
$new_ids = array_merge($new_ids, $queryVariables['customPostIds']);
}
// Merge without duplicates
if (!empty($new_ids)) {
$a_post_ids = array_unique(array_merge($a_post_ids, $new_ids));
$a_post_ids = array_values($a_post_ids); // Reindexing
}
// Saving the array of post_id of posts currently being translated in the WP options
my_global_store_value('gato-translate-post_ids', $a_post_ids);
}
/**
* The translation process ends here
*/
function my_gato_query_execution_end (string $querySlug): void
{
if ( 'translate-customposts' !== $querySlug ) {
return;
}
// The translations are done, we can empty the stored array of post_id
$a_post_ids = [];
my_global_store_value('gato-translate-post_ids', $a_post_ids);
}
/**
* This is where you define your custom prompt
*
* @param string[] $contents The strings to be translated (eg: `['hello world', 'how are you?']`).
*/
function my_gato_custom_prompt(
string $prompt,
string $providerName,
array $contents,
string $sourceLanguageCode,
string $sourceLanguageName,
string $targetLanguageCode,
string $targetLanguageName,
string $targetCountryCode,
string $targetCountryName
): string {
// Retrieve the array of post IDs for posts currently being translated from the WP options
$a_post_ids = my_global_get_value('gato-translate-post_ids');
if ( !$a_post_ids ) {
$a_post_ids = array();
}
// If we are currently translating only one post, then define a custom prompt
if (empty($a_post_ids) || !is_array($a_post_ids)) {
// Empty or not a valid array
$custom_prompt = "";
} else {
// There is more than one post_id in the array, so we cannot make a more precise prompt
// To avoid this case, go to the plugin settings, "Plugin Configuration" tab, "Translation Option"
// and check "Translate custom posts separately? When translating multiple custom posts at once, enable translating each post separately (in its own request to the API)"
if (count($a_post_ids) > 1) {
$custom_prompt = "";
} else {
// Define your custom prompt here
$custom_prompt = "";
// Add your prompt logic here
//
// Example for translating names into Russian and Asian languages depending on the target language
//
// Russian
if ('ru' === $targetLanguageCode ) {
// Start the custom prompt with 2 line returns (it will be appended to the $prompt at the end)
$custom_prompt .= "\n\nConvert person names to Cyrillic script for the Russian translation. Always translate from a name written in Latin script.";
}
// Japanese
if ('ja' === $targetLanguageCode ) {
// Start the custom prompt with 2 line returns (it will be appended to the $prompt at the end)
$custom_prompt .= "\n\nConvert person names to Japanese with this method : Listen to the original pronunciation of the name, break it into Japanese syllables, write it in katakana.";
}
// Korean
if ('ko' === $targetLanguageCode ) {
// Start the custom prompt with 2 line returns (it will be appended to the $prompt at the end)
$custom_prompt .= "\n\nConvert person names in Hangul, the Korean alphabet, to match the pronunciation.";
}
// Simplified Chinese
if ('zh' === $targetLanguageCode ) {
// Start the custom prompt with 2 line returns (it will be appended to the $prompt at the end)
$custom_prompt .= "\n\nConvert person names by phonetic transliteration using Simplified Chinese characters that match the pronunciation, following Mandarin Pinyin standards. Choose characters with positive or neutral meanings, keep them short (usually 2–3 for given names, 1–2 for family names), and maintain name order unless adapting to Chinese conventions. Do not translate the meaning unless it’s a pseudonym or brand with a clear concept. Use existing standard transliterations for well-known names when possible.";
}
}
}
// Add your custom prompt to the initial $prompt and strip off backslashes (while recognizing C-like \n, \r ..., octal and hexadecimal representation)
$prompt = stripcslashes($prompt . $custom_prompt);
// the following line is necessary to really backslash the sentence
$prompt = str_replace('adding a backslash before them (")', 'adding a backslash before them (\")', $prompt);
return $prompt;
}
/**
* Stores an option value in WordPress for global access across all plugins and themes.
* Uses both the options table and, if available, the external object cache (e.g., Redis or Memcached).
*
* @param $my_value An option value to store (mixed). Must be serializable if non-scalar. Expected to not be SQL-escaped.
*/
function my_global_store_value(string $my_key, $my_value): void {
// Save the value in the WordPress options table (persistent across servers).
update_option($my_key, $my_value);
// If an external object cache is active (e.g., Redis, Memcached), store it there too.
if (wp_using_ext_object_cache()) {
wp_cache_set($my_key, $my_value, 'my_cache_group');
}
}
/**
* Retrieves an option value from either the object cache or the options table.
* Ensures the data is available site-wide, even in a multi-server setup.
*
* @return $my_value A value (mixed). Value of the option. A value of any type may be returned, including scalar (string, boolean, float, integer), null, array, object.
*/
function my_global_get_value(string $my_key): mixed {
// First, try to get the data from the external object cache (fastest option).
if (wp_using_ext_object_cache()) {
$my_value = wp_cache_get($my_key, 'my_cache_group');
// If the data was found in cache, return it immediately.
if ($my_value !== false) {
return $my_value;
}
}
// Fallback: read from the WordPress options table (persistent storage).
return get_option($my_key, false); // return false if $my_key does not exist
}