Skip to content

Commit a615110

Browse files
authored
Merge pull request #709 from newfold-labs/multilingual-support
add locale support
2 parents 1f684b4 + f627fea commit a615110

File tree

20 files changed

+433
-28
lines changed

20 files changed

+433
-28
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
3+
namespace NewfoldLabs\WP\Module\Onboarding\RestApi;
4+
5+
use NewfoldLabs\WP\Module\Onboarding\Permissions;
6+
use NewfoldLabs\WP\Module\Onboarding\Services\LanguageService;
7+
8+
/**
9+
* Controller for handling language-related endpoints.
10+
*/
11+
class LanguagesController {
12+
13+
/**
14+
* The namespace of this controller's route.
15+
*
16+
* @var string
17+
*/
18+
protected $namespace = 'newfold-onboarding/v1';
19+
20+
/**
21+
* The base of this controller's route.
22+
*
23+
* @var string
24+
*/
25+
protected $rest_base = '/languages';
26+
27+
/**
28+
* Register routes for LanguagesController.
29+
*/
30+
public function register_routes() {
31+
register_rest_route(
32+
$this->namespace,
33+
$this->rest_base,
34+
array(
35+
array(
36+
'methods' => \WP_REST_Server::READABLE,
37+
'callback' => array( $this, 'get_languages' ),
38+
'permission_callback' => array( Permissions::class, 'rest_is_authorized_admin' ),
39+
),
40+
)
41+
);
42+
}
43+
44+
/**
45+
* Get available languages in WordPress.
46+
*
47+
* @return WP_REST_Response
48+
*/
49+
public function get_languages() {
50+
// Use LanguageService to get languages
51+
$languages = LanguageService::get_all_languages();
52+
53+
return new \WP_REST_Response(
54+
array(
55+
'languages' => $languages,
56+
),
57+
200
58+
);
59+
}
60+
}

includes/RestApi/RestApi.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ final class RestApi {
3030
'NewfoldLabs\\WP\\Module\\Onboarding\\RestApi\\SiteClassificationController',
3131
'NewfoldLabs\\WP\\Module\\Onboarding\\RestApi\\SiteGenController',
3232
'NewfoldLabs\\WP\\Module\\Onboarding\\RestApi\\BlockRenderController',
33+
'NewfoldLabs\\WP\\Module\\Onboarding\\RestApi\\LanguagesController',
3334
);
3435

3536
/**

includes/RestApi/SiteGenController.php

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ public function sitegen_meta_args() {
116116
'required' => true,
117117
'type' => 'string',
118118
),
119+
'locale' => array(
120+
'required' => true,
121+
'type' => 'string',
122+
),
119123
'skip_cache' => array(
120124
'required' => false,
121125
'type' => 'boolean',
@@ -135,6 +139,10 @@ public function get_homepages_args() {
135139
'type' => 'string',
136140
'sanitize_callback' => 'sanitize_text_field',
137141
),
142+
'locale' => array(
143+
'required' => true,
144+
'type' => 'string',
145+
),
138146
);
139147
}
140148

@@ -204,10 +212,15 @@ public function generate_sitegen_meta( \WP_REST_Request $request ) {
204212

205213
$site_info = $request->get_param( 'site_info' );
206214
$identifier = $request->get_param( 'identifier' );
215+
$locale = $request->get_param( 'locale' );
207216
$skip_cache = $request->get_param( 'skip_cache' );
208217

209-
// TODO Implement the main function and do computations if required.
210-
return SiteGenService::instantiate_site_meta( $site_info, $identifier, $skip_cache );
218+
return SiteGenService::instantiate_site_meta(
219+
$site_info,
220+
$identifier,
221+
$locale,
222+
$skip_cache
223+
);
211224
}
212225

213226
/**
@@ -223,22 +236,24 @@ public function get_homepages( \WP_REST_Request $request ) {
223236
}
224237

225238
$site_description = $request->get_param( 'site_description' );
239+
$locale = $request->get_param( 'locale' );
226240
$site_info = array( 'site_description' => $site_description );
227241

228-
$target_audience = SiteGenService::instantiate_site_meta( $site_info, 'target_audience' );
242+
$target_audience = SiteGenService::instantiate_site_meta( $site_info, 'target_audience', $locale );
229243
if ( is_wp_error( $target_audience ) ) {
230244
return $target_audience;
231245
}
232246

233-
$content_style = SiteGenService::instantiate_site_meta( $site_info, 'content_tones' );
247+
$content_style = SiteGenService::instantiate_site_meta( $site_info, 'content_tones', $locale );
234248
if ( is_wp_error( $content_style ) ) {
235249
return $content_style;
236250
}
237251

238252
$homepages = SiteGenService::generate_homepages(
239253
$site_description,
240254
$content_style,
241-
$target_audience
255+
$target_audience,
256+
$locale,
242257
);
243258

244259
if ( is_wp_error( $homepages ) ) {
@@ -260,20 +275,22 @@ public function regenerate_homepage( \WP_REST_Request $request ) {
260275
$color_palette = $request->get_param( 'palette' );
261276
$is_favorite = $request->get_param( 'isFavorite' );
262277
$site_info = array( 'site_description' => $site_description );
278+
$locale = $request->get_param( 'locale' );
279+
$skip_cache = $request->get_param( 'skip_cache' );
263280

264-
$target_audience = SiteGenService::instantiate_site_meta( $site_info, 'target_audience' );
281+
$target_audience = SiteGenService::instantiate_site_meta( $site_info, 'target_audience', $locale, $skip_cache );
265282
if ( is_wp_error( $target_audience ) ) {
266283
return $target_audience;
267284
}
268-
$content_style = SiteGenService::instantiate_site_meta( $site_info, 'content_tones' );
285+
$content_style = SiteGenService::instantiate_site_meta( $site_info, 'content_tones', $locale, $skip_cache );
269286
if ( is_wp_error( $content_style ) ) {
270287
return $content_style;
271288
}
272289

273290
if ( $is_favorite ) {
274291
$result = SiteGenService::regenerate_favorite_homepage( $slug, $color_palette );
275292
} else {
276-
$result = SiteGenService::regenerate_homepage( $site_description, $content_style, $target_audience );
293+
$result = SiteGenService::regenerate_homepage( $site_description, $content_style, $target_audience, $locale );
277294
}
278295

279296
if ( null === $result ) {
@@ -298,23 +315,25 @@ public function regenerate_homepage( \WP_REST_Request $request ) {
298315
public function publish_sitemap_pages( \WP_REST_Request $request ) {
299316
$site_description = $request->get_param( 'site_description' );
300317
$site_info = array( 'site_description' => $site_description );
318+
$locale = $request->get_param( 'locale' );
319+
$skip_cache = $request->get_param( 'skip_cache' );
301320

302-
$target_audience = SiteGenService::instantiate_site_meta( $site_info, 'target_audience' );
321+
$target_audience = SiteGenService::instantiate_site_meta( $site_info, 'target_audience', $locale, $skip_cache );
303322
if ( is_wp_error( $target_audience ) ) {
304323
return $target_audience;
305324
}
306325

307-
$content_style = SiteGenService::instantiate_site_meta( $site_info, 'content_tones' );
326+
$content_style = SiteGenService::instantiate_site_meta( $site_info, 'content_tones', $locale, $skip_cache );
308327
if ( is_wp_error( $content_style ) ) {
309328
return $content_style;
310329
}
311330

312-
$sitemap = SiteGenService::instantiate_site_meta( $site_info, 'sitemap' );
331+
$sitemap = SiteGenService::instantiate_site_meta( $site_info, 'sitemap', $locale, $skip_cache );
313332
if ( is_wp_error( $sitemap ) ) {
314333
return $sitemap;
315334
}
316335

317-
SiteGenService::publish_sitemap_pages( $site_description, $content_style, $target_audience, $sitemap );
336+
SiteGenService::publish_sitemap_pages( $site_description, $content_style, $target_audience, $sitemap, $locale );
318337

319338
return new \WP_REST_Response( array(), 201 );
320339
}

includes/Services/LanguageService.php

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<?php
2+
3+
namespace NewfoldLabs\WP\Module\Onboarding\Services;
4+
5+
/**
6+
* Class LanguageService
7+
*
8+
* Handles language-related operations for the onboarding module.
9+
*/
10+
class LanguageService {
11+
12+
/**
13+
* Get all available languages including the default English.
14+
*
15+
* @return array List of language data
16+
*/
17+
public static function get_all_languages() {
18+
// Load translation-install.php if the function doesn't exist
19+
if ( ! function_exists( 'wp_get_available_translations' ) ) {
20+
require_once ABSPATH . 'wp-admin/includes/translation-install.php';
21+
}
22+
23+
// Get all available translations from WordPress API
24+
$translations = \wp_get_available_translations();
25+
26+
// If translations API fails, provide basic fallback
27+
if ( empty( $translations ) ) {
28+
return self::get_fallback_languages();
29+
}
30+
31+
// Format data for response - include English as default
32+
$formatted_languages = array(
33+
array(
34+
'code' => 'en_US',
35+
'name' => 'English (United States)',
36+
'native_name' => 'English (United States)',
37+
),
38+
);
39+
40+
// Add translated languages with proper format
41+
foreach ( $translations as $locale => $translation ) {
42+
$formatted_languages[] = array(
43+
'code' => $locale,
44+
'name' => $translation['english_name'],
45+
'native_name' => $translation['native_name'],
46+
);
47+
}
48+
49+
return $formatted_languages;
50+
}
51+
52+
/**
53+
* Get language data array formatted for the language selection component.
54+
* Returns array of [language_name, language_code] pairs.
55+
*
56+
* @return array Array of language name and code pairs
57+
*/
58+
public static function get_languages_for_selection() {
59+
$languages = self::get_all_languages();
60+
$language_list = array();
61+
62+
foreach ( $languages as $language ) {
63+
$language_list[] = array(
64+
$language['name'],
65+
$language['code'],
66+
);
67+
}
68+
69+
return $language_list;
70+
}
71+
72+
/**
73+
* Get fallback languages in case the translations API fails.
74+
*
75+
* @return array Basic list of language data
76+
*/
77+
private static function get_fallback_languages() {
78+
return array(
79+
array(
80+
'code' => 'en_US',
81+
'name' => 'English (United States)',
82+
'native_name' => 'English (United States)',
83+
),
84+
array(
85+
'code' => 'es_ES',
86+
'name' => 'Spanish (Spain)',
87+
'native_name' => 'Español',
88+
),
89+
array(
90+
'code' => 'fr_FR',
91+
'name' => 'French (France)',
92+
'native_name' => 'Français',
93+
),
94+
array(
95+
'code' => 'de_DE',
96+
'name' => 'German',
97+
'native_name' => 'Deutsch',
98+
),
99+
);
100+
}
101+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { memo } from '@wordpress/element';
2+
3+
const LanguageSelection = ( {
4+
languageSelectionLabel,
5+
languageList,
6+
selectedLocale,
7+
setSelectedLocale,
8+
} ) => {
9+
return <div className={ 'nfd-sg-language' }>
10+
<label htmlFor={ 'nfd-site-output__languages' } className={ 'nfd-sg-language__label' }>{ languageSelectionLabel }</label>
11+
<select
12+
className={ 'nfd-sg-language__select' } id={ 'nfd-site-output__languages' }
13+
onChange={ ( event ) => {
14+
setSelectedLocale( event.target.value );
15+
} }
16+
value={ selectedLocale || '' }>
17+
<option value="">Choose a language</option>
18+
{ languageList.map( ( [ language, value ] ) => {
19+
return <option
20+
key={ value }
21+
value={ value }
22+
>
23+
{ language }
24+
</option>;
25+
} ) }
26+
</select>
27+
</div>;
28+
};
29+
30+
export default memo( LanguageSelection );
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
.nfd-sg-language {
2+
width: 100% !important;
3+
display: flex;
4+
flex-direction: column;
5+
6+
&__label {
7+
font-size: 0.87rem;
8+
margin-top: 2%;
9+
color: var(--nfd-onboarding-primary);
10+
padding-left: 2px;
11+
}
12+
13+
&__select {
14+
margin-top: 1%;
15+
border-radius: 8px !important;
16+
}
17+
}

src/OnboardingSPA/components/NewfoldInterfaceSkeleton/SiteGen/index.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,12 +150,14 @@ const SiteGen = () => {
150150
async function performSiteGenMetaGeneration(
151151
siteInfo,
152152
identifier,
153+
locale,
153154
skipCache,
154155
retryCount = 1
155156
) {
156157
const data = await generateSiteGenMeta(
157158
siteInfo,
158159
identifier,
160+
locale,
159161
skipCache
160162
);
161163

@@ -165,6 +167,7 @@ const SiteGen = () => {
165167
return performSiteGenMetaGeneration(
166168
siteInfo,
167169
identifier,
170+
locale,
168171
skipCache,
169172
retryCount + 1
170173
);
@@ -234,7 +237,8 @@ const SiteGen = () => {
234237
// Get the homepages and set that in flow
235238
setIsGeneratingHomepages( true );
236239
const response = await getHomepages(
237-
currentData.sitegen.siteDetails.prompt
240+
currentData.sitegen.siteDetails.prompt,
241+
currentData.sitegen.siteDetails.locale,
238242
);
239243

240244
if ( response.error ) {
@@ -316,10 +320,12 @@ const SiteGen = () => {
316320
site_description: currentData.sitegen?.siteDetails?.prompt,
317321
};
318322

323+
const locale = currentData.sitegen?.siteDetails?.locale;
324+
319325
const skipCache = currentData.sitegen?.skipCache;
320326
// Iterate over Identifiers and fire Requests!
321327
identifiers.forEach( ( identifier ) => {
322-
performSiteGenMetaGeneration( siteInfo, identifier, skipCache );
328+
performSiteGenMetaGeneration( siteInfo, identifier, locale, skipCache );
323329
} );
324330
}
325331

0 commit comments

Comments
 (0)