Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
saeziae committed Jan 17, 2024
0 parents commit b7c0dce
Show file tree
Hide file tree
Showing 12 changed files with 2,883 additions and 0 deletions.
20 changes: 20 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:react/recommended',
'plugin:react/jsx-runtime',
'plugin:react-hooks/recommended',
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
settings: { react: { version: '18.2' } },
plugins: ['react-refresh'],
rules: {
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
}
24 changes: 24 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# 吳語姓名轉寫系統
13 changes: 13 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="zh-wuu-Hant">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>吳語姓名轉寫系統</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
30 changes: 30 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "name-transliterator",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"@popperjs/core": "^2.11.8",
"bootstrap": "^5.3.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"vite-plugin-svgr": "^4.2.0"
},
"devDependencies": {
"@types/react": "^18.2.43",
"@types/react-dom": "^18.2.17",
"@vitejs/plugin-react": "^4.2.1",
"eslint": "^8.55.0",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.5",
"sass": "^1.69.7",
"vite": "^5.0.8"
}
}
197 changes: 197 additions & 0 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
import { useState, memo } from "react";
import dictData from "./assets/char_phon_simp.json";
import Dinishing from "./assets/dinishing.svg?react";
const footerlinks = [
{ link: "https://github.com/DINISHING/name-transliterator", text: "原始碼" },
{
link: "https://github.com/DINISHING/standards/tree/main/phonetics",
text: "拼音方案",
},
{ link: "https://github.com/vocabulary", text: "字音庫" },
];

function App() {
const [name, setName] = useState("");
const [name1, setName1] = useState("");
const [spelling, setSpelling] = useState(false);
return (
<>
<div className="d-flex px-3 pt-5 align-items-center">
<div className="col-md-6 col-lg-4 mx-auto">
<h1>吳語姓名轉寫系統</h1>
<div className="input-group mb-3">
<input
type="text"
className="form-control"
value={name}
onChange={(e) => {
setName(e.target.value);
}}
/>
<button
className="btn btn-outline-primary"
type="button"
onClick={() => {
setName1(name);
}}
>
轉換
</button>
</div>
<div className="form-check form-switch">
<input
className="form-check-input"
type="checkbox"
role="switch"
id="flexSwitchCheckDefault"
checked={spelling}
onChange={(e) => {
setSpelling(!spelling);
}}
/>
<label
className="form-check-label"
htmlFor="flexSwitchCheckDefault"
>
標準拼寫/教會式
</label>
</div>
<div className="my-3">
<Romanization name={name1} spelling={spelling} />
</div>
<div className="alert alert-primary" role="alert">
<ul>
<li>請輸入正體漢字,簡體字會尋弗着</li>
<li>一次輸入大量字數會卡死瀏覽器</li>
<li>結果僅供參考</li>
<li>
任何字音錯誤請到
<a href="https://github.com/vocabulary">該個倉庫</a>反饋
</li>
</ul>
</div>
<hr />
<ul className="nav justify-content-center">
{footerlinks.map((item) => (
<li className="nav-item">
<a className="nav-link" href={item.link}>
{item.text}
</a>
</li>
))}
<li className="nav-item">
<a className="nav-link" href="https://github.com/DINISHING/">
<Dinishing id="dns" />
</a>
</li>
</ul>
</div>
</div>
</>
);
}

const Romanization = memo(function Romanization({ name, spelling }) {
if (!name) {
return null;
}
const romanizationList = lookupRomanization(name);
console.log(romanizationList);
if (!romanizationList) {
return null;
}
const listItems = romanizationList.map((rom) => (
<li className="list-group-item">
{capitalizeWords(spelling ? piauciunToKauwei(rom) : rom)}
</li>
));
return <ul className="list-group">{listItems}</ul>;
});

function lookupRomanization(name) {
function generateCombinations(arr, current = []) {
if (arr.length === 0) {
return [current];
}

const firstArray = arr[0];
let combinations = [];

for (let i = 0; i < firstArray.length; i++) {
const newCurrent = [...current, firstArray[i]];
combinations = combinations.concat(
generateCombinations(arr.slice(1), newCurrent)
);
}
return combinations;
}

const chName = name.replace(/[^\u4E00-\u9FA5,]/g, "").replace(",", ",");
if (!chName.length) {
return null;
}

var result = [];

for (const char of chName) {
if (char == ",") {
result.push([","]);
} else {
const A = dictData[char];
result.push(A ? A : ["[未知讀音]"]);
}
}

return generateCombinations(result).map((innerArray) => innerArray.join(" "));
}

function piauciunToKauwei(inputString) {
const replacements = [
[/([ptkc])h/g, "$1"],
[/(m|n|l|ng)h/g, "$1"],
[/j/g, "dj"],
[/zh/g, "j"],
[/sh/g, "X"],
[/gh/g, ""],
[/u([nk])/g, "U$1"],
[/iu/g, "iui"],
[/yu/g, "yui"],
[/U/g, "u"],
[/ngi([aeou])/g, "ny$1"],
[/ngi/g, "nyi"],
[/([kgh])i([aeou])/g, "$1y$2"],
[/([kgh])i/g, "$1yi"],
[/([kgh]|ng)u([aeo])/g, "$1w$2"],
[/([cXj])i([aeou])/g, "$1$2"],
[/X/g, "sh"],
[/c/g, "ch"],
[/tz/g, "ts"],
[/([hjsz])y/g, "$1z"],
[/([ao])h/g, "$1eh"],
];

let resultString = inputString;

for (const replacement of replacements) {
const regex = replacement[0];
const replaceWith = replacement[1];
resultString = resultString.replace(regex, replaceWith);
}
return resultString;
}

function capitalizeWords(str) {
// Split the string into an array of words
let words = str.split(" ");

// Capitalize the first letter of each word
let capitalizedWords = words.map((word) => {
return word.charAt(0).toUpperCase() + word.slice(1);
});

// Join the capitalized words back into a string
let result = capitalizedWords.join(" ");
return result.replace(/\d/g, "");
}

export default App;
1 change: 1 addition & 0 deletions src/assets/char_phon_simp.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/assets/dinishing.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
35 changes: 35 additions & 0 deletions src/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Color Override

$white: #fcfaf2 !default; //Shironeri*/
$gray-100: #ededed !default;
$gray-200: #e9ecef !default;
$gray-300: #dee2e6 !default;
$gray-400: #bdc0ba !default; //Shironezumi
$gray-500: #91989f !default; //Ginnezumi
$gray-600: #787d7b !default; //Sunezumi
$gray-700: #707C74 !default; //Rikyunezumi
$gray-800: #4F4F48 !default; //Dobunezumi
$gray-900: #1c1c1c !default; //Sumi
$black: #080808 !default; //Kuro

$blue: #006284 !default; //Hanada
$indigo: #113285 !default; //Konjo
$purple: #66327C !default; //Sumire
$pink: #E03C8A !default; //Tsutsuji
$red: #CB1B45 !default; //Kurenai
$orange: #F75C2F !default; //Benihi
$yellow: #FFB11B !default; //Yamabuki
$green: #227D51 !default; //Midori
$teal: #00AA90 !default; //Aomidori
$cyan: #81C7D4 !default; //Mizu

@import "bootstrap/scss/bootstrap";
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@500&family=Noto+Sans+TC:wght@500&display=swap");

body {
font-family: Inter, "Noto Sans TC", var(--bs-body-font-family);
}

#dns {
height: 1.8em;
}
11 changes: 11 additions & 0 deletions src/main.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.scss'
import * as bootstrap from 'bootstrap'

ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)
8 changes: 8 additions & 0 deletions vite.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import svgr from "vite-plugin-svgr";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [svgr(), react()],
base: ''
})
Loading

0 comments on commit b7c0dce

Please sign in to comment.