Files
dikte/tests/test_i18n.py
yusufipek 2f59029261 Put the modules in a package and the scripts in a folder
Twenty-two files at the top of the tree was the first thing anybody saw of
this repository. They are one package now, imported relatively, and the three
scripts that are not the front door moved under scripts/. install.sh stays
where the README has always said it is.

What starts the application is dikte/__main__.py: python3 -m dikte runs it,
and so does naming the file, which is what the launcher symlink, both .desktop
files, the macOS bundle and every registered shortcut do. Run by path there is
no package around it, so it puts the checkout on sys.path itself.

The installers now keep the keys you chose when they are given none, which is
what an update is: update.sh no longer has to read them out and pass them back.
An updater from before this commit cannot read them at all, so the one thing it
can say, the default key with an empty discard key, is read as "nothing was
asked for" rather than obeyed. That guard can go once nobody is updating across
this commit.
2026-08-16 14:01:01 +03:00

123 lines
4.8 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Translation lookup, and the table itself.
The table test is the one that matters for a pull request: a Turkish string
whose placeholder was renamed raises KeyError at the moment the message is
shown, which is exactly when nobody is watching a terminal.
"""
import string
import unittest
from unittest import mock
from dikte import i18n
from tests.support import DikteTest
def placeholders(text):
return {name for _, name, _, _ in string.Formatter().parse(text) if name}
class Resolve(unittest.TestCase):
def test_an_explicit_language_wins(self):
with mock.patch.dict("os.environ", {"LANG": "tr_TR.UTF-8"}):
self.assertEqual(i18n.resolve("en"), "en")
self.assertEqual(i18n.resolve("tr"), "tr")
def test_auto_reads_the_locale(self):
with mock.patch.dict("os.environ", {"LANG": "tr_TR.UTF-8"}, clear=True):
self.assertEqual(i18n.resolve("auto"), "tr")
with mock.patch.dict("os.environ", {"LANG": "en_GB.UTF-8"}, clear=True):
self.assertEqual(i18n.resolve("auto"), "en")
def test_lc_all_outranks_lang(self):
with mock.patch.dict("os.environ",
{"LC_ALL": "tr_TR.UTF-8", "LANG": "en_GB.UTF-8"},
clear=True):
self.assertEqual(i18n.resolve("auto"), "tr")
def test_no_locale_at_all_falls_back_to_english(self):
with mock.patch.dict("os.environ", {}, clear=True):
self.assertEqual(i18n.resolve("auto"), "en")
def test_an_unknown_code_is_not_taken_at_its_word(self):
with mock.patch.dict("os.environ", {}, clear=True):
self.assertEqual(i18n.resolve("de"), "en")
class Translate(DikteTest):
def test_english_returns_the_source_string(self):
self.assertEqual(i18n.t("Quit"), "Quit")
def test_turkish_looks_the_string_up(self):
i18n.set_language("tr")
self.assertEqual(i18n.t("Quit"), "Çık")
def test_an_untranslated_string_falls_through(self):
i18n.set_language("tr")
self.assertEqual(i18n.t("Nobody translated this"), "Nobody translated this")
def test_placeholders_are_filled_in_both_languages(self):
self.assertEqual(i18n.t("Unknown key: {key}", key="f13"), "Unknown key: f13")
i18n.set_language("tr")
self.assertIn("f13", i18n.t("Unknown key: {key}", key="f13"))
def test_a_string_with_no_arguments_is_not_formatted(self):
# Braces in the text itself must survive when nothing is passed in.
self.assertEqual(i18n.t("{not a placeholder}"), "{not a placeholder}")
def test_a_placeholder_may_be_called_anything(self):
"""Including the names of t()'s own parameters, which is why they are
positional-only: worker.py says {text}, and that has to work."""
self.assertEqual(i18n.t("Discarded: {text}", text="hello"), "Discarded: hello")
self.assertEqual(i18n.name("Claude", case="dative"), "Claude")
class Names(DikteTest):
def test_english_leaves_the_name_alone(self):
self.assertEqual(i18n.name("Claude", "dative"), "Claude")
def test_turkish_inflects_by_the_vowels_of_the_name(self):
i18n.set_language("tr")
self.assertEqual(i18n.name("Claude", "dative"), "Claude'a")
self.assertEqual(i18n.name("Codex", "dative"), "Codex'e")
self.assertEqual(i18n.name("OpenRouter", "accusative"), "OpenRouter'ı")
def test_no_case_asked_for(self):
i18n.set_language("tr")
self.assertEqual(i18n.name("Claude"), "Claude")
def test_an_unlisted_name_or_case_comes_back_unchanged(self):
i18n.set_language("tr")
self.assertEqual(i18n.name("Ollama", "dative"), "Ollama")
self.assertEqual(i18n.name("Claude", "ablative"), "Claude")
class Table(unittest.TestCase):
"""The Turkish table against the English strings it stands in for."""
def test_every_translation_keeps_the_placeholders_of_its_source(self):
for source, translated in i18n.TR.items():
with self.subTest(source=source[:50]):
self.assertEqual(
placeholders(source), placeholders(translated),
"the Turkish string does not take the same arguments",
)
def test_nothing_is_translated_to_an_empty_string(self):
for source, translated in i18n.TR.items():
with self.subTest(source=source[:50]):
self.assertTrue(translated.strip())
def test_every_translation_is_formattable(self):
"""Whatever the table holds, .format() must not blow up on it."""
for source, translated in i18n.TR.items():
names = placeholders(translated)
if not names:
continue
with self.subTest(source=source[:50]):
translated.format(**{key: "x" for key in names})
if __name__ == "__main__":
unittest.main()