flutter: 其余中文全部国际化

支持英文界面。
所有中文注释删除。
This commit is contained in:
Calcitem 2020-11-29 15:56:14 +08:00
parent 10c4fe1c47
commit 564de203ac
17 changed files with 419 additions and 180 deletions

View File

@ -30,7 +30,7 @@ jobs:
run: flutter --version
- name: Install dependencies
run: cd src/ui/flutter; flutter pub get
run: cd src/ui/flutter; flutter pub get; flutter pub global activate intl_utils; flutter --no-color pub global run intl_utils:generate
# Uncomment this step to verify the use of 'dart format' on each commit.
# - name: Verify formatting

View File

@ -230,7 +230,6 @@ Value search(Position *pos, Sanmill::Stack<Position> &ss, Depth depth, Depth ori
#endif
#ifdef ENDGAME_LEARNING
// 检索残局库
Endgame endgame;
if (gameOptions.getLearnEndgameEnabled() &&
@ -269,7 +268,7 @@ Value search(Position *pos, Sanmill::Stack<Position> &ss, Depth depth, Depth ori
bestValue = probeVal;
#if 0
// TODO: 有必要针对深度微调 value?
// TODO: Need adjust value?
if (position->turn == BLACK)
bestValue += tte.depth - depth;
else

View File

@ -18,5 +18,237 @@
"humanVsCloud": "Human Vs Cloud",
"@humanVsCloud": {
"description": "Human Vs Cloud"
},
"gameRecord": "Game Record",
"@gameRecord": {
"description": "Game Record"
},
"noGameRecord": "No record",
"@noGameRecord": {
"description": "No record"
},
"ok": "OK",
"@ok": {
"description": "OK"
},
"cancel": "Cancel",
"@cancel": {
"description": "Cancel"
},
"daSanQi": "Da San Qi",
"@daSanQi": {
"description": "Da San Qi"
},
"copyright": "Copyright © 2019-2020 The Sanmill Authors",
"@copyright": {
"description": "Copyright"
},
"gameWarning": "",
"@gameWarning": {
"description": "Game Warning"
},
"tipSelectWrong": "Select wrong piece",
"@tipSelectWrong": {
"description": "Select wrong piece"
},
"tipPlace": "Please place",
"@tipPlace": {
"description": "Please place"
},
"tipBanPlace": "Cannot place here",
"@tipBanPlace": {
"description": "Cannot place here"
},
"tipPlaced": "Placed",
"@tipPlaced": {
"description": "Placed"
},
"tipRemove": "Please remove",
"@tipRemove": {
"description": "Please remove"
},
"tipBanRemove": "Cannot remove",
"@tipBanRemove": {
"description": "Cannot remove"
},
"tipRemoved": "Removed",
"@tipRemoved": {
"description": "Removed"
},
"tipMove": "Please move",
"@tipMove": {
"description": "Please move"
},
"blackWin": "Black win",
"@blackWin": {
"description": "Black win"
},
"whiteWin": "White win",
"@whiteWin": {
"description": "White win"
},
"draw": "Draw",
"@draw": {
"description": "Draw"
},
"thinking": "Thinking ...",
"@thinking": {
"description": "Thinking ..."
},
"newGame": "New Game",
"@newGame": {
"description": "New Game"
},
"restartGame": "Restart Game?",
"@restartGame": {
"description": "Restart Game?"
},
"gameStarted": "Game started, please place",
"@gameStarted": {
"description": "Game started, please place"
},
"analyzing": "Analyzing ...",
"@analyzing": {
"description": "Analyzing ..."
},
"error": "Error",
"@error": {
"description": "Error"
},
"winRate": "Win Rate",
"@winRate": {
"description": "Win Rate"
},
"score": "Score",
"@score": {
"description": "Score"
},
"black": "Black",
"@black": {
"description": "Black"
},
"white": "White",
"@white": {
"description": "White"
},
"loseReasonlessThanThree": " piece count is less than three.",
"@loseReasonlessThanThree": {
"description": " piece count is less than three."
},
"loseReasonResign": " resign.",
"@loseReasonResign": {
"description": " resign."
},
"loseReasonNoWay": " is no way to go.",
"@loseReasonNoWay": {
"description": " is no way to go."
},
"loseReasonBoardIsFull": "The board is full, no way to go.",
"@loseReasonBoardIsFull": {
"description": "The board is full, no way to go."
},
"loseReasonTimeOver": "Time Over",
"@loseReasonTimeOver": {
"description": "Time Over"
},
"drawReasonRule50": "Rule50",
"@drawReasonRule50": {
"description": "Rule50"
},
"drawReasonBoardIsFull": "Draw, because the board is full",
"@drawReasonBoardIsFull": {
"description": "Draw, because the board is full"
},
"drawReasonThreefoldRepetition": "Draw, because three fold repetition.",
"@drawReasonThreefoldRepetition": {
"description": "Draw, because three fold repetition."
},
"gameOverUnknownReason": "Game Over! Unknown reason.",
"@gameOverUnknownReason": {
"description": "Game Over! Unknown reason."
},
"youWin": "You win! Congratulations!",
"@youWin": {
"description": "You win! Congratulations!"
},
"youLose": "You Lose!",
"@youLose": {
"description": "You Lose!"
},
"regret": "Regret",
"@regret": {
"description": "Regret"
},
"analyze": "Analyze",
"@analyze": {
"description": "Analyze"
},
"playerName": "Player Name",
"@playerName": {
"description": "Player Name"
},
"about": "About",
"@about": {
"description": "About"
},
"version": "Version",
"@version": {
"description": "Version"
},
"releaseBaseOn": "Release base On GPLv3",
"@releaseBaseOn": {
"description": "Release base On GPLv3"
},
"webSite": "Website",
"@webSite": {
"description": "Web Site"
},
"whatsNew": "What's New",
"@whatsNew": {
"description": "What's New"
},
"fastUpdateChannel": "Fast Update Channel",
"@fastUpdateChannel": {
"description": "Fast Update Channel"
},
"thanks": "Thanks",
"@thanks": {
"description": "Thanks"
},
"thankWho": "Thanks to following programmers and teams:",
"@thankWho": {
"description": "Thank who"
},
"stockfish": "Stockfish - UCI chess engine",
"@stockfish": {
"description": "Stockfish - UCI chess engine"
},
"chessRoad": "ChessRoad by He Zhaoyun",
"@chessRoad": {
"description": "ChessRoad"
},
"nineChess": "NineChess by liuweilhy",
"@nineChess": {
"description": "NineChess"
},
"settings": "Settings",
"@settings": {
"description": "Settings"
},
"level": "Level",
"@level": {
"description": "Level"
},
"sound": "Sound",
"@sound": {
"description": "Sound"
},
"tone": "Tone",
"@tone": {
"description": "Tone"
},
"leaderBoard": "Leader Board",
"@leaderBoard": {
"description": "Leader Board"
}
}

View File

@ -3,5 +3,63 @@
"humanVsAi": "人机对战",
"humanVsHuman": "双人对战",
"aiVsAi": "机器对战",
"humanVsCloud": "挑战云端"
"humanVsCloud": "挑战云端",
"gameRecord": "棋谱",
"noGameRecord": "暂无招法",
"ok": "好的",
"cancel": "取消",
"daSanQi": "打三棋",
"copyright": "版权所有 © 2019-2020 The Sanmill Authors",
"gameWarning": " 健康游戏忠告\n抵制不良游戏拒绝盗版游戏。\n注意自我保护谨防受骗上当。\n适度游戏益脑沉迷游戏伤身。\n合理安排时间享受健康生活。",
"tipSelectWrong": "选择的子不对",
"tipPlace": "请落子",
"tipBanPlace": "不能落在此处",
"tipPlaced": "已落子",
"tipRemove": "请吃子",
"tipBanRemove": "不能吃这颗子",
"tipRemoved": "已吃子",
"tipMove": "请走子",
"blackWin": "黑方胜",
"whiteWin": "白方胜",
"draw": "和棋",
"thinking": "对方思考中...",
"newGame": "新局",
"restartGame": "重新开局?",
"gameStarted": "游戏开始 请落子",
"analyzing": "正在分析局面...",
"error": "错误",
"winRate": "胜率",
"score": "分数",
"black": "黑方",
"white": "白方",
"loseReasonlessThanThree": "剩余棋子少于3枚。",
"loseReasonResign": "认输了。",
"loseReasonNoWay": "被闷杀。",
"loseReasonBoardIsFull": "因棋盘摆满而无路可走。",
"loseReasonTimeOver": "超时判负。",
"drawReasonRule50": "连续超过50步未吃子判和。",
"drawReasonBoardIsFull": "棋盘摆满,无路可走,判和。",
"drawReasonThreefoldRepetition": "三次重复局面和。",
"gameOverUnknownReason": "游戏结束,原因未知!",
"youWin": "恭喜你赢了",
"youLose": "你输了",
"regret": "悔棋",
"analyze": "分析",
"playerName": "棋手姓名",
"about": "关于",
"version": "版本",
"releaseBaseOn": "依照 GPLv3 协议发布",
"webSite": "官方网站",
"whatsNew": "新版变化",
"fastUpdateChannel": "快速更新通道",
"thanks": "Thanks",
"thankWho": "直棋 离不开以下人员的无私贡献,感激不尽!\n代码贡献者: Calcitem\n开源库: 所基于的开源库太多,难以罗列,在这里仅列出主要的几项,同时也感谢其他默默无闻为开源事业做出贡献的人们:'",
"stockfish": "Stockfish - UCI 国际象棋引擎",
"chessRoad": "ChessRoad (棋路) by He Zhaoyun",
"nineChess": "NineChess (九联棋) by liuweilhy",
"settings": "设置",
"level": "游戏难度",
"sound": "Sound",
"tone": "提示音效",
"leaderBoard": "排行榜"
}

View File

@ -30,7 +30,6 @@ class Game {
String sideToMove = Color.black;
//
bool isColorInverted;
Map<String, bool> isAi = {Color.black: false, Color.white: true};
@ -44,28 +43,20 @@ class Game {
position.start();
}
//
bool hasAnimation;
//
int durationTime;
int animationDurationTime;
//
static bool hasSound = true;
//
bool resignIfMostLose = false;
//
bool isAutoChangeFirstMove = false;
// AI
bool isAiFirstMove = false;
//
int ruleIndex;
//
String tips;
List<String> moveHistory = [""];
@ -111,7 +102,7 @@ class Game {
bool regret({moves = 2}) {
//
//
// Can regret only our turn
// TODO
if (_position.side != Color.white) {
//Audios.playTone('invalid.mp3');
@ -120,7 +111,7 @@ class Game {
var regretted = false;
///
/// Regret 2 step
for (var i = 0; i < moves; i++) {
//
@ -164,7 +155,6 @@ class Game {
int total;
double blackWinRate, whiteWinRate, drawRate;
//
if (position.phase == Phase.ready) {
start();
}

View File

@ -52,7 +52,6 @@ int makeSquare(int file, int rank) {
return (file << 3) + rank - 1;
}
///
enum GameResult { pending, win, lose, draw }
class Color {
@ -119,7 +118,7 @@ class Move {
MoveType type;
// FEN FEN Counter
// Used to restore fen step conter when regreting
String counterMarks;
parse() {
@ -163,10 +162,10 @@ class Move {
parse();
}
/// :
/// (1,2)
/// -(1,2)
/// (3,1)->(2,1)
/// Format:
/// Place: (1,2)
/// Remove: -(1,2)
/// Move: (3,1)->(2,1)
Move.set(String move) {
this.move = move;

View File

@ -1464,7 +1464,7 @@ class Position {
if (lastMove.removed != Piece.noPiece) {
//
// NativeEngine
// Find last remove position (or opening), NativeEngine need
final tempPosition = Position.clone(this);
final moves = recorder.reverseMovesToPrevRemove();

View File

@ -20,10 +20,9 @@
import 'mill.dart';
import 'position.dart';
import 'types.dart';
import 'package:sanmill/generated/l10n.dart';
class GameRecorder {
//
//
int halfMove, fullMove;
String lastPositionWithRemove;
final _history = <Move>[];
@ -99,7 +98,7 @@ class GameRecorder {
}
if (manualText.isEmpty) {
manualText = '<暂无招法>';
manualText = "";
}
return manualText;

View File

@ -18,7 +18,7 @@
*/
class Rule {
String name = "打三棋";
String name = "Da San Qi";
String description;
int nTotalPiecesEachSide = 12; // 9 or 12
int nPiecesAtLeast = 3; // Default is 3

View File

@ -44,7 +44,7 @@ class PiecesPainter extends PiecesBasePainter {
this.blurIndex = Move.invalidMove,
}) : super(width: width) {
//
pieceWidth = squareWidth * 0.9; //
pieceWidth = squareWidth * 0.9; // size of square
}
@override
@ -56,7 +56,6 @@ class PiecesPainter extends PiecesBasePainter {
gridWidth: gridWidth,
squareWidth: squareWidth,
pieceWidth: pieceWidth,
// 线
offsetX: Board.padding + squareWidth / 2,
offsetY: Board.padding + Board.digitsHeight + squareWidth / 2,
focusIndex: focusIndex,
@ -66,7 +65,6 @@ class PiecesPainter extends PiecesBasePainter {
@override
bool shouldRepaint(CustomPainter oldDelegate) {
// Painter
return true;
}
@ -89,11 +87,12 @@ class PiecesPainter extends PiecesBasePainter {
final shadowPath = Path();
final piecesToDraw = <PiecePaintPair>[];
//
// Draw pieces on board
for (var row = 0; row < 7; row++) {
for (var col = 0; col < 7; col++) {
//
final piece = position.pieceOnGrid(row * 7 + col); //
final piece =
position.pieceOnGrid(row * 7 + col); // No Pieces when initial
if (piece == Piece.noPiece) continue;
@ -107,7 +106,7 @@ class PiecesPainter extends PiecesBasePainter {
}
}
//
// Draw shadow of piece
canvas.drawShadow(shadowPath, Colors.black, 2, true);
paint.style = PaintingStyle.fill;
@ -122,19 +121,19 @@ class PiecesPainter extends PiecesBasePainter {
piecesToDraw.forEach((pps) {
var pieceRadius = pieceWidth / 2;
var pieceInnerRadius = pieceRadius * 0.99; //
var pieceInnerRadius = pieceRadius * 0.99;
//
// Draw Border of Piece
switch (pps.piece) {
case Piece.blackStone:
paint.color = UIColors.blackPieceBorderColor;
canvas.drawCircle(pps.pos, pieceRadius, paint); //
canvas.drawCircle(pps.pos, pieceRadius, paint); // For debugging
paint.color = UIColors.blackPieceColor;
canvas.drawCircle(pps.pos, pieceInnerRadius, paint);
break;
case Piece.whiteStone:
paint.color = UIColors.whitePieceBorderColor;
canvas.drawCircle(pps.pos, pieceRadius, paint); //
canvas.drawCircle(pps.pos, pieceRadius, paint); // For debugging
paint.color = UIColors.whitePieceColor;
canvas.drawCircle(pps.pos, pieceInnerRadius, paint);
break;

View File

@ -52,7 +52,7 @@ class Player extends RankItem {
final playerInfoJson = profile['_rank-player-info'] ?? '{}';
final values = jsonDecode(playerInfoJson);
name = values['name'] ?? '无名英雄';
name = values['name'] ?? 'Anonymous';
winCloudEngine = values['win_cloud_engine'] ?? 0;
winAi = values['win_ai'] ?? 0;
}

View File

@ -26,19 +26,19 @@ class RankItem {
int winCloudEngine, winAi;
RankItem(Map<String, dynamic> values) {
name = values['name'] ?? '无名英雄';
name = values['name'] ?? 'Anonymous';
winCloudEngine = values['win_cloud_engine'] ?? 0;
winAi = values['win_ai'] ?? 0;
}
RankItem.empty() {
name = '无名英雄';
name = 'Anonymous';
winCloudEngine = 0;
winAi = 0;
}
RankItem.mock() {
name = '我是英雄';
name = 'I am a hero';
winCloudEngine = 3;
winAi = 12;
}

View File

@ -20,57 +20,37 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
// Toast
enum ToastPostion { top, center, bottom }
class Toast {
// toast靠它加到屏幕上
static OverlayEntry _overlayEntry;
// toast是否正在showing
static bool _showing = false;
// toast的当前时间
static DateTime _startedTime;
//
static String _msg;
// toast显示时间
static int _showTime;
//
static Color _bgColor;
//
static Color _textColor;
//
static double _textSize;
//
static ToastPostion _toastPosition;
//
static double _pdHorizontal;
//
static double _pdVertical;
static void toast(
BuildContext context, {
//
String msg,
//
int showTime = 1000,
//
int showTimeMs = 1000,
Color bgColor = Colors.black,
//
Color textColor = Colors.white,
//
double textSize = 16.0,
//
ToastPostion position = ToastPostion.center,
//
double pdHorizontal = 20.0,
//
double pdVertical = 10.0,
}) async {
assert(msg != null);
_msg = msg;
_startedTime = DateTime.now();
_showTime = showTime;
_showTime = showTimeMs;
_bgColor = bgColor;
_textColor = textColor;
_textSize = textSize;
@ -78,18 +58,13 @@ class Toast {
_pdHorizontal = pdHorizontal;
_pdVertical = pdVertical;
// OverlayState
OverlayState overlayState = Overlay.of(context);
_showing = true;
if (_overlayEntry == null) {
//
// OverlayEntry负责构建布局
// OverlayEntry将构建的布局插入到整个布局的最上层
_overlayEntry = OverlayEntry(
builder: (BuildContext context) => Positioned(
// top值toast在屏幕中的位置
top: buildToastPosition(context),
child: Container(
alignment: Alignment.center,
@ -97,7 +72,7 @@ class Toast {
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 40.0),
child: AnimatedOpacity(
opacity: _showing ? 1.0 : 0.0, //
opacity: _showing ? 1.0 : 0.0,
duration: _showing
? Duration(milliseconds: 100)
: Duration(milliseconds: 400),
@ -107,18 +82,15 @@ class Toast {
),
);
//
overlayState.insert(_overlayEntry);
//
} else {
// UIsetState
// Redraw UI, like setState
_overlayEntry.markNeedsBuild();
}
//
await Future.delayed(Duration(milliseconds: _showTime));
// 2
if (DateTime.now().difference(_startedTime).inMilliseconds >= _showTime) {
_showing = false;
_overlayEntry.markNeedsBuild();
@ -128,7 +100,6 @@ class Toast {
}
}
// toast
static _buildToastWidget() {
return Center(
child: Card(
@ -143,7 +114,6 @@ class Toast {
);
}
// toast位置
static buildToastPosition(context) {
//
var backResult;

View File

@ -19,6 +19,7 @@
import 'package:flutter/material.dart';
import 'package:sanmill/style/colors.dart';
import 'package:sanmill/generated/l10n.dart';
class EditPage extends StatefulWidget {
//
@ -65,7 +66,7 @@ class _EditPageState extends State<EditPage> {
title: Text(widget.title, style: TextStyle(fontFamily: '')),
actions: <Widget>[
FlatButton(
child: Text('确定',
child: Text(S.of(context).ok,
style: TextStyle(fontFamily: '', color: Colors.white)),
onPressed: () => onSubmit(_textController.text),
)

View File

@ -66,21 +66,21 @@ class _GamePageState extends State<GamePage> {
switch (winner) {
case Color.nobody:
if (Game.shared.position.phase == Phase.placing) {
changeStatus('请摆子');
changeStatus(S.of(context).tipPlace);
} else if (Game.shared.position.phase == Phase.moving) {
changeStatus('请走子');
changeStatus(S.of(context).tipMove);
}
break;
case Color.black:
changeStatus('黑方胜');
changeStatus(S.of(context).blackWin);
gotWin();
break;
case Color.white:
changeStatus('白方胜');
changeStatus(S.of(context).whiteWin);
gotLose();
break;
case Color.draw:
changeStatus('和棋');
changeStatus(S.of(context).draw);
gotDraw();
break;
}
@ -91,82 +91,71 @@ class _GamePageState extends State<GamePage> {
int sq = indexToSquare[index];
//
if (sq == null) {
print("putPiece skip index: $index");
return;
}
// AI
if (Game.shared.isAiToMove() || Game.shared.aiIsSearching()) {
return false;
}
//
if (position.phase == Phase.ready) {
Game.shared.start();
}
//
bool ret = false;
switch (position.action) {
case Act.place:
if (position.putPiece(sq)) {
if (position.action == Act.remove) {
//
//Audios.playTone('mill.mp3');
changeStatus('请吃子');
changeStatus(S.of(context).tipRemove);
} else {
//
//Audios.playTone('put.mp3');
changeStatus('已落子');
changeStatus(S.of(context).tipPlaced);
}
ret = true;
print("putPiece: [$sq]");
break;
} else {
print("putPiece: skip [$sq]");
changeStatus('不能落在此处');
changeStatus(S.of(context).tipBanPlace);
}
// break
// If cannot move, retry select, do not break
//[[fallthrough]];
continue select;
select:
case Act.select:
if (position.selectPiece(sq)) {
//
//Audios.playTone('select.mp3');
Game.shared.select(index);
ret = true;
print("selectPiece: [$sq]");
changeStatus('请落子');
changeStatus(S.of(context).tipPlace);
} else {
//
//Audios.playTone('banned.mp3');
print("selectPiece: skip [$sq]");
changeStatus('选择的子不对');
changeStatus(S.of(context).tipSelectWrong);
}
break;
case Act.remove:
if (position.removePiece(sq)) {
//
//Audios.playTone('remove.mp3');
ret = true;
print("removePiece: [$sq]");
changeStatus('已吃子');
changeStatus(S.of(context).tipRemoved);
} else {
//
//Audios.playTone('banned.mp3');
print("removePiece: skip [$sq]");
changeStatus('不能吃这个子');
changeStatus(S.of(context).tipBanRemove);
}
break;
default:
//
break;
}
@ -185,11 +174,8 @@ class _GamePageState extends State<GamePage> {
Move m = Move(position.cmdline);
position.recorder.moveIn(m, position);
//
setState(() {});
// AI设置
//
if (position.winner == Color.nobody) {
engineToGo();
} else {
@ -208,7 +194,7 @@ class _GamePageState extends State<GamePage> {
// TODO
while (Game.shared.position.winner == Color.nobody &&
Game.shared.position.sideToMove() == Color.white) {
changeStatus('对方思考中...');
changeStatus(S.of(context).thinking);
final response = await widget.engine.search(Game.shared.position);
@ -229,7 +215,7 @@ class _GamePageState extends State<GamePage> {
confirm() {
Navigator.of(context).pop();
Game.shared.newGame();
changeStatus('游戏开始 请摆子');
changeStatus(S.of(context).gameStarted);
if (Game.shared.isAiToMove()) {
print("New Game: AI's turn.");
@ -243,11 +229,13 @@ class _GamePageState extends State<GamePage> {
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('新局?', style: TextStyle(color: UIColors.primaryColor)),
content: SingleChildScrollView(child: Text('重新开局?')),
title: Text(S.of(context).newGame,
style: TextStyle(color: UIColors.primaryColor)),
content:
SingleChildScrollView(child: Text(S.of(context).restartGame)),
actions: <Widget>[
FlatButton(child: Text('确定'), onPressed: confirm),
FlatButton(child: Text('取消'), onPressed: cancel),
FlatButton(child: Text(S.of(context).ok), onPressed: confirm),
FlatButton(child: Text(S.of(context).cancel), onPressed: cancel),
],
);
},
@ -256,12 +244,14 @@ class _GamePageState extends State<GamePage> {
analyzePosition() async {
//
Toast.toast(context, msg: '正在分析局面...', position: ToastPostion.bottom);
Toast.toast(context,
msg: S.of(context).analyzing, position: ToastPostion.bottom);
setState(() => _searching = true);
try {} catch (e) {
Toast.toast(context, msg: '错误: $e', position: ToastPostion.bottom);
Toast.toast(context,
msg: S.of(context).error + ": $e", position: ToastPostion.bottom);
} finally {
setState(() => _searching = false);
}
@ -279,8 +269,8 @@ class _GamePageState extends State<GamePage> {
children.add(
ListTile(
title: Text(item.moveName, style: TextStyle(fontSize: 18)),
subtitle: Text('胜率:${item.winRate}%'),
trailing: Text('分数:${item.score}'),
subtitle: Text(S.of(context).winRate + ": ${item.winRate}%"),
trailing: Text(S.of(context).score + ": ${item.score}'"),
onTap: () => callback(item),
),
);
@ -300,39 +290,38 @@ class _GamePageState extends State<GamePage> {
String getGameOverReasonString(GameOverReason reason, String winner) {
String loseReasonStr;
String winnerStr = winner == Color.black ? "黑方" : "白方";
String loserStr = winner == Color.black ? "白方" : "黑方";
String winnerStr =
winner == Color.black ? S.of(context).black : S.of(context).white;
String loserStr =
winner == Color.black ? S.of(context).white : S.of(context).black;
switch (Game.shared.position.gameOverReason) {
case GameOverReason.loseReasonlessThanThree:
loseReasonStr = "$loserStr剩余棋子少于3枚";
loseReasonStr = loserStr + S.of(context).loseReasonlessThanThree;
break;
case GameOverReason.loseReasonResign:
loseReasonStr = "$loserStr认输了";
loseReasonStr = loserStr + S.of(context).loseReasonResign;
break;
case GameOverReason.loseReasonNoWay:
loseReasonStr = "$loserStr被闷杀";
loseReasonStr = loserStr + S.of(context).loseReasonNoWay;
break;
case GameOverReason.loseReasonBoardIsFull:
loseReasonStr = "棋盘摆满,$loserStr无路可走";
loseReasonStr = loserStr + S.of(context).loseReasonBoardIsFull;
break;
case GameOverReason.loseReasonTimeOver:
loseReasonStr = "$loserStr超时判负";
loseReasonStr = loserStr + S.of(context).loseReasonTimeOver;
break;
case GameOverReason.drawReasonRule50:
loseReasonStr = "连续超过50步未吃子判和。";
break;
case GameOverReason.drawReasonRule50:
loseReasonStr = "连续超过50步未吃子判和。";
loseReasonStr = S.of(context).drawReasonRule50;
break;
case GameOverReason.drawReasonBoardIsFull:
loseReasonStr = "棋盘摆满,无路可走,判和。";
loseReasonStr = S.of(context).drawReasonBoardIsFull;
break;
case GameOverReason.drawReasonThreefoldRepetition:
loseReasonStr = "三次重复局面和。";
loseReasonStr = S.of(context).drawReasonThreefoldRepetition;
break;
default:
loseReasonStr = "未知原因,棋局结束。";
loseReasonStr = S.of(context).gameOverUnknownReason;
break;
}
@ -349,13 +338,14 @@ class _GamePageState extends State<GamePage> {
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text('恭喜你赢了', style: TextStyle(color: UIColors.primaryColor)),
title: Text(S.of(context).youWin,
style: TextStyle(color: UIColors.primaryColor)),
content: Text(getGameOverReasonString(
Game.shared.position.gameOverReason,
Game.shared.position.winner)),
actions: <Widget>[
FlatButton(
child: Text('好的'),
child: Text(S.of(context).ok),
onPressed: () => Navigator.of(context).pop()),
],
);
@ -378,13 +368,14 @@ class _GamePageState extends State<GamePage> {
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text('你输了', style: TextStyle(color: UIColors.primaryColor)),
title: Text(S.of(context).youLose,
style: TextStyle(color: UIColors.primaryColor)),
content: Text(getGameOverReasonString(
Game.shared.position.gameOverReason,
Game.shared.position.winner)),
actions: <Widget>[
FlatButton(
child: Text('好的'),
child: Text(S.of(context).ok),
onPressed: () => Navigator.of(context).pop()),
],
);
@ -401,13 +392,14 @@ class _GamePageState extends State<GamePage> {
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text('和棋', style: TextStyle(color: UIColors.primaryColor)),
title: Text(S.of(context).draw,
style: TextStyle(color: UIColors.primaryColor)),
content: Text(getGameOverReasonString(
Game.shared.position.gameOverReason,
Game.shared.position.winner)),
actions: <Widget>[
FlatButton(
child: Text('好的'),
child: Text(S.of(context).ok),
onPressed: () => Navigator.of(context).pop()),
],
);
@ -417,7 +409,7 @@ class _GamePageState extends State<GamePage> {
void calcScreenPaddingH() {
//
// 16/9
// when screen's height/width rate is less than 16/9, limit witdh of board
final windowSize = MediaQuery.of(context).size;
double height = windowSize.height, width = windowSize.width;
@ -511,10 +503,12 @@ class _GamePageState extends State<GamePage> {
padding: EdgeInsets.symmetric(vertical: 2),
child: Row(children: <Widget>[
Expanded(child: SizedBox()),
FlatButton(child: Text('新局', style: buttonStyle), onPressed: newGame),
FlatButton(
child: Text(S.of(context).newGame, style: buttonStyle),
onPressed: newGame),
Expanded(child: SizedBox()),
FlatButton(
child: Text('悔棋', style: buttonStyle),
child: Text(S.of(context).regret, style: buttonStyle),
onPressed: () {
Game.shared.regret(steps: 2);
setState(() {});
@ -522,7 +516,7 @@ class _GamePageState extends State<GamePage> {
),
Expanded(child: SizedBox()),
FlatButton(
child: Text('分析', style: buttonStyle),
child: Text(S.of(context).analyze, style: buttonStyle),
onPressed: _searching ? null : analyzePosition,
),
Expanded(child: SizedBox()),
@ -571,12 +565,13 @@ class _GamePageState extends State<GamePage> {
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text('棋谱', style: TextStyle(color: UIColors.primaryColor)),
title: Text(S.of(context).gameRecord,
style: TextStyle(color: UIColors.primaryColor)),
content:
SingleChildScrollView(child: Text(text, style: manualStyle)),
actions: <Widget>[
FlatButton(
child: Text('好的'),
child: Text(S.of(context).ok),
onPressed: () => Navigator.of(context).pop(),
),
],

View File

@ -135,15 +135,10 @@ class _MainMenuState extends State<MainMenu> with TickerProviderStateMixin {
onPressed: () => navigateTo(GamePage(EngineType.aiVsAi)),
),
Expanded(child: SizedBox()),
Text(
' 健康游戏忠告\n'
'抵制不良游戏,拒绝盗版游戏。\n'
'注意自我保护,谨防受骗上当。\n'
'适度游戏益脑,沉迷游戏伤身。\n'
'合理安排时间,享受健康生活。',
Text(S.of(context).gameWarning,
style: TextStyle(color: Colors.black54, fontSize: 16)),
Expanded(child: SizedBox()),
Text('Copyright © 2019-2020 The Sanmill Authors',
Text(S.of(context).copyright,
style: TextStyle(color: Colors.black54, fontSize: 16)),
Expanded(child: SizedBox()),
],

View File

@ -20,6 +20,7 @@
import 'package:flutter/material.dart';
import 'package:package_info/package_info.dart';
import 'package:sanmill/common/config.dart';
import 'package:sanmill/generated/l10n.dart';
import 'package:sanmill/services/audios.dart';
import 'package:sanmill/services/player.dart';
import 'package:sanmill/style/colors.dart';
@ -70,7 +71,7 @@ class _SettingsPageState extends State<SettingsPage> {
SizedBox(height: 10),
RadioListTile(
activeColor: UIColors.primaryColor,
title: Text('初级'),
title: Text('L1'),
groupValue: Config.thinkingTime,
value: 5000,
onChanged: callback,
@ -78,7 +79,7 @@ class _SettingsPageState extends State<SettingsPage> {
Divider(),
RadioListTile(
activeColor: UIColors.primaryColor,
title: Text('中级'),
title: Text('L2'),
groupValue: Config.thinkingTime,
value: 15000,
onChanged: callback,
@ -86,7 +87,7 @@ class _SettingsPageState extends State<SettingsPage> {
Divider(),
RadioListTile(
activeColor: UIColors.primaryColor,
title: Text('高级'),
title: Text('L3'),
groupValue: Config.thinkingTime,
value: 30000,
onChanged: callback,
@ -126,8 +127,8 @@ class _SettingsPageState extends State<SettingsPage> {
//
final newName = await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
EditPage('棋手姓名', initValue: Player.shared.name)),
builder: (context) => EditPage(S.of(context).playerName,
initValue: Player.shared.name)),
);
if (newName != null) nameChanged(newName);
@ -156,16 +157,18 @@ class _SettingsPageState extends State<SettingsPage> {
context: context,
barrierDismissible: false,
builder: (context) => AlertDialog(
title: Text('关于「直棋 」', style: TextStyle(color: UIColors.primaryColor)),
title: Text(S.of(context).about + S.of(context).appName,
style: TextStyle(color: UIColors.primaryColor)),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(height: 5),
Text('版本: $_version', style: TextStyle(fontFamily: '')),
Text(S.of(context).version + ": $_version",
style: TextStyle(fontFamily: '')),
SizedBox(height: 15),
InkWell(
child: Text('依照 GPLv3 协议发布',
child: Text(S.of(context).releaseBaseOn,
style: TextStyle(
fontFamily: '',
color: Colors.blue,
@ -175,7 +178,7 @@ class _SettingsPageState extends State<SettingsPage> {
),
SizedBox(height: 15),
InkWell(
child: Text('官方网站',
child: Text(S.of(context).webSite,
style: TextStyle(
fontFamily: '',
color: Colors.blue,
@ -183,7 +186,7 @@ class _SettingsPageState extends State<SettingsPage> {
onTap: () => _launchURL('https://github.com/calcitem/Sanmill'),
),
InkWell(
child: Text('新版变化',
child: Text(S.of(context).whatsNew,
style: TextStyle(
fontFamily: '',
color: Colors.blue,
@ -192,7 +195,7 @@ class _SettingsPageState extends State<SettingsPage> {
'https://github.com/calcitem/Sanmill/commits/master'),
),
InkWell(
child: Text('快速更新通道',
child: Text(S.of(context).fastUpdateChannel,
style: TextStyle(
fontFamily: '',
color: Colors.blue,
@ -202,16 +205,13 @@ class _SettingsPageState extends State<SettingsPage> {
),
SizedBox(height: 15),
InkWell(
child: Text('致谢'),
child: Text(S.of(context).thanks),
),
InkWell(
child: Text('直棋 离不开以下人员的无私贡献,感激不尽!\n'
'代码贡献者: Calcitem\n'
'开源库: '
'所基于的开源库太多,难以罗列,在这里仅列出主要的几项,同时也感谢其他默默无闻为开源事业做出贡献的人们:'),
child: Text(S.of(context).thankWho),
),
InkWell(
child: Text('Stockfish - UCI chess engine',
child: Text(S.of(context).stockfish,
style: TextStyle(
fontFamily: '',
color: Colors.blue,
@ -220,7 +220,7 @@ class _SettingsPageState extends State<SettingsPage> {
_launchURL('https://github.com/official-stockfish/Stockfish'),
),
InkWell(
child: Text('ChessRoad (棋路) by He Zhaoyun',
child: Text(S.of(context).chessRoad,
style: TextStyle(
fontFamily: '',
color: Colors.blue,
@ -228,7 +228,7 @@ class _SettingsPageState extends State<SettingsPage> {
onTap: () => _launchURL('https://github.com/hezhaoyun/chessroad'),
),
InkWell(
child: Text('NineChess (九联棋) by liuweilhy',
child: Text(S.of(context).nineChess,
style: TextStyle(
fontFamily: '',
color: Colors.blue,
@ -239,7 +239,8 @@ class _SettingsPageState extends State<SettingsPage> {
),
actions: <Widget>[
FlatButton(
child: Text('好的'), onPressed: () => Navigator.of(context).pop()),
child: Text(S.of(context).ok),
onPressed: () => Navigator.of(context).pop()),
],
),
);
@ -254,14 +255,14 @@ class _SettingsPageState extends State<SettingsPage> {
return Scaffold(
backgroundColor: UIColors.lightBackgroundColor,
appBar: AppBar(title: Text('设置')),
appBar: AppBar(title: Text(S.of(context).settings)),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const SizedBox(height: 10.0),
Text("人机难度", style: headerStyle),
Text(S.of(context).level, style: headerStyle),
const SizedBox(height: 10.0),
Card(
color: UIColors.boardBackgroundColor,
@ -270,14 +271,14 @@ class _SettingsPageState extends State<SettingsPage> {
child: Column(
children: <Widget>[
ListTile(
title: Text("游戏难度", style: itemStyle),
title: Text(S.of(context).level, style: itemStyle),
trailing:
Row(mainAxisSize: MainAxisSize.min, children: <Widget>[
Text(Config.thinkingTime <= 5000
? '初级'
? 'L1'
: Config.thinkingTime <= 15000
? '中级'
: '高级'),
? 'L2'
: 'L3'),
Icon(Icons.keyboard_arrow_right,
color: UIColors.secondaryColor),
]),
@ -287,7 +288,7 @@ class _SettingsPageState extends State<SettingsPage> {
),
),
const SizedBox(height: 16),
Text("声音", style: headerStyle),
Text(S.of(context).sound, style: headerStyle),
Card(
color: UIColors.boardBackgroundColor,
margin: const EdgeInsets.symmetric(vertical: 10),
@ -296,28 +297,28 @@ class _SettingsPageState extends State<SettingsPage> {
SwitchListTile(
activeColor: UIColors.primaryColor,
value: Config.bgmEnabled,
title: Text("背景音乐", style: itemStyle),
title: Text(S.of(context).sound, style: itemStyle),
onChanged: switchMusic,
),
_buildDivider(),
SwitchListTile(
activeColor: UIColors.primaryColor,
value: Config.toneEnabled,
title: Text("提示音效", style: itemStyle),
title: Text(S.of(context).tone, style: itemStyle),
onChanged: switchTone,
),
],
),
),
const SizedBox(height: 16),
Text("排行榜", style: headerStyle),
Text(S.of(context).leaderBoard, style: headerStyle),
Card(
color: UIColors.boardBackgroundColor,
margin: const EdgeInsets.symmetric(vertical: 10),
child: Column(
children: <Widget>[
ListTile(
title: Text("棋手姓名", style: itemStyle),
title: Text(S.of(context).playerName, style: itemStyle),
trailing:
Row(mainAxisSize: MainAxisSize.min, children: <Widget>[
Text(Player.shared.name),
@ -330,14 +331,15 @@ class _SettingsPageState extends State<SettingsPage> {
),
),
const SizedBox(height: 16),
Text("关于", style: headerStyle),
Text(S.of(context).about, style: headerStyle),
Card(
color: UIColors.boardBackgroundColor,
margin: const EdgeInsets.symmetric(vertical: 10),
child: Column(
children: <Widget>[
ListTile(
title: Text("关于「直棋」", style: itemStyle),
title: Text(S.of(context).about + S.of(context).appName,
style: itemStyle),
trailing:
Row(mainAxisSize: MainAxisSize.min, children: <Widget>[
Text(_version ?? ''),