AppThere Loki Text is a distraction-free writing application designed for focused document creation. It specializes in the OpenDocument Text (.odt) format, providing a cross-platform experience across Desktop (Windows, macOS, Linux) and Android.
The main goal of Loki Text is to provide a clean, "zen" environment for writers who need to produce structured documents without the bloat of traditional office suites. It features:
- ODT First: Native support for OpenDocument Text, ensuring compatibility with LibreOffice and other standards-compliant editors.
- Style-Centric Editing: A streamlined approach to paragraph styling, including "Next Style" logic for efficient drafting.
- Cross-Platform: Built with Tauri to run natively on Desktop and Mobile.
- Atkinson Hyperlegible Next: Optimized for readability with high-legibility typography.
Prototype / Early Development This project is currently in active development. Core ODT parsing, styling logic, and basic editor functionality are implemented, but features are subject to significant changes.
To build and run this project, you will need:
- Rust (latest stable)
- Node.js (v18+) and npm
- Tauri CLI dependencies for your OS
- For Android Build:
- Android Studio
- Android SDK, NDK, and Java (JDK 17+)
- Rust Android targets:
rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android
Clone the repository and install dependencies:
npm installRun the application in development mode:
npm run tauri devTo run on a connected Android device or emulator:
npm run tauri android devTo create a production bundle:
Desktop:
npm run tauri buildAndroid:
npm run tauri android buildAppThere Loki Text is released under the Apache License 2.0. See the LICENSE file (if available) for more details.
Copyright © 2026 AppThere. All rights reserved.
Loki ships with a full i18n system built on i18next and react-i18next. Locale JSON files are loaded at runtime via i18next-http-backend; the OS locale is detected through a Tauri command backed by the sys-locale Rust crate.
- Add the key to
public/locales/en/common.json(general UI) orpublic/locales/en/editor.json(canvas / document strings). - Use
t('your.key')in the component (importuseTranslationfromreact-i18next). - Run the locale validator to surface gaps in other locales:
node scripts/validate-locales.js
- Optionally fill in translations for other locales — missing keys fall through to the English fallback at runtime.
See src/templates/Component.tsx for a copy-paste starter component with full i18n wiring.
import { setLanguage } from '@/i18n';
setLanguage('fr'); // persists to localStorage and updates document.dir for RTLA user preference stored in localStorage under the key loki.language always takes precedence over the OS locale.
node scripts/validate-locales.jsExits with code 0 if every non-English locale contains the same key structure as English; exits with code 1 and prints a per-locale report of missing keys otherwise.
| Tag | Language |
|---|---|
ar |
Arabic |
bg |
Bulgarian |
cs |
Czech |
da |
Danish |
de |
German |
el |
Greek |
en |
English (reference) |
es |
Spanish |
et |
Estonian |
fi |
Finnish |
fr |
French |
ga |
Irish |
hi |
Hindi |
hr |
Croatian |
hu |
Hungarian |
it |
Italian |
ja |
Japanese |
ko |
Korean |
lt |
Lithuanian |
lv |
Latvian |
mt |
Maltese |
nl |
Dutch |
pl |
Polish |
pt |
Portuguese |
ro |
Romanian |
sk |
Slovak |
sl |
Slovenian |
sv |
Swedish |
zh-Hans |
Chinese (Simplified) |
Arabic (ar) is the only RTL locale in the supported set. setLanguage('ar') automatically sets document.documentElement.dir = 'rtl'; all other locales set it to 'ltr'. Components should rely on logical CSS properties (margin-inline-start, padding-inline-end, etc.) rather than physical left/right to respond correctly to the direction change.
The ESLint rule i18next/no-literal-string is configured at error level in eslint.config.js with mode: 'jsx-only'. Any literal string placed directly inside a JSX expression will fail linting, guiding developers to use t() instead. Pure integers, SCREAMING_SNAKE_CASE constants, whitespace-only strings, single characters, and version strings are excluded from the rule.