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
2 changes: 2 additions & 0 deletions translate-backend/mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@
"?": "⠢",
"「": "⠤",
"」": "⠤",
"&": "⠰⠯",
"&": "⠰⠯",
}

mapping_alpha = {
Expand Down
63 changes: 61 additions & 2 deletions translate/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
IconButton,
Typography,
TextField,
FormControlLabel,
Switch,
} from "@mui/material";
import MenuIcon from "@mui/icons-material/Menu";
import { useTheme } from "@mui/material/styles";
Expand All @@ -35,6 +37,10 @@ function App() {
const [thumbup, setThumbup] = React.useState(false);
const [thumbdown, setThumbdown] = React.useState(false);

const [isPageNumberOn, setIsPageNumberOn] = useState(false);
const [fileName, setFileName] = useState("");
const [showWarning, setShowWarning] = useState(false);

async function source2wakati(text: string) {
const response = await fetch(
`${API_ENDPOINT}/source2wakati?sourceText=` + text,
Expand Down Expand Up @@ -167,15 +173,68 @@ function App() {
Copy
</Button>
</div>
<div>
<label>
ファイル名:
<input
type="text"
value={fileName}
onChange={(name) => {
setFileName(name.target.value);
setShowWarning(false);
}} // ユーザーの入力に反応してファイル名を更新
/>
.BES
</label>
{showWarning && (
<div style={{ color: "red" }}>
ファイル名を入力してください。
</div>
)}
</div>
<div style={{ display: "flex", justifyContent: "flex-end" }}>
<FormControlLabel
control={
<Switch
checked={isPageNumberOn}
onChange={() => {
setIsPageNumberOn(!isPageNumberOn);
}}
/>
}
label="ページ番号あり"
labelPlacement="start"
/>
</div>
<div style={{ display: "flex", justifyContent: "flex-end" }}>
<FormControlLabel
control={
<Switch
onChange={(e) => {
navigator.clipboard.writeText(targetText);
}}
/>
}
label="ページ番号あり"
labelPlacement="start"
/>
</div>
<div style={{ display: "flex", justifyContent: "flex-end" }}>
<Button
onClick={() => {
const buffer = unicodeToBes(targetText.replace(/\n/g, "\\n"));
const buffer = unicodeToBes(
targetText.replace(/\n/g, "\\n"),
isPageNumberOn,
);
const blob = new Blob([buffer], { type: "text/plain" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
if (fileName.trim() === "") {
setShowWarning(true); // ファイル名が空の場合、警告を表示
return;
}
a.href = url;
a.download = "output.BES";
a.download = fileName + ".BES";
a.click();
}}
>
Expand Down
247 changes: 246 additions & 1 deletion translate/src/modules/unicodeToBes.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@
import { PagesRounded } from "@mui/icons-material";

export function unicodeToBes(unicode: string): Uint8Array {
export function unicodeToBes(
unicode: string,
isPageNumberOn: boolean,
): Uint8Array {
const output = [
0x25, 0x42, 0x45, 0x54, 0x34, 0x30, 0x30, 0x25, 0x32, 0x30, 0x32, 0x33,
0x2f, 0x30, 0x35, 0x2f, 0x31, 0x36, 0x20, 0x20, 0x45, 0x35, 0x33, 0x33,
0x32, 0x32, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30,
];
const mapping_num = {
"1": "⠁",
"2": "⠃",
"3": "⠉",
"4": "⠙",
"5": "⠑",
"6": "⠋",
"7": "⠛",
"8": "⠓",
"9": "⠊",
"0": "⠚",
};
for (var i = 0; i < 512 - 32; i++) {
output.push(0x20);
}
Expand All @@ -20,6 +35,7 @@ export function unicodeToBes(unicode: string): Uint8Array {
var header = [0xff, 0x00, 0x00, 0xfd];
// 2つ目,3つ目はBESファイルの文字数を表す

/***ページ番号なし
for (var i = 0; i < 4; i++) {
output.push(header[i]);
console.log(output.length);
Expand Down Expand Up @@ -84,6 +100,235 @@ export function unicodeToBes(unicode: string): Uint8Array {
var letters_num = 0x1a + all_letters;
output[1025] = (letters_num % 255) + 12;
output[1026] = Math.floor(letters_num / 255);
*/

if (isPageNumberOn) {
console.log("have index");
// ページ番号あり
for (var i = 0; i < 4; i++) {
output.push(header[i]);
}
var letters_on_page = 0;
for (var i = 0; i < 27; i++) {
output.push(0xa0);
letters_on_page += 1;
}
output.push(0xdc);
var num = "⠁";
var num_codePoint = num.codePointAt(0);
if (num_codePoint != null) {
output.push(num_codePoint - 0x2800 + 0xa0);
}
letters_on_page += 2;
output.push(0xfe);
var letters = 0;
var lines = 0;
var pages = 0;
var separate_pos = 0; // 単語区切りの空白の位置
var num_pos = 1025; // ページごとの文字数を入力する位置
var letters_num = 0x1a;

for (const char of unicode) {
const codePoint = char.codePointAt(0);

if (lines === 21) {
// ページをまたぐとき
lines = 0;
pages += 1;
letters_num = 0x19 + letters_on_page;
output[num_pos] = (letters_num % 255) - Math.floor(letters_num / 255);
/***
if (pages === 1) {
output[num_pos] = (letters_num % 255) + 13;
} else {
output[num_pos] = letters_num % 255;
}
*/
// 8B 01 <> 89 01
output[num_pos + 1] = Math.floor(letters_num / 255);
console.log("Page: ", pages, num_pos, Math.floor(letters_num / 255));
num_pos = output.length;
console.log("sep", num_pos);
output.push(0x00);
// console.log(output.length);
output.push(0x00);
output.push(0xfd);
letters_on_page = 0;
for (var i = 0; i < 27; i++) {
output.push(0xa0);
letters_on_page += 1;
}
output.push(0xdc);
letters_on_page += 1;
const num_str = String(pages + 1);
for (var i = 0; i < num_str.length; i++) {
num = mapping_num[num_str[i]];
console.log(i, num_str, num);
num_codePoint = num.codePointAt(0);
if (num_codePoint != null) {
output.push(num_codePoint - 0x2800 + 0xa0);
}
letters_on_page += 1;
}
output.push(0xfe);
}
if (letters === 33) {
// 文が1行におさまらないとき改行
if (codePoint === 0x2800) {
output.push(0xfe);
lines += 1;
letters = 0;
} else {
// 次の文字が空白でないとき、単語区切りに戻って改行
output.splice(separate_pos, 0, 0xfe);
lines += 1;
letters = output.length - separate_pos - 1;
}
if (lines === 21) {
// ページをまたぐとき
lines = 0;
pages += 1;
// 次ページに移った文字数を引く
letters_on_page = letters_on_page - letters;
letters_num = 0x19 + letters_on_page;
output[num_pos] = (letters_num % 255) - Math.floor(letters_num / 255);
output[num_pos + 1] = Math.floor(letters_num / 255);
console.log("Page: ", pages, num_pos, Math.floor(letters_num / 255));
num_pos = separate_pos + 1;
console.log("con", num_pos);
output.splice(separate_pos + 1, 0, 0x00);
output.splice(separate_pos + 2, 0, 0x00);
output.splice(separate_pos + 3, 0, 0xfd);
letters_on_page = letters;
for (var i = 0; i < 27; i++) {
output.splice(separate_pos + i + 4, 0, 0xa0);
letters_on_page += 1;
}
output.splice(separate_pos + 31, 0, 0xdc);
letters_on_page += 1;
const num_str = String(pages + 1);
for (var i = 0; i < num_str.length; i++) {
num = mapping_num[num_str[i]];
num_codePoint = num.codePointAt(0);
if (num_codePoint != null) {
output.splice(
separate_pos + 32 + i,
0,
num_codePoint - 0x2800 + 0xa0,
);
}
letters_on_page += 1;
}
output.splice(separate_pos + 32 + num_str.length, 0, 0xfe);
}
}

if (codePoint === 0x2800) {
separate_pos = output.length;
}
if (codePoint != null) {
if (codePoint >= 0x2800 && codePoint <= 0x28ff) {
output.push(codePoint - 0x2800 + 0xa0);
letters += 1;
letters_on_page += 1;
}
}
if (char === "n") {
// "\n"で改行
output.push(0x0d);
letters_on_page += 1;
output.push(0xfe);
lines += 1;
letters = 0;
}
}

if (pages < 10) {
output[31] = 0x30 + pages;
} else {
output[31] = 0x30 + Math.floor(pages / 10);
output[32] = 0x30 + (pages % 10);
}

for (var i = 0; i + lines < 21; i++) {
output.push(0xfe);
}
output.push(0xff);

letters_num = 0x19 + letters_on_page;
output[num_pos] = letters_num % 255;
output[num_pos + 1] = Math.floor(letters_num / 255);
} else {
console.log("No index");
console.log(isPageNumberOn);
// ページ番号なし
for (var i = 0; i < 4; i++) {
output.push(header[i]);
console.log(output.length);
}
var all_letters = 0;
for (var i = 0; i < 27; i++) {
output.push(0xa0);
all_letters += 1;
}
output.push(0xfe);
var letters = 0;
var lines = 0;
var pages = 0;
var separate_pos = 0; // 単語区切りの空白の位置
for (const char of unicode) {
const codePoint = char.codePointAt(0);

if (lines == 21) {
// ページをまたぐとき
lines = 0;
pages += 1;
}
if (letters == 33) {
// 文字が1行におさまらず改行
if (codePoint == 0x2800) {
output.push(0xfe);
lines += 1;
letters = 0;
} else {
// 次の文字が空白でないとき、単語区切りに戻って改行
output.splice(separate_pos, 0, 0xfe);
lines += 1;
letters = output.length - separate_pos - 1;
}
}

if (codePoint == 0x2800) {
separate_pos = output.length;
}
if (codePoint != null) {
if (codePoint >= 0x2800 && codePoint <= 0x28ff) {
output.push(codePoint - 0x2800 + 0xa0);
letters += 1;
all_letters += 1;
}
}
if (char == "n") {
// "\n"で改行
output.push(0x0d);
output.push(0xfe);
lines += 1;
letters = 0;
}
}
output[31] = 0x30 + pages;
for (var i = 0; i + lines < 21; i++) {
output.push(0xfe);
}
output.push(0xff);

// 文字数を代入
var letters_num = 0x1a + all_letters;
output[1025] = (letters_num % 255) + 12;
output[1026] = Math.floor(letters_num / 255);
}

return new Uint8Array(output);
}

// 71 01 -> 77 01