Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit8cf85f4

Browse files
committed
Set up frontend translations
1 parent8e55e3f commit8cf85f4

File tree

14 files changed

+386
-155
lines changed

14 files changed

+386
-155
lines changed

‎core/generate_static_files.py‎

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,22 @@
2525
frompathlibimportPath
2626

2727
importbirdseye
28-
fromlittleutilsimportstrip_required_prefix,json_to_file
28+
fromlittleutilsimportstrip_required_prefix,json_to_file,file_to_json
29+
frommarkdownimportmarkdown
2930

3031
fromcoreimporttranslationast
3132
fromcore.checkerimportcheck_entry
3233
fromcore.runner.utilsimportsite_packages
3334
fromcore.textimportget_pages,step_test_entries,load_chapters
35+
fromcore.utilsimportunwrapped_markdown
3436

3537
str("import sentry_sdk after core.utils for stubs")
3638
importsentry_sdk# noqa imported lazily
3739

40+
this_dir=Path(__file__).parent
41+
frontend=this_dir/"../frontend"
42+
frontend_src=frontend/"src"
43+
3844

3945
defrun_steps():
4046
for*_,entryinstep_test_entries():
@@ -78,16 +84,23 @@ def tarfile_filter(tar_info):
7884
returntar_info
7985

8086

87+
deffrontend_terms():
88+
forkey,valueinfile_to_json(frontend_src/"english_terms.json").items():
89+
translation=t.get(f"frontend.{key}",value)
90+
if"\n"intranslation:
91+
value=markdown(translation)
92+
else:
93+
value=unwrapped_markdown(translation)
94+
yieldkey,value
95+
96+
8197
defmain():
8298
print("Generating files...")
8399
t.set_language(os.environ.get("FUTURECODER_LANGUAGE","en"))
84-
this_dir=Path(__file__).parent
85-
frontend=this_dir/"../frontend"
86-
frontend_src=frontend/"src"
87100

88-
chapters=list(load_chapters())
101+
json_to_file(list(load_chapters()),frontend_src/"chapters.json")
89102
json_to_file(get_pages(),frontend_src/"book/pages.json.load_by_url")
90-
json_to_file(chapters,frontend_src/"chapters.json")
103+
json_to_file(dict(frontend_terms()),frontend_src/"terms.json")
91104

92105
birdseye_dest=frontend/"public/birdseye"
93106
shutil.rmtree(birdseye_dest,ignore_errors=True)

‎core/markdown_extensions.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def run(self, root):
4343
ifcopyable:
4444
node.append(
4545
etree.fromstring(
46-
f'<button>{t.Terms.copy_button}</button>'
46+
f'<buttonx x-first x-last"> copy-button">{t.Terms.copy_button}</button>'
4747
)
4848
)
4949
node.set("class",node.get("class","")+" copyable")

‎frontend/src/App.js‎

Lines changed: 31 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import {interrupt, runCode, terminalRef} from "./RunCode";
4545
importfirebasefrom"firebase/app";
4646
import{TableOfContents}from"./TableOfContents";
4747
importHeaderLoginInfofrom"./components/HeaderLoginInfo";
48+
import*astermsfrom"./terms.json"
4849

4950

5051
constEditorButtons=(
@@ -64,15 +65,15 @@ const EditorButtons = (
6465
className="btn btn-danger"
6566
onClick={()=>interrupt()}
6667
>
67-
<FontAwesomeIconicon={faStop}/>Stop
68+
<FontAwesomeIconicon={faStop}/>{terms.stop}
6869
</button>
6970
:
7071
<button
7172
disabled={disabled}
7273
className="btn btn-primary"
7374
onClick={()=>runCode({source:"editor"})}
7475
>
75-
<FontAwesomeIconicon={faPlay}/>Run
76+
<FontAwesomeIconicon={faPlay}/>{terms.run}
7677
</button>
7778
}
7879

@@ -144,7 +145,7 @@ const EditorButtons = (
144145
{showQuestionButton&&!disabled&&
145146
<aclassName="btn btn-success"
146147
href={"#question"}>
147-
<FontAwesomeIconicon={faQuestionCircle}/>Ask for help
148+
<FontAwesomeIconicon={faQuestionCircle}/>{terms.ask_for_help}
148149
</a>}
149150
</div>;
150151

@@ -200,42 +201,11 @@ const QuestionWizard = (
200201
expectedOutput,
201202
})=>
202203
<>
203-
<h1>Question Wizard</h1>
204-
<p>
205-
If you need help, there are many sites like
206-
{" "}<atarget="_blank"rel="noreferrer"href="https://stackoverflow.com/">Stack Overflow</a>{" "}
207-
and<atarget="_blank"rel="noreferrer"href="https://www.reddit.com/r/learnpython/">reddit</a> where
208-
you can ask questions.
209-
This is a tool to help you write a good quality question that is likely to get answers.
210-
</p>
211-
<p>
212-
Enter and run your code on the right. If you don't have any code because you don't know where to get started,
213-
I'm afraid this tool can't help you. You can still ask for help, but it might be good to first
214-
read<atarget="_blank"rel="noreferrer"
215-
href="https://stackoverflow.com/help/dont-ask">What types of questions should I avoid asking?</a>
216-
</p>
217-
<p>
218-
If your question is about servers (e.g. Django or Flask), web requests, databases, or a package that can't be
219-
imported here, then this tool won't work. However, just because your current code<em>involves</em> those things,
220-
that doesn't mean that's what your question is<em>about</em>. If you're having a general
221-
Python/programming/logic problem, then extract that problem from the other stuff.
222-
Python with Django is still Python. If you can't do that, then
223-
read<atarget="_blank"rel="noreferrer"
224-
href="https://stackoverflow.com/help/minimal-reproducible-example">
225-
How to create a Minimal, Reproducible Example</a> before
226-
asking your question.
227-
</p>
204+
<h1>{terms.question_wizard}</h1>
205+
<divdangerouslySetInnerHTML={{__html:terms.question_wizard_intro}}/>
228206
<hr/>
229207
{requestExpectedOutput&&<>
230-
<p>
231-
Good, now enter the output you expect/want from your program below.
232-
What would it show if it worked correctly?
233-
If it's not supposed to output anything, then add some<code>print()</code> calls to your
234-
code so that it would output something useful.
235-
</p>
236-
<p>
237-
When you're done, click 'Run' again to generate your question.
238-
</p>
208+
<divdangerouslySetInnerHTML={{__html:terms.question_wizard_expected_output}}/>
239209
<AceEditor
240210
onChange={value=>bookSetState("questionWizard.expectedOutput",value)}
241211
theme={"monokai"}
@@ -273,10 +243,10 @@ const Markdown = (
273243
onClick={(event)=>{
274244
// https://stackoverflow.com/questions/54109790/how-to-add-onclick-event-to-a-string-rendered-by-dangerouslysetinnerhtml-in-reac
275245
constbutton=event.target.closest("button");
276-
if(button&&event.currentTarget.contains(button)&&button.textContent==="Copy"){
246+
if(button&&event.currentTarget.contains(button)&&button.classList.contains("copy-button")){
277247
constcodeElement=button.closest("code");
278248
letcodeText=codeElement.textContent;
279-
codeText=codeText.substring(0,codeText.length-"\nCopy".length);
249+
codeText=codeText.substring(0,codeText.length-1-button.textContent.length);
280250
copyFunc(codeText);
281251
}
282252
}}
@@ -309,13 +279,13 @@ const CourseText = (
309279
{page.index>0&&
310280
<buttonclassName="btn btn-primary previous-button"
311281
onClick={()=>movePage(-1)}>
312-
Previous
282+
{terms.previous}
313283
</button>}
314284
{" "}
315285
{page.index<Object.keys(pages).length-1&&step_index===page.steps.length-1&&
316286
<buttonclassName="btn btn-success next-button"
317287
onClick={()=>movePage(+1)}>
318-
Next
288+
{terms.next}
319289
</button>}
320290
</div>
321291
<br/>
@@ -377,7 +347,7 @@ class AppComponent extends React.Component {
377347
<HeaderLoginInfoemail={user.email}/>
378348
</span>
379349
<aclassName="nav-item nav-link"href="#toc">
380-
<FontAwesomeIconicon={faListOl}/>Table of Contents
350+
<FontAwesomeIconicon={faListOl}/>{terms.table_of_contents}
381351
</a>
382352
</nav>
383353

@@ -448,9 +418,9 @@ const StepButton = ({delta, label}) =>
448418

449419
constStepButtons=()=>
450420
<divstyle={{position:"fixed",bottom:0}}>
451-
<StepButtondelta={-1}label="Reverse step"/>
421+
<StepButtondelta={-1}label={terms.reverse_step}/>
452422
{" "}
453-
<StepButtondelta={+1}label="Skip step"/>
423+
<StepButtondelta={+1}label={terms.skip_step}/>
454424
</div>
455425

456426

@@ -462,21 +432,22 @@ const MenuPopup = ({user}) =>
462432
</button>}
463433
>
464434
{close=><divclassName="menu-popup">
465-
<p><button
466-
className="btn btn-danger"
467-
onClick={()=>{
468-
close();
469-
bookSetState("user.uid",null)
470-
firebase.auth().signOut();
471-
}}
472-
>
473-
<FontAwesomeIconicon={faSignOutAlt}/> Sign out
474-
</button></p>
435+
<p>
436+
<button
437+
className="btn btn-danger"
438+
onClick={()=>{
439+
close();
440+
bookSetState("user.uid",null)
441+
firebase.auth().signOut();
442+
}}
443+
>
444+
<FontAwesomeIconicon={faSignOutAlt}/>{terms.sign_out}
445+
</button></p>
475446
<p>
476447
<Popup
477448
trigger={
478449
<buttonclassName="btn btn-primary">
479-
<FontAwesomeIconicon={faCog}/>Settings
450+
<FontAwesomeIconicon={faCog}/>{terms.settings}
480451
</button>
481452
}
482453
modal
@@ -489,7 +460,7 @@ const MenuPopup = ({user}) =>
489460
<Popup
490461
trigger={
491462
<buttonclassName="btn btn-success">
492-
<FontAwesomeIconicon={faBug}/>Feedback
463+
<FontAwesomeIconicon={faBug}/>{terms.feedback}
493464
</button>
494465
}
495466
modal
@@ -505,17 +476,17 @@ const MenuPopup = ({user}) =>
505476

506477
constSettingsModal=({user})=>(
507478
<divclassName="settings-modal">
508-
<h1>Settings</h1>
479+
<h1>{terms.settings}</h1>
509480
<br/>
510481
<label>
511482
<Toggle
512483
defaultChecked={user.developerMode}
513484
onChange={(e)=>setDeveloperMode(e.target.checked)}
514485
/>
515-
<b>Developer mode</b>
486+
<b>{terms.developer_mode}</b>
516487
</label>
517488

518-
<p>Enables the "Reverse step" and "Skip step" buttons.</p>
489+
<p>{terms.developer_mode_description}</p>
519490
</div>
520491
)
521492

@@ -531,22 +502,7 @@ const checkCopy = () => {
531502
])
532503
.some((node)=>node&&!node.classList.contains("copyable"))
533504
){
534-
addMessage(`
535-
<div>
536-
<p><strong>STOP!</strong></p>
537-
<p>
538-
Try to avoid copy pasting code. You will learn, absorb, and remember better if you
539-
type in the code yourself.
540-
</p>
541-
<p>
542-
When copying is appropriate, there will be a button to click to make it easy.
543-
If there's no button, try typing.
544-
</p>
545-
<p>
546-
Having said that, we're not going to force you. Copy if you really want to.
547-
</p>
548-
</div>
549-
`);
505+
addMessage(terms.copy_warning);
550506
}
551507
}
552508

‎frontend/src/Feedback.js‎

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import Popup from "reactjs-popup";
55
import_from"lodash";
66
import{bookSetState,bookState}from"./book/store";
77
importaxiosfrom"axios";
8+
import*astermsfrom"./terms.json"
89

910

1011
exportconstFeedbackModal=({close, error})=>{
@@ -13,14 +14,10 @@ export const FeedbackModal = ({close, error}) => {
1314
initialTitle=error.title;
1415
descriptionExtra="\n\n```"+error.details+"```";
1516
instructions=<>
16-
<h3>Report error</h3>
17-
<p>
18-
Oops, something went wrong!
19-
Please describe what you were just doing and what steps someone can take
20-
to reproduce the problem, then click Submit. Or click Cancel to not send a report.
21-
</p>
17+
<h3>{terms.report_error}</h3>
18+
<p>{terms.report_error_instructions}</p>
2219
<details>
23-
<summary>Click for error details</summary>
20+
<summary>{terms.click_for_error_details}</summary>
2421
<pre>{error.details}</pre>
2522
</details>
2623

@@ -29,33 +26,28 @@ export const FeedbackModal = ({close, error}) => {
2926
initialTitle="";
3027
descriptionExtra="";
3128
instructions=<>
32-
<h3>Give feedback</h3>
33-
<p>Tell us what you like or don't like! If you're reporting a bug, give a detailed description of the problem:</p>
34-
<ul>
35-
<li>What were you doing before and when the problem occurred?</li>
36-
<li>What steps can someone take to reproduce it?</li>
37-
<li>What do you observe happening, and what do you expect to happen instead?</li>
38-
</ul>
29+
<h3>{terms.give_feedback}</h3>
30+
<divdangerouslySetInnerHTML={{__html:terms.give_feedback_instructions}}/>
3931
</>
4032
}
4133
constemail=useInput(bookState.user.email||"",{
42-
placeholder:'Email (optional, publicly visible)',
34+
placeholder:terms.feedback_email_placeholder,
4335
type:'text',
4436
className:'form-control',
4537
style:{
4638
width:"100%",
4739
},
4840
});
4941
consttitle=useInput(initialTitle,{
50-
placeholder:'Title',
42+
placeholder:terms.title,
5143
type:'text',
5244
className:'form-control',
5345
style:{
5446
width:"100%",
5547
},
5648
});
5749
constdescription=useInput('',{
58-
placeholder:'Description',
50+
placeholder:terms.description,
5951
className:'form-control',
6052
style:{
6153
width:"100%",
@@ -110,34 +102,34 @@ ${JSON.stringify(state)}
110102
close();
111103
}}
112104
>
113-
Submit
105+
{terms.submit}
114106
</button>
115107

116108
<button
117109
className="btn btn-default"
118110
onClick={close}
119111
>
120-
Cancel
112+
{terms.cancel}
121113
</button>
122114
</div>
123115
<br/>
124116
<br/>
125117
<div>
126-
Alternatively, you can contact us directly:
118+
{terms.contact_directly}
127119
<ul>
128120
<li>
129121
<ahref="mailto:hello@futurecoder.io">
130-
Email hello@futurecoder.io
122+
{terms.send_email_to} hello@futurecoder.io
131123
</a>
132124
</li>
133125
<li>
134126
<ahref="https://github.com/alexmojaki/futurecoder/issues/new">
135-
Open an issue on GitHub
127+
{terms.open_github_issue}
136128
</a>
137129
</li>
138130
<li>
139131
<ahref="https://join.slack.com/t/futurecoder/shared_invite/zt-tp8cmwra-CbdEeX9u3k1VyoMLDupAeQ">
140-
Chat on Slack
132+
{terms.chat_on_slack}
141133
</a>
142134
</li>
143135
</ul>

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp