AtCoderStudyBooster 0.4.0__py3-none-any.whl → 0.4.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
atcdr/download.py CHANGED
@@ -11,6 +11,7 @@ from rich import print
11
11
  from rich.prompt import Prompt
12
12
 
13
13
  from atcdr.util.filetype import FILE_EXTENSIONS, Lang
14
+ from atcdr.util.i18n import _, i18n
14
15
  from atcdr.util.parse import ProblemHTML
15
16
  from atcdr.util.problem import Contest, Problem
16
17
  from atcdr.util.session import load_session
@@ -25,32 +26,37 @@ class Downloader:
25
26
  retry_attempts = 3
26
27
  retry_wait = 1 # 1 second
27
28
 
28
- for _ in range(retry_attempts):
29
+ for attempt in range(retry_attempts):
29
30
  response = session.get(problem.url)
30
31
  if response.status_code == 200:
31
32
  return ProblemHTML(response.text)
32
33
  elif response.status_code == 429:
33
34
  print(
34
- f'[bold yellow][Error {response.status_code}][/bold yellow] 再試行します。{problem}'
35
+ f'[bold yellow][Error {response.status_code}][/bold yellow] '
36
+ + _('retry_problem', problem)
35
37
  )
36
38
  time.sleep(retry_wait)
37
39
  elif 300 <= response.status_code < 400:
38
40
  print(
39
- f'[bold yellow][Error {response.status_code}][/bold yellow] リダイレクトが発生しました。{problem}'
41
+ f'[bold yellow][Error {response.status_code}][/bold yellow] '
42
+ + _('redirect_occurred', problem)
40
43
  )
41
44
  elif 400 <= response.status_code < 500:
42
45
  print(
43
- f'[bold red][Error {response.status_code}][/bold red] 問題が見つかりません。{problem}'
46
+ f'[bold red][Error {response.status_code}][/bold red] '
47
+ + _('problem_not_found', problem)
44
48
  )
45
49
  break
46
50
  elif 500 <= response.status_code < 600:
47
51
  print(
48
- f'[bold red][Error {response.status_code}][/bold red] サーバーエラーが発生しました。{problem}'
52
+ f'[bold red][Error {response.status_code}][/bold red] '
53
+ + _('server_error', problem)
49
54
  )
50
55
  break
51
56
  else:
52
57
  print(
53
- f'[bold red][Error {response.status_code}][/bold red] {problem}に対応するHTMLファイルを取得できませんでした。'
58
+ f'[bold red][Error {response.status_code}][/bold red] '
59
+ + _('html_fetch_failed', problem)
54
60
  )
55
61
  break
56
62
  return ProblemHTML('')
@@ -68,7 +74,7 @@ def save_problem(problem: Problem, path: Path, session: requests.Session) -> Non
68
74
  problem_content = downloader.get(problem)
69
75
 
70
76
  if not problem_content:
71
- print(f'[bold red][Error][/] {problem}の保存に失敗しました')
77
+ print('[bold red][Error][/] ' + _('save_failed', problem))
72
78
  return
73
79
 
74
80
  # ディレクトリ作成(pathをそのまま使用)
@@ -80,26 +86,26 @@ def save_problem(problem: Problem, path: Path, session: requests.Session) -> Non
80
86
  # HTMLファイル保存
81
87
  html_path = path / (title + FILE_EXTENSIONS[Lang.HTML])
82
88
  html_path.write_text(problem_content.html, encoding='utf-8')
83
- print(f'[bold green][+][/bold green] ファイルを保存しました: {html_path}')
89
+ print('[bold green][+][/bold green] ' + _('file_saved', html_path))
84
90
 
85
91
  # Markdownファイル保存
86
- md = problem_content.make_problem_markdown('ja')
92
+ md = problem_content.make_problem_markdown(i18n.language)
87
93
  md_path = path / (title + FILE_EXTENSIONS[Lang.MARKDOWN])
88
94
  md_path.write_text(md, encoding='utf-8')
89
- print(f'[bold green][+][/bold green] ファイルを保存しました: {md_path}')
95
+ print('[bold green][+][/bold green] ' + _('file_saved', md_path))
90
96
 
91
97
 
92
98
  def interactive_download(session) -> None:
93
- CONTEST = '1. コンテストの問題を解きたい'
94
- ONE_FILE = '2. 1問だけダウンロードする'
95
- END = '3. 終了する'
99
+ CONTEST = '1. ' + _('solve_contest_problems')
100
+ ONE_FILE = '2. ' + _('download_one_problem')
101
+ END = '3. ' + _('exit')
96
102
 
97
103
  choice = q.select(
98
- message='AtCoderの問題のHTMLファイルをダウンロードします',
104
+ message=_('download_atcoder_html'),
99
105
  qmark='',
100
106
  pointer='❯❯❯',
101
107
  choices=[CONTEST, ONE_FILE, END],
102
- instruction='\n 十字キーで移動,[enter]で実行',
108
+ instruction='\n ' + _('navigate_with_arrows'),
103
109
  style=q.Style(
104
110
  [
105
111
  ('question', 'fg:#2196F3 bold'),
@@ -112,7 +118,7 @@ def interactive_download(session) -> None:
112
118
  ).ask()
113
119
 
114
120
  if choice == CONTEST:
115
- name = Prompt.ask('コンテスト名を入力してください (例: abc012, abs, typical90)')
121
+ name = Prompt.ask(_('input_contest_name'))
116
122
  try:
117
123
  contest = Contest(name, session)
118
124
  for problem in contest.problems:
@@ -121,18 +127,18 @@ def interactive_download(session) -> None:
121
127
  print(f'[red][Error][/red] {e}')
122
128
 
123
129
  elif choice == ONE_FILE:
124
- name = Prompt.ask('コンテスト名を入力してください (例: abc012, abs, typical90)')
130
+ name = Prompt.ask(_('input_contest_name'))
125
131
  try:
126
132
  contest = Contest(name, session)
127
133
  problem = q.select(
128
- message='どの問題をダウンロードしますか?',
134
+ message=_('which_problem_download'),
129
135
  qmark='',
130
136
  pointer='❯❯❯',
131
137
  choices=[
132
138
  q.Choice(title=f'{p.label:10} | {p.url}', value=p)
133
139
  for p in contest.problems
134
140
  ],
135
- instruction='\n 十字キーで移動,[enter]で実行',
141
+ instruction='\n ' + _('navigate_with_arrows'),
136
142
  style=q.Style(
137
143
  [
138
144
  ('question', 'fg:#2196F3 bold'),
@@ -148,9 +154,9 @@ def interactive_download(session) -> None:
148
154
  print(f'[red][Error][/red] {e}')
149
155
 
150
156
  elif choice == END:
151
- print('[bold red]終了します[/]')
157
+ print('[bold red]' + _('exiting') + '[/]')
152
158
  else:
153
- print('[bold red]無効な選択です[/]')
159
+ print('[bold red]' + _('invalid_selection') + '[/]')
154
160
 
155
161
 
156
162
  def plan_download(
@@ -179,7 +185,7 @@ def plan_download(
179
185
  for problem in contest.problems
180
186
  ]
181
187
  else:
182
- raise ValueError('コンテスト名を指定してください')
188
+ raise ValueError(_('specify_contest_name'))
183
189
  elif len(groups) == 2:
184
190
  result = []
185
191
  for i, j in product(groups[0], groups[1]):
@@ -195,16 +201,15 @@ def plan_download(
195
201
  result.append((problem, Path(i) / j.name))
196
202
  return result
197
203
  else:
198
- raise ValueError('ダウンロードの引数が正しくありません')
204
+ raise ValueError(_('invalid_download_args'))
199
205
 
200
206
 
201
- @click.command(short_help='AtCoder の問題をダウンロード')
207
+ @click.command(short_help=_('cmd_download'), help=_('cmd_download'))
202
208
  @click.argument('args', nargs=-1)
203
209
  def download(args: List[str]) -> None:
204
210
  """
205
- 例:
206
- download abc{001..012} {A..C}
207
- download {A..E} abc{001..012}
211
+ download abc{001..012} {A..C}
212
+ download {A..E} abc{001..012}
208
213
  """
209
214
  session = load_session()
210
215
 
atcdr/generate.py CHANGED
@@ -17,6 +17,7 @@ from atcdr.util.filetype import (
17
17
  str2lang,
18
18
  )
19
19
  from atcdr.util.gpt import ChatGPT, Model, set_api_key
20
+ from atcdr.util.i18n import _
20
21
  from atcdr.util.parse import ProblemHTML
21
22
 
22
23
 
@@ -58,21 +59,19 @@ def generate_code(file: Filename, lang: Lang, model: Model) -> None:
58
59
  system_prompt=f"""You are an excellent programmer. You solve problems in competitive programming.When a user provides you with a problem from a programming contest called AtCoder, including the Problem,Constraints, Input, Output, Input Example, and Output Example, please carefully consider these and solve the problem.Make sure that your output code block contains no more than two blocks. Pay close attention to the Input, Input Example, Output, and Output Example.Create the solution in {lang2str(lang)}.""",
59
60
  model=model,
60
61
  )
61
- with console.status(f'コード生成中 (by {gpt.model.value})'):
62
+ with console.status(_('generating_code', gpt.model.value)):
62
63
  reply = gpt.tell(md)
63
64
 
64
65
  code = get_code_from_gpt_output(reply)
65
- console.print('[green][+][/green] コードの生成に成功しました. ')
66
- console.rule(f'{gpt.model.value}による{lang2str(lang)}コード')
66
+ console.print('[green][+][/green] ' + _('code_generation_success'))
67
+ console.rule(_('code_by_model', lang2str(lang), gpt.model.value))
67
68
  console.print(Syntax(code=code, lexer=lang2str(lang)))
68
69
 
69
70
  saved_filename = (
70
71
  os.path.splitext(file)[0] + f'_by_{gpt.model.value}' + FILE_EXTENSIONS[lang]
71
72
  )
72
73
  with open(saved_filename, 'w') as f:
73
- console.print(
74
- f'[green][+][/green] {gpt.model.value} の出力したコードを保存しました:{f.name}'
75
- )
74
+ console.print('[green][+][/green] ' + _('code_saved', gpt.model.value, f.name))
76
75
  f.write(code)
77
76
 
78
77
 
@@ -98,15 +97,13 @@ The user will provide a problem from a programming contest called AtCoder. This
98
97
 
99
98
  You must not solve the problem. Please faithfully reproduce the variable names defined in the problem.
100
99
  """
101
- with console.status(f'{lang2str(lang)}のテンプレートを生成しています...'):
100
+ with console.status(_('generating_template', lang2str(lang))):
102
101
  reply = gpt.tell(md + propmpt)
103
102
  code = get_code_from_gpt_output(reply)
104
103
 
105
104
  savaed_filename = os.path.splitext(file)[0] + FILE_EXTENSIONS[lang]
106
105
  with open(savaed_filename, 'x') as f:
107
- console.print(
108
- f'[green][+][/green] テンプレートファイルを作成 :{savaed_filename}'
109
- )
106
+ console.print('[green][+][/green] ' + _('template_created', savaed_filename))
110
107
  f.write(code)
111
108
 
112
109
 
@@ -128,7 +125,7 @@ def solve_problem(file: Filename, lang: Lang, model: Model) -> None:
128
125
  file_without_ext = os.path.splitext(file)[0]
129
126
 
130
127
  for i in range(1, 4):
131
- with console.status(f'{i}回目のコード生成中 (by {gpt.model.value})'):
128
+ with console.status(_('nth_code_generation', i, gpt.model.value)):
132
129
  if i == 1:
133
130
  test_report = ''
134
131
  reply = gpt.tell(md)
@@ -137,7 +134,7 @@ def solve_problem(file: Filename, lang: Lang, model: Model) -> None:
137
134
  {test_report}
138
135
  Please provide an updated version of the code in {lang2str(lang)}."""
139
136
  console.print(
140
- f'[green][+][/] 次のプロンプトを{gpt.model.value}に与え,再生成します'
137
+ '[green][+][/] ' + _('regenerating_with_prompt', gpt.model.value)
141
138
  )
142
139
  console.print(Panel(prompt))
143
140
  reply = gpt.tell(prompt)
@@ -151,11 +148,11 @@ Please provide an updated version of the code in {lang2str(lang)}."""
151
148
  + FILE_EXTENSIONS[lang]
152
149
  )
153
150
  with open(saved_filename, 'w') as f:
154
- console.print(f'[green][+][/] コードの生成に成功しました!:{f.name}')
151
+ console.print('[green][+][/] ' + _('code_generation_success_file', f.name))
155
152
  f.write(code)
156
153
 
157
154
  with console.status(
158
- f'{gpt.model.value}が生成したコードをテスト中', spinner='circleHalves'
155
+ _('testing_generated_code', gpt.model.value), spinner='circleHalves'
159
156
  ):
160
157
  test = TestRunner(saved_filename, labeled_cases)
161
158
  test_report, is_ac = render_result_for_GPT(test)
@@ -163,10 +160,10 @@ Please provide an updated version of the code in {lang2str(lang)}."""
163
160
  console.print(create_renderable_test_info(test.info))
164
161
 
165
162
  if is_ac:
166
- console.print('[green][+][/] コードのテストに成功!')
163
+ console.print('[green][+][/] ' + _('test_success'))
167
164
  break
168
165
  else:
169
- console.print('[red][-][/] コードのテストに失敗!')
166
+ console.print('[red][-][/] ' + _('test_failed'))
170
167
 
171
168
  with open(
172
169
  'log_'
@@ -175,19 +172,17 @@ Please provide an updated version of the code in {lang2str(lang)}."""
175
172
  + FILE_EXTENSIONS[Lang.JSON],
176
173
  'w',
177
174
  ) as f:
178
- console.print(
179
- f'[green][+][/] {gpt.model.value}の出力のログを保存しました:{f.name}'
180
- )
175
+ console.print('[green][+][/] ' + _('log_saved', gpt.model.value, f.name))
181
176
  f.write(json.dumps(gpt.messages, indent=2))
182
177
  return
183
178
 
184
179
 
185
- @click.command(short_help='コードを生成')
180
+ @click.command(short_help=_('cmd_generate'), help=_('cmd_generate'))
186
181
  @add_file_selector('files', filetypes=[Lang.HTML])
187
- @click.option('--lang', default='Python', help='出力するプログラミング言語')
188
- @click.option('--model', default=Model.GPT41_MINI.value, help='使用するGPTモデル')
189
- @click.option('--without-test', is_flag=True, help='テストケースを省略して生成')
190
- @click.option('--template', is_flag=True, help='テンプレートを生成')
182
+ @click.option('--lang', default='Python', help=_('opt_output_lang'))
183
+ @click.option('--model', default=Model.GPT41_MINI.value, help=_('opt_model'))
184
+ @click.option('--without-test', is_flag=True, help=_('opt_without_test'))
185
+ @click.option('--template', is_flag=True, help=_('opt_template'))
191
186
  def generate(files, lang, model, without_test, template):
192
187
  """HTMLファイルからコード生成またはテンプレート出力を行います。"""
193
188
  la = str2lang(lang)
atcdr/login.py CHANGED
@@ -6,6 +6,7 @@ import webview
6
6
  from requests import Session
7
7
  from rich.console import Console
8
8
 
9
+ from atcdr.util.i18n import _
9
10
  from atcdr.util.session import load_session, save_session, validate_session
10
11
 
11
12
  ATCODER_LOGIN_URL = 'https://atcoder.jp/login'
@@ -14,17 +15,17 @@ ATCODER_HOME_URL = 'https://atcoder.jp/home'
14
15
  console = Console()
15
16
 
16
17
 
17
- @click.command(short_help='AtCoderへログイン')
18
+ @click.command(short_help=_('cmd_login'), help=_('cmd_login'))
18
19
  def login() -> None:
19
20
  """AtCoderへログインします."""
20
21
  session = load_session()
21
22
  if validate_session(session):
22
- console.print('[green][+][/] すでにログインしています. ')
23
+ console.print('[green][+][/] ' + _('already_logged_in'))
23
24
  return
24
25
 
25
26
  # Prompt in CLI
26
- username = console.input('[cyan]ユーザー名: [/]').strip()
27
- password = console.input('[cyan]パスワード: [/]').strip()
27
+ username = console.input('[cyan]' + _('username') + '[/]').strip()
28
+ password = console.input('[cyan]' + _('password') + '[/]').strip()
28
29
 
29
30
  window = webview.create_window('AtCoder Login', ATCODER_LOGIN_URL, hidden=False)
30
31
 
@@ -36,16 +37,14 @@ def login() -> None:
36
37
  window.evaluate_js(js_fill)
37
38
 
38
39
  def poll_and_submit():
39
- with console.status(
40
- 'キャプチャー認証を解決してください', spinner='circleHalves'
41
- ):
40
+ with console.status(_('solve_captcha'), spinner='circleHalves'):
42
41
  while True:
43
42
  try:
44
43
  token = window.evaluate_js(
45
44
  'document.querySelector(\'input[name=\\"cf-turnstile-response\\"]\').value'
46
45
  )
47
46
  if token:
48
- console.print('[green][+][/] ログインします')
47
+ console.print('[green][+][/] ' + _('logging_in'))
49
48
  window.evaluate_js(
50
49
  "document.getElementById('submit').click();"
51
50
  )
@@ -55,7 +54,7 @@ def login() -> None:
55
54
 
56
55
  time.sleep(0.5)
57
56
 
58
- with console.status('ログインの結果の待機中...', spinner='circleHalves'):
57
+ with console.status(_('waiting_login_result'), spinner='circleHalves'):
59
58
  while True:
60
59
  try:
61
60
  current_url = window.get_current_url()
@@ -63,7 +62,7 @@ def login() -> None:
63
62
  current_url = None
64
63
 
65
64
  if current_url and current_url.startswith(ATCODER_HOME_URL):
66
- console.print('[green][+][/] ログイン成功!')
65
+ console.print('[green][+][/] ' + _('login_success'))
67
66
 
68
67
  session = Session()
69
68
  session = move_cookies_from_webview_to_session(window, session)
@@ -82,7 +81,7 @@ def login() -> None:
82
81
  err = ''
83
82
 
84
83
  if err:
85
- console.print(f'[red][-][/] エラー: {err}')
84
+ console.print('[red][-][/] ' + _('error', err))
86
85
  session = Session()
87
86
  session = move_cookies_from_webview_to_session(window, session)
88
87
  save_session(session)
atcdr/logout.py CHANGED
@@ -2,21 +2,22 @@ import rich_click as click
2
2
  import webview
3
3
  from rich import print
4
4
 
5
+ from atcdr.util.i18n import _
5
6
  from atcdr.util.session import delete_session, load_session, validate_session
6
7
 
7
8
  ATCODER_LOGIN_URL = 'https://atcoder.jp/login'
8
9
 
9
10
 
10
- @click.command(short_help='AtCoderへログアウト')
11
+ @click.command(short_help=_('cmd_logout'), help=_('cmd_logout'))
11
12
  def logout() -> None:
12
13
  """AtCoderからログアウトします."""
13
14
  session = load_session()
14
15
  if not validate_session(session):
15
- print('[red][-][/] ログインしていません.')
16
+ print('[red][-][/] ' + _('not_logged_in'))
16
17
  return
17
18
 
18
19
  delete_session()
19
- print('[green][+][/] ログアウトしました.')
20
+ print('[green][+][/] ' + _('logout_success'))
20
21
 
21
22
  window = webview.create_window('AtCoder Logout', ATCODER_LOGIN_URL, hidden=True)
22
23
 
atcdr/markdown.py CHANGED
@@ -6,6 +6,7 @@ from rich.markdown import Markdown
6
6
 
7
7
  from atcdr.util.fileops import add_file_selector
8
8
  from atcdr.util.filetype import FILE_EXTENSIONS, Lang
9
+ from atcdr.util.i18n import _, i18n
9
10
  from atcdr.util.parse import ProblemHTML
10
11
 
11
12
 
@@ -19,7 +20,7 @@ def save_markdown(html_path: str, lang: str) -> None:
19
20
 
20
21
  with open(md_path, 'w', encoding='utf-8') as f:
21
22
  f.write(md)
22
- console.print('[green][+][/green] Markdownファイルを作成しました.')
23
+ console.print('[green][+][/green] ' + _('markdown_created'))
23
24
 
24
25
 
25
26
  def print_markdown(html_path: str, lang: str) -> None:
@@ -30,12 +31,15 @@ def print_markdown(html_path: str, lang: str) -> None:
30
31
  console.print(Markdown(md))
31
32
 
32
33
 
33
- @click.command(short_help='Markdown形式で問題を表示します')
34
+ @click.command(short_help=_('cmd_markdown'), help=_('cmd_markdown'))
34
35
  @add_file_selector('files', filetypes=[Lang.HTML])
35
- @click.option('--lang', default='ja', help='出力する言語を指定')
36
- @click.option('--save', is_flag=True, help='変換結果をファイルに保存')
36
+ @click.option('--lang', default=None, help=_('opt_lang'))
37
+ @click.option('--save', is_flag=True, help=_('opt_save'))
37
38
  def markdown(files, lang, save):
38
- """Markdown形式で問題を表示します"""
39
+ """問題をMarkdown形式で表示します"""
40
+ # langが指定されていない場合は現在のロケールを使用
41
+ if lang is None:
42
+ lang = i18n.language
39
43
  for path in files:
40
44
  if save:
41
45
  save_markdown(path, lang)
atcdr/open.py CHANGED
@@ -2,6 +2,7 @@ import webbrowser # noqa: I001
2
2
  from rich.panel import Panel
3
3
  from rich.console import Console
4
4
 
5
+ from atcdr.util.i18n import _
5
6
  from atcdr.util.filetype import Lang
6
7
  from atcdr.util.fileops import add_file_selector
7
8
  import rich_click as click
@@ -16,7 +17,7 @@ def open_html(file: str) -> None:
16
17
  except FileNotFoundError:
17
18
  console.print(
18
19
  Panel(
19
- f"{file}' [red]が見つかりません[/]",
20
+ f"{file}' [red]" + _('not_found') + '[/]',
20
21
  border_style='red',
21
22
  )
22
23
  )
@@ -27,20 +28,20 @@ def open_html(file: str) -> None:
27
28
  webbrowser.open_new_tab(url)
28
29
  console.print(
29
30
  Panel(
30
- f'[green]URLを開きました[/] {url}',
31
+ '[green]' + _('url_opened') + f'[/] {url}',
31
32
  border_style='green',
32
33
  )
33
34
  )
34
35
  else:
35
36
  console.print(
36
37
  Panel(
37
- f'{file} [yellow]にURLが見つかりませんでした[/]',
38
+ f'{file} [yellow]' + _('url_not_found_in') + '[/]',
38
39
  border_style='yellow',
39
40
  )
40
41
  )
41
42
 
42
43
 
43
- @click.command(short_help='HTMLファイルを開く')
44
+ @click.command(short_help=_('cmd_open'), help=_('cmd_open'))
44
45
  @add_file_selector('files', filetypes=[Lang.HTML])
45
46
  def open_files(files):
46
47
  """指定したHTMLファイルをブラウザで開きます。"""
atcdr/submit.py CHANGED
@@ -29,6 +29,7 @@ from atcdr.util.filetype import (
29
29
  lang2str,
30
30
  str2lang,
31
31
  )
32
+ from atcdr.util.i18n import _
32
33
  from atcdr.util.parse import ProblemHTML, get_submission_id
33
34
  from atcdr.util.session import load_session, validate_session
34
35
 
@@ -61,14 +62,14 @@ def choose_langid_interactively(lang_dict: dict, lang: Lang) -> int:
61
62
  options = [*filter(lambda option: option.lang == lang, options)]
62
63
 
63
64
  langid = q.select(
64
- message=f'以下の一覧から{lang2str(lang)}の実装/コンパイラーを選択してください',
65
+ message=_('select_implementation', lang2str(lang)),
65
66
  qmark='',
66
67
  pointer='❯❯❯',
67
68
  choices=[
68
69
  q.Choice(title=f'{option.display_name}', value=option.id)
69
70
  for option in options
70
71
  ],
71
- instruction='\n 十字キーで移動,[enter]で実行',
72
+ instruction='\n ' + _('navigate_with_arrows'),
72
73
  style=q.Style(
73
74
  [
74
75
  ('question', 'fg:#2196F3 bold'),
@@ -136,24 +137,24 @@ def post_source(source_path: str, url: str, session: requests.Session) -> Option
136
137
 
137
138
  window.events.loaded += on_loaded
138
139
 
139
- with Status('キャプチャー認証を解決してください', spinner='circleHalves'):
140
+ with Status(_('solve_captcha'), spinner='circleHalves'):
140
141
  webview.start(private_mode=False)
141
142
 
142
143
  if 'submit' in api.url:
143
- print('[red][-][/red] 提出に失敗しました')
144
+ print('[red][-][/red] ' + _('submission_failed'))
144
145
  return None
145
146
  elif 'submissions' in api.url:
146
147
  submission_id = get_submission_id(api.html)
147
148
  if not submission_id:
148
- print('[red][-][/red] 提出IDが取得できませんでした')
149
+ print('[red][-][/red] ' + _('submission_id_not_found'))
149
150
  return None
150
151
 
151
152
  url = api.url.replace('/me', f'/{submission_id}')
152
- print('[green][+][/green] 提出に成功しました!')
153
- print(f'提出ID: {submission_id}, URL: {url}')
153
+ print('[green][+][/green] ' + _('submission_success'))
154
+ print(_('submission_details', submission_id, url))
154
155
  return url + '/status/json'
155
156
  else:
156
- print('[red][-][/red] 提出に失敗しました')
157
+ print('[red][-][/red] ' + _('submission_failed'))
157
158
  return None
158
159
 
159
160
 
@@ -211,19 +212,19 @@ def print_status_submission(
211
212
  BarColumn(),
212
213
  )
213
214
 
214
- with Status('ジャッジ待機中', spinner='dots'):
215
- for _ in range(15):
215
+ with Status(_('waiting_judge'), spinner='dots'):
216
+ for i in range(15):
216
217
  time.sleep(1)
217
218
  data = session.get(api_url).json()
218
219
  status = parse_submission_status_json(data)
219
220
  if status.total or status.current:
220
221
  break
221
222
  else:
222
- print('[red][-][/] 15秒待ってもジャッジが開始されませんでした')
223
+ print('[red][-][/] ' + _('judge_timeout'))
223
224
  return
224
225
 
225
226
  total = status.total or 0
226
- task_id = progress.add_task(description='ジャッジ中', total=total)
227
+ task_id = progress.add_task(description=_('judging'), total=total)
227
228
 
228
229
  test_info = TestInformation(
229
230
  lang=detect_language(path),
@@ -248,24 +249,22 @@ def print_status_submission(
248
249
  test_info.summary = status.status
249
250
  test_info.results = [ResultStatus.AC] * total
250
251
 
251
- progress.update(task_id, description='ジャッジ完了', completed=total)
252
+ progress.update(task_id, description=_('judge_completed'), completed=total)
252
253
  live.update(create_renderable_test_info(test_info, progress))
253
254
 
254
255
 
255
256
  def submit_source(path: str, no_test: bool, no_feedback: bool) -> None:
256
257
  session = load_session()
257
258
  if not validate_session(session):
258
- print('[red][-][/] ログインしていません.')
259
+ print('[red][-][/] ' + _('not_logged_in'))
259
260
  login()
260
261
  if not validate_session(session):
261
- print('[red][-][/] ログインに失敗しました.')
262
+ print('[red][-][/] ' + _('login_failed'))
262
263
  return
263
264
 
264
265
  html_files = [file for file in os.listdir('.') if file.endswith('.html')]
265
266
  if not html_files:
266
- print(
267
- '問題のファイルが見つかりません \n問題のファイルが存在するディレクトリーに移動してから実行してください'
268
- )
267
+ print(_('problem_file_not_found'))
269
268
  return
270
269
 
271
270
  with open(html_files[0], 'r') as file:
@@ -279,7 +278,7 @@ def submit_source(path: str, no_test: bool, no_feedback: bool) -> None:
279
278
  print(create_renderable_test_info(test.info))
280
279
 
281
280
  if test.info.summary != ResultStatus.AC and not no_test:
282
- print('[red][-][/] サンプルケースが AC していないので提出できません')
281
+ print('[red][-][/] ' + _('sample_not_ac'))
283
282
  return
284
283
 
285
284
  api_status_link = post_source(path, url, session)
@@ -290,12 +289,10 @@ def submit_source(path: str, no_test: bool, no_feedback: bool) -> None:
290
289
  print_status_submission(api_status_link, path, session)
291
290
 
292
291
 
293
- @click.command(short_help='ソースを提出')
292
+ @click.command(short_help=_('cmd_submit'), help=_('cmd_submit'))
294
293
  @add_file_selector('files', filetypes=COMPILED_LANGUAGES + INTERPRETED_LANGUAGES)
295
- @click.option('--no-test', is_flag=True, default=False, help='テストをスキップ')
296
- @click.option(
297
- '--no-feedback', is_flag=True, default=False, help='フィードバックをスキップ'
298
- )
294
+ @click.option('--no-test', is_flag=True, default=False, help=_('opt_no_test'))
295
+ @click.option('--no-feedback', is_flag=True, default=False, help=_('opt_no_feedback'))
299
296
  def submit(files, no_test, no_feedback):
300
297
  """指定したファイルをAtCoderへ提出します。"""
301
298
  for path in files: