Hi everyone!
I don’t knew if there’s just a similar source but i think it’s important to share thath.
I create a custom language switch from posts, page, custom post type, categories, custom taxonomies translations.
I’m using Wpml as wordpress plugin.
It’s not very clean code, but it’s working
First i need to do some modify to the Rest Api
<?php
//functions.php -> wordpress
//register the translate id in Rest Api post, page, custom post type
add_action( 'rest_api_init', function () {
register_rest_field( 'post', 'translate_api', mol_related_translation_api() );
register_rest_field( 'page', 'translate_api', mol_related_translation_api() );
register_rest_field( 'mostre', 'translate_api', mol_related_translation_api() ); // Optional: Custom posttype
register_rest_field( 'eventi', 'translate_api', mol_related_translation_api() ); // Optional: Custom posttype
});
function mol_related_translation_api() {
return array(
'methods' => 'GET',
'get_callback' => 'related_translate_api',
'schema' => null,
);
}
function related_translate_api( $data ) {
$post_id = $data['id'];
$currentLang = apply_filters( 'wpml_post_language_details', '', $post_id )['language_code'];
if($currentLang === 'it') {
$otherLang = 'en';
} else {
$otherLang = 'it';
}
$postData = apply_filters( 'wpml_object_id', $post_id, get_post_type(), false, $otherLang );
$langArray = array(
'key' => apply_filters( 'wpml_post_language_details', '', $postData )['language_code'],
'id' => $postData,
'slug' => get_post($postData)->post_name,
'path' => wp_make_link_relative(get_the_permalink($postData))
);
return $langArray;
}
///register the is_home attribute in a page post type
add_action( 'rest_api_init', function () {
register_rest_field( 'page', 'is_home', mol_is_site_home_page() );
});
function mol_is_site_home_page() {
return array(
'methods' => 'GET',
'get_callback' => 'register_is_site_home_api_rest',
'schema' => null,
);
}
function register_is_site_home_api_rest( $data ) {
$post_id = $data['id'];
if ( intval(get_option( 'page_on_front' )) === $post_id ) {
$PPPosts = true;
} else {
$PPPosts = false;
}
return $PPPosts;
}
/// register translate params for all used taxonomies and categories
add_action( 'rest_api_init', function () {
register_rest_field( 'category', 'taxonomy_translate', mol_test_category() );
register_rest_field( 'tipodievento', 'taxonomy_translate', mol_test_category() );
});
function mol_test_category() {
return array(
'methods' => 'GET',
'get_callback' => 'register_test_category',
'schema' => null,
);
}
function register_test_category( $data ) {
$term_id = $data['id'];
$term = get_term( $term_id );
$taxonomy = $term->taxonomy;
$currentLang = apply_filters( 'wpml_current_language', null );
if($currentLang === 'it') {
$otherLang = 'en';
} else {
$otherLang = 'it';
}
global $translateId;
$translateId = apply_filters( 'wpml_object_id', $term_id, $taxonomy, true , $otherLang );
$translated_url = apply_filters( 'wpml_permalink', get_term_link($term_id) , $otherLang, true);
$slugParts = explode("/", $translated_url);
if($translateId !== $term_id) {
$langArray = array(
'key' => $otherLang,
'id' => $translateId,
'slug' => $slugParts[count($slugParts) - 2],
'path' => wp_make_link_relative($translated_url)
);
} else {
$langArray = array(
'key' => null,
'id' => null,
'slug' => null,
'path' => null
);
}
return $langArray;
}
?>
In my index.js i need to set a couple of parameters to determinate language and current navigation.
const myTheme = {
name: "my-theme",
roots: {
theme: Root,
},
state: {
theme: {
...
lang: "it",
rapidNavIta:'navigazione-rapida',
rapidNavEng:'rapid-navigation',
relativePathEng:'',
relativePathIta:'',
isInEng:false,
isInIta:false,
...
},
},
actions: {
theme: {
toggleLang:({state}) => {
state.theme.lang = state.lang
},
toggleUrl:({state}) => {
state.theme.isUrlVisible = !state.theme.isUrlVisible
},
beforeSSR: async ({ state, actions }) => {
await actions.source.fetch("/pages");
await actions.source.fetch("/posts")
await actions.source.fetch("/eventi");
},
},
},
libraries: {
html2react: {
processors: [...]
},
source: {
handlers: [...],
},
}
}
export default myTheme
The language switcher
const LanguageSwitch = ({ actions, state }) => {
const { lang } = state.theme;
return (
<>
<Box>
{state.theme.isInEng &&
<a
href={state.theme.relativePathEng !== '' ? `${state.theme.relativePathEng}` : '/en/'}
className="toggleicon"
onClick={actions.theme.toggleLang}
>EN</a>
}
{state.theme.isInIta &&
<a
// href="/"
href={state.theme.relativePathIta !== '' ? `${state.theme.relativePathIta}` : '/'}
className="toggleicon">
IT
</a>
}
</Box>
</>
)
}
I made a function to set the language switcher to related translated post. After i call thath function in useEffect in every template (Page, Post, Archive, Tax)
export const setLanguageInfos = (endpoint, state) => {
console.log('SOURCE')
if(endpoint['translate_api']['id'] !== null) {
if(endpoint['translate_api']['key'] == 'en') {
state.isInIta=false
state.isInEng=true
if(endpoint['is_home']) {
state.relativePathEng='/en';
} else {
state.relativePathEng=endpoint['translate_api']['path']
}
} else {
state.isInIta=true;
state.isInEng=false
state.relativePathIta=endpoint['translate_api']['path']
if(endpoint['is_home']) {
state.relativePathIta='/'
} else {
state.relativePathIta=endpoint['translate_api']['path']
}
}
} else {
state.isInIta=false
state.isInEng=false
}
}
The post.js call a useEffect and pass parameters to function setLanguageInfos to get the translate version of post and set the language switcher.
import React, {useEffect} from "react"
import { connect } from "frontity"
import dayjs from "dayjs"
const Post = ({ state, libraries }) => {
const data = state.source.get(state.router.link)
const post = state.source[data.type][data.id]
const formattedDate = dayjs(post.date).format("DD MMMM YYYY")
const Html2React = libraries.html2react.Component
useEffect(() => {
setLanguageInfos(post, state.theme)
},[])
return (
<div>
<p>
<strong>Posted: </strong>
{formattedDate}
</p>
<h2>{post.title.rendered}</h2>
<Html2React html={post.content.rendered} />
</div>
)
}
export default connect(Post)
This is a page.js how i set the lang switch like as post.js
import React, {useEffect} from "react"
import { connect } from "frontity"
//functions
import { setLanguageInfos } from "./functions/setLanguageInfos"
const Page = ({ state, libraries }) => {
const data = state.source.get(state.router.link)
const page = state.source[data.type][data.id]
const Html2React = libraries.html2react.Component
const dataPosts = state.source.get('/')
useEffect(() => {
setLanguageInfos(page, state.theme)
},[])
return (
<div>
PAGE
<h2>{page.title.rendered}</h2>
<Html2React html={page.content.rendered} />
</div>
)
}
export default connect(Page)
This is the Archive.js / Taxonomy.js
import React, {useEffect} from "react"
import { connect } from "frontity"
import Link from "@frontity/components/link"
import List from "./List"
const IsArchive = ({ state, actions }) => {
const data = state.source.get(state.router.link)
const postTypes = state.source.postTypes
const taxonomy = state.source[data.taxonomy][data.id]
const setRelativePath = () => {
if(data.isTerm) {
if(taxonomy['key'] !== null) {
state.theme.relativePathEng=`${taxonomy['taxonomy_translate']['path']}`
state.theme.relativePathIta=`${taxonomy['taxonomy_translate']['path']}`
if(state.lang === 'en') {
state.theme.isInIta=true
state.theme.isInEng=false
} else {
state.theme.isInIta=false
state.theme.isInEng=true
}
} else {
state.theme.isInIta=false
state.theme.isInEng=false
}
} else {
if(data.route === '/news/' || data.route === '/en/news/') {
state.theme.relativePathEng='/en/news'
state.theme.relativePathIta='/news'
if(state.lang === 'en') {
state.theme.isInIta=true
state.theme.isInEng=false
} else {
state.theme.isInIta=false
state.theme.isInEng=true
}
} else {
postTypes && postTypes.map(postType => {
if(data.route === `/${postType.endpoint}/` || data.route === `/en/${postType.endpoint}/`) {
state.theme.relativePathEng=`/en/${postType.endpoint}`
state.theme.relativePathIta=`/${postType.endpoint}`
if(state.lang === 'en') {
state.theme.isInIta=true
state.theme.isInEng=false
} else {
state.theme.isInIta=false
state.theme.isInEng=true
}
}
})
}
}
}
useEffect(() => {
setRelativePath()
},[])
useEffect(() => {
setRelativePath()
},[state.lang])
return (
<div>
PFP
<List/>
</div>
)
}
export default connect(IsArchive)
Enjoy