Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion data/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -204,5 +204,8 @@
"Der blev fundet 1 produkt.": "1 product found.",
"Der blev fundet {count} produkter.": "{count} products found.",
"Beskrivelsen er på dansk. Engelsk oversættelse er på vej.": "This description is in Danish. An English translation is pending.",
"Se produktets hjemmeside": "Visit the product website"
"Se produktets hjemmeside": "Visit the product website",
"Et enkelt badge til jeres egen teknologi.": "A simple badge for your own technology.",
"Til jeres egen teknologi": "For your own technology",
"Et enkelt badge til jeres egen teknologi. Badget linker til listen.": "A simple badge for your own technology. The badge links to the directory."
}
2 changes: 1 addition & 1 deletion docs/maintainers.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ På `/` vælges sprog i rækkefølgen: gyldig `dts_language`-cookie → browsere

Søgning bevares ved sprogskift som `q` i URL'en. Systemets lyse/mørke tema følges automatisk; temaknappen gemmer et manuelt valg i `localStorage` under `dts-theme`. Uden adgang til storage fungerer systemtemaet og knappen stadig. Produktkort bruger et eksisterende billede fra `images/`, derefter favicon og til sidst produktets initial, hvis billederne fejler.

Badgesiden har et selvstændigt valg af badgesprog (`?sprog=da` eller `?sprog=en`), så man også kan hente engelske badges fra den danske side. De danske SVG- og embedadresser er bevaret. Engelske SVG'er serveres under `/en/badge/…` og linker til den engelske side. De generelle produktbadges har teksten “Dansk teknologi” og “Nordic tech”. De konkrete alternativbadges har “Dansk alternativ til …” og “European alternative to …”; støttebadgene har “Vi støtter dansk tech” og “We support Nordic tech”. Begge sprog tilbyder kompakt/stort og lyst/mørkt udseende samt HTML og Markdown.
Badgesiden har et selvstændigt valg af badgesprog (`?sprog=da` eller `?sprog=en`), så man også kan hente engelske badges fra den danske side. De danske SVG- og embedadresser er bevaret. Engelske SVG'er serveres under `/en/badge/…` og linker til den engelske side. De korte badges har teksten “Dansk tech” og “Nordic tech” og kan kopieres direkte fra badgesiden uden produktvalg. De konkrete alternativbadges har “Dansk alternativ til …” og “European alternative to …”; støttebadgene har “Vi støtter dansk tech” og “We support Nordic tech”. Begge sprog tilbyder kompakt/stort og lyst/mørkt udseende samt HTML og Markdown.

Oversættelser vedligeholdes internt i `data/translations/`: `en.json` indeholder sidernes tekster med den danske tekst som nøgle, `products.en.json` produktbeskrivelser med URL som nøgle, og `product-guides.en.json` FAQ-forklaringer og afklaringspunkter. Produktoversættelser bruger samme `sourceHash` som produktguides. Guideoversættelser har også `guideHash` (SHA-256 af dansk forklaring + linjeskift + afklaringspunkt), så en ændret dansk guide ikke efterlader en forældet engelsk forklaring. Manglende eller forældede guideoversættelser bruger den aktuelle produktbeskrivelse; manglende eller forældede produktoversættelser bruger den danske kildebeskrivelse. Der kaldes ingen oversættelsestjeneste ved sidevisning. Bidragydere foreslår fortsat produkter i `products.json`; oversættelser gennemgås af vedligeholderne.

Expand Down
8 changes: 4 additions & 4 deletions lib/badges.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
if (!defined('APP_ROOT')) { http_response_code(404); exit; }

// Badges til produkternes egne websites: "Dansk alternativ til Stripe" eller det generelle
// "Dansk teknologi" / "Nordic tech" - og "Vi støtter dansk tech" til alle andre. Teksten tegnes som vektorer ud fra skriften Inter (data/badge-font.json, lavet af
// "Dansk tech" / "Nordic tech" - og "Vi støtter dansk tech" til alle andre. Teksten tegnes som vektorer ud fra skriften Inter (data/badge-font.json, lavet af
// tools/badge/build-font.py), så badget ser ens ud overalt, og bredden altid passer til teksten.

const BADGE_GENERIC = 'listet-paa-dansktechstack';
Expand Down Expand Up @@ -44,14 +44,14 @@ function product_badges(array $product, $language = null) {
return $badges;
}

// "Dansk teknologi" / "Nordic tech" - til alle produkter på listen.
// "Dansk tech" / "Nordic tech" - kan også hentes uden produktvalg.
// Sluggen er bevaret, så eksisterende embedadresser fortsat virker.
function generic_badge($language = null) {
$language ??= locale();
return [
'slug' => BADGE_GENERIC,
'label' => '',
'name' => $language === 'en' ? 'Nordic tech' : 'Dansk teknologi',
'name' => $language === 'en' ? 'Nordic tech' : 'Dansk tech',
'link' => locale_url('/', $language),
'language' => $language,
];
Expand All @@ -74,7 +74,7 @@ function supporter_badges($language = null) {
];
}

// Alle badges der ikke kræver et produkt (inkl. det generelle "Dansk software")
// Alle badges der ikke kræver et produkt (inkl. "Dansk tech" / "Nordic tech")
function standalone_badges() {
return [BADGE_GENERIC => generic_badge()] + supporter_badges();
}
Expand Down
17 changes: 15 additions & 2 deletions pages/badge.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
$badgeLanguage = badge_language();
$badges = $product ? product_badges($product, $badgeLanguage) : [];
$badge = $badges[query_value('badge')] ?? ($badges ? reset($badges) : null);
$generic = generic_badge($badgeLanguage);
$supporter = supporter_badges($badgeLanguage)['vi-stoetter-dansk-tech'];

$url = locale_url('/badge');
Expand Down Expand Up @@ -44,7 +45,12 @@
<p class="mt-3 max-w-2xl text-sm/6 text-gray-700 dark:text-gray-300"><?php echo e(t('Den engelske udgave fremhæver jeres nordiske rødder: “Nordic tech” eller “European alternative to …”.')); ?></p>
</section>

<div class="mt-10 grid grid-cols-1 gap-6 lg:grid-cols-2">
<div class="mt-10 grid grid-cols-1 gap-6 lg:grid-cols-3">
<a href="#tech" class="group rounded-2xl border border-gray-200 p-6 hover:border-gray-300 hover:shadow-md transition-all duration-200 dark:border-gray-700">
<p lang="<?php echo $badgeLanguage; ?>" class="text-base font-semibold text-gray-900 dark:text-white"><?php echo e($generic['name']); ?></p>
<p class="mt-1 text-sm/6 text-gray-700 dark:text-gray-300"><?php echo e(t('Et enkelt badge til jeres egen teknologi.')); ?></p>
<div class="badge-preview mt-5" aria-hidden="true"><?php echo badge_svg($generic, 'lys', 'kompakt'); ?></div>
</a>
<a href="#produkt" class="group rounded-2xl border border-gray-200 p-6 hover:border-gray-300 hover:shadow-md transition-all duration-200 dark:border-gray-700">
<p class="text-base font-semibold text-gray-900 dark:text-white"><?php echo e(t('Er jeres produkt på listen?')); ?></p>
<p class="mt-1 text-sm/6 text-gray-700 dark:text-gray-300"><?php echo e(t('Vis kunderne, at I er et dansk alternativ.')); ?></p>
Expand All @@ -57,6 +63,13 @@
</a>
</div>

<section id="tech" class="mt-20 scroll-mt-6 border-t border-gray-200 pt-16 dark:border-white/10" aria-labelledby="tech-heading">
<p class="text-sm font-semibold text-gray-700 dark:text-gray-300"><?php echo e(t('Til jeres egen teknologi')); ?></p>
<h2 id="tech-heading" lang="<?php echo $badgeLanguage; ?>" class="mt-2 text-3xl font-semibold tracking-tight text-gray-900 dark:text-white"><?php echo e($generic['name']); ?></h2>
<p class="mt-4 max-w-2xl text-base/7 text-gray-700 dark:text-gray-300"><?php echo e(t('Et enkelt badge til jeres egen teknologi. Badget linker til listen.')); ?></p>
<?php partial('badge-variants', ['product' => null, 'badge' => $generic]); ?>
</section>

<section id="produkt" class="mt-20 scroll-mt-6 border-t border-gray-200 pt-16 dark:border-white/10">
<p class="text-sm font-semibold text-gray-700 dark:text-gray-300"><?php echo e(t('Til produkterne på listen')); ?></p>
<h2 class="mt-2 text-3xl font-semibold tracking-tight text-gray-900 dark:text-white"><?php echo e(t('Er jeres produkt på listen?')); ?></h2>
Expand All @@ -81,7 +94,7 @@
<p class="mt-2 text-sm/6 text-gray-700 dark:text-gray-300"><?php echo e(t('Anbefalet: Badges med et alternativ linker til den relevante side på listen.')); ?></p>
<div class="mt-5 flex flex-wrap gap-2">
<?php foreach ($badges as $item): $active = $item['slug'] === $badge['slug']; ?>
<a href="<?php echo e(locale_path('/badge')); ?>?<?php echo e(http_build_query(['produkt' => product_slug($product), 'badge' => $item['slug'], 'sprog' => $badgeLanguage])); ?>#udseende"<?php echo $active ? ' aria-current="true"' : ''; ?> class="rounded-full px-3.5 py-1.5 text-sm font-medium <?php echo $active ? 'bg-gray-900 text-white dark:bg-white dark:text-gray-900' : 'border border-gray-300 text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:text-gray-300 dark:hover:bg-gray-800'; ?>"><?php echo e($item['slug'] === BADGE_GENERIC ? t('Generelt badge') : $item['name']); ?></a>
<a href="<?php echo e(locale_path('/badge')); ?>?<?php echo e(http_build_query(['produkt' => product_slug($product), 'badge' => $item['slug'], 'sprog' => $badgeLanguage])); ?>#udseende"<?php echo $active ? ' aria-current="true"' : ''; ?><?php echo $item['slug'] === BADGE_GENERIC ? ' lang="' . $badgeLanguage . '"' : ''; ?> class="rounded-full px-3.5 py-1.5 text-sm font-medium <?php echo $active ? 'bg-gray-900 text-white dark:bg-white dark:text-gray-900' : 'border border-gray-300 text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:text-gray-300 dark:hover:bg-gray-800'; ?>"><?php echo e($item['name']); ?></a>
<?php endforeach; ?>
</div>
</section>
Expand Down
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ Opret derefter en pull request fra din fork til `Boligforeningsweb/dansk-tech`.

Sitet findes på [dansk](https://dansktechstack.dk/) og [engelsk](https://dansktechstack.dk/en). Du bidrager fortsat med én dansk produktbeskrivelse i `products.json`; vedligeholderne står for den engelske udgave.

På [badgesiden](https://dansktechstack.dk/badge) kan du hente gratis badges på begge sprog, fx **Dansk teknologi** eller **Nordic tech**, samt badges med konkrete alternativnavne. Badges er frivillige.
På [badgesiden](https://dansktechstack.dk/badge) kan du hente gratis badges på begge sprog, fx **Dansk tech** eller **Nordic tech**, samt badges med konkrete alternativnavne. Badges er frivillige.

**English contributions are welcome.** To suggest a product or correction, [open an issue](https://github.com/Boligforeningsweb/dansk-tech/issues/new) with its name, URL, description, connection to Denmark and international alternatives. No coding or Danish translation is required to submit an issue.

Expand Down
24 changes: 24 additions & 0 deletions tools/browser/check-site.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,30 @@ async function main() {
await c.close();
}
});
await check('short tech badges can be found and copied without selecting a product', async () => {
const c = await context(); const p = await c.newPage();
for (const pageLanguage of ['da', 'en']) for (const badgeLanguage of ['da', 'en']) {
const prefix = pageLanguage === 'en' ? '/en' : '';
const label = badgeLanguage === 'en' ? 'Nordic tech' : 'Dansk tech';
await p.goto(origin + prefix + '/badge?sprog=' + badgeLanguage);
assert.equal(await p.locator('#produkt-valg').inputValue(), '');
const card = p.locator('a[href="#tech"]');
assert((await card.innerText()).includes(label)); await card.click();
assert.equal(new URL(p.url()).hash, '#tech');
assert.equal(await p.locator('#tech-heading').innerText(), label);
assert.equal(await p.locator('#tech .badge-preview svg').count(), 4);
await p.evaluate(() => Object.defineProperty(navigator, 'clipboard', { configurable: true, value: { writeText: async text => { window.copied = text; } } }));
await p.locator('#tech button.copy').first().click();
const html = await p.evaluate(() => window.copied);
assert(html.includes(label) && !html.includes('We support') && !html.includes('Vi støtter'));
assert(html.includes('/badge/listet-paa-dansktechstack.svg'));
const response = await c.request.get(origin + (badgeLanguage === 'en' ? '/en' : '') + '/badge/listet-paa-dansktechstack.svg');
assert.equal(response.status(), 200); assert((await response.text()).includes(label));
const supporter = await p.locator('#stoette svg title').first().textContent();
assert(supporter.includes(badgeLanguage === 'en' ? 'We support Nordic tech' : 'Vi støtter dansk tech'));
}
await c.close();
});
await check('badge previews, SVG files and embeds keep their own language', async () => {
const c = await context(); const p = await c.newPage();
for (const pageLanguage of ['da', 'en']) for (const badgeLanguage of ['da', 'en']) {
Expand Down
6 changes: 6 additions & 0 deletions tools/check-localization.php
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,12 @@ function check_page($page, $path, array $vars = []) {
// Both page/badge language combinations, including HTML copied to another website.
foreach (['da', 'en'] as $pageLanguage) {
foreach (['da', 'en'] as $badgeLanguage) {
[, $shortXpath] = page_document('badge', locale_path('/badge', $pageLanguage), [], ['sprog' => $badgeLanguage]);
$shortLabel = $badgeLanguage === 'en' ? 'Nordic tech' : 'Dansk tech';
check($shortXpath->evaluate('string(//h2[@id="tech-heading"])') === $shortLabel,
'Det korte badge kan ikke findes uden produktvalg.');
check($shortXpath->query('//section[@id="tech"]//button[@data-copy]')->length === 8,
'Det korte badge mangler kopierbare HTML-/Markdown-varianter.');
[, $xpath] = page_document('badge', locale_path('/badge', $pageLanguage), [],
['produkt' => 'alunta-com', 'sprog' => $badgeLanguage]);
foreach ($xpath->query('//div[contains(@class,"badge-preview")]/svg') as $svg) {
Expand Down
Loading