diff --git a/composer.json b/composer.json index 882060a..f9ad761 100644 --- a/composer.json +++ b/composer.json @@ -81,7 +81,7 @@ "test -f ./bin/strauss.phar || curl -o bin/strauss.phar -L -C - https://github.com/BrianHenryIE/strauss/releases/download/0.26.5/strauss.phar" ], "clean-faker-lang": [ - "[ -d './vendor/fakerphp/faker/src/Faker/Provider' ] && echo 'Removing folders:' && find ./vendor/fakerphp/faker/src/Faker/Provider -mindepth 1 -maxdepth 1 -type d ! -name 'en_US' -print -exec rm -r {} + || true" + "[ -d './vendor/fakerphp/faker/src/Faker/Provider' ] && echo 'Removing folders:' && find ./vendor/fakerphp/faker/src/Faker/Provider -mindepth 1 -maxdepth 1 -type d ! -name 'en_US' ! -name 'fr_FR' ! -name 'de_DE' ! -name 'es_ES' ! -name 'pt_BR' ! -name 'it_IT' ! -name 'nl_NL' ! -name 'ja_JP' ! -name 'zh_CN' ! -name 'ru_RU' -print -exec rm -r {} + || true" ], "strauss": [ "@strauss-install", diff --git a/src/FakerPress/Module/Abstract_Module.php b/src/FakerPress/Module/Abstract_Module.php index e100edf..d60b88c 100644 --- a/src/FakerPress/Module/Abstract_Module.php +++ b/src/FakerPress/Module/Abstract_Module.php @@ -2,7 +2,9 @@ namespace FakerPress\Module; +use FakerPress\ThirdParty\Faker\Factory; use FakerPress\ThirdParty\Faker\Generator; +use function FakerPress\fakerpress_get_available_locales; use function FakerPress\is_truthy; /** @@ -41,6 +43,15 @@ abstract class Abstract_Module implements Interface_Module { */ protected $provider_class; + /** + * Faker locale for generated content. + * + * @since 0.10.0 + * + * @var ?string + */ + protected ?string $locale = null; + /** * Stores the generated data. * @@ -108,7 +119,11 @@ public function get_amount_allowed(): int { */ public function get_faker(): Generator { if ( ! $this->faker ) { - $this->faker = \FakerPress\ThirdParty\Faker\Factory::create(); + $locale = $this->locale && isset( fakerpress_get_available_locales()[ $this->locale ] ) + ? $this->locale + : Factory::DEFAULT_LOCALE; + + $this->faker = Factory::create( $locale ); // We need to merge the Provider to the Dependencies, so everything is loaded. $providers = array_merge( $this->get_dependencies(), (array) $this->get_provider_class() ); @@ -123,6 +138,30 @@ public function get_faker(): Generator { return $this->faker; } + /** + * Set the Faker locale for generated content. + * + * @since 0.10.0 + * + * @param ?string $locale Locale code (e.g. 'fr_FR'), or null for default. + * + * @return self + */ + public function set_locale( ?string $locale ): self { + $locale = '' !== $locale ? $locale : null; + + // Invalidate any cached faker when the locale changes, so the generator is + // rebuilt with the new locale on the next get_faker() call. Without this, + // the first get_faker() pins the locale for the entire request. + if ( $this->locale !== $locale ) { + $this->faker = null; + } + + $this->locale = $locale; + + return $this; + } + /** * Filters the dependencies classes for this module. * diff --git a/src/FakerPress/Module/Attachment.php b/src/FakerPress/Module/Attachment.php index dc4e073..56dd90c 100644 --- a/src/FakerPress/Module/Attachment.php +++ b/src/FakerPress/Module/Attachment.php @@ -5,6 +5,7 @@ use FakerPress\Provider\Image\LoremPicsum; use WP_Error; use FakerPress; +use function FakerPress\get; class Attachment extends Abstract_Module { @@ -306,6 +307,8 @@ public function parse_request( $qty, $request = [] ) { // The quantity is already calculated by the REST endpoint or passed directly // We should use the $qty parameter, not recalculate from request + $this->set_locale( get( $request, 'locale', null ) ); + // Process date range if ( isset( $request['interval_date'] ) ) { $date_range = [ diff --git a/src/FakerPress/Module/Comment.php b/src/FakerPress/Module/Comment.php index 77f781c..6f69213 100644 --- a/src/FakerPress/Module/Comment.php +++ b/src/FakerPress/Module/Comment.php @@ -133,6 +133,8 @@ public function parse_request( int $qty, array $request = [] ) { return new WP_Error( 'fakerpress_zero_comments', __( 'Zero is not a good number of comments to fake...', 'fakerpress' ) ); } + $this->set_locale( get( $request, 'locale', null ) ); + $comment_content_size = get( $request, 'content_size', [ 1, 5 ] ); $comment_content_use_html = is_truthy( get( $request, 'use_html', 'off' ) ); $comment_content_html_tags = array_map( 'trim', explode( ',', get( $request, 'html_tags' ) ) ); diff --git a/src/FakerPress/Module/Post.php b/src/FakerPress/Module/Post.php index 0860e2f..163c6d7 100644 --- a/src/FakerPress/Module/Post.php +++ b/src/FakerPress/Module/Post.php @@ -130,6 +130,8 @@ public function parse_request( int $qty, array $request = [] ) { return new WP_Error( 'fakerpress_zero_posts', __( 'Zero is not a good number of posts to fake...', 'fakerpress' ) ); } + $this->set_locale( get( $request, 'locale', null ) ); + // Fetch Comment Status $comment_status = get( $request, 'comment_status', '' ); $comment_status = array_map( 'trim', explode( ',', $comment_status ) ); diff --git a/src/FakerPress/Module/Term.php b/src/FakerPress/Module/Term.php index 7a5a8de..14ef9ba 100644 --- a/src/FakerPress/Module/Term.php +++ b/src/FakerPress/Module/Term.php @@ -109,6 +109,8 @@ public function parse_request( int $qty, array $request = [] ) { return new WP_Error( 'fakerpress_zero_terms', __( 'Zero is not a good number of terms to fake...', 'fakerpress' ) ); } + $this->set_locale( get( $request, 'locale', null ) ); + $name_size = get( $request, 'size' ); // Fetch taxonomies diff --git a/src/FakerPress/Module/User.php b/src/FakerPress/Module/User.php index eccf778..6f03112 100644 --- a/src/FakerPress/Module/User.php +++ b/src/FakerPress/Module/User.php @@ -136,6 +136,8 @@ public function parse_request( int $qty, array $request = [] ) { return new WP_Error( 'fakerpress_zero_users', __( 'Zero is not a good number of users to fake...', 'fakerpress' ) ); } + $this->set_locale( get( $request, 'locale', null ) ); + $description_size = get( $request, 'description_size', [ 1, 5 ] ); $description_use_html = get( $request, 'use_html', 'off' ) === 'on'; $description_html_tags = array_map( 'trim', explode( ',', get( $request, 'html_tags', '' ) ) ); diff --git a/src/FakerPress/Plugin.php b/src/FakerPress/Plugin.php index c04212c..ab9ecae 100644 --- a/src/FakerPress/Plugin.php +++ b/src/FakerPress/Plugin.php @@ -167,6 +167,7 @@ protected function static_load(): void { require_once $this->plugin_path . 'src' . DIRECTORY_SEPARATOR . 'functions' . DIRECTORY_SEPARATOR . 'conditionals.php'; require_once $this->plugin_path . 'src' . DIRECTORY_SEPARATOR . 'functions' . DIRECTORY_SEPARATOR . 'sorting.php'; require_once $this->plugin_path . 'src' . DIRECTORY_SEPARATOR . 'functions' . DIRECTORY_SEPARATOR . 'assets.php'; + require_once $this->plugin_path . 'src' . DIRECTORY_SEPARATOR . 'functions' . DIRECTORY_SEPARATOR . 'locale.php'; } /** diff --git a/src/FakerPress/REST/Abstract_Endpoint.php b/src/FakerPress/REST/Abstract_Endpoint.php index 7b6fb57..f502236 100644 --- a/src/FakerPress/REST/Abstract_Endpoint.php +++ b/src/FakerPress/REST/Abstract_Endpoint.php @@ -15,6 +15,8 @@ use WP_REST_Server; use WP_Error; +use function FakerPress\fakerpress_get_available_locales; + /** * Abstract class Abstract_Endpoint * @@ -388,6 +390,31 @@ protected function get_batching_args(): array { ]; } + /** + * Get the locale argument definition shared across all generation endpoints. + * + * @since 0.10.0 + * + * @return array + */ + protected function get_locale_args(): array { + return [ + 'locale' => [ + 'description' => __( 'Locale for generated content (e.g. fr_FR, de_DE). Falls back to en_US.', 'fakerpress' ), + 'type' => 'string', + 'default' => null, + 'sanitize_callback' => 'sanitize_text_field', + 'validate_callback' => function ( $value ) { + if ( $value === null || '' === $value ) { + return true; + } + + return isset( fakerpress_get_available_locales()[ $value ] ); + }, + ], + ]; + } + /** * Convert endpoint args to request schema format. * diff --git a/src/FakerPress/REST/Endpoints/Attachments.php b/src/FakerPress/REST/Endpoints/Attachments.php index c69bcf7..89a43f3 100644 --- a/src/FakerPress/REST/Endpoints/Attachments.php +++ b/src/FakerPress/REST/Endpoints/Attachments.php @@ -295,7 +295,8 @@ protected function get_endpoint_args(): array { 'type' => 'object', ], ], - $this->get_batching_args() + $this->get_batching_args(), + $this->get_locale_args() ); } diff --git a/src/FakerPress/REST/Endpoints/Comments.php b/src/FakerPress/REST/Endpoints/Comments.php index 90f22e2..755a24c 100644 --- a/src/FakerPress/REST/Endpoints/Comments.php +++ b/src/FakerPress/REST/Endpoints/Comments.php @@ -226,7 +226,8 @@ protected function get_endpoint_args(): array { 'type' => 'object', ], ], - $this->get_batching_args() + $this->get_batching_args(), + $this->get_locale_args() ); } diff --git a/src/FakerPress/REST/Endpoints/Posts.php b/src/FakerPress/REST/Endpoints/Posts.php index 6d88624..6baa158 100644 --- a/src/FakerPress/REST/Endpoints/Posts.php +++ b/src/FakerPress/REST/Endpoints/Posts.php @@ -245,7 +245,8 @@ protected function get_endpoint_args(): array { 'type' => 'object', ], ], - $this->get_batching_args() + $this->get_batching_args(), + $this->get_locale_args() ); } diff --git a/src/FakerPress/REST/Endpoints/Terms.php b/src/FakerPress/REST/Endpoints/Terms.php index 9e55092..67f5816 100644 --- a/src/FakerPress/REST/Endpoints/Terms.php +++ b/src/FakerPress/REST/Endpoints/Terms.php @@ -229,7 +229,8 @@ protected function get_endpoint_args(): array { 'type' => 'object', ], ], - $this->get_batching_args() + $this->get_batching_args(), + $this->get_locale_args() ); } diff --git a/src/FakerPress/REST/Endpoints/Users.php b/src/FakerPress/REST/Endpoints/Users.php index 75802e7..042f058 100644 --- a/src/FakerPress/REST/Endpoints/Users.php +++ b/src/FakerPress/REST/Endpoints/Users.php @@ -225,7 +225,8 @@ protected function get_endpoint_args(): array { 'type' => 'object', ], ], - $this->get_batching_args() + $this->get_batching_args(), + $this->get_locale_args() ); } diff --git a/src/FakerPress/REST/Traits/Handles_Batching.php b/src/FakerPress/REST/Traits/Handles_Batching.php index abf9c37..99f3ea3 100644 --- a/src/FakerPress/REST/Traits/Handles_Batching.php +++ b/src/FakerPress/REST/Traits/Handles_Batching.php @@ -31,6 +31,14 @@ trait Handles_Batching { * @return array Array containing quantity, offset, total, and is_capped. */ protected function calculate_batched_quantity( $params, $module ) { + // Apply the requested locale before any get_faker() call below, so the + // generator is built with the right locale on first instantiation. parse_request() + // sets it again later, but that runs after this method may have already cached + // an en_US faker via numberBetween() for a qty range. + if ( isset( $params['locale'] ) ) { + $module->set_locale( $params['locale'] ); + } + $allowed = $module->get_amount_allowed(); $offset = absint( $params['offset'] ?? 0 ); $total = absint( $params['total'] ?? 0 ); diff --git a/src/functions/locale.php b/src/functions/locale.php new file mode 100644 index 0000000..6c4dad7 --- /dev/null +++ b/src/functions/locale.php @@ -0,0 +1,35 @@ + human-readable label. + */ +function fakerpress_get_available_locales(): array { + return [ + 'en_US' => 'English (United States)', + 'fr_FR' => 'French (France)', + 'de_DE' => 'German (Germany)', + 'es_ES' => 'Spanish (Spain)', + 'pt_BR' => 'Portuguese (Brazil)', + 'it_IT' => 'Italian (Italy)', + 'nl_NL' => 'Dutch (Netherlands)', + 'ja_JP' => 'Japanese (Japan)', + 'zh_CN' => 'Chinese (Simplified, China)', + 'ru_RU' => 'Russian (Russia)', + ]; +} diff --git a/src/templates/pages/attachments.php b/src/templates/pages/attachments.php index c16d5ad..6beb4d1 100644 --- a/src/templates/pages/attachments.php +++ b/src/templates/pages/attachments.php @@ -197,6 +197,27 @@ ] ); +$_locale_options = []; +foreach ( fakerpress_get_available_locales() as $locale_code => $locale_label ) { + $_locale_options[] = [ + 'id' => $locale_code, + 'text' => $locale_label, + ]; +} + +$fields[] = new Field( + 'dropdown', + [ + 'id' => 'locale', + 'options' => $_locale_options, + 'value' => 'en_US', + ], + [ + 'label' => __( 'Locale', 'fakerpress' ), + 'description' => __( 'Language for generated content. Falls back to English if the locale data is unavailable.', 'fakerpress' ), + ] +); + $fields[] = new Field( 'meta', [ diff --git a/src/templates/pages/comments.php b/src/templates/pages/comments.php index 4f95cf1..38662ba 100644 --- a/src/templates/pages/comments.php +++ b/src/templates/pages/comments.php @@ -146,6 +146,27 @@ ] ); +$_locale_options = []; +foreach ( fakerpress_get_available_locales() as $locale_code => $locale_label ) { + $_locale_options[] = [ + 'id' => $locale_code, + 'text' => $locale_label, + ]; +} + +$fields[] = new Field( + 'dropdown', + [ + 'id' => 'locale', + 'options' => $_locale_options, + 'value' => 'en_US', + ], + [ + 'label' => __( 'Locale', 'fakerpress' ), + 'description' => __( 'Language for generated content. Falls back to English if the locale data is unavailable.', 'fakerpress' ), + ] +); + $fields[] = new Field( 'meta', [ diff --git a/src/templates/pages/posts.php b/src/templates/pages/posts.php index e5ed42c..62a2d3a 100644 --- a/src/templates/pages/posts.php +++ b/src/templates/pages/posts.php @@ -223,6 +223,27 @@ ] ); +$_locale_options = []; +foreach ( fakerpress_get_available_locales() as $locale_code => $locale_label ) { + $_locale_options[] = [ + 'id' => $locale_code, + 'text' => $locale_label, + ]; +} + +$fields[] = new Field( + 'dropdown', + [ + 'id' => 'locale', + 'options' => $_locale_options, + 'value' => 'en_US', + ], + [ + 'label' => __( 'Locale', 'fakerpress' ), + 'description' => __( 'Language for generated content. Falls back to English if the locale data is unavailable.', 'fakerpress' ), + ] +); + $fields[] = new Field( 'meta', [ diff --git a/src/templates/pages/terms.php b/src/templates/pages/terms.php index 720125f..a09ed66 100644 --- a/src/templates/pages/terms.php +++ b/src/templates/pages/terms.php @@ -47,6 +47,27 @@ ] ); +$_locale_options = []; +foreach ( fakerpress_get_available_locales() as $locale_code => $locale_label ) { + $_locale_options[] = [ + 'id' => $locale_code, + 'text' => $locale_label, + ]; +} + +$fields[] = new Field( + 'dropdown', + [ + 'id' => 'locale', + 'options' => $_locale_options, + 'value' => 'en_US', + ], + [ + 'label' => __( 'Locale', 'fakerpress' ), + 'description' => __( 'Language for generated content. Falls back to English if the locale data is unavailable.', 'fakerpress' ), + ] +); + if ( version_compare( $GLOBALS['wp_version'], '4.4-beta', '>=' ) ) { $fields[] = new Field( 'meta', diff --git a/src/templates/pages/users.php b/src/templates/pages/users.php index 33d5564..4d144c2 100644 --- a/src/templates/pages/users.php +++ b/src/templates/pages/users.php @@ -87,6 +87,27 @@ ] ); +$_locale_options = []; +foreach ( fakerpress_get_available_locales() as $locale_code => $locale_label ) { + $_locale_options[] = [ + 'id' => $locale_code, + 'text' => $locale_label, + ]; +} + +$fields[] = new Field( + 'dropdown', + [ + 'id' => 'locale', + 'options' => $_locale_options, + 'value' => 'en_US', + ], + [ + 'label' => __( 'Locale', 'fakerpress' ), + 'description' => __( 'Language for generated content. Falls back to English if the locale data is unavailable.', 'fakerpress' ), + ] +); + $fields[] = new Field( 'meta', [