Skip to content

Commit ee2e37f

Browse files
committed
chore: add bilingual support and export options modal for Markdown to DOCX converter
1 parent 4bb21ad commit ee2e37f

File tree

4 files changed

+289
-31
lines changed

4 files changed

+289
-31
lines changed

web/index.html

Lines changed: 98 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
<title>Markdown to DOCX Converter</title>
88
<meta name="robots" content="index, follow" />
99
<meta name="author" content="MarkdownDocx Team" />
10-
<meta property="og:title" content="Markdown to DOCX Converter" />
11-
<meta property="og:description" content="Convert Markdown files to DOCX format easily." />
10+
<meta property="og:title" content="Markdown to DOCX Converter | 转换 Markdown 文件为 DOCX" />
11+
<meta property="og:description" content="Convert Markdown files to DOCX format easily. | 在线转换 Markdown 文件为 DOCX 格式" />
1212
<meta property="og:image" content="/icon.svg" />
1313
<meta property="og:url" content="https://github.com/vace/markdown-docx" />
1414
<meta name="twitter:card" content="summary_large_image" />
15-
<meta name="twitter:title" content="Markdown to DOCX Converter" />
16-
<meta name="twitter:description" content="Convert Markdown files to DOCX format easily." />
15+
<meta name="twitter:title" content="Markdown to DOCX Converter | 转换 Markdown 文件为 DOCX" />
16+
<meta name="twitter:description" content="Convert Markdown files to DOCX format easily. | 在线转换 Markdown 文件为 DOCX 格式" />
1717
<meta name="twitter:image" content="/icon.svg" />
1818
<meta name="description" content="Convert Markdown files to DOCX format easily." />
1919
</head>
@@ -33,10 +33,8 @@
3333
</div>
3434

3535
<div class="flex items-center space-x-4">
36-
<button id="clear" class="px-3 py-1 text-sm rounded hover:bg-gray-100 cursor-pointer">
37-
38-
</button>
39-
<label for="upload" class="px-3 py-1 text-sm rounded bg-gray-200 hover:bg-gray-100 cursor-pointer flex items-center" title="Upload Markdown file">
36+
<button id="lang-toggle" class="px-3 py-1 text-sm rounded bg-gray-200 hover:bg-gray-100 cursor-pointer">EN</button>
37+
<label for="upload" class="px-3 py-1 rounded bg-gray-200 hover:bg-gray-100 cursor-pointer flex items-center" title="Upload Markdown file">
4038
<svg class="h-5 w-5 mr-2" viewBox="0 0 48 48" fill="none"
4139
xmlns="http://www.w3.org/2000/svg">
4240
<mask maskUnits="userSpaceOnUse" x="0" y="0" width="48" height="48"
@@ -49,22 +47,22 @@
4947
<path d="M23.9917 32V6" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" />
5048
</g>
5149
</svg>
52-
Upload
50+
<span class="lang" data-lang="upload">Upload</span>
5351
<input id="upload" type="file" accept=".md, .markdown, .txt" class="hidden">
5452
</label>
5553
<button id="download" class="px-3 py-1 bg-indigo-600 text-white rounded hover:bg-indigo-700 flex items-center">
5654
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="currentColor" viewBox="0 0 24 24">
5755
<path d="M12 16l4-5h-3v-6h-2v6h-3l4 5zm-8 2v2h16v-2h-16z" />
5856
</svg>
59-
Download Docx
57+
<span class="lang" data-lang="download">Download Docx</span>
6058
</button>
6159

6260
<a href="https://github.com/vace/markdown-docx" target="_blank" class="text-gray-700 hover:text-gray-700 flex items-center bg-gray-200 hover:bg-gray-100 rounded px-3 py-1">
6361
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24">
6462
<path
6563
d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" />
6664
</svg>
67-
<span class="hidden sm:inline-block ml-2 font-semibold">GitHub</span>
65+
<span data-lang="github" class="lang hidden sm:inline-block ml-2 font-semibold">GitHub</span>
6866
</a>
6967
</div>
7068

@@ -80,11 +78,19 @@
8078

8179
<!-- Main content - split view -->
8280
<div class="flex flex-col md:flex-row flex-1 overflow-hidden">
83-
<div class="w-full md:w-1/2 p-2 overflow-auto">
81+
<div class="w-full md:w-1/2 p-2 overflow-auto relative">
8482
<div class="w-full h-full border rounded focus:outline-none focus:ring-2 focus:ring-indigo-500">
8583
<textarea id="markdown-input"
8684
class="w-full h-full p-4 resize-none"
87-
placeholder="Enter your Markdown here..."></textarea>
85+
placeholder="Enter your Markdown here..."
86+
data-placeholder-lang="markdown_placeholder"></textarea>
87+
</div>
88+
<div class="absolute top-4 right-4 z-10">
89+
<button id="clear-markdown" class="p-1 rounded bg-gray-200 hover:bg-gray-300 text-gray-700 focus:outline-none focus:ring-2 focus:ring-indigo-500" title="Clear text">
90+
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
91+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
92+
</svg>
93+
</button>
8894
</div>
8995
</div>
9096
<div class="w-full md:w-1/2 p-2 bg-white">
@@ -95,6 +101,85 @@
95101
</div>
96102
</div>
97103
</div>
104+
105+
<div id="download-setting" class="fixed z-10 inset-0 overflow-y-auto hidden" aria-labelledby="modal-title" role="dialog" aria-modal="true">
106+
<div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
107+
<div class="fixed inset-0 bg-gray-500/80 bg-opacity-75 transition-opacity" aria-hidden="true"></div>
108+
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
109+
<div
110+
class="relative inline-block align-bottom bg-white rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-md sm:w-full sm:p-6">
111+
<div>
112+
<h3 class="text-lg leading-6 font-medium text-gray-900 flex items-center" id="modal-title">
113+
<span class="lang" data-lang="modal_options">Export Options</span>
114+
<span class="text-sm text-gray-500"> (MarkdownDocx v1.0)</span>
115+
<!-- close -->
116+
<button class="ml-auto text-gray-400 hover:text-gray-500 focus:outline-none cursor-pointer" id="close-modal">
117+
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
118+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
119+
</svg>
120+
<span class="sr-only">Close</span>
121+
</button>
122+
</h3>
123+
<div class="mt-3 text-center sm:mt-5">
124+
<form class="mt-2">
125+
<div class="mb-4">
126+
<label for="doc-name" class="block text-sm font-medium text-gray-700 text-left lang" data-lang="filename">Filename</label>
127+
<input type="text" id="doc-name" name="doc-name" class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" placeholder="Document Name" data-placeholder-lang="document_name">
128+
</div>
129+
130+
<div class="mb-4">
131+
<label for="doc-title" class="block text-sm font-medium text-gray-700 text-left lang" data-lang="title">Title</label>
132+
<input type="text" id="doc-title" name="doc-title" class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" placeholder="Document Title" data-placeholder-lang="document_title">
133+
</div>
134+
135+
<div class="mb-4">
136+
<label for="doc-description" class="block text-sm font-medium text-gray-700 text-left lang" data-lang="description">Description</label>
137+
<textarea id="doc-description" name="doc-description" rows="2" class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" placeholder="Document Description" data-placeholder-lang="document_description"></textarea>
138+
</div>
139+
140+
<div class="mt-4 space-y-2">
141+
<div class="flex items-start">
142+
<div class="flex items-center h-5">
143+
<input id="ignore-image" name="ignore-image" type="checkbox" class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded">
144+
</div>
145+
<div class="ml-3 text-sm">
146+
<label for="ignore-image" class="font-medium text-gray-700 lang" data-lang="ignore_images">Ignore Images</label>
147+
</div>
148+
</div>
149+
150+
<div class="flex items-start">
151+
<div class="flex items-center h-5">
152+
<input id="ignore-footnote" name="ignore-footnote" type="checkbox" class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded">
153+
</div>
154+
<div class="ml-3 text-sm">
155+
<label for="ignore-footnote" class="font-medium text-gray-700 lang" data-lang="ignore_footnotes">Ignore Footnotes</label>
156+
</div>
157+
</div>
158+
159+
<div class="flex items-start">
160+
<div class="flex items-center h-5">
161+
<input id="ignore-html" name="ignore-html" type="checkbox" class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded">
162+
</div>
163+
<div class="ml-3 text-sm">
164+
<label for="ignore-html" class="font-medium text-gray-700 lang" data-lang="ignore_html">Ignore HTML</label>
165+
</div>
166+
</div>
167+
</div>
168+
</form>
169+
</div>
170+
</div>
171+
<div class="mt-5 sm:mt-6">
172+
<button
173+
type="button"
174+
id="export-docx"
175+
class="inline-flex justify-center w-full rounded-md border border-transparent shadow-sm px-4 py-2 bg-indigo-600 text-base font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:text-sm">
176+
<span class="lang" data-lang="export_to_docx">Export to DOCX</span>
177+
</button>
178+
</div>
179+
</div>
180+
</div>
181+
</div>
182+
98183
<script type="module" src="/src/main.js"></script>
99184
</body>
100185
</html>

web/src/lang.js

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
export const lang = {
2+
upload: {
3+
zh: '上传',
4+
en: 'Upload',
5+
},
6+
download: {
7+
zh: '下载 Docx',
8+
en: 'Download Docx',
9+
},
10+
github: {
11+
zh: 'GitHub',
12+
en: 'GitHub',
13+
},
14+
modal_options: {
15+
zh: '导出选项',
16+
en: 'Export Options',
17+
},
18+
local_processing: {
19+
zh: '内容不会上传,仅在本地处理。',
20+
en: 'Nothing is uploaded, all processing happens locally.'
21+
},
22+
markdown_placeholder: {
23+
zh: '在此输入 Markdown 内容...',
24+
en: 'Enter your Markdown here...'
25+
},
26+
filename: {
27+
zh: '文件名',
28+
en: 'Filename'
29+
},
30+
title: {
31+
zh: '标题',
32+
en: 'Title'
33+
},
34+
description: {
35+
zh: '描述',
36+
en: 'Description'
37+
},
38+
document_name: {
39+
zh: '文档名称',
40+
en: 'Document Name'
41+
},
42+
document_title: {
43+
zh: '文档标题',
44+
en: 'Document Title'
45+
},
46+
document_description: {
47+
zh: '文档描述',
48+
en: 'Document Description'
49+
},
50+
ignore_images: {
51+
zh: '忽略图片',
52+
en: 'Ignore Images'
53+
},
54+
ignore_footnotes: {
55+
zh: '忽略脚注',
56+
en: 'Ignore Footnotes'
57+
},
58+
ignore_html: {
59+
zh: '忽略 HTML',
60+
en: 'Ignore HTML'
61+
},
62+
export_to_docx: {
63+
zh: '导出到 DOCX',
64+
en: 'Export to DOCX'
65+
}
66+
}
67+
68+
69+
// Initialize language system
70+
export function initLanguage() {
71+
// Get preferred language from localStorage or use browser language
72+
const savedLanguage = localStorage.getItem('preferred_language')
73+
const browserLanguage = navigator.language.startsWith('zh') ? 'zh' : 'en'
74+
const currentLanguage = savedLanguage || browserLanguage
75+
const langToggle = document.getElementById('lang-toggle')
76+
77+
langToggle.addEventListener('click', () => {
78+
const newLang = langToggle.textContent === 'EN' ? 'en' : 'zh'
79+
langToggle.textContent = newLang === 'zh' ? 'EN' : '中'
80+
setLanguage(newLang)
81+
})
82+
// Set initial language
83+
setLanguage(currentLanguage)
84+
return currentLanguage
85+
}
86+
87+
/**
88+
* Updates all language elements in the document based on the current language
89+
* @param {string} language - 'zh' or 'en'
90+
*/
91+
export function updateDocumentLangs(language = 'zh') {
92+
// Update all elements with .lang class
93+
document.querySelectorAll('.lang').forEach(el => {
94+
const key = el.getAttribute('data-lang');
95+
if (key && lang[key] && lang[key][language]) {
96+
el.textContent = lang[key][language];
97+
}
98+
});
99+
100+
// Update placeholders for inputs and textareas
101+
document.querySelectorAll('[data-placeholder-lang]').forEach(el => {
102+
const key = el.getAttribute('data-placeholder-lang');
103+
if (key && lang[key] && lang[key][language]) {
104+
el.placeholder = lang[key][language];
105+
}
106+
});
107+
108+
// Update titles/tooltips with data-title-lang if needed
109+
document.querySelectorAll('[data-title-lang]').forEach(el => {
110+
const key = el.getAttribute('data-title-lang');
111+
if (key && lang[key] && lang[key][language]) {
112+
el.title = lang[key][language];
113+
}
114+
});
115+
}
116+
117+
/**
118+
* Set the current language and update all elements
119+
* @param {string} language - 'zh' or 'en'
120+
*/
121+
export function setLanguage(language = 'zh') {
122+
// Store the language preference
123+
localStorage.setItem('preferred_language', language);
124+
// Update document language attribute
125+
document.documentElement.lang = language === 'zh' ? 'zh-CN' : 'en';
126+
// Update all language elements
127+
updateDocumentLangs(language);
128+
}

web/src/main.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import './style.css'
22
import { initTemplates } from './templates'
33
import { initMarkdown } from './markdown'
44
import { initTools } from './tools'
5+
import { initLanguage } from './lang.js'
56

67
// Initialize app when DOM is loaded
78
document.addEventListener('DOMContentLoaded', () => {
@@ -15,6 +16,7 @@ function createApp(container) {
1516
markdown: null,
1617
templates: null,
1718
tools: null,
19+
lang: initLanguage()
1820
}
1921

2022
// Initialize the editor and preview

0 commit comments

Comments
 (0)