WP Residence Help WP Residence Help

  • WPRESIDENCE
  • Video Tutorials
  • Client Support
  • API
Home / WPEstate Translate Plugin / String Scanner — Developer Guide

String Scanner — Developer Guide

221 views 0

This article is the developer companion to the user-facing string scanner documentation. It traces the scanner in WPEstate Translate 1.0.9 end to end, names the functions involved, and lists the option keys and signatures you need when debugging. Product context lives on the multi-language real estate website page.

CONTENT

  • Files Involved
  • Entry Point
  • Target Construction
  • Incremental Scan State
  • Parsing
  • Persistence
  • Options Touched
  • Reset
  • Failure Modes
  • Non-Latin Safety
  • Extension Ideas
  • Further Reading

Files Involved

File Role
includes/string-catalog.php Catalog entry points: wpr_translate_string_catalog_refresh(), _discover_scopes(), _persist_scope(), _query().
includes/string-catalog-filesystem.php wpr_translate_string_catalog_scope_fingerprint() – incremental-scan signature.
includes/string-catalog-normalization.php wpr_translate_string_catalog_file_priority() – which file wins when several translate the same string.
includes/string-catalog-commands.php Ingest, save one translation, delete (used by Reset).
includes/admin/string-scanner.php wpr_translate_admin_handle_strings_actions(), wpr_translate_admin_scan_strings(), wpr_translate_admin_get_languages_directory_mtime(), wpr_translate_admin_reset_strings().
includes/admin/string-targets.php wpr_translate_admin_get_scan_targets(), wpr_translate_admin_get_theme_domain(), wpr_translate_admin_get_plugin_domain(), wpr_translate_admin_locate_languages_directory().
includes/admin/string-parser.php wpr_translate_admin_collect_strings_from_path(), wpr_translate_admin_locate_translation_files(), wpr_translate_admin_gather_language_files(), wpr_translate_admin_extract_strings_from_translation_file(), wpr_translate_admin_determine_language_code_from_file().
includes/admin/string-storage.php wpr_translate_admin_build_language_maps(), wpr_translate_admin_persist_detected_strings(), wpr_translate_admin_get_existing_strings_map(), wpr_translate_admin_insert_string_rows_batch().
includes/admin/string-database.php Table check and lazy column upgrades: processed, msgctxt, plural.

Entry Point

The scan is triggered from WPEstate Translate > Theme & Plugins Strings by a POST form with nonce action wpr_translate_scan_strings / field wpr_translate_scan_nonce. wpr_translate_admin_handle_strings_actions() checks manage_options and the nonce, then calls:

$report = wpr_translate_string_catalog_refresh();
// = wpr_translate_admin_scan_strings( wpr_translate_string_catalog_discover_scopes() )
// returns array( 'new', 'conflicts', 'scopes_completed', 'scopes_incomplete',
//                'scopes_skipped', 'files_parsed', 'files_failed', 'storage_failures' )
// or WP_Error

The UI reports new as “Scan completed. N new strings were registered.”

Target Construction

wpr_translate_admin_get_scan_targets() returns an ordered list of targets (context, path, languages_path, domain):

  • Child theme – context = 'theme:' . sanitize_title( $child_slug ).
  • Parent theme – included when $theme->parent() is a WP_Theme and its realpath differs from the child path.
  • Active plugins – merged with active_sitewide_plugins on multisite; single-file plugins are skipped. context = 'plugin:' . sanitize_title( $slug ).

A target without a readable languages/ directory is dropped. The domain helpers prefer the Text Domain header and fall back to the stylesheet/template name or plugin folder slug.

Incremental Scan State

For each target the scanner computes a fingerprint with wpr_translate_string_catalog_scope_fingerprint(): a sha256 of the language signature plus the relative path, size and mtime of every eligible file. State is stored in wpr_translate_scan_state, keyed by context:

array(
  'theme:wpresidence' => array(
    'mtime'       => 1713300000,
    'languages'   => md5( wp_json_encode( $languages ) ),
    'fingerprint' => '<sha256>',
  ),
  'plugin:woocommerce' => ...
)

A target is skipped when both the fingerprint and the language signature match the last run. A target whose files failed to parse, or whose storage failed, gets no state entry, so it is scanned again next time. Reset deletes the option.

Parsing

wpr_translate_admin_collect_strings_from_path( $path, $context, $locale_map, $code_map, &$report ):

  1. List files – .po, .pot and .mo under languages/ that match a configured language (all .pot). The plugin’s generated-files folder is skipped: it holds the plugin’s own generated files and would read cleared translations back in.
  2. Parse each file – wpr_translate_admin_extract_strings_from_translation_file(); files with an error_code count as files_failed.
  3. Pick the language – wpr_translate_admin_determine_language_code_from_file() with the locale/code maps from wpr_translate_admin_build_language_maps().
  4. Key the entry by gettext key – $key = $msgctxt ? $msgctxt . "\4" . $msgid : $msgid; bucket md5( $context . '|' . $key ), name = 'str_' . md5( $key ). The same msgid under two contexts gives two rows, so _x() strings translate.
  5. Keep plurals – the singular entry stores its msgid_plural in plural.
  6. Resolve duplicates by priority – wpr_translate_string_catalog_file_priority(): exact locale match 300, code match 200, base-language match 100, plus .po 20 / .mo 10. The highest wins; two different translations at the same priority count as a conflict and neither is stored.

Persistence

wpr_translate_admin_persist_detected_strings( $strings, $languages, $default_code ) runs once per scope, so a failure in one scope does not discard the others:

  1. Schema check – wpr_translate_admin_strings_table_exists(), then lazy processed, msgctxt and plural columns.
  2. Load existing rows – wpr_translate_admin_get_existing_strings_map() in chunks of 25 contexts, keyed context|name|language_code.
  3. Open a transaction – START TRANSACTION … COMMIT.
  4. Build one row per language – the default language row stores translation = value, status = 1; other rows get status = 1 only when the file translation is non-empty after wp_strip_all_tags(). processed is 0 when the row needs export.
  5. Update existing rows safely – value, md5, plural are refreshed; a second-language translation is written only if the stored one is empty. A rescan never overwrites a translation saved in the Strings editor.
  6. Insert new rows – in batches of 50 with one multi-row INSERT (wpr_translate_admin_insert_string_rows_batch()).
  7. Invalidate runtime caches – wpr_translate_runtime_strings_changed().

The return value is the number of new default-language rows.

Options Touched

Option Purpose
wpr_translate_languages Active language codes/locales and the is_default flag. Required for scanning.
wpr_translate_scan_state Per-context mtime, language signature and fingerprint.
wpr_translate_theme_admin_strings_domain Domain used for theme admin strings declared in wpr/theme_admin_strings.json.
wpr_translate_theme_admin_strings_hash Hash of that JSON file to skip reimport when unchanged.

Reset

wpr_translate_admin_reset_strings() calls wpr_translate_string_catalog_delete( array( 'all' => true ) ): it deletes every row of wpestate_translation_strings, deletes wpr_translate_scan_state and removes the generated .mo files from the generated-files directory.

Failure Modes

  • No languages configured → WP_Error( 'wpr_translate_missing_languages' ).
  • No default language → WP_Error( 'wpr_translate_no_default_language' ).
  • Missing helper wpr_translate_admin_get_default_language_code() → WP_Error( 'wpr_translate_missing_helper' ).
  • Unparseable file → counted in files_failed; the scope is marked incomplete and rescanned next time.
  • Storage error in one scope → counted in storage_failures; other scopes are still saved.

Non-Latin Safety

Language codes are lowercased and locales normalized; value and translation are stored verbatim. Do not pass them through sanitize_title() in extensions – Cyrillic, Arabic and CJK text must survive end to end.

Extension Ideas

  • Scan a custom set of targets by passing your own array to wpr_translate_admin_scan_strings( $targets ) (same keys as wpr_translate_admin_get_scan_targets()).
  • Force a full rescan with delete_option( 'wpr_translate_scan_state' ) followed by wpr_translate_string_catalog_refresh().
  • After an update that adds context or plural columns, rescan so existing _x() and _n() strings get their new rows.

Further Reading

  • Translating Theme & Plugin Strings – the admin UI that uses the scanner’s output.
  • Gettext Pipeline & MO Files – how exported files reach gettext().

See also the multi-language real estate website guide.

WPEstate Translate Plugin

Related Articles

  • The String Scanner
  • Gettext Pipeline & MO Files — Developer Guide
  • Gettext & MO Files — Making Translations Appear on the Front End
  • Automatic Translation — Developer Guide
MLSImportWordPress IDX Plugin for MLS ListingsImport MLS listings into your WordPress website, customize your property pages, and keep your inventory updated.Start free 30-day trial →

Help Categories

  • 51 Getting Started
  • 72 Installation & Setup
  • 243 Installation FAQ
  • 18Agent, Agency & Developers
  • 5Blog Posts & Blog Lists
  • 39Elementor Shortcodes Built-In
  • 56FAQ
  • 15Footer
  • 37Header
  • 2IDX & MLSImport
  • 23Maps & Location Settings
  • 21Multi-Language - Third Party Plugins
  • 7Other Third party Plugins
  • 21Pages
  • 4Payments & Monetization
  • 20Property Lists, Categories & Archive
  • 37Property Pages & Layouts
  • 32Search & Filtering
  • 162Technical how to | Custom Code
  • 8Technical: Actions and filters
  • 7Technical: Child Theme
  • 86Theme Options & Global Settings
  • 6Translations & Languages
  • 16WPBakery Shortcodes
  • 50WPEstate Translate Plugin
  • 51WPResidence / WPEstate CRM
  • 50WPResidence 5.0 Documentation
  • 9WPResidence Elementor Studio

Join Us On

Powered by WP Estate - All Rights Reserved
  • WPRESIDENCE
  • Video Tutorials
  • Client Support
  • API