Add fallback i18n if strings are missing from locale (#26)

On page load, at most three locales are loaded: user locale
from Accept-Language, the default locale (if they aren't the
same), and the template locale. Using function getIntlString(),
if the user locale doesn't have a string, the string is fetched
from the default locale (if they aren't the same), and then,
finally, if neither the user or the default locale have the string,
it is taken from the template (which only contains string labels).
The lang attribute is set when possible.

Reviewed-on: #26
Co-authored-by: Denise <denisebitca@42l.fr>
Co-committed-by: Denise <denisebitca@42l.fr>
This commit is contained in:
Denise 2025-04-11 16:28:01 +02:00 committed by Miraty
parent 70490efb44
commit 80ee070168

View file

@ -27,7 +27,39 @@ if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
}
}
}
require "locales/" . $locale . ".php";
require "locales/" . $locale . ".php";
$chosen_loc = $loc;
if ($locale != DEFAULT_LOCALE) {
require "locales/" . DEFAULT_LOCALE . ".php";
$default_loc = $loc;
} else
$default_loc = $chosen_loc;
require "locales/template.php";
$template_loc = $loc;
// Function to get a specific string from the locale file, fall back on default then template if missing
function getIntlString(
$string_label,
$raw = false
) {
global $chosen_loc, $default_loc, $template_loc, $locale;
if (array_key_exists($string_label, $chosen_loc))
return $chosen_loc[$string_label];
if ($locale != DEFAULT_LOCALE AND array_key_exists($string_label, $default_loc)) {
if ($raw)
return $default_loc[$string_label];
return "<span lang=\"" . DEFAULT_LOCALE . "\">" . $default_loc[$string_label] . "</span>";
}
if ($raw)
return $template_loc[$string_label];
return "<span lang=\"en\">" . $template_loc[$string_label] . "</span>";
}
$params = array(
"txt" => "",
@ -147,8 +179,8 @@ if (
<html lang="<?= $locale ?>">
<head>
<meta charset="utf-8">
<title>LibreQR · <?= $loc['subtitle'] ?></title>
<meta name="description" content="<?= $loc['description'] ?>">
<title>LibreQR · <?= getIntlString('subtitle') ?></title>
<meta name="description" content="<?= getIntlString('description', raw: true) ?>">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="dark light">
<meta name="application-name" content="LibreQR">
@ -174,7 +206,7 @@ foreach($themeDimensionsIcons as $dimFav) // Set all icons dimensions
<a id="linkTitles" href="./">
<div id="titles">
<h1>LibreQR</h1>
<h2><?= $loc['subtitle'] ?></h2>
<h2><?= getIntlString('subtitle') ?></h2>
</div>
</a>
</header>
@ -183,21 +215,21 @@ foreach($themeDimensionsIcons as $dimFav) // Set all icons dimensions
<div class="param" id="txtParam">
<details>
<summary><label for="txt"><?= $loc['label_content'] ?></label></summary>
<summary><label for="txt"><?= getIntlString('label_content') ?></label></summary>
<div class="helpText">
<?= $loc['help_content'] ?>
<?= getIntlString('help_content') ?>
</div>
</details>
<textarea rows="3" required="" id="txt" placeholder="<?= $loc['placeholder'] ?>" name="txt"><?= htmlspecialchars($params['txt']) ?></textarea>
<textarea rows="3" required="" id="txt" placeholder="<?= getIntlString('placeholder', raw: true) ?>" name="txt"><?= htmlspecialchars($params['txt']) ?></textarea>
</div>
<div id="sideParams">
<div class="param">
<details>
<summary><label for="redundancy"><?= $loc['label_redundancy'] ?></label></summary>
<summary><label for="redundancy"><?= getIntlString('label_redundancy') ?></label></summary>
<p class="helpText">
<?= $loc['help_redundancy'] ?>
<?= getIntlString('help_redundancy') ?>
</p>
</details>
<select id="redundancy" name="redundancy">
@ -210,9 +242,9 @@ foreach($themeDimensionsIcons as $dimFav) // Set all icons dimensions
<div class="param">
<details>
<summary><label for="margin"><?= $loc['label_margin'] ?></label></summary>
<summary><label for="margin"><?= getIntlString('label_margin') ?></label></summary>
<p class="helpText">
<?= $loc['help_margin'] ?>
<?= getIntlString('help_margin') ?>
</p>
</details>
<input type="number" id="margin" placeholder="<?= DEFAULT_MARGIN ?>" name="margin" required="" min="0" max="1024" value="<?= htmlspecialchars($params['margin']) ?>">
@ -220,9 +252,9 @@ foreach($themeDimensionsIcons as $dimFav) // Set all icons dimensions
<div class="param">
<details>
<summary><label for="size"><?= $loc['label_size'] ?></label></summary>
<summary><label for="size"><?= getIntlString('label_size') ?></label></summary>
<p class="helpText">
<?= $loc['help_size'] ?>
<?= getIntlString('help_size') ?>
</p>
</details>
<input type="number" id="size" placeholder="<?= DEFAULT_SIZE ?>" name="size" required="" min="21" max="4096" value="<?= htmlspecialchars($params['size']) ?>">
@ -232,17 +264,17 @@ foreach($themeDimensionsIcons as $dimFav) // Set all icons dimensions
<div id="colors">
<div class="param">
<label for="bgColor"><?= $loc['label_bgColor'] ?></label>
<label for="bgColor"><?= getIntlString('label_bgColor') ?></label>
<input type="color" name="bgColor" id="bgColor" value="#<?= htmlspecialchars($params['bgColor']) ?>">
</div>
<div class="param">
<label for="fgColor"><?= $loc['label_fgColor'] ?></label>
<label for="fgColor"><?= getIntlString('label_fgColor') ?></label>
<input type="color" name="fgColor" id="fgColor" value="#<?= htmlspecialchars($params['fgColor']) ?>">
</div>
</div>
<div class="centered">
<input class="button" type="submit" value="<?= $loc['button_create'] ?>" />
<input class="button" type="submit" value="<?= getIntlString('button_create', raw: true) ?>" />
</div>
</form>
@ -258,11 +290,11 @@ if ($qrCodeAvailable) {
<section id="output">
<div class="centered" id="downloadQR">
<a href="<?= $dataUri ?>" class="button" download="<?= htmlspecialchars($params['txt']); ?>.png"><?= $loc['button_download'] ?></a>
<a href="<?= $dataUri ?>" class="button" download="<?= htmlspecialchars($params['txt']); ?>.png"><?= getIntlString('button_download') ?></a>
</div>
<div class="centered" id="showOnlyQR">
<a title="<?= $loc['title_showOnlyQR'] ?>" href="<?= $dataUri ?>"><img width="<?= $qrSize ?>" height="<?= $qrSize ?>" alt='<?= $loc['alt_QR_before'] ?><?= htmlspecialchars($params['txt']); ?><?= $loc['alt_QR_after'] ?>' id="qrCode"<?php
<a title="<?= getIntlString('title_showOnlyQR', raw: true) ?>" href="<?= $dataUri ?>"><img width="<?= $qrSize ?>" height="<?= $qrSize ?>" alt='<?= getIntlString('alt_QR_before', raw: true) ?><?= htmlspecialchars($params['txt']); ?><?= getIntlString('alt_QR_after', raw: true) ?>' id="qrCode"<?php
// Compute the difference between the QR code and theme background colors
$diffLight = abs($rgbBgColor['r']-hexdec(substr($colorScheme['bg-light'],-6,2))) + abs($rgbBgColor['g']-hexdec(substr($colorScheme['bg-light'],-4,2))) + abs($rgbBgColor['b']-hexdec(substr($colorScheme['bg-light'],-2,2)));
@ -280,14 +312,14 @@ if ($qrCodeAvailable) {
<?php
} else if ($qrCodeAvailable === false) {
echo " <p><strong>" . $loc['error_generation'] . "</strong></p></body></html>";
echo " <p><strong>" . getIntlString('error_generation') . "</strong></p></body></html>";
}
?>
<footer>
<section id="info" class="metaText">
<?= $loc['metaText_qr'] ?>
<?= getIntlString('metaText_qr') ?>
</section>
<?php if (CUSTOM_TEXT_ENABLED) { ?>
@ -297,7 +329,7 @@ if ($qrCodeAvailable) {
<?php } ?>
<section class="metaText">
<small><?= $loc['metaText_legal'] ?></small>
<small><?= getIntlString('metaText_legal') ?></small>
</section>
</footer>