Skip to content

Instantly share code, notes, and snippets.

@CourteousCoder
Last active February 20, 2020 01:31
Show Gist options
  • Save CourteousCoder/45ec1142f3cd8a39dc327baa94a2728a to your computer and use it in GitHub Desktop.
Save CourteousCoder/45ec1142f3cd8a39dc327baa94a2728a to your computer and use it in GitHub Desktop.
A bookmarklet to import custom Mandarin Chinese vocabulary into Anki
<a href="javascript:(() => {
const url = 'https://www.archchinese.com/type_chinese.html';
if(window.location.href !== url) return (window.location.href = url);
let data = ['chinese', 'pinyin', 'english']
.map(col => Array
.from(document.querySelectorAll(`#vocabtable input[name='${col}[]']`))
.map(input => input.value));
csv = data[0]
.map((col, i) => data.map(row => row[i]))
.map(row => JSON.stringify(row))
.join('\n')
.replace(/(^\[)|(\]$)/mg, '');
const file = encodeURI('data:text/csv;charset=utf-8,' + csv);
const a = document.createElement('a');
a.setAttribute('href', file);
a.setAttribute('download', 'chinese.csv');
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
})();
">Export Chinese Flashcards to CSV for Anki</a>
<ol>
<li>Drag the above bookmarklet to your bookmarks bar.</li>
<li>Click the bookmarklet.</li>
<li>Once the page loads, add Chinese vocab to the Vocab List, one per line <small>(You can also use the pinyin input)</small>.</li>
<li>Click the <button disabled>Generate Vocab List</button> button.</li>
<li>Once it loads, click the bookmarklet again.</li>
<li>Save the file</li>
<li><a href="https://superuser.com/a/705116">Import to Anki</a></li>
<li>Designed to be used with a card template like <a href="https://gist.github.com/DanielSchetritt/45ec1142f3cd8a39dc327baa94a2728a#file-sample-card-template-with-online-audio-and-formatting-html">the one I made.</a>
<!-- BEGIN Front of card -->
<h1>{{Simplified}}</h1>
<!-- END Front of card -->
<!-- BEGIN Back of card -->
{{FrontSide}}
<hr id="answer">
<h2 id="pinyin">{{Pinyin}}</h2>
<p>{{Meaning}}</p>
<!-- This script can be in either the front or the back of the card, depending on where you want to show pinyin -->
<script>
var toneCharMap = {};
toneCharMap['a']='āáǎà';
toneCharMap['e']='ēéěè';
toneCharMap['i']='īíǐì';
toneCharMap['o']='ōóǒò';
toneCharMap['u']='ūúǔù';
toneCharMap['ü']='ǖǘǚǜ';
function toneToColorClass(pinyinCharacter) {
return 'tone' + pinyinCharacter.charAt(pinyinCharacter.length - 1);
}
function numberToToneMark(pinyinCharacter) {
var tonelessPinyin = pinyinCharacter.substring(0, pinyinCharacter.length - 1);
var toneNum = pinyinCharacter.charAt(pinyinCharacter.length - 1);
if (toneNum < 1 || toneNum > 5 || tonelessPinyin.length < 1) {
return tonelessPinyin + toneNum; // not real pinyin
}
tonelessPinyin = tonelessPinyin.replace('v', 'ü');
if (toneNum == 5) {
return tonelessPinyin;
}
var charToReplace;
var vowels = tonelessPinyin.replace(/[^aeiouü]/g, '');
switch (vowels.length) {
case 0:
charToReplace = tonelessPinyin.charAt(0);
break;
case 1:
charToReplace = vowels.charAt(0);
break;
default:
if (vowels.indexOf("a") >= 0) {
charToReplace = 'a';
}
else if (vowels.indexOf("e") >= 0) {
charToReplace = 'e';
}
else if (vowels.indexOf("ou") >= 0) {
charToReplace = 'o';
}
else {
charToReplace = vowels.charAt(1);
}
}
var tonesStr = toneCharMap[charToReplace];
var replacementChar = tonesStr == null ? null : tonesStr.charAt(toneNum - 1);
if (replacementChar == null || replacementChar == ' ') {
return tonelessPinyin + toneNum;
}
else {
return tonelessPinyin.replace(charToReplace, replacementChar);
}
return pinyinCharacter;
}
function formatPinyinCharacter(pinyinCharacter) {
return ('<a class="'+ toneToColorClass(pinyinCharacter) + '" href="https://www.purpleculture.net/mp3/'+ pinyinCharacter + '.mp3">' + numberToToneMark(pinyinCharacter) + '</a>');
}
function splitWords(str) {
var words = [];
if (str.length === 0) {
return words;
}
var word = str.charAt(0);
for (var c = 1; c < str.length; c++) {
char = str.charAt(c);
if (char !== ' ') {
word += char;
}
else if(word.length > 0) {
words.push(word);
word = '';
}
}
if(word.length > 0) {
words.push(word);
}
return words;
}
function formatPinyin() {
var pinyinElement = document.getElementById('pinyin');
var pinyinCharacters = splitWords(pinyinElement.innerHTML);
var formattedPinyin = '';
for (var i = 0; i < pinyinCharacters.length; i++) {
formattedPinyin += formatPinyinCharacter(pinyinCharacters[i]);
}
pinyinElement.innerHTML = formattedPinyin;
}
formatPinyin();
</script>
<!-- END Back of card. -->
<!--Put the contents of the <style> tag into Anki's "Styling" section. -->
<style>
.card {
font-family: arial;
font-size: 20px;
text-align: center;
color: black;
background-color: white;
}
.tone1 {
color: red;
}
.tone2 {
color: orange;
}
.tone3 {
color: green;
}
.tone4 {
color: blue;
}
.tone5 {
color: darkgrey;
}
a {
text-decoration: none;
}
a:visited {
text-decoration: none;
}
a:visited.tone1 {
color: red;
}
a:visited.tone2 {
color: orange;
}
a:visited.tone3 {
color: green;
}
a:visited.tone4 {
color: blue;
}
a:visited.tone5 {
color: darkgrey;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment