고스트 CMS 다국어 블로그: 4. tag 다국어 처리
news태그 페이지로 접속해보자.
https://{host}/tag/news/
해당 태그 페이지를 조회해보면 한국어 포스트(#ko: ko news1, ko news2), 영어 포스트(#en: en news1, en news2), 언어태그가 지정되지 않은 포스트(Comming Soon)가 전부 보여지고 있다.
routes.yaml을 다시 봐보자
영어와 한국어 포스트 경로를 아예 다르게 설정했다. (/, /ko/)
그러나 tag는 그렇게 할 수 없다. tag는 여러개의 경로를 설정할 수 없으며 현재 /tag/{slug}/ 로 설정되어 있다. 즉, 하나의 화면에서 다국어 처리를 해야한다.
다음과 같이 tag페이지를 구현해서 다국어 처리를 해보자.
- Language selector에 선택된 언어태그를 가지는 포스트만 노출시키기
- Language selector에서 언어를 변경하면 보여지는 포스트 변경하기
Language selector 작동 방식 변경
현재는 Language selector값을 변경시 / 또는 /ko/로 리다이렉트 된다.
tag페이지에서는 Language selector값을 변경시, 리다이렉트 되지 않고 해당 언어태그를 가지는 포스트만 노출되도록 하고 바꾸어 보겠다.
Language selector가 tag페이지와 tag가 아닌 다른페이지의 경우에 따라 다르게 작동하도록 default.hbs를 수정하자.
{{ghost_foot}}
<script>
function initializeLanguageSelector() {
var selector = document.getElementById('languageSelector');
var currentUrl = window.location.href;
if (!currentUrl.includes('/tag/')) {
var urlLanguage = currentUrl.includes('/ko/') ? 'ko' : 'en';
localStorage.setItem('selectedLanguage', urlLanguage);
selector.value = urlLanguage;
} else {
selector.value = localStorage.getItem('selectedLanguage') || 'en';
}
selector.style.display = 'block';
selector.addEventListener('change', function() {
localStorage.setItem('selectedLanguage', this.value);
if (!currentUrl.includes('/tag/')) {
window.location.href = this.value === 'ko' ? '/ko/' : '/';
}
else {
window.location = window.location.href;
}
});
}
initializeLanguageSelector();
</script>
- 8행과 20행에서 tag페이지인지 아닌지 조건을 확인한다.
- if (!currentUrl.includes('/tag/'))
- 13행
- 만약 tag페이지라면 url을 확인하지 않고 현재 localStorage에 저장된 selectedLanguage값을 그대로 가져와 Language selector의 값으로 설정해준다. 만약 해당 값이 없다면(바로 url로 접속한 경우) 기본값인 en으로 설정해준다.
- selector.value = localStorage.getItem('selectedLanguage') || 'en';
- 24행
- 만약 tag페이지라면, /ko/나 /로 리다이렉트하지 않고 그냥 새로고침을 한다.
- window.location = window.location.href;
새로고침을 하는 이유는 해당 언어에 맞는 포스트를 보여주기 위해서이다. 여기까지 적용을 하면 tag페이지에서 Language selector값을 변경한다고 해서 /ko나 /로 리다이렉트 되진 않는다. 그러나 해당 언어에 맞는 포스트가 보이진 않는다. 이를 위해서 tag.hbs를 수정해야 한다.
tag.hbs 수정
수정된 tag.hbs 코드는 아래 링크에서 확인할 수 있다.
아이디어는 다음과 같다.
- 템플릿은 서버사이드에서 처리된다. 프론트엔드에서 가지고 있는 localStorage값을 활용해 특정 언어의 포스트만 가져올 수 없다.
- 일단 다 가져온 다음에 거르는 방식을 활용해야 한다.
- tag페이지에서 post는 <div class="post-card"> 형태이다. 이 div에 언어정보도 함께 넣어준 뒤 프론트엔드에서 필터링을 하자.
그러나 문제는 해당 포스트가 어떤 언어태그를 가지고 있는지 템플릿단에서 알 수 있는 방법이 없다. 이를 해결하기위해 첫번째 포스트에서 정한 이 튜토리얼의 규칙이 있다.
{{#foreach posts}}
<div class="post-card" data-language="{{tags.[1].name}}">
{{!-- The tag below includes the markup for each post - partials/post-card.hbs --}}
{{> "post-card"}}
</div>
{{/foreach}}
두번째 태그(tags.[1].name)를 가져오면 해당 포스트의 언어를 템플릿단에서 넘겨줄 수 있게 된다.
이제 프론트엔드 부분을 보자. 먼저 모든 post-card를 안보이게 처리해야 한다. opacity를 0으로 만들자. language selector에서 언어 변경시 포스트가 부드럽게 나나는 효과를 주기 위해 5번행을 추가했다.
<style>
.post-card-excerpt,
div.post-card {
opacity: 0; /* Initially set all post cards to be transparent */
transition: opacity 0.5s ease; /* Transition for smooth display */
}
</style>
조건에 맞는 포스트는 opacity를 1로 만들어서 보이게 하자
<script>
document.addEventListener('DOMContentLoaded', function() {
const selectedLanguage = localStorage.getItem('selectedLanguage') || 'en'; // Read language setting from local storage or use default 'en'
const postCards = document.querySelectorAll('div.post-card[data-language]');
let visibleCount = 0;
postCards.forEach(card => {
// Remove '#' character and update language setting
const language = card.getAttribute('data-language');
const cleanedLanguage = language.replace('#', '');
card.setAttribute('data-language', cleanedLanguage);
// Check if it matches the selected language, then show or hide
if (cleanedLanguage !== selectedLanguage) {
card.style.display = 'none';
} else {
visibleCount++; // Count the number of posts that match the selected language
setTimeout(() => { // Use setTimeout for a smooth display
card.style.opacity = 1; // Set opacity to 1 to make the element visible
}, 10);
}
});
// Dynamically update text
const collectionText = document.querySelector('.post-card-excerpt');
if (collectionText) {
const text = visibleCount === 0 ? 'zero posts' :
visibleCount === 1 ? '1 post' :
`${visibleCount} posts`; // Set text based on the count
collectionText.innerHTML = `A collection of ${text}`; // Set text in HTML
setTimeout(() => { // Use setTimeout for a smooth display
collectionText.style.opacity = 1; // Set opacity to 1 to make the element visible
}, 10);
}
});
</script>
- localStorage에 저장된 selectedLanguage값을 가져오며 해당 값이 없는 경우 기본깂인 'en'을 쓴다.
- 언어태그는 #en 또는 #ko이다. selectedLangugae값은 en또는 ko이다. 직접적인 비교를 위해 data-language attribute에서 #을 전부 제외해주자.
- 조건에 맞지 않으면 display = 'none', 조건에 맞으면 opacity = 1로 변경해서 포스트를 노출시킨다
- 이 과정을 처리하며 visibleCount값을 카운트해서 몇 개의 포스트가 있는지 화면에 나타내준다.
결과
원하는대로 잘 구현되었다. 더 간결한 방법으로 CSS처리를 할 수 있을거 같은데 내 지식으로는 여기까지가 최선인듯 하다.
앞으로
- About, Author페이지 다국어처리
- 좌측상단 로고 클릭시 무조건 /로 리다이렉트 됨
아직 처리할 부분이 많이 있다. 그러나 사용성에 크게 영향을 미치지 않는 부분이라 차근차근 수정해보려고 한다.