summaryrefslogtreecommitdiff
path: root/src/application/i18n.php
diff options
context:
space:
mode:
Diffstat (limited to 'src/application/i18n.php')
-rw-r--r--src/application/i18n.php98
1 files changed, 98 insertions, 0 deletions
diff --git a/src/application/i18n.php b/src/application/i18n.php
new file mode 100644
index 0000000..964439f
--- /dev/null
+++ b/src/application/i18n.php
@@ -0,0 +1,98 @@
+<?php
+
+const MESSAGE_DIR = __DIR__ . "/messages";
+
+$__i18n_msg_store = [];
+$__i18n_current_locale = null;
+
+function i18n_parse(string $contents, ?string $filename = null): array {
+ $syntax_error = fn(string $msg, ?int $line = null): never =>
+ throw new Exception("i18n syntax error: $msg (in " . ($filename ?? "unknown") . ":" . ($line ?? 0) . ")");
+
+ $msgs = [];
+ $lines = explode("\n", $contents);
+ $currentId = "";
+ $currentContext = "";
+ $currentMessage = "";
+ $isInMessage = false;
+ foreach ($lines as $i => $ln) {
+ $lnNum = $i + 1;
+ if (trim($ln) === "")
+ continue;
+
+ switch ($ln[0]) {
+ case "#":
+ continue 2;
+ case ":":
+ if ($currentId !== "") {
+ if ($currentContext !== "")
+ $currentId = $currentContext . "\004" . $currentId;
+ $msgs[$currentId] ??= $currentMessage;
+ }
+ $currentId = json_decode(substr($ln, 2));
+ $currentContext = "";
+ $currentMessage = "";
+ $isInMessage = false;
+ break;
+ case "=":
+ $isInMessage = true;
+ $currentMessage = json_decode(substr($ln, 2));
+ break;
+ case "?":
+ if ($isInMessage)
+ $syntax_error("context must be defined before start of message", $lnNum);
+ $currentContext = json_decode(substr($ln, 2));
+ break;
+ case " ":
+ if ($isInMessage)
+ $currentMessage .= json_decode(substr($ln, 2));
+ else
+ $currentId .= json_decode(substr($ln, 2));
+ break;
+ default:
+ $syntax_error("invalid start of line '" . $ln[0] . "' (0x" . str_pad(strtoupper(dechex(ord($ln[0]))), 2, "0", STR_PAD_LEFT) . ")", $lnNum);
+ break;
+ }
+ }
+
+ if ($currentId !== "") {
+ if ($currentContext !== "")
+ $currentId = $currentContext . "\x7F" . $currentId;
+ $msgs[$currentId] ??= $currentMessage;
+ }
+ return $msgs;
+}
+
+function i18n_locale(string $locale) {
+ global $__i18n_current_locale;
+ $__i18n_current_locale = $locale;
+}
+
+function i18n_get(string $msgid, array $params = [], ?string $context = null): string {
+ global $__i18n_current_locale, $__i18n_msg_store;
+
+ $key = $msgid;
+ if ($context !== null)
+ $key = $context . "\x7F" . $msgid;
+
+ $msg = ($__i18n_msg_store[$__i18n_current_locale] ?? [])[$msgid] ?? $key;
+
+ uksort($params, fn(string $a, string $b): int => strlen($b) <=> strlen($a));
+ return str_replace(
+ array_map(fn(string $k): string => "%$k%", array_keys($params)),
+ array_values($params),
+ $msg
+ );
+}
+
+function __(string $msgid, array $params = [], ?string $context = null): string {
+ return i18n_get($msgid, $params, $context);
+}
+
+foreach (scandir(MESSAGE_DIR) as $ent) {
+ $path = MESSAGE_DIR . "/" . $ent;
+ if ($ent[0] === "." || !is_file($path) || strcasecmp(pathinfo($ent, PATHINFO_EXTENSION), "msg") !== 0)
+ continue;
+ $lang = pathinfo($ent, PATHINFO_FILENAME);
+ $__i18n_msg_store[$lang] = i18n_parse(file_get_contents($path), $ent);
+}