Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨Sodo search translation helper added, strings wrapped, ready for translator work! #21055

Merged
merged 8 commits into from
Sep 24, 2024
10 changes: 8 additions & 2 deletions apps/sodo-search/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import './App.css';
import AppContext from './AppContext';
import PopupModal from './components/PopupModal';
import SearchIndex from './search-index.js';
import i18nLib from '@tryghost/i18n';

export default class App extends React.Component {
constructor(props) {
Expand All @@ -13,11 +14,15 @@ export default class App extends React.Component {
apiKey: props.apiKey
});

const i18nLanguage = this.props.locale || 'en';
const i18n = i18nLib(i18nLanguage, 'search');

this.state = {
searchIndex,
showPopup: false,
indexStarted: false,
indexComplete: false
indexComplete: false,
t: i18n.t
};

this.inputRef = React.createRef();
Expand Down Expand Up @@ -163,7 +168,8 @@ export default class App extends React.Component {
...data
});
}
}
},
t: this.state.t
}}>
<PopupModal />
</AppContext.Provider>
Expand Down
3 changes: 2 additions & 1 deletion apps/sodo-search/src/AppContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ const AppContext = React.createContext({
dispatch: (_action, _data) => {},
searchIndex: null,
indexComplete: false,
searchValue: ''
searchValue: '',
t: () => {}
});

export default AppContext;
26 changes: 17 additions & 9 deletions apps/sodo-search/src/components/PopupModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class PopupContent extends React.Component {
}

function SearchBox() {
const {searchValue, dispatch, inputRef} = useContext(AppContext);
const {searchValue, dispatch, inputRef, t} = useContext(AppContext);
const containerRef = useRef(null);
useEffect(() => {
setTimeout(() => {
Expand Down Expand Up @@ -117,7 +117,7 @@ function SearchBox() {
}
}}
className='grow -my-5 py-5 -ml-3 pl-3 text-[1.65rem] focus-visible:outline-none placeholder:text-gray-400 outline-none truncate'
placeholder='Search posts, tags and authors'
placeholder={t('Search posts, tags and authors')}
/>
<Loading />
<CancelButton />
Expand Down Expand Up @@ -154,7 +154,7 @@ function Loading() {
}

function CancelButton() {
const {dispatch} = useContext(AppContext);
const {dispatch, t} = useContext(AppContext);

return (
<button
Expand All @@ -165,7 +165,7 @@ function CancelButton() {
});
}}
>
Cancel
{t('Cancel')}
</button>
);
}
Expand Down Expand Up @@ -195,6 +195,8 @@ function TagListItem({tag, selectedResult, setSelectedResult}) {
}

function TagResults({tags, selectedResult, setSelectedResult}) {
const {t} = useContext(AppContext);

if (!tags?.length) {
return null;
}
Expand All @@ -210,7 +212,7 @@ function TagResults({tags, selectedResult, setSelectedResult}) {
});
return (
<div className='border-t border-gray-200 py-3 px-4 sm:px-7'>
<h1 className='uppercase text-xs text-neutral-400 font-semibold mb-1 tracking-wide'>Tags</h1>
<h1 className='uppercase text-xs text-neutral-400 font-semibold mb-1 tracking-wide'>{t('Tags')}</h1>
{TagItems}
</div>
);
Expand Down Expand Up @@ -355,6 +357,8 @@ function HighlightWord({word, isExcerpt}) {
}

function ShowMoreButton({posts, maxPosts, setMaxPosts}) {
const {t} = useContext(AppContext);

if (!posts?.length || maxPosts >= posts?.length) {
return null;
}
Expand All @@ -366,12 +370,13 @@ function ShowMoreButton({posts, maxPosts, setMaxPosts}) {
setMaxPosts(updatedMaxPosts);
}}
>
Show more results
{t('Show more results')}
</button>
);
}

function PostResults({posts, selectedResult, setSelectedResult}) {
const {t} = useContext(AppContext);
const [maxPosts, setMaxPosts] = useState(DEFAULT_MAX_POSTS);
useEffect(() => {
setMaxPosts(DEFAULT_MAX_POSTS);
Expand All @@ -392,7 +397,7 @@ function PostResults({posts, selectedResult, setSelectedResult}) {
});
return (
<div className='border-t border-neutral-200 py-3 px-4 sm:px-7'>
<h1 className='uppercase text-xs text-neutral-400 font-semibold mb-1 tracking-wide'>Posts</h1>
<h1 className='uppercase text-xs text-neutral-400 font-semibold mb-1 tracking-wide'>{t('Posts')}</h1>
{PostItems}
<ShowMoreButton setMaxPosts={setMaxPosts} maxPosts={maxPosts} posts={posts} />
</div>
Expand Down Expand Up @@ -437,6 +442,8 @@ function AuthorAvatar({name, avatar}) {
}

function AuthorResults({authors, selectedResult, setSelectedResult}) {
const {t} = useContext(AppContext);

if (!authors?.length) {
return null;
}
Expand All @@ -453,7 +460,7 @@ function AuthorResults({authors, selectedResult, setSelectedResult}) {

return (
<div className='border-t border-neutral-200 py-3 px-4 sm:px-7'>
<h1 className='uppercase text-xs text-neutral-400 font-semibold mb-1 tracking-wide'>Authors</h1>
<h1 className='uppercase text-xs text-neutral-400 font-semibold mb-1 tracking-wide'>{t('Authors')}</h1>
{AuthorItems}
</div>
);
Expand Down Expand Up @@ -572,9 +579,10 @@ function Results({posts, authors, tags}) {
}

function NoResultsBox() {
const {t} = useContext(AppContext);
return (
<div className='py-4 px-7'>
<p className='text-[1.65rem] text-neutral-400 leading-normal'>No matches found</p>
<p className='text-[1.65rem] text-neutral-400 leading-normal'>{t('No matches found')}</p>
</div>
);
}
Expand Down
7 changes: 4 additions & 3 deletions apps/sodo-search/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ function getSiteData() {
const adminUrl = scriptTag.dataset.sodoSearch;
const apiKey = scriptTag.dataset.key;
const stylesUrl = scriptTag.dataset.styles;
return {adminUrl, apiKey, stylesUrl};
const locale = scriptTag.dataset.locale || 'en';
return {adminUrl, apiKey, stylesUrl, locale};
}
return {};
}
Expand All @@ -30,14 +31,14 @@ function setup() {
}

function init() {
const {adminUrl, apiKey, stylesUrl} = getSiteData();
const {adminUrl, apiKey, stylesUrl, locale} = getSiteData();
const adminBaseUrl = (adminUrl || window.location.origin)?.replace(/\/+$/, '');
setup();
ReactDOM.render(
<React.StrictMode>
<App
adminUrl={adminBaseUrl} apiKey={apiKey}
stylesUrl={stylesUrl}
stylesUrl={stylesUrl} locale={locale}
/>
</React.StrictMode>,
document.getElementById(ROOT_DIV_ID)
Expand Down
3 changes: 2 additions & 1 deletion ghost/core/core/frontend/helpers/ghost_head.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ function getSearchHelper(frontendKey) {
const attrs = {
key: frontendKey,
styles: stylesUrl,
'sodo-search': adminUrl
'sodo-search': adminUrl,
locale: settingsCache.get('locale') || 'en'
};
const dataAttrs = getDataAttributes(attrs);
let helper = `<script defer src="${scriptUrl}" ${dataAttrs} crossorigin="anonymous"></script>`;
Expand Down
Loading
Loading