Skip to content

Commit 794ca7b

Browse files
Dale KunceDale Kunce
authored andcommitted
Implement multilingual blog post deduplication and language links
- Add post grouping logic to avoid duplicate posts on same day - Include language links for posts available in multiple languages - Add translation strings for 'also available in' text across all languages - Style language links with professional appearance - Maintain backward compatibility with single-language posts
1 parent eab96ff commit 794ca7b

6 files changed

Lines changed: 231 additions & 14 deletions

File tree

app/_data/cs.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -468,14 +468,14 @@ checker:
468468
title: "MapRoulette"
469469
text: "<a href=\"https://maproulette.org/\">MapRoulette</a> is a gamified approach to fixing OSM bugs that breaks common OpenStreetMap data problems into micro tasks. This tool is best used after your event."
470470

471-
###################
472471
## Blog CONTENT ##
473472
###################
474473
blog:
475474
title: "Blog"
476475
tags: "Štítky Blogu"
477476
categories: "Kategorie"
478-
nocontent: "Dosud nebyl publikován žádný blog v angličtině."
477+
nocontent: "Dosud nebyl publikován žádný blog v angličtině."
478+
also_available: "Také dostupné v"
479479

480480
#####################
481481
## OSM STATS ##

app/_data/en.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,7 @@ blog:
470470
tags: "Blog Tags"
471471
categories: "Blog Categories"
472472
nocontent: "No blogs currently published in english."
473+
also_available: "Also available in"
473474

474475
#####################
475476
## OSM STATS ##

app/_data/es.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,7 @@ blog:
466466
tags: "Blog Tags"
467467
categories: "Blog Categorías"
468468
nocontent: "No hay blogs en ​​español publicado actualmente."
469+
also_available: "También disponible en"
469470

470471
#####################
471472
## OSM STATS ##

app/_data/fr.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,7 @@ blog:
466466
tags: "Blog Tags"
467467
categories: "Blog Catégories"
468468
nocontent: "Il n'y a pas des blogs de langue espagnole actuellement publiés."
469+
also_available: "Aussi disponible en"
469470

470471
#####################
471472
## COUNTRY STATS ##

app/_includes/blog.html

Lines changed: 67 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,78 @@
55
<div id="site-canvas">
66
<div class="header-image header-blog">
77
<div class="dark-overlay center-text">
8-
<h1 class="title feature-header">{{site.data[locale].blog.title}}</h1>
8+
<h1 class="title feature-header">{{site.data[site.active_lang].blog.title}}</h1>
99
</div>
1010
</div>
1111
<div class="row">
1212
<div class="large-12 columns">
13-
{% for post in site.posts %}
14-
{% if post.lang == locale %}
15-
<div class="textbox blog-preview">
16-
<h2 class="title"><a href="{{ post.url }}">{{ post.title }}</a></h2>
17-
<a href="{{ post.url }}">
18-
<img class="medium-4 pull-right blog-img stack-for-small" src="{{ post.banner }}" alt="{{ post.title }}" />
13+
{% comment %}
14+
Group posts by date to handle multilingual posts.
15+
For posts with the same date, show only one version with links to other languages.
16+
{% endcomment %}
17+
{% assign posts_by_date = site.posts | group_by: 'date' %}
18+
{% for date_group in posts_by_date %}
19+
{% assign posts_for_date = date_group.items %}
20+
{% assign current_lang_post = nil %}
21+
{% assign english_post = nil %}
22+
{% assign other_posts = "" | split: "," %}
23+
24+
{% comment %}Find the best post to display for this date{% endcomment %}
25+
{% for post in posts_for_date %}
26+
{% if post.lang == site.active_lang %}
27+
{% assign current_lang_post = post %}
28+
{% elsif post.lang == 'en' %}
29+
{% assign english_post = post %}
30+
{% endif %}
31+
{% assign other_posts = other_posts | push: post %}
32+
{% endfor %}
33+
34+
{% comment %}Choose which post to display (prefer current language, fallback to English){% endcomment %}
35+
{% if current_lang_post %}
36+
{% assign display_post = current_lang_post %}
37+
{% elsif english_post %}
38+
{% assign display_post = english_post %}
39+
{% else %}
40+
{% assign display_post = posts_for_date.first %}
41+
{% endif %}
42+
43+
<article class="blog-card">
44+
<div class="blog-card__image">
45+
<a href="{{ display_post.url }}" aria-label="Read {{ display_post.title }}">
46+
<img src="{{ display_post.banner }}" alt="{{ display_post.title }}" />
1947
</a>
20-
{% assign month_number = post.date | date: "%-m" | plus: 0 %}
21-
<p><span class="blog-date">{{ post.date | date: "%-d" }} {{ site.data[site.active_lang].months[month_number] }} {{ post.date | date: "%Y" }} </span> &nbsp;|&nbsp; by {{ post.author }}</p>
22-
<p class="medium-7">{{ post.excerpt }}</p>
23-
</div>
24-
{% endif %}
48+
</div>
49+
<div class="blog-card__content">
50+
<h2 class="blog-card__title">
51+
<a href="{{ display_post.url }}">{{ display_post.title }}</a>
52+
</h2>
53+
<div class="blog-card__meta">
54+
{% assign month_number = display_post.date | date: "%-m" | plus: 0 %}
55+
<span class="blog-date">{{ display_post.date | date: "%-d" }} {{ site.data[site.active_lang].months[month_number] }} {{ display_post.date | date: "%Y" }}</span>
56+
<span class="blog-author">by {{ display_post.author }}</span>
57+
</div>
58+
59+
{% comment %}Show language links if there are multiple versions{% endcomment %}
60+
{% if posts_for_date.size > 1 %}
61+
<div class="blog-card__languages">
62+
<span class="language-label">{{site.data[site.active_lang].blog.also_available}}: </span>
63+
{% for post in posts_for_date %}
64+
{% unless post.url == display_post.url %}
65+
<a href="{{ post.url }}" class="language-link" title="{{ post.title }}">
66+
{% if post.lang == 'en' %}English{% endif %}
67+
{% if post.lang == 'fr' %}Français{% endif %}
68+
{% if post.lang == 'es' %}Español{% endif %}
69+
{% if post.lang == 'cs' %}Čeština{% endif %}
70+
</a>
71+
{% unless forloop.last %} | {% endunless %}
72+
{% endunless %}
73+
{% endfor %}
74+
</div>
75+
{% endif %}
76+
77+
<div class="blog-card__excerpt">{{ display_post.excerpt }}</div>
78+
</div>
79+
</article>
2580
{% endfor %}
2681
</div>
2782
</div>

app/assets/styles/_blog.scss

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,164 @@
22
/* Blog Page */
33
/*----------------------------------------------*/
44

5+
/* Modern Blog Card Layout */
6+
.blog-card {
7+
display: flex;
8+
gap: 20px;
9+
margin-bottom: 30px;
10+
padding: 20px 0;
11+
border-bottom: 1px solid #eee;
12+
13+
&:last-child {
14+
border-bottom: none;
15+
}
16+
17+
&__image {
18+
flex-shrink: 0;
19+
width: 280px;
20+
height: 180px;
21+
overflow: hidden;
22+
border-radius: 4px;
23+
24+
img {
25+
width: 100%;
26+
height: 100%;
27+
object-fit: cover;
28+
border: 1px solid $lightgrey;
29+
transition: transform 0.2s ease;
30+
}
31+
32+
a:hover img {
33+
transform: scale(1.05);
34+
}
35+
}
36+
37+
&__content {
38+
flex: 1;
39+
min-width: 0; // Allow text to wrap properly
40+
display: flex;
41+
flex-direction: column;
42+
}
43+
44+
&__title {
45+
margin: 0 0 12px 0;
46+
font-size: 1.4em;
47+
font-weight: 600;
48+
line-height: 1.3;
49+
50+
a {
51+
color: inherit;
52+
text-decoration: none;
53+
54+
&:hover {
55+
color: $mmblue;
56+
}
57+
}
58+
}
59+
60+
&__meta {
61+
display: flex;
62+
align-items: center;
63+
gap: 15px;
64+
margin-bottom: 12px;
65+
font-size: 0.9em;
66+
color: #666;
67+
68+
.blog-date {
69+
font-style: italic;
70+
font-weight: 300;
71+
}
72+
73+
.blog-author {
74+
&:before {
75+
content: '|';
76+
margin-right: 15px;
77+
color: #ccc;
78+
}
79+
}
80+
}
81+
82+
&__languages {
83+
margin: 8px 0 12px 0;
84+
font-size: 0.9em;
85+
86+
.language-label {
87+
color: #666;
88+
font-weight: 500;
89+
}
90+
91+
.language-link {
92+
color: $primary-color;
93+
text-decoration: none;
94+
margin: 0 4px;
95+
font-weight: 500;
96+
97+
&:hover {
98+
text-decoration: underline;
99+
}
100+
}
101+
}
102+
103+
&__excerpt {
104+
line-height: 1.6;
105+
color: #444;
106+
flex: 1;
107+
}
108+
109+
&__languages {
110+
margin: 8px 0 12px 0;
111+
font-size: 0.9em;
112+
113+
.language-label {
114+
color: #666;
115+
font-weight: 500;
116+
}
117+
118+
.language-link {
119+
color: #007cba;
120+
text-decoration: none;
121+
font-weight: 500;
122+
margin: 0 4px;
123+
124+
&:hover {
125+
text-decoration: underline;
126+
}
127+
128+
&:first-of-type {
129+
margin-left: 8px;
130+
}
131+
}
132+
}
133+
}
134+
135+
// Mobile responsive
136+
@media (max-width: 768px) {
137+
.blog-card {
138+
flex-direction: column;
139+
gap: 15px;
140+
141+
&__image {
142+
width: 100%;
143+
height: 200px;
144+
}
145+
146+
&__title {
147+
font-size: 1.2em;
148+
}
149+
150+
&__meta {
151+
flex-direction: column;
152+
align-items: flex-start;
153+
gap: 5px;
154+
155+
.blog-author:before {
156+
display: none;
157+
}
158+
}
159+
}
160+
}
161+
162+
/* Legacy blog preview support */
5163
.blog-preview{
6164
margin-bottom: 30px;
7165
overflow: auto;
@@ -83,6 +241,7 @@
83241
position: relative;
84242
margin: 0 10px 10px 0;
85243
text-decoration: none;
244+
transition: color 0.2s;
86245
-webkit-transition: color 0.2s;
87246
}
88247

0 commit comments

Comments
 (0)