Skip to content
Open
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
17 changes: 17 additions & 0 deletions srghmakhmerdict/components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"$schema": "https://shadcn-svelte.com/schema.json",
"style": "nova",
"typescript": true,
"tailwind": {
"config": "tailwind.config.js",
"css": "src/App.css",
"baseColor": "slate",
"cssVariables": true
},
"aliases": {
"components": "$lib/components",
"ui": "$lib/components/ui",
"utils": "$lib/utils",
"lib": "$lib"
}
}
44 changes: 44 additions & 0 deletions srghmakhmerdict/convert_i18n.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import fs from 'fs';
import path from 'path';

const locales = ['en', 'ru', 'uk', 'km'];
const baseDir = './src/i18n';
const outDir = './messages';

if (!fs.existsSync(outDir)) fs.mkdirSync(outDir);

function flatten(obj, prefix = '') {
let result = {};
for (const key in obj) {
const newKey = prefix ? `${prefix}_${key}` : key;
if (typeof obj[key] === 'object' && obj[key] !== null && !Array.isArray(obj[key])) {
Object.assign(result, flatten(obj[key], newKey));
} else {
result[newKey] = String(obj[key]);
}
}
return result;
}

async function convert() {
for (const locale of locales) {
const filePath = path.join(baseDir, locale, 'index.ts');
if (!fs.existsSync(filePath)) continue;
let content = fs.readFileSync(filePath, 'utf-8');
content = content.replace(/^import.*$/m, '');
content = content.replace(/satisfies Translation/g, '');
const tempFile = `./temp-${locale}.js`;
fs.writeFileSync(path.join(baseDir, tempFile), content);
try {
const module = await import(`./src/i18n/temp-${locale}.js`);
const flattened = flatten(module.default);
fs.writeFileSync(path.join(outDir, `${locale}.json`), JSON.stringify(flattened, null, 2));
console.log(`Converted ${locale}`);
} catch (e) {
console.error(`Failed to convert ${locale}`, e);
} finally {
if (fs.existsSync(path.join(baseDir, tempFile))) fs.unlinkSync(path.join(baseDir, tempFile));
}
}
}
convert();
216 changes: 216 additions & 0 deletions srghmakhmerdict/messages/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
{
"SETTINGS_TITLE": "App Settings",
"SETTINGS_SUBTITLE": "Customize your dictionary experience.",
"SETTINGS_GROUPS_TOOLS": "Tools",
"SETTINGS_GROUPS_SEARCH": "Search",
"SETTINGS_GROUPS_INTERFACE": "Interface",
"SETTINGS_GROUPS_TEXT_SIZE": "Text Size",
"SETTINGS_GROUPS_KHMER_DICT": "Khmer Dictionary",
"SETTINGS_GROUPS_PROJECT": "Project",
"SETTINGS_ACTIONS_OPEN_KHMER_COMPLEX_TABLE": "Open Khmer Characters Table",
"SETTINGS_ACTIONS_OPEN_KHMER_ANALYZER": "Open Khmer Analyzer",
"SETTINGS_ACTIONS_ABOUT": "About Dictionary",
"SETTINGS_ACTIONS_DONATE": "Donate",
"SETTINGS_LABELS_SEARCH_MODE": "Search Mode",
"SETTINGS_LABELS_SEARCH_MODE_HINT": "Choose how to match your query",
"SETTINGS_LABELS_SEARCH_IN_CONTENT": "Search in Content",
"SETTINGS_LABELS_SEARCH_IN_CONTENT_HINT": "Include results from definitions",
"SETTINGS_LABELS_HIGHLIGHT_IN_LIST": "Highlight in List",
"SETTINGS_LABELS_HIGHLIGHT_IN_LIST_HINT": "Highlight matches in word list",
"SETTINGS_LABELS_HIGHLIGHT_IN_DETAILS": "Highlight in Details",
"SETTINGS_LABELS_HIGHLIGHT_IN_DETAILS_HINT": "Highlight matches in definition",
"SETTINGS_LABELS_THEME": "Theme",
"SETTINGS_LABELS_THEME_HINT": "Toggle dark/light theme",
"SETTINGS_LABELS_APP_LANGUAGE": "App Language",
"SETTINGS_LABELS_APP_LANGUAGE_HINT": "Choose interface language",
"SETTINGS_LABELS_AUTO": "Auto",
"SETTINGS_LABELS_UI_SIZE": "UI Size",
"SETTINGS_LABELS_DEFINITION_TEXT_SIZE": "Definition Text Size",
"SETTINGS_LABELS_DESCRIPTION_FILTER": "Filter",
"SETTINGS_LABELS_ALL": "Show All",
"SETTINGS_LABELS_ONLY_VERIFIED": "Only Verified",
"ABOUT_TITLE": "About Khmer Dictionary",
"ABOUT_DEVELOPER_INFO": "Developer Info",
"ABOUT_HELP_PROJECT": "Help the Project",
"ABOUT_SUPPORT_DEVELOPMENT": "Support development",
"ABOUT_DONATE_SUBTITLE": "Support my work via Google Pay",
"ABOUT_RATE_APP": "Rate the App",
"ABOUT_SUCCESS_MODAL_TITLE": "Success!",
"ABOUT_SUCCESS_MODAL_BODY_1": "Thank you for your generous support! It means a lot for the development of the project.",
"ABOUT_SUCCESS_MODAL_BODY_2": "Support this free feature with a quick rating!",
"ABOUT_SUCCESS_MODAL_BUTTON_YES": "Yes, I will support!",
"ABOUT_SUCCESS_MODAL_BUTTON_NO": "Not now",
"ABOUT_CANCELLATION_MODAL_TITLE": "OOPS...",
"ABOUT_CANCELLATION_MODAL_BODY": "We are sorry that you cancelled the donation",
"ABOUT_CANCELLATION_MODAL_BUTTON": "I understand",
"ABOUT_DEV_SECTION_NAME": "My name is <strong class=\"text-foreground\">Serhii Khoma</strong>.",
"ABOUT_DEV_SECTION_GITHUB": "My github: <a href=\"https://github.com/srghma\" class=\"font-semibold text-primary\">srghma</a>.",
"ABOUT_DEV_SECTION_SOURCE_CODE": "The source code of this dictionary is open and available at <a href=\"https://github.com/srghma/khmer\" class=\"font-semibold text-primary\">github.com/srghma/khmer</a>",
"ABOUT_PRESENTATION_SECTION_BODY_1": "I also know how people appeared in the universe from (<b>autocatalyzer</b> =&gt; <b>the first molecular robot-self-replicator</b> 🤖).",
"ABOUT_PRESENTATION_SECTION_BODY_2": "You can read about it in my presentation.",
"ABOUT_PRESENTATION_SECTION_BODY_3": "(Also there is a story about how russians 🇷🇺 tortured my 🇺🇦 friend Ivan).",
"ABOUT_PRESENTATION_SECTION_BUTTON": "View Presentation",
"ABOUT_OCR_SECTION_TITLE": "You can significantly help by finding mistakes in dictionaries. More - in GitHub.",
"TABS_HISTORY": "History",
"TABS_FAVORITES": "Favorites",
"TABS_SETTINGS": "Settings",
"ANALYZER_TITLE": "Khmer Analyzer",
"ANALYZER_PLACEHOLDER": "Enter Khmer text to analyze...",
"ANALYZER_SEGMENTATION": "Word Segmentation",
"ANALYZER_CHARACTER_ANALYSIS": "Character Analysis",
"ANALYZER_USING_APP_DICT": "using app dictionary",
"ANALYZER_USING_INTL_SEGMENTER": "using intl segmenter",
"ANALYZER_EMPTY_TEXT": "Enter some text to start analysis",
"ANALYZER_NO_KHMER_CHAR": "No Khmer characters detected in the provided text.",
"ANALYZER_FETCHING_DEFS": "Fetching word definitions...",
"ANALYZER_DEFS_FETCH_FAILED": "Error fetching definitions",
"ANALYZER_DEFS_FETCH_ERROR": "An unknown error occurred while fetching definitions.",
"ANALYZER_EXPAND_DEFINITION": "Click to expand definition",
"ANALYZER_MARKDOWN_ERROR_EMPTY": "Markdown output is empty after parsing.",
"ANALYZER_MARKDOWN_ERROR": "An error occurred while parsing Markdown.",
"ANALYZER_SEGMENTER_LABEL": "Segmenters",
"ANALYZER_INTL_SEGMENTER": "Intl Segmenter",
"ANALYZER_APP_DICT": "App Dictionary",
"ANALYZER_BOTH": "Both",
"ANALYZER_MARKDOWN_LABEL": "Markdown",
"ANALYZER_SEGMENTATION_LABEL": "Segmentation",
"ANALYZER_CHARACTER_ANALYSIS_LABEL": "Char Analysis",
"ANALYZER_WORD_NOT_IN_KHMER_DICTIONARY": "Word {word} not found in Khmer dictionary.",
"ANALYZER_WORD_NOT_IN_ENGLISH_DICTIONARY": "Word {word} not found in English dictionary.",
"ANALYZER_WORD_NOT_IN_RUSSIAN_DICTIONARY": "Word {word} not found in Russian dictionary.",
"ANKI_NO_FAVORITES": "Favorites is empty. Add words to favorites to start learning.",
"ANKI_CARD_NOT_FOUND": "Card not found",
"ANKI_SELECT_CARD": "Select a card to start",
"ANKI_FETCH_FAILED": "Failed to load definition",
"ANKI_DUE": "Due",
"ANKI_DIFF_EXTRA": "Extra character",
"ANKI_DIFF_MISSING": "Missing character",
"ANKI_MODES_GUESSING": "Guessing",
"ANKI_MODES_TRANSLATE_TO_EN_RU": "Translate to En/Ru",
"ANKI_MODES_TRANSLATE_TO": "Translate to {lang}",
"ANKI_ARIA_TABS": "Anki Dictionary Tabs",
"ANKI_BUTTONS_AGAIN": "😵 Again",
"ANKI_BUTTONS_HARD": "😐 Hard",
"ANKI_BUTTONS_GOOD": "😊 Good",
"ANKI_BUTTONS_EASY": "😎 Easy",
"ANKI_BUTTONS_SHOW_ANSWER": "Show Answer",
"ANKI_SESSION_FINISHED": "Session finished!",
"ANKI_YOUR_GUESS": "Your Guess ({field} field)",
"ANKI_ANSWER_PLACEHOLDER": "Answer... ({field} field)",
"ANKI_LANGUAGES_KHMER": "Khmer",
"ANKI_LANGUAGES_ENGLISH": "English",
"ANKI_LANGUAGES_RUSSIAN": "Russian",
"ANKI_LANGUAGES_EN_RU": "En/Ru",
"ANKI_IMPORT_TITLE": "Import Words",
"ANKI_IMPORT_DESCRIPTION": "Enter one word per line. We'll automatically detect the language.",
"ANKI_IMPORT_PLACEHOLDER": "សួស្តី\nHello\nПривет",
"ANKI_IMPORT_BUTTON": "Import",
"ANKI_IMPORT_SUMMARY_TITLE": "Import Summary",
"ANKI_IMPORT_SUCCESS": "Success",
"ANKI_IMPORT_SKIPPED": "Skipped (already exists)",
"ANKI_IMPORT_NOT_FOUND": "Not found in dictionary",
"ANKI_EXPORT_TITLE": "Export Words",
"ANKI_EXPORT_DESCRIPTION": "Export all your favorite words as a list.",
"ANKI_EXPORT_BUTTON": "Export",
"ANKI_SETTINGS_TITLE": "Anki Settings",
"ANKI_FIELDS_FRONT_NOTE": "Front Note",
"ANKI_FIELDS_BACK_NOTE": "Back Note",
"SIDEBAR_LOADING_DICT": "Loading Dictionary...",
"SIDEBAR_FILTERING": "Filtering...",
"SIDEBAR_ERROR_NOT_LOADED": "Dictionary not loaded or empty",
"SIDEBAR_ARIA_TABS": "Dictionary Tabs",
"SIDEBAR_LEVEL_1": "1st",
"SIDEBAR_LEVEL_2": "2nd",
"COMMON_WELCOME_TITLE": "Welcome to Khmer Dictionary",
"COMMON_WELCOME_SUBTITLE": "Select a word from the list to view details",
"COMMON_STARTS_WITH": "Starts With",
"COMMON_INCLUDES": "Includes",
"COMMON_REGEX": "Regex",
"COMMON_FOUND_IN_CONTENT": "Found in Content",
"COMMON_CANCEL": "Cancel",
"COMMON_CONFIRM": "Confirm",
"COMMON_NOTHING": "Nothing",
"COMMON_LOADING": "Loading...",
"COMMON_NO_ITEMS_FOUND": "No items found.",
"COMMON_CLEAR_ALL": "Clear All",
"COMMON_ALREADY_OPENED": "Already opened",
"HISTORY_RECENT_TITLE_WITH_COUNT": "Recent History ({count})",
"HISTORY_CLEAR_TITLE": "Clear Search History?",
"HISTORY_CONFIRM_DELETE_ALL": "Are you sure you want to delete all {count} items?",
"FAVORITES_TITLE_WITH_COUNT": "Favorites ({count})",
"FAVORITES_CLEAR_TITLE": "Clear Favorites?",
"FAVORITES_CONFIRM_DELETE_ALL": "Are you sure you want to delete all {count} items?",
"FAVORITES_OPEN_ANKI": "Open Anki",
"FAVORITES_ANKI_BUTTON": "Anki",
"DETAIL_NOT_FOUND": "Word \"{word}\" not found in dictionary.",
"DETAIL_ANALYSIS_HINT": "Try adjusting the text or checking the Khmer Analyzer below.",
"DETAIL_PLACEHOLDER": "Translate text...",
"DETAIL_SECTION_DEFINITION": "Definition",
"DETAIL_SECTION_DEFINITION_EN": "English Definition",
"DETAIL_SECTION_EN_KM": "En-Km Dictionary",
"DETAIL_SECTION_ENGLISH": "English Dictionary",
"DETAIL_SECTION_NOUN_FORMS": "Noun Forms",
"DETAIL_SECTION_PRONUNCIATIONS": "Pronunciations",
"DETAIL_SECTION_WIKTIONARY": "Wiktionary",
"DETAIL_SECTION_RU_WIKI": "Russian Wiki",
"DETAIL_SECTION_GORGONIEV": "Gorgoniev Dictionary",
"DETAIL_SECTION_CHUON_NATH": "Chuon Nath Dictionary",
"DETAIL_TESTER_TITLE": "Processors Logic Test",
"DETAIL_TESTER_ORIGINAL_VALUE": "Original Value",
"DETAIL_TESTER_PROCESSED_RESULTS": "Processed Results",
"DETAIL_SEARCH_STARTS": "Starts",
"DETAIL_SEARCH_INCLUDES": "Includes",
"DETAIL_SEARCH_REGEX": "Regex",
"ACTIONS_HIDE_KM": "Hide Khmer words",
"ACTIONS_SHOW_KM": "Show Khmer words",
"ACTIONS_HIDE_NON_KM": "Hide NON-Khmer words",
"ACTIONS_SHOW_NON_KM": "Show NON-Khmer words",
"ACTIONS_DISABLE_LINKS": "Disable links",
"ACTIONS_ENABLE_LINKS": "Enable links",
"ACTIONS_FONT_LABEL": "Select Khmer Font",
"ACTIONS_COLOR_LABEL": "Colorization Mode",
"ACTIONS_COLOR_SEGMENTER": "Words Segmentation (Colors)",
"ACTIONS_COLOR_DICT": "Dictionary-based coloring",
"ACTIONS_COLOR_NONE": "No coloring",
"ACTIONS_FAV_ADD": "Add to favorites",
"ACTIONS_FAV_REMOVE": "Remove from favorites",
"ACTIONS_AUTOFOCUS_ON": "Autofocus answer field: ON",
"ACTIONS_AUTOFOCUS_OFF": "Autofocus answer field: OFF",
"ACTIONS_ENTER_HTML_OR_TEXT": "Enter text or HTML...",
"ACTIONS_CANCEL": "Cancel",
"ACTIONS_SAVE": "Save",
"ACTIONS_EDIT": "Edit",
"ACTIONS_ADD": "Add",
"ACTIONS_ADD_NOTE": "Add Note",
"ACTIONS_HIDE_SHORT_DETAIL": "Hide short details",
"ACTIONS_SHOW_SHORT_DETAIL": "Show short details",
"AUTOREAD_TITLE": "Auto-read on reveal",
"AUTOREAD_DISABLED": "Disabled",
"AUTOREAD_GOOGLE_THEN_NATIVE": "Google TTS or Native when offline",
"AUTOREAD_GOOGLE_ONLY": "Google TTS only",
"AUTOREAD_NATIVE_ONLY": "Native TTS only",
"SPEECH_OFFLINE": "Offline (Google TTS unavailable)",
"SPEECH_GOOGLE": "Listen with Google TTS",
"SPEECH_NATIVE": "Listen with Native TTS",
"SEARCH_PLACEHOLDER_REGEX": "Search with Regex...",
"SEARCH_PLACEHOLDER_STARTS_WITH": "Search starts with...",
"SEARCH_PLACEHOLDER_INCLUDES": "Search includes...",
"OFFLINE_CHECK_FAILED": "Failed to verify offline assets",
"OFFLINE_STARTING_DOWNLOAD": "Starting download...",
"OFFLINE_NOT_DOWNLOADED": "Images not downloaded",
"OFFLINE_READY": "Ready ({count} files)",
"OFFLINE_NO_FILES_FOUND": "No dictionary files found for download",
"OFFLINE_DOWNLOAD_FAILED": "Failed to download dictionary images",
"OFFLINE_TITLE": "Offline Support",
"OFFLINE_LABEL": "Offline Images",
"OFFLINE_HINT_AVAILABLE": "Images available offline ({count} files)",
"OFFLINE_HINT_NOT_AVAILABLE": "Images only available when online",
"OFFLINE_DOWNLOAD_BUTTON": "Download Offline Images",
"OFFLINE_DOWNLOADING": "Downloading...",
"OFFLINE_ASSETS_AVAILABLE": "Offline assets available ({count} files)",
"ERROR_BOUNDARY_TITLE": "Application Error",
"ERROR_BOUNDARY_SUBTITLE": "Something went wrong.",
"ERROR_BOUNDARY_BODY": "An unexpected error occurred. Please try reloading the application.",
"ERROR_BOUNDARY_RELOAD_BUTTON": "Reload Application",
"COMPLEX_TABLE_TITLE": "Khmer Characters Table"
}
Loading