This is a project for making Chinese study, through Anki, more enjoyable by automatically styling the flashcards and providing convenience features. This project enables one to focus more on studying rather than perfecting their form of studying.
The below is showcasing various phonic types and orientations. This may be configured to your preferred study needs. The variety shown is for demonstration purposes.
Recognition | Sentence |
---|---|
Tones | Secondary Recognition |
---|---|
Secondary Sentence | Audio |
---|---|
Writing (Under Construction) |
---|
This one has regressed too much. It was left un-maintained after several upgrades and isn't worth showing in its current state. Works fine in prior versions if you are eager to utilize it. |
Whether your study involves simplified or traditional characters, this project can make Chinese flashcards look nice by copying/pasting a few lines of logic in your Anki template. It can also auto-magically generate some data, please go here to see what is available.
Try it out now by navigating to the jsFiddle page, or follow the instructions below to set this up within your own installation of Anki.
YOUR_FIELD_NAME
with the names defined in your deck (see {{text:YOUR_FIELD_NAME}})Aside from making your flashcards look beautiful, this project has a few note-worthy features:
Simplified And/Or Traditional Character Support
Automatic Secondary Character Generation
Pinyin Or Zhuyin Phonic Support
Automatic Phonic Generation
Dictionary Integration
Stroke Order Animation - Under Construction
A full example of the Front of a recognition card is found below:
<!--Styling may be placed in the Styling Anki tab - but for ease of use let's add it here only-->
<style>
/*desktop anki*/
body {
margin: 0;
}
/*ankidroid*/
#content {
margin: 0;
}
</style>
<script>
// if the custom element material-beautify-chinese-study is not a known element
//// manually create the html script to import the module so the browser has
//// the necessary logic to create element
if (!customElements.get('material-beautify-chinese-study')) {
console.log('Custom element does not exist - Creating script to pull it in');
var script = document.createElement('script');
script.setAttribute('id', 'import-script');
script.setAttribute('type', 'module');
// this will retrieve the newest, bleeding edge version of the package
// doing this could cause issues if something in the package is updated and the older
//// version no longer exists
// one solution is to require a specific version by adding @VERSION-NUMBER like the example below
//// https://cdn.jsdelivr.net/npm/beautify-chinese-study@1.1.48/dist/beautify-chinese-study/beautify-chinese-study.esm.js
// versions can be viewed here https://www.npmjs.com/package/beautify-chinese-study
script.setAttribute('src', 'https://cdn.jsdelivr.net/npm/beautify-chinese-study/dist/beautify-chinese-study/beautify-chinese-study.esm.js');
document.body.appendChild(script);
} else {
console.log('Custom element exists.');
}
// locate the custom element material-beautify-chinese-study on the DOM
//// if it has data - remove everything
var beautify = document.querySelector('material-beautify-chinese-study');
if (beautify !== null) {
beautify.remove();
}
// create a brand new material-beautify-chinese-study element and define
//// its attributes and attribute values
// IMPORTANT - the text below that contains {{text:YOUR_FIELD_NAME}} is meant to be exchanged
//// with the field names on your Anki card fields
//// eg if the english translation field on your Anki card is called English the value you type below
//// would be
//// beautify.setAttribute('meaning', "{{text:English}}")
// Remove the above references to {{text:YOUR_FIELD_NAME}} and {{text:EngLish}}
//// even though they are comments - Anki will still see this as an error
var beautify = document.createElement('material-beautify-chinese-study');
beautify.setAttribute('id', 'beautify');
beautify.setAttribute('primary-character', `{{text:YOUR_FIELD_NAME}}`);
beautify.setAttribute('secondary-character', `{{text:YOUR_FIELD_NAME}}`);
beautify.setAttribute('numbered-pinyin', `{{text:YOUR_FIELD_NAME}}`);
beautify.setAttribute('primary-character-sentence', `{{text:YOUR_FIELD_NAME}}`);
beautify.setAttribute('secondary-character-sentence', `{{text:YOUR_FIELD_NAME}}`);
beautify.setAttribute('sentence-numbered-pinyin', `{{text:YOUR_FIELD_NAME}}`);
beautify.setAttribute('meaning', `{{text:YOUR_FIELD_NAME}}`);
beautify.setAttribute('card-type', 'recognition');
beautify.setAttribute('card-orientation', 'question');
beautify.setAttribute('preferred-phonic', 'zhuyin');
// add the element to the DOM body
document.body.appendChild(beautify);
</script>
<!--Always add audio and keep it invisible-->
<div style="display:none;">{{Audio}}{{SentenceAudio}}</div>
A full example of the Back of a recognition card is found below:
<!--Styling may be placed in the Styling Anki tab - but for ease of use let's add it here only-->
<style>
/*desktop anki*/
body {
margin: 0;
}
/*ankidroid*/
#content {
margin: 0;
}
</style>
<script>
// if the custom element material-beautify-chinese-study is not a known element
//// manually create the html script to import the module so the browser has
//// the necessary logic to create element
if (!customElements.get('material-beautify-chinese-study')) {
var script = document.createElement('script');
script.setAttribute('id', 'import-script');
script.setAttribute('type', 'module');
// this will retrieve the newest, bleeding edge version of the package
// doing this could cause issues if something in the package is updated and the older
//// version no longer exists
// one solution is to require a specific version by adding @VERSION-NUMBER like the example below
//// https://cdn.jsdelivr.net/npm/beautify-chinese-study@1.1.48/dist/beautify-chinese-study/beautify-chinese-study.esm.js
// versions can be viewed here https://www.npmjs.com/package/beautify-chinese-study
script.setAttribute('src', 'https://cdn.jsdelivr.net/npm/beautify-chinese-study/dist/beautify-chinese-study/beautify-chinese-study.esm.js');
document.body.appendChild(script);
}
// since we are on the back of the card the custom element from the front of the card
//// may have been retained - in instances of AnkiDroid a new webview is created and
//// the element will need to be recreated from scratch
var beautify = document.querySelector('#beautify');
if (!beautify) {
// probably executing because on AnkiDroid
// recreating element from scratch
// IMPORTANT - the text below that contains {{text:YOUR_FIELD_NAME}} is meant to be exchanged
//// with the field names on your Anki card fields
//// eg if the english translation field on your Anki card is called EngLish the value you type below
//// would be
//// beautify.setAttribute('meaning', "{{text:EngLish}}")
// Remove the above references to {{text:YOUR_FIELD_NAME}} and {{text:EngLish}}
//// even though they are comments - Anki will still see this as an error
var beautify = document.createElement('material-beautify-chinese-study');
beautify.setAttribute('id', 'beautify');
beautify.setAttribute('primary-character', `{{text:YOUR_FIELD_NAME}}`);
beautify.setAttribute('secondary-character', `{{text:YOUR_FIELD_NAME}}`);
beautify.setAttribute('writing', `{{text:YOUR_FIELD_NAME}}`);
beautify.setAttribute('numbered-pinyin', `{{text:YOUR_FIELD_NAME}}`);
beautify.setAttribute('primary-character-sentence', `{{text:YOUR_FIELD_NAME}}`);
beautify.setAttribute('secondary-character-sentence', `{{text:YOUR_FIELD_NAME}}`);
beautify.setAttribute('sentence-numbered-pinyin', `{{text:YOUR_FIELD_NAME}}`);
beautify.setAttribute('meaning', `{{text:YOUR_FIELD_NAME}}`);
beautify.setAttribute('card-type', 'recognition');
beautify.setAttribute('card-orientation', 'answer');
beautify.setAttribute('preferred-phonic', 'zhuyin');
document.body.appendChild(beautify);
} else {
// element already exist
// redefine the card type just for safe keeping
// redefine the card orientation to display the answer logic
beautify.setAttribute('card-type', 'recognition');
beautify.setAttribute('card-orientation', 'answer');
}
</script>
<!--Always add audio and keep it invisible-->
<div style="display:none;">{{Audio}}{{SentenceAudio}}</div>
The logic attempts to make custom styling and additional logic work the same across Desktop Anki and Anki Droid (ios anki not tested). The above code snippets contain inline comments to address what is being done, but an explanation is also below.
Feel free see to this project in action using this jsFiddle.
Feel free to browse over my personal cards that I have saved in Anki.
Anki utilizes web technologies to generate its flashcards. This codebase is using a technology called Web Components that will allow users to add three html tags(due to different behaviours between Anki Clients we have to add some logic as a workaround for Anki's inconsistent behaviour) the above logic to their Anki card templates, and the rest is handled automatically by the web component.
While this project handles most of the styling for the user, there is styling that cannot be overridden from Anki Desktop and AnkiDroid (iOS anki app not tested). Fortunately, by adding a few lines this can be fixed. These few lines of code are in the above code snippet, but may also be placed an Anki's Template Styling section. It is up to the user's preference for the placement of the CSS code. Functionality, it makes no difference where it is located.
At the time of this writing, there are seven different template types that may be used. The following will be a list of fields that are mandatory to successfully generate the card template; in addition to the mandatory types, please feel free to add any other optional data as they will be available on each card - all available attribute values found here:
In addition to the above information needed for particular card types, the following is also needed:
Please follow the link here to read the full documentation of this element. This documentation is autogenerated and more reliable than handwriting it.
Please feel free to make any improvements to the project as you see fit by creating a Pull Request with a detailed description about the issue
or enhancement
that your PR will be adding to the project. Please also be sure to add a how
section that gives a brief overview of how the issue
or enhancement
is being done.
If you want to get an idea of what I am thinking of for improvements to the repo, please head over to the Improvements section. It's, roughly, listed from most important to least important.
This project uses Typescript, which means that any code found in the dist
directory is ephemeral, or computer generated code and will be deleted and recreated each time the Typescript files are transpiled. If you are new to Typescript please familarize yourself with the basics. I'd hate for someone to spend a long time on a great contribution but be unaware that the Javascript code is computer generated.
This project is leveraging the StencilJs library to create Web Components in Typescript.
See issue tab for more information.
typing
type card is being developed utilizing Anki's {{type:FIELD_NAME_HERE}}
functionality.There are three strategies we recommend for using web components built with Stencil.
The first step for all three of these strategies is to publish to NPM.
Assuming you are already logged in, the steps are below:
npm version MANUALLY-INCREMENT-VERSION-NUMBER
package.json
filenpm publish --access public
<script src='https://unpkg.com/my-component@0.0.1/dist/mycomponent.js'></script>
in the head of your index.htmlnpm run build
A release via GitHub will create a git tag and publish a new version to the npm registry. These releases and tags need to be named the version that is intended for npm registry.