├── .nvmrc
├── .github
├── ISSUE_TEMPLATE
│ ├── config.yml
│ ├── system-support.md
│ ├── feature-request.yml
│ └── bug-report.yml
├── FUNDING.yml
├── dependabot.yml
└── workflows
│ ├── checks.yml
│ └── release.yml
├── .gulp.json
├── .husky
└── pre-commit
├── src
├── fonts
│ ├── ArCiela.ttf
│ ├── Aztec.ttf
│ ├── Daedra.otf
│ ├── Davek.otf
│ ├── Dethek.otf
│ ├── Espruar.otf
│ ├── Floki.ttf
│ ├── Kargi.ttf
│ ├── Pulsian.ttf
│ ├── Qijomi.otf
│ ├── Saurian.ttf
│ ├── Skaven.ttf
│ ├── Tengwar.ttf
│ ├── Thorass.otf
│ ├── Tuzluca.ttf
│ ├── Barazhad.otf
│ ├── Celestial.ttf
│ ├── DarkEldar.ttf
│ ├── Eltharin.ttf
│ ├── Infernal.ttf
│ ├── Iokharic.otf
│ ├── MarasEye.otf
│ ├── MusiQwik.ttf
│ ├── Ophidian.otf
│ ├── Oriental.ttf
│ ├── OrkGlyphs.ttf
│ ├── Rellanic.otf
│ ├── Semphari.otf
│ ├── Valmaric.ttf
│ ├── HighDrowic.otf
│ ├── JungleSlang.ttf
│ ├── MageScript.otf
│ ├── NyStormning.otf
│ ├── OldeEnglish.ttf
│ ├── OldeEspruar.otf
│ ├── OldeThorass.otf
│ ├── Reanaarian.otf
│ ├── Thassilonian.ttf
│ ├── ElderFutharkFS.ttf
│ ├── FingerAlphabet.ttf
│ ├── KremlinPremier.ttf
│ ├── MiroslavNormal.ttf
│ ├── HighschoolRunes.ttf
│ ├── MeroiticDemotic.ttf
│ ├── ScrapbookChinese.ttf
│ ├── dragon_alphabet.ttf
│ ├── licenses
│ │ ├── elder futhark fs.txt
│ │ ├── aztec.txt
│ │ ├── kremlin premier.txt
│ │ ├── infernal.txt
│ │ ├── dragon alphabet.txt
│ │ ├── pixel sagas.txt
│ │ └── ny stormning.txt
│ └── _licenses.md
├── styles
│ ├── _system-specific.scss
│ ├── _forms.scss
│ ├── forms
│ │ ├── _general-settings.scss
│ │ ├── _common.scss
│ │ ├── _font-settings.scss
│ │ └── _language-settings.scss
│ ├── _journal.scss
│ ├── _chat.scss
│ ├── _init.scss
│ ├── _language-selector.scss
│ ├── polyglot.scss
│ └── fonts.css
├── module
│ ├── providers
│ │ ├── _shared.js
│ │ ├── fgg.js
│ │ ├── splittermond.js
│ │ ├── dcc.js
│ │ ├── aria.js
│ │ ├── d35e.js
│ │ ├── coc7.js
│ │ ├── templates
│ │ │ └── Generic.js
│ │ ├── sfrpg.js
│ │ ├── dnd4e.js
│ │ ├── ars.js
│ │ ├── shadowrun5e.js
│ │ ├── tormenta20.js
│ │ ├── uesrpg-d100.js
│ │ ├── _module.js
│ │ ├── a5e.js
│ │ ├── dark-heresy.js
│ │ ├── wwn.js
│ │ ├── swade.js
│ │ ├── earthdawn4e.js
│ │ ├── demonlord.js
│ │ ├── ose.js
│ │ ├── gurps.js
│ │ ├── wfrp4e.js
│ │ ├── draw-steel.js
│ │ ├── pf1.js
│ │ ├── cyberpunk-red-core.js
│ │ ├── dnd5e.js
│ │ └── sw5e.js
│ ├── preloadTemplates.js
│ ├── libs
│ │ ├── colorPicker.js
│ │ └── libWrapper.js
│ ├── polyglot.js
│ ├── api.js
│ ├── tour.js
│ └── forms
│ │ ├── FontSettings.js
│ │ ├── LanguageSettings.js
│ │ └── GeneralSettings.js
├── templates
│ ├── GeneralSettings.hbs
│ ├── partials
│ │ └── settings.hbs
│ ├── FontSettings.hbs
│ └── LanguageSettings.hbs
├── module.json
└── lang
│ ├── ja.json
│ ├── ko.json
│ ├── sv.json
│ ├── it.json
│ ├── es.json
│ └── fi.json
├── .prettierignore
├── .eslintignore
├── .prettierrc
├── .editorconfig
├── rollup.config.mjs
├── .gitignore
├── package.json
├── LICENSE.txt
├── README.md
├── CONTRIBUTING.md
├── gulpfile.mjs
└── .eslintrc.cjs
/.nvmrc:
--------------------------------------------------------------------------------
1 | lts/*
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 |
--------------------------------------------------------------------------------
/.gulp.json:
--------------------------------------------------------------------------------
1 | {
2 | "flags": {
3 | "gulpfile": "gulpfile.mjs"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | . "$(dirname -- "$0")/_/husky.sh"
3 |
4 | npx lint-staged
5 |
--------------------------------------------------------------------------------
/src/fonts/ArCiela.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/ArCiela.ttf
--------------------------------------------------------------------------------
/src/fonts/Aztec.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/Aztec.ttf
--------------------------------------------------------------------------------
/src/fonts/Daedra.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/Daedra.otf
--------------------------------------------------------------------------------
/src/fonts/Davek.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/Davek.otf
--------------------------------------------------------------------------------
/src/fonts/Dethek.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/Dethek.otf
--------------------------------------------------------------------------------
/src/fonts/Espruar.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/Espruar.otf
--------------------------------------------------------------------------------
/src/fonts/Floki.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/Floki.ttf
--------------------------------------------------------------------------------
/src/fonts/Kargi.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/Kargi.ttf
--------------------------------------------------------------------------------
/src/fonts/Pulsian.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/Pulsian.ttf
--------------------------------------------------------------------------------
/src/fonts/Qijomi.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/Qijomi.otf
--------------------------------------------------------------------------------
/src/fonts/Saurian.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/Saurian.ttf
--------------------------------------------------------------------------------
/src/fonts/Skaven.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/Skaven.ttf
--------------------------------------------------------------------------------
/src/fonts/Tengwar.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/Tengwar.ttf
--------------------------------------------------------------------------------
/src/fonts/Thorass.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/Thorass.otf
--------------------------------------------------------------------------------
/src/fonts/Tuzluca.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/Tuzluca.ttf
--------------------------------------------------------------------------------
/src/fonts/Barazhad.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/Barazhad.otf
--------------------------------------------------------------------------------
/src/fonts/Celestial.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/Celestial.ttf
--------------------------------------------------------------------------------
/src/fonts/DarkEldar.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/DarkEldar.ttf
--------------------------------------------------------------------------------
/src/fonts/Eltharin.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/Eltharin.ttf
--------------------------------------------------------------------------------
/src/fonts/Infernal.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/Infernal.ttf
--------------------------------------------------------------------------------
/src/fonts/Iokharic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/Iokharic.otf
--------------------------------------------------------------------------------
/src/fonts/MarasEye.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/MarasEye.otf
--------------------------------------------------------------------------------
/src/fonts/MusiQwik.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/MusiQwik.ttf
--------------------------------------------------------------------------------
/src/fonts/Ophidian.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/Ophidian.otf
--------------------------------------------------------------------------------
/src/fonts/Oriental.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/Oriental.ttf
--------------------------------------------------------------------------------
/src/fonts/OrkGlyphs.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/OrkGlyphs.ttf
--------------------------------------------------------------------------------
/src/fonts/Rellanic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/Rellanic.otf
--------------------------------------------------------------------------------
/src/fonts/Semphari.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/Semphari.otf
--------------------------------------------------------------------------------
/src/fonts/Valmaric.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/Valmaric.ttf
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | dist
2 | module.json
3 |
4 | **/*.js
5 | **/*.cjs
6 | **/*.mjs
7 | **/fonts.css
8 | **/_fonts.scss
--------------------------------------------------------------------------------
/src/fonts/HighDrowic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/HighDrowic.otf
--------------------------------------------------------------------------------
/src/fonts/JungleSlang.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/JungleSlang.ttf
--------------------------------------------------------------------------------
/src/fonts/MageScript.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/MageScript.otf
--------------------------------------------------------------------------------
/src/fonts/NyStormning.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/NyStormning.otf
--------------------------------------------------------------------------------
/src/fonts/OldeEnglish.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/OldeEnglish.ttf
--------------------------------------------------------------------------------
/src/fonts/OldeEspruar.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/OldeEspruar.otf
--------------------------------------------------------------------------------
/src/fonts/OldeThorass.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/OldeThorass.otf
--------------------------------------------------------------------------------
/src/fonts/Reanaarian.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/Reanaarian.otf
--------------------------------------------------------------------------------
/src/fonts/Thassilonian.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/Thassilonian.ttf
--------------------------------------------------------------------------------
/src/fonts/ElderFutharkFS.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/ElderFutharkFS.ttf
--------------------------------------------------------------------------------
/src/fonts/FingerAlphabet.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/FingerAlphabet.ttf
--------------------------------------------------------------------------------
/src/fonts/KremlinPremier.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/KremlinPremier.ttf
--------------------------------------------------------------------------------
/src/fonts/MiroslavNormal.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/MiroslavNormal.ttf
--------------------------------------------------------------------------------
/src/fonts/HighschoolRunes.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/HighschoolRunes.ttf
--------------------------------------------------------------------------------
/src/fonts/MeroiticDemotic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/MeroiticDemotic.ttf
--------------------------------------------------------------------------------
/src/fonts/ScrapbookChinese.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/ScrapbookChinese.ttf
--------------------------------------------------------------------------------
/src/fonts/dragon_alphabet.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mclemente/fvtt-module-polyglot/HEAD/src/fonts/dragon_alphabet.ttf
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: mclemente
2 | ko_fi: mclemente
3 | custom: https://www.paypal.com/donate/?hosted_button_id=UVFV99HDGE5F8
4 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2022 Johannes Loher
2 | #
3 | # SPDX-License-Identifier: MIT
4 |
5 | dist
6 | gulpfile.mjs
7 | libWrapper.js
--------------------------------------------------------------------------------
/src/styles/_system-specific.scss:
--------------------------------------------------------------------------------
1 | &.wfrp4e {
2 | select {
3 | color: $color_1;
4 | option {
5 | color: $color_2;
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/styles/_forms.scss:
--------------------------------------------------------------------------------
1 | @import "forms/common";
2 | @import "forms/font-settings";
3 | @import "forms/general-settings";
4 | @import "forms/language-settings";
5 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 120,
3 | "tabWidth": 4,
4 | "useTabs": true,
5 | "overrides": [
6 | {
7 | "files": "**/*.{hbs}",
8 | "options": {
9 | "parser": "glimmer"
10 | }
11 | }
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/src/module/providers/_shared.js:
--------------------------------------------------------------------------------
1 | /** Providers whose systems use "-"" in their names */
2 | export const providerKeys = {
3 | "cyberpunk-red-core": "cyberpunkRed",
4 | "dark-heresy": "darkHeresy",
5 | "draw-steel": "drawSteel",
6 | "uesrpg-d100": "uesrpg",
7 | };
8 |
--------------------------------------------------------------------------------
/src/styles/forms/_general-settings.scss:
--------------------------------------------------------------------------------
1 | &.polyglot-general-settings {
2 | .tab {
3 | .form-group {
4 | textarea {
5 | resize: vertical;
6 | min-height: 57px;
7 | }
8 | select[name="allowOOC"] {
9 | flex: 1;
10 | }
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/fonts/licenses/elder futhark fs.txt:
--------------------------------------------------------------------------------
1 | The FontStruction “Elder Futhark *FS”
2 | (https://fontstruct.com/fontstructions/show/1527205) by Doug Peters is licensed
3 | under a Creative Commons Attribution Share Alike license
4 | (http://creativecommons.org/licenses/by-sa/3.0/).
5 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "npm"
4 | directory: "/"
5 | schedule:
6 | interval: "weekly"
7 |
8 | - package-ecosystem: "github-actions"
9 | directory: "/"
10 | schedule:
11 | interval: "weekly"
12 |
--------------------------------------------------------------------------------
/src/styles/_journal.scss:
--------------------------------------------------------------------------------
1 | .polyglot-journal {
2 | background-color: $background-color_1;
3 |
4 | &-temp {
5 | background-color: $background-color_2;
6 | }
7 | }
8 | li[data-action="polyglot"] {
9 | ul {
10 | max-height: 100vh;
11 | overflow: auto;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2022 Johannes Loher
2 | #
3 | # SPDX-License-Identifier: MIT
4 |
5 | root = true
6 |
7 | [*]
8 | end_of_line = lf
9 | insert_final_newline = true
10 | indent_style = space
11 | indent_size = 2
12 | charset = utf-8
13 | trim_trailing_whitespace = true
14 |
--------------------------------------------------------------------------------
/src/styles/_chat.scss:
--------------------------------------------------------------------------------
1 | .polyglot-translation-text {
2 | border-top: 1px solid var(--color-border-light-2);
3 | -webkit-user-select: text;
4 | -moz-user-select: text;
5 | -ms-user-select: text;
6 | user-select: text;
7 | }
8 |
9 | a.polyglot-message-language.unclickable {
10 | cursor: default;
11 | }
12 |
--------------------------------------------------------------------------------
/src/fonts/licenses/aztec.txt:
--------------------------------------------------------------------------------
1 | This font is made by Levi and may be used free of charge for non-commercial projects. Please contact me if you plan to use it for other purposes. It also may be distributed free of charge on any websites provided this file is intact.
2 | Contact:
3 | url: http://www.geocities.com/noimage_2001/
4 | email: halmoslevi@yahoo.com
5 |
--------------------------------------------------------------------------------
/rollup.config.mjs:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: 2022 Johannes Loher
2 | // SPDX-FileCopyrightText: 2022 David Archibald
3 | //
4 | // SPDX-License-Identifier: MIT
5 |
6 | import { nodeResolve } from "@rollup/plugin-node-resolve";
7 |
8 | export default () => ({
9 | input: "src/module/polyglot.js",
10 | output: {
11 | dir: "dist/module",
12 | format: "es",
13 | sourcemap: true,
14 | },
15 | plugins: [nodeResolve()],
16 | });
17 |
--------------------------------------------------------------------------------
/src/styles/forms/_common.scss:
--------------------------------------------------------------------------------
1 | & {
2 | .polyglot-languages-list {
3 | list-style: none;
4 | padding: 0;
5 |
6 | li {
7 | &.flexrow {
8 | flex-wrap: nowrap;
9 | }
10 | }
11 | }
12 |
13 | input.selectatr[type="number"] {
14 | width: 30px;
15 | height: 100%;
16 | background: none;
17 | border: none;
18 | border-radius: 0;
19 | border-bottom: 1px solid var(--color-border-light-tertiary);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/styles/_init.scss:
--------------------------------------------------------------------------------
1 | $color_1: #e2e2e2;
2 | $color_2: fieldtext;
3 | $color_3: red;
4 | $font-family_1: var(--polyglot-chat-bubble-font);
5 | $background-color_1: rgba(var(--polyglot-journal-color), var(--polyglot-journal-opacity));
6 | $background-color_2: rgba(var(--polyglot-journal-color-temp), var(--polyglot-journal-opacity-temp));
7 | $background-color_3: rgba(255, 255, 255, 0.4);
8 | $border-color_1: fieldtext transparent transparent transparent;
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2022 Johannes Loher
2 | #
3 | # SPDX-License-Identifier: MIT
4 |
5 | # IDE
6 | .idea/
7 | .vs/
8 |
9 | # Node Modules
10 | node_modules/
11 | npm-debug.log
12 |
13 | # yarn2
14 | .yarn/*
15 | !.yarn/patches
16 | !.yarn/releases
17 | !.yarn/plugins
18 | !.yarn/sdks
19 | !.yarn/versions
20 | .pnp.*
21 |
22 | # Local configuration
23 | foundryconfig.json
24 |
25 | # Distribution files
26 | dist
27 |
28 | # ESLint
29 | .eslintcache
30 |
31 | # Junit results
32 | junit.xml
33 |
--------------------------------------------------------------------------------
/src/module/preloadTemplates.js:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: 2022 Johannes Loher
2 | //
3 | // SPDX-License-Identifier: MIT
4 |
5 | export async function preloadTemplates() {
6 | const templatePaths = [
7 | "modules/polyglot/templates/partials/settings.hbs",
8 | "modules/polyglot/templates/FontSettings.hbs",
9 | "modules/polyglot/templates/GeneralSettings.hbs",
10 | "modules/polyglot/templates/LanguageSettings.hbs",
11 | ];
12 |
13 | return foundry.applications.handlebars.loadTemplates(templatePaths);
14 | }
15 |
--------------------------------------------------------------------------------
/src/module/providers/fgg.js:
--------------------------------------------------------------------------------
1 | import LanguageProvider from "./templates/Base.js";
2 |
3 | export default class fggLanguageProvider extends LanguageProvider {
4 | getUserLanguages(actor) {
5 | let knownLanguages = new Set();
6 | let literateLanguages = new Set();
7 | for (let lang of actor.system.languages.value) knownLanguages.add(lang.toLowerCase());
8 | if (actor.system.languages.custom) {
9 | for (let lang of actor.system.languages.custom.split(/[,;]/)) knownLanguages.add(lang.trim().toLowerCase());
10 | }
11 | return [knownLanguages, literateLanguages];
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/styles/forms/_font-settings.scss:
--------------------------------------------------------------------------------
1 | &.polyglot-font-settings {
2 | min-height: 255px;
3 | min-width: 780px;
4 |
5 | input.selectatr[type="number"] {
6 | width: 40px;
7 | }
8 |
9 | .polyglot-alphabet {
10 | margin: auto;
11 | }
12 | .font-name {
13 | flex: 0 0 150px;
14 | margin: auto;
15 | }
16 |
17 | .polyglot-languages-list {
18 | margin: 0;
19 |
20 | li {
21 | .font-name {
22 | flex: 0 0 150px;
23 | margin: auto;
24 | }
25 | .fontSize {
26 | flex: 0 0 90px;
27 | text-align: center;
28 | margin: auto;
29 | }
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/styles/forms/_language-settings.scss:
--------------------------------------------------------------------------------
1 | &.polyglot-language-settings {
2 | min-height: 265px;
3 | min-width: 600px;
4 |
5 | .font-name {
6 | text-transform: capitalize;
7 | }
8 | .selectatr {
9 | text-transform: capitalize;
10 | }
11 | .window-content {
12 | padding: 0;
13 | }
14 | form {
15 | height: 100%;
16 | section {
17 | padding: 1rem;
18 | overflow: hidden auto;
19 | }
20 | footer {
21 | margin: 1rem;
22 | flex: 0;
23 | }
24 | }
25 |
26 | .polyglot-languages-warn {
27 | font-weight: bold;
28 | color: $color_3;
29 | text-align: center;
30 | margin-bottom: 0.5em;
31 | display: none;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/module/libs/colorPicker.js:
--------------------------------------------------------------------------------
1 | // Color Picker by kaelad02
2 | // License: MIT
3 | // Documentation: https://github.com/kaelad02/adv-reminder/blob/54207ec1ef0500439e57521f15956c07e4c02af4/src/settings.js#L91-L104
4 |
5 | export function colorPicker(settingId, html, settingValue) {
6 | const colorPickerElement = document.createElement("input");
7 | colorPickerElement.setAttribute("type", "color");
8 | colorPickerElement.setAttribute("data-edit", settingId);
9 | colorPickerElement.value = settingValue;
10 |
11 | // Add color picker
12 | const stringInputElement = html[0].querySelector(`input[name="${settingId}"]`);
13 | stringInputElement.classList.add("color");
14 | stringInputElement.after(colorPickerElement);
15 | }
16 |
--------------------------------------------------------------------------------
/src/module/providers/splittermond.js:
--------------------------------------------------------------------------------
1 | import LanguageProvider from "./templates/Base.js";
2 |
3 | export default class splittermondLanguageProvider extends LanguageProvider {
4 | getUserLanguages(actor) {
5 | let knownLanguages = new Set();
6 | let literateLanguages = new Set();
7 | const isLiterate = actor.items.filter((item) => item.name === "Literat" && item.type === "strength").length > 0;
8 | actor.items
9 | .filter((item) => item.type === "language")
10 | .forEach((item) => {
11 | const name = item.name.trim().toLowerCase();
12 | knownLanguages.add(name);
13 | if (isLiterate) literateLanguages.add(name);
14 | });
15 | return [knownLanguages, literateLanguages];
16 | }
17 |
18 | conditions(lang) {
19 | return game.polyglot.literateLanguages.has(lang);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/system-support.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: System support
3 | about: Request to support a system
4 | title: ''
5 | labels: enhancement, system support
6 | assignees: ''
7 |
8 | ---
9 |
10 | **System Name:**
11 | e.g. D&D 5e
12 |
13 | **System Repository or Foundry VTT link:**
14 | e.g. https://gitlab.com/foundrynet/dnd5e or https://foundryvtt.com/packages/dnd5e/
15 |
16 | **Does the system has the languages set up on Foundry?**
17 | It's generally on modules/config.js file
18 |
19 | **Does the system uses languages as items?**
20 | Similar to how WFRP and SWADE do.
21 |
22 | **[Optional] If it isn't straightforward, how do I add a language to a character?**
23 | e.g. DCC system doesn't inform you that you need to change your sheet template to add languages.
24 |
25 | **Additional context**
26 | Add any other context about the system here.
27 |
--------------------------------------------------------------------------------
/src/styles/_language-selector.scss:
--------------------------------------------------------------------------------
1 | &.polyglot-lang-select {
2 | margin: -6px 0;
3 | .ts-wrapper {
4 | &.disabled {
5 | text-decoration: line-through;
6 | }
7 | .ts-control {
8 | background: var(--color-cool-5-75);
9 | border: none;
10 | border-radius: 4px;
11 | padding: 1px 8px;
12 | }
13 | .ts-dropdown {
14 | bottom: 100%;
15 | top: unset;
16 | .optgroup-header, .option {
17 | padding: 1px 8px;
18 | }
19 | }
20 | &.focus .ts-control, .ts-control:hover {
21 | background: var(--color-cool-5);
22 | }
23 | &.input-active .ts-control {
24 | cursor: pointer;
25 | }
26 | }
27 | }
28 |
29 | &.polyglot-user-list {
30 | display: inline-flex;
31 | max-width: max-content;
32 | margin: auto;
33 | flex-wrap: wrap;
34 | div {
35 | width: 10px;
36 | height: 10px;
37 | border-radius: 50%;
38 | margin: 1px 2px;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/templates/GeneralSettings.hbs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/module/providers/dcc.js:
--------------------------------------------------------------------------------
1 | import LanguageProvider from "./templates/Base.js";
2 |
3 | export default class dccLanguageProvider extends LanguageProvider {
4 | languages = {
5 | common: {
6 | font: "Thorass",
7 | },
8 | draconic: {
9 | font: "Iokharic",
10 | },
11 | dwarvish: {
12 | font: "Dethek",
13 | },
14 | elvish: {
15 | font: "Espruar",
16 | },
17 | giant: {
18 | font: "Dethek",
19 | },
20 | gnoll: {
21 | font: "Kargi",
22 | },
23 | goblin: {
24 | font: "Dethek",
25 | },
26 | halfling: {
27 | font: "Thorass",
28 | },
29 | orc: {
30 | font: "Dethek",
31 | },
32 | cant: {
33 | font: "Thorass",
34 | },
35 | };
36 |
37 | getUserLanguages(actor) {
38 | let knownLanguages = new Set();
39 | let literateLanguages = new Set();
40 | for (let lang of actor.system.details.languages.split(/[,;]/)) knownLanguages.add(lang.trim().toLowerCase());
41 | return [knownLanguages, literateLanguages];
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "build": "gulp build",
4 | "build:watch": "gulp watch",
5 | "link-project": "gulp link",
6 | "clean": "gulp clean",
7 | "clean:link": "gulp link --clean",
8 | "lint": "eslint --ext .js,.cjs,.mjs .",
9 | "lint:fix": "eslint --ext .js,.cjs,.mjs --fix .",
10 | "postinstall": "husky install"
11 | },
12 | "devDependencies": {
13 | "@rollup/plugin-node-resolve": "^16.0.3",
14 | "@rollup/stream": "^3.0.1",
15 | "@typhonjs-fvtt/eslint-config-foundry.js": "^0.8.0",
16 | "eslint": "^8.57.1",
17 | "fs-extra": "^11.3.2",
18 | "gulp": "^5.0.1",
19 | "gulp-autoprefixer": "^10.0.0",
20 | "gulp-dart-sass": "^1.1.0",
21 | "gulp-sourcemaps": "^3.0.0",
22 | "husky": "^9.1.7",
23 | "lint-staged": "^16.2.5",
24 | "rollup": "^2.79.2",
25 | "tom-select": "^2.4.3",
26 | "vinyl-buffer": "^1.0.1",
27 | "vinyl-source-stream": "^2.0.0",
28 | "yargs": "^18.0.0"
29 | },
30 | "lint-staged": {
31 | "*.(js|cjs|mjs)": "eslint --fix",
32 | "*.(html|hbs|json|yml|css)": "prettier --write"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/fonts/licenses/kremlin premier.txt:
--------------------------------------------------------------------------------
1 | BoltCutterDesign True Type Fonts/graphics
2 | Copyright (C) 2008 BCD/MFA
3 |
4 | This program/graphic is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version. It may not be sold/resold individualy or
8 | in a compilation.
9 |
10 | This notice must accompany the font/graphic upon distribution/redistribution.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | http://www.gnu.org/copyleft/gpl.html
21 |
22 | boltcutterdesign@yahoo.com
23 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Matheus Pereira Clemente
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.yml:
--------------------------------------------------------------------------------
1 | name: Feature Request
2 | description: Request a Feature
3 | labels: ["enhancement"]
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: |
8 | Use this form to request a new Feature or an update to an existing Feature on Polyglot
9 | - type: textarea
10 | id: user-experience
11 | attributes:
12 | label: User Experience
13 | description: What problem does this solve? What should it function like?
14 | placeholder: In order to help with bulk creation of documents, I would like a new button...
15 | validations:
16 | required: true
17 | - type: checkboxes
18 | id: checkboxes
19 | attributes:
20 | label: Have you read the Wiki?
21 | description: "Are you sure you're not suggesting something that hasn't [already been implemented](https://github.com/mclemente/fvtt-module-polyglot/wiki#features) or that doesn't break [core Foundry behavior](https://github.com/mclemente/fvtt-module-polyglot/wiki#understanding-core-behavior)?"
22 | options:
23 | - label: "Yes"
24 | required: true
25 | validations:
26 | required: true
27 |
--------------------------------------------------------------------------------
/src/templates/partials/settings.hbs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/module/providers/aria.js:
--------------------------------------------------------------------------------
1 | import LanguageProvider from "./templates/Base.js";
2 |
3 | export default class ariaLanguageProvider extends LanguageProvider {
4 | languages = {
5 | common: {
6 | font: "Thorass",
7 | },
8 | kohestien: {
9 | font: "Tuzluca",
10 | },
11 | aqab: {
12 | font: "Ar Ciela",
13 | },
14 | staum: {
15 | font: "Floki",
16 | },
17 | osmanlien: {
18 | font: "Eltharin",
19 | },
20 | mon: {
21 | font: "Valmaric",
22 | },
23 | nok: {
24 | font: "Dark Eldar",
25 | },
26 | carredass: {
27 | font: "Celestial",
28 | },
29 | blanc: {
30 | font: "Ork Glyphs",
31 | },
32 | knigien: {
33 | font: "Tengwar",
34 | },
35 | esperan: {
36 | font: "Thassilonian",
37 | },
38 | altabiancais: {
39 | font: "Espruar",
40 | },
41 | altanegrais: {
42 | font: "Espruar",
43 | },
44 | };
45 |
46 | getUserLanguages(actor) {
47 | let knownLanguages = new Set();
48 | let literateLanguages = new Set();
49 | knownLanguages.add(game.i18n.localize("ARIA.languages.Common"));
50 | for (let lang of actor.items) {
51 | if (lang.system.language) knownLanguages.add(lang.name.toLowerCase());
52 | }
53 | return [knownLanguages, literateLanguages];
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report.yml:
--------------------------------------------------------------------------------
1 | name: Bug Report
2 | description: File a bug report
3 | labels: ["bug"]
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: |
8 | Use this form to report an issue with Polyglot
9 | - type: textarea
10 | id: what-happened
11 | attributes:
12 | label: What happened?
13 | description: Also tell us, what did you expect to happen?
14 | placeholder: Tell us what you see!
15 | validations:
16 | required: true
17 | - type: textarea
18 | id: repro-steps
19 | attributes:
20 | label: Reproduction Steps
21 | description: Keep them simple, include screenshots as needed. Note what System(s) you tested in, if relevant.
22 | placeholder: To encounter the bug, first open up...
23 | validations:
24 | required: true
25 | - type: input
26 | id: game-system
27 | attributes:
28 | label: Which game system, and which version, are you using?
29 | placeholder: "e.g. dnd5e 2.4.1"
30 | validations:
31 | required: true
32 | - type: input
33 | id: polyglot-version
34 | attributes:
35 | label: Which Polyglot version are you using?
36 | placeholder: "e.g. 2.3.28"
37 | validations:
38 | required: true
39 |
--------------------------------------------------------------------------------
/src/templates/FontSettings.hbs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/module/providers/d35e.js:
--------------------------------------------------------------------------------
1 | import LanguageProvider from "./templates/Base.js";
2 |
3 | export default class d35eLanguageProvider extends LanguageProvider {
4 | languages = {
5 | common: {
6 | font: "Thorass",
7 | },
8 | aarakocra: {
9 | font: "Olde Thorass",
10 | },
11 | abyssal: {
12 | font: "Infernal",
13 | },
14 | aquan: {
15 | font: "Dethek",
16 | },
17 | auran: {
18 | font: "Dethek",
19 | },
20 | celestial: {
21 | font: "Celestial",
22 | },
23 | deep: {
24 | font: "Ar Ciela",
25 | },
26 | draconic: {
27 | font: "Iokharic",
28 | },
29 | druidic: {
30 | font: "Jungle Slang",
31 | },
32 | dwarven: {
33 | font: "Dethek",
34 | },
35 | elven: {
36 | font: "Espruar",
37 | },
38 | giant: {
39 | font: "Dethek",
40 | },
41 | gith: {
42 | font: "tirsu",
43 | },
44 | gnoll: {
45 | font: "Kargi",
46 | },
47 | gnome: {
48 | font: "Dethek",
49 | },
50 | goblin: {
51 | font: "Dethek",
52 | },
53 | halfling: {
54 | font: "Thorass",
55 | },
56 | ignan: {
57 | font: "Dethek",
58 | },
59 | infernal: {
60 | font: "Infernal",
61 | },
62 | orc: {
63 | font: "Dethek",
64 | },
65 | primordial: {
66 | font: "Dethek",
67 | },
68 | sylvan: {
69 | font: "Olde Espruar",
70 | },
71 | terran: {
72 | font: "Dethek",
73 | },
74 | cant: {
75 | font: "Thorass",
76 | },
77 | treant: {
78 | font: "Olde Espruar",
79 | },
80 | undercommon: {
81 | font: "High Drowic",
82 | },
83 | };
84 | }
85 |
--------------------------------------------------------------------------------
/src/module/polyglot.js:
--------------------------------------------------------------------------------
1 | import { PolyglotAPI } from "./api.js";
2 | import { Polyglot } from "./logic.js";
3 | import { preloadTemplates } from "./preloadTemplates.js";
4 | import { LanguageProvider } from "./providers/_module.js";
5 | import {
6 | registerProviderSettings,
7 | registerSettings,
8 | renderPolyglotGeneralSettingsHandler
9 | } from "./settings.js";
10 | import { registerTours } from "./tour.js";
11 |
12 | Hooks.once("init", () => {
13 | CONFIG.TinyMCE.content_css.push("/modules/polyglot/styles/polyglot.css");
14 | registerSettings();
15 | const api = new PolyglotAPI();
16 | api.init();
17 | game.polyglot = new Polyglot();
18 | game.polyglot.init();
19 | api.attach();
20 | Hooks.callAll("polyglot.init", LanguageProvider);
21 | api.defaultProvider();
22 | api.updateProvider();
23 | game.polyglot.languageProvider.init();
24 | return preloadTemplates();
25 | });
26 |
27 | Hooks.once("i18nInit", () => {
28 | registerProviderSettings();
29 | game.polyglot.languageProvider.i18nInit();
30 | });
31 |
32 | Hooks.on("setup", () => {
33 | if (game.user.isGM && game.user.character) {
34 | console.warn(
35 | `Polyglot | ${game.i18n.format("POLYGLOT.GameMasterHasAssignedCharacter", {
36 | GM: game.i18n.localize("USER.RoleGamemaster"),
37 | })}`,
38 | );
39 | }
40 | registerTours();
41 | game.polyglot.languageProvider.setup();
42 | });
43 | Hooks.on("ready", async () => {
44 | await game.polyglot.ready();
45 | Hooks.callAll("polyglot.ready", LanguageProvider);
46 | await game.polyglot.languageProvider.ready();
47 | });
48 | Hooks.on("renderPolyglotGeneralSettings", renderPolyglotGeneralSettingsHandler);
49 |
--------------------------------------------------------------------------------
/src/module/providers/coc7.js:
--------------------------------------------------------------------------------
1 | import LanguageProvider from "./templates/Base.js";
2 |
3 | export default class coc7LanguageProvider extends LanguageProvider {
4 | get settings() {
5 | return {
6 | LanguageRegex: {
7 | type: String,
8 | default: game.i18n.localize("POLYGLOT.Generic.Language"),
9 | },
10 | };
11 | }
12 |
13 | getUserLanguages(actor) {
14 | let knownLanguages = new Set();
15 | let literateLanguages = new Set();
16 | for (let item of actor.items) {
17 | const match = item.name.match(`${game.settings.get("polyglot", "LanguageRegex")}\\s*\\((.+)\\)`, "i")
18 | || item.name.match(`${game.i18n.localize("POLYGLOT.COC7.LanguageOwn")}\\s*\\((.+)\\)`, "i")
19 | || item.name.match(`${game.i18n.localize("POLYGLOT.COC7.LanguageAny")}\\s*\\((.+)\\)`, "i")
20 | || item.name.match(`${game.i18n.localize("POLYGLOT.COC7.LanguageOther")}\\s*\\((.+)\\)`, "i");
21 | // adding only the descriptive language name, not "Language (XYZ)"
22 | if (match) knownLanguages.add(match[1].trim().toLowerCase());
23 | else {
24 | switch (item.system.specialization) {
25 | case "LanguageSpec":
26 | case "Language":
27 | case "Language (Own)":
28 | case "Language (Other)":
29 | case game.i18n.localize("POLYGLOT.COC7.LanguageOwn"):
30 | case game.i18n.localize("POLYGLOT.COC7.LanguageAny"):
31 | case game.i18n.localize("POLYGLOT.COC7.LanguageOther"):
32 | case game.i18n.localize("CoC7.language"):
33 | knownLanguages.add(item.name.trim().toLowerCase());
34 | break;
35 | default:
36 | break;
37 | }
38 | }
39 | }
40 | return [knownLanguages, literateLanguages];
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/styles/polyglot.scss:
--------------------------------------------------------------------------------
1 | @import "init";
2 | @import "chat";
3 |
4 | :root {
5 | --polyglot-journal-color: 255, 180, 0;
6 | --polyglot-journal-opacity: 0.25;
7 | --polyglot-journal-color-temp: 255, 180, 0;
8 | --polyglot-journal-opacity-temp: 0.25;
9 | }
10 |
11 | @import "journal";
12 |
13 | .polyglot {
14 | &.polyglot-chat-bubble {
15 | font-family: $font-family_1;
16 | }
17 |
18 | @import "forms";
19 | @import "language-selector";
20 | @import "system-specific";
21 | }
22 |
23 | #interface,
24 | .application.chat-sidebar {
25 | &.theme-dark {
26 | .polyglot.polyglot-lang-select {
27 | .ts-wrapper {
28 | .ts-control {
29 | color: var(--color-light-1);
30 | }
31 | .ts-dropdown {
32 | background: var(--color-cool-5);
33 | .optgroup-header {
34 | border-bottom: solid 1px;
35 | }
36 | .option.active {
37 | background: var(--color-cool-3);
38 | color: var(--color-light-2);
39 | }
40 | .optgroup-header, .option {
41 | background: var(--color-cool-5);
42 | color: var(--color-light-1);
43 | }
44 | .ts-dropdown-content {
45 | scrollbar-width: none;
46 | }
47 | }
48 | }
49 | }
50 | }
51 | &.theme-light {
52 | .polyglot.polyglot-lang-select {
53 | .ts-wrapper {
54 | .ts-control {
55 | background: rgba(255, 255, 255, 0.6);
56 | }
57 | .ts-dropdown {
58 | .optgroup-header {
59 | border-bottom: solid 1px;
60 | }
61 | }
62 | .option.active {
63 | background: #e0eef7;
64 | }
65 | &.focus .ts-control, .ts-control:hover {
66 | background: rgba(255, 255, 255, 0.85);
67 | }
68 | }
69 | }
70 | }
71 | }
--------------------------------------------------------------------------------
/src/module/providers/templates/Generic.js:
--------------------------------------------------------------------------------
1 | import LanguageProvider from "./Base.js";
2 |
3 | export default class GenericLanguageProvider extends LanguageProvider {
4 | get settings() {
5 | return {
6 | languageDataPath: {
7 | hint: game.i18n.format("POLYGLOT.languageDataPath.hint", {
8 | setting: game.i18n.localize("POLYGLOT.LanguageRegex.title"),
9 | }),
10 | default: "",
11 | type: String,
12 | requiresReload: true,
13 | },
14 | literacyDataPath: {
15 | hint: game.i18n.format("POLYGLOT.literacyDataPath.hint", {
16 | setting: game.i18n.localize("POLYGLOT.languageDataPath.title"),
17 | }),
18 | default: "",
19 | type: String,
20 | requiresReload: true,
21 | },
22 | LanguageRegex: {
23 | type: String,
24 | default: game.i18n.localize("POLYGLOT.Generic.Language"),
25 | },
26 | useLiteracy: {
27 | type: Boolean,
28 | default: false,
29 | },
30 | LiteracyRegex: {
31 | type: String,
32 | default: game.i18n.localize("POLYGLOT.Generic.Literacy"),
33 | },
34 | };
35 | }
36 |
37 | async setup() {
38 | this.languageDataPath = game.settings.get("polyglot", "languageDataPath");
39 | this.literacyDataPath = game.settings.get("polyglot", "literacyDataPath");
40 | if (this.languageDataPath.startsWith("actor.")) this.languageDataPath = this.languageDataPath.slice(6);
41 | if (this.literacyDataPath.startsWith("actor.")) this.literacyDataPath = this.literacyDataPath.slice(6);
42 | super.setup();
43 | }
44 |
45 | conditions(lang) {
46 | if (game.settings.get("polyglot", "useLiteracy")) {
47 | return game.polyglot.literateLanguages.has(lang);
48 | }
49 | return super.conditions(lang);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/module/providers/sfrpg.js:
--------------------------------------------------------------------------------
1 | import LanguageProvider from "./templates/Base.js";
2 |
3 | export default class sfrpgLanguageProvider extends LanguageProvider {
4 | languages = {
5 | common: {
6 | font: "Thorass",
7 | },
8 | abyssal: {
9 | font: "Barazhad",
10 | },
11 | akito: {
12 | font: "Thorass",
13 | },
14 | aklo: {
15 | font: "Ophidian",
16 | },
17 | arkanen: {
18 | font: "Thorass",
19 | },
20 | aquan: {
21 | font: "Olde Thorass",
22 | },
23 | auran: {
24 | font: "Olde Thorass",
25 | },
26 | azlanti: {
27 | font: "Tengwar",
28 | },
29 | celestial: {
30 | font: "Celestial",
31 | },
32 | draconic: {
33 | font: "Iokharic",
34 | },
35 | drow: {
36 | font: "High Drowic",
37 | },
38 | dwarven: {
39 | font: "Dethek",
40 | },
41 | elven: {
42 | font: "Espruar",
43 | },
44 | gnome: {
45 | font: "Dethek",
46 | },
47 | goblin: {
48 | font: "Kargi",
49 | },
50 | halfling: {
51 | font: "Thorass",
52 | },
53 | ignan: {
54 | font: "Dethek",
55 | },
56 | infernal: {
57 | font: "Infernal",
58 | },
59 | kalo: {
60 | font: "Thorass",
61 | },
62 | kasatha: {
63 | font: "Thorass",
64 | },
65 | Nchaki: {
66 | font: "Thorass",
67 | },
68 | orc: {
69 | font: "Dethek",
70 | },
71 | sarcesian: {
72 | font: "Thorass",
73 | },
74 | shirren: {
75 | font: "Thorass",
76 | },
77 | shobhad: {
78 | font: "Thorass",
79 | },
80 | terran: {
81 | font: "Olde Thorass",
82 | },
83 | triaxian: {
84 | font: "Thorass",
85 | },
86 | vercite: {
87 | font: "Thorass",
88 | },
89 | vesk: {
90 | font: "Thorass",
91 | },
92 | ysoki: {
93 | font: "Thorass",
94 | },
95 | };
96 | }
97 |
--------------------------------------------------------------------------------
/src/module/providers/dnd4e.js:
--------------------------------------------------------------------------------
1 | import LanguageProvider from "./templates/Base.js";
2 |
3 | export default class dnd4eLanguageProvider extends LanguageProvider {
4 | languages = {
5 | common: {
6 | font: "Thorass",
7 | },
8 | abyssal: {
9 | font: "Barazhad",
10 | },
11 | deep: {
12 | font: "Ar Ciela",
13 | },
14 | draconic: {
15 | font: "Iokharic",
16 | },
17 | dwarven: {
18 | font: "Davek",
19 | },
20 | elven: {
21 | font: "Rellanic",
22 | },
23 | giant: {
24 | font: "Davek",
25 | },
26 | goblin: {
27 | font: "Davek",
28 | },
29 | primordial: {
30 | font: "Davek",
31 | },
32 | supernal: {
33 | font: "Celestial",
34 | },
35 | };
36 |
37 | addToConfig(key, lang) {
38 | CONFIG.DND4E.spoken[key] = lang;
39 | }
40 |
41 | removeFromConfig(key) {
42 | delete CONFIG.DND4E.spoken[key];
43 | }
44 |
45 | async getLanguages() {
46 | const langs = {};
47 | if (this.replaceLanguages) {
48 | CONFIG.DND4E.spoken = {};
49 | }
50 | const languagesSetting = game.settings.get("polyglot", "Languages");
51 | for (let lang in CONFIG.DND4E.spoken) {
52 | langs[lang] = {
53 | label: CONFIG.DND4E.spoken[lang],
54 | font: languagesSetting[lang]?.font || this.languages[lang]?.font || this.defaultFont,
55 | rng: languagesSetting[lang]?.rng ?? "default",
56 | };
57 | }
58 | this.languages = langs;
59 | }
60 |
61 | getUserLanguages(actor) {
62 | let knownLanguages = new Set();
63 | let literateLanguages = new Set();
64 | for (let lang of actor.system.languages.spoken.value) {
65 | knownLanguages.add(lang);
66 | }
67 | // for (let lang of actor.system.languages.script.value) {
68 | // literateLanguages.add(lang);
69 | // }
70 | return [knownLanguages, literateLanguages];
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/module/providers/ars.js:
--------------------------------------------------------------------------------
1 | import LanguageProvider from "./templates/Base.js";
2 |
3 | export default class arsLanguageProvider extends LanguageProvider {
4 | get settings() {
5 | return {
6 | LanguageRegex: {
7 | type: String,
8 | default: game.i18n.localize("POLYGLOT.Generic.Language"),
9 | }
10 | };
11 | }
12 |
13 | async getLanguages() {
14 | this.languages = {};
15 | if (this.replaceLanguages) return;
16 | if (game.modules.get("osric-compendium")?.active) {
17 | const langs = {};
18 | const osricPack = game.packs.get("osric-compendium.items");
19 | const osricItemList = await osricPack.getIndex();
20 | const languagesSetting = game.settings.get("polyglot", "Languages");
21 | let myRegex = new RegExp(`(?:Language:|${game.settings.get("polyglot", "LanguageRegex")}:)\\s*(.+)`, "i");
22 | for (let item of osricItemList) {
23 | if (myRegex.test(item.name)) {
24 | let label = item.name.match(myRegex)[1].trim();
25 | let key = label.toLowerCase();
26 | if (!label) continue;
27 | langs[key] = {
28 | label,
29 | font: languagesSetting[key]?.font || this.languages[key]?.font || this.defaultFont,
30 | rng: languagesSetting[key]?.rng ?? "default",
31 | };
32 | }
33 | }
34 | this.languages = langs;
35 | }
36 | }
37 |
38 | getUserLanguages(actor) {
39 | let knownLanguages = new Set();
40 | let literateLanguages = new Set();
41 | let myRegex = new RegExp(`(?:Language:|${game.settings.get("polyglot", "LanguageRegex")}:)\\s*(.+)`, "i");
42 | for (let item of actor.items) {
43 | // adding only the descriptive language name, not "Language: XYZ"
44 | if (myRegex.test(item.name)) knownLanguages.add(item.name.match(myRegex)[1].trim().toLowerCase());
45 | }
46 | return [knownLanguages, literateLanguages];
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 | 
3 |
4 | [](https://ko-fi.com/mclemente)
5 |
6 | # Polyglot
7 |
8 | Talk to others using a language you can speak and scrambles text you can't understand, into several fantasy scripts.
9 |
10 | ## How to Use
11 | ### Set Up
12 | #### As a GM
13 | - Check the module settings to configure it according to your preferences.
14 | - Check the Tour under the Tour Management window.
15 | - Check the [wiki](https://github.com/mclemente/fvtt-module-polyglot/wiki) for more in-depth information.
16 |
17 | #### As a Player
18 | - Assign a character on the User Configuration window.
19 |
20 | ### Using
21 | - Select tokens to speak and read messages as them.
22 | - Right-click the chat selector to enable/disable speaking in a language.
23 |
24 | ## Attribution
25 |
26 | - `@Talwin Greenwood` on the FVTT discord, for the original idea for this module.
27 | - [@KaKaRoTo](https://github.com/kakaroto/) for the original PolyGlot module, which was licensed under [Creative Commons Attribution 4.0 International License](http://creativecommons.org/licenses/by/4.0/).
28 | - [@ElizeuAngelo](https://github.com/elizeuangelo) for the 'fantasy languages' adaptation.
29 | - [@ironmonk88](https://github.com/ironmonk88) for the Translation Box.
30 | - [@manuelVo](https://github.com/manuelVo) for the API code.
31 | - [@Ghost](https://github.com/ghost-fvtt) for the Foundry Factory.
32 |
33 | ## Community Contribution
34 |
35 | See the [CONTRIBUTING](/CONTRIBUTING.md) file for information about how you can help this project.
36 |
--------------------------------------------------------------------------------
/src/module/providers/shadowrun5e.js:
--------------------------------------------------------------------------------
1 | import LanguageProvider from "./templates/Base.js";
2 |
3 | export default class shadowrun5eLanguageProvider extends LanguageProvider {
4 | defaultFont = "Olde English";
5 |
6 | languages = {
7 | cityspeak: {
8 | label: "Cityspeak",
9 | font: "Olde English",
10 | },
11 | spanish: {
12 | label: "Spanish",
13 | font: "Olde English",
14 | },
15 | lakota: {
16 | label: "Lakota",
17 | font: "Olde English",
18 | },
19 | dakota: {
20 | label: "Dakota",
21 | font: "Olde English",
22 | },
23 | navajo: {
24 | label: "Navajo",
25 | font: "Olde English",
26 | },
27 | russian: {
28 | label: "Russian",
29 | font: "Kremlin Premier",
30 | },
31 | french: {
32 | label: "French",
33 | font: "Olde English",
34 | },
35 | italian: {
36 | label: "Italian",
37 | font: "Olde English",
38 | },
39 | german: {
40 | label: "German",
41 | font: "Olde English",
42 | },
43 | aztlaner: {
44 | label: "Aztlaner Spanish",
45 | font: "Aztec",
46 | },
47 | sperethiel: {
48 | label: "Sperethiel",
49 | font: "Espruar",
50 | },
51 | orzet: {
52 | label: "Or'zet",
53 | font: "Ork Glyphs",
54 | },
55 | english: {
56 | label: "English",
57 | font: "Olde English",
58 | },
59 | japanese: {
60 | label: "Japanese",
61 | font: "Oriental",
62 | },
63 | mandarin: {
64 | label: "Mandarin",
65 | font: "Scrapbook Chinese",
66 | },
67 | };
68 |
69 | getSystemDefaultLanguage() {
70 | return "cityspeak";
71 | }
72 |
73 | getUserLanguages(actor) {
74 | let knownLanguages = new Set();
75 | let literateLanguages = new Set();
76 | for (let lang in actor.system.skills.language.value) {
77 | knownLanguages.add(actor.system.skills.language.value[lang].name.toLowerCase());
78 | }
79 | return [knownLanguages, literateLanguages];
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/module/providers/tormenta20.js:
--------------------------------------------------------------------------------
1 | import LanguageProvider from "./templates/Base.js";
2 |
3 | export default class tormenta20LanguageProvider extends LanguageProvider {
4 | languages = {
5 | comum: {
6 | font: "Thorass",
7 | },
8 | abissal: {
9 | font: "Barazhad",
10 | },
11 | anao: {
12 | font: "Dethek",
13 | },
14 | aquan: {
15 | font: "Olde Thorass",
16 | },
17 | auran: {
18 | font: "Olde Thorass",
19 | },
20 | celestial: {
21 | font: "Celestial",
22 | },
23 | draconico: {
24 | font: "Iokharic",
25 | },
26 | elfico: {
27 | font: "Espruar",
28 | },
29 | gigante: {
30 | font: "Meroitic Demotic",
31 | },
32 | gnoll: {
33 | font: "Kargi",
34 | },
35 | goblin: {
36 | font: "Kargi",
37 | },
38 | ignan: {
39 | font: "Olde Thorass",
40 | },
41 | infernal: {
42 | font: "Infernal",
43 | },
44 | orc: {
45 | font: "Dethek",
46 | },
47 | silvestre: {
48 | font: "Olde Espruar",
49 | },
50 | terran: {
51 | font: "Olde Thorass",
52 | },
53 | };
54 |
55 | getSystemDefaultLanguage() {
56 | return "comum";
57 | }
58 |
59 | async getLanguages() {
60 | const languagesSetting = game.settings.get("polyglot", "Languages");
61 | const langs = {};
62 | if (this.replaceLanguages) {
63 | CONFIG.T20.idiomas = {};
64 | }
65 | Object.keys(CONFIG.T20.idiomas).forEach((key) => {
66 | const label = CONFIG.T20.idiomas[key];
67 | if (label) {
68 | langs[key] = {
69 | label,
70 | font: languagesSetting[key]?.font || this.languages[key]?.font || this.defaultFont,
71 | rng: languagesSetting[key]?.rng ?? "default",
72 | };
73 | }
74 | });
75 | this.languages = langs;
76 | }
77 |
78 | getUserLanguages(actor) {
79 | let knownLanguages = new Set();
80 | let literateLanguages = new Set();
81 | for (let lang of actor.system.tracos.idiomas.value) knownLanguages.add(lang);
82 | return [knownLanguages, literateLanguages];
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/.github/workflows/checks.yml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2022 Johannes Loher
2 | #
3 | # SPDX-License-Identifier: MIT
4 |
5 | name: Checks
6 |
7 | on:
8 | - push
9 | - pull_request
10 |
11 | env:
12 | node_version: 22
13 |
14 | jobs:
15 | lint:
16 | runs-on: ubuntu-latest
17 | steps:
18 | - name: Checkout code
19 | uses: actions/checkout@v5
20 |
21 | - name: Install node
22 | uses: actions/setup-node@v6
23 | with:
24 | node-version: ${{ env.node_version }}
25 |
26 | - name: Cache Node.js modules
27 | uses: actions/cache@v4
28 | with:
29 | path: .npm
30 | key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }}
31 | restore-keys: |
32 | ${{ runner.OS }}-node-
33 | ${{ runner.OS }}-
34 |
35 | - name: Install dependencies
36 | run: npm ci --cache .npm --prefer-offline
37 |
38 | - name: Lint
39 | run: npm run lint
40 |
41 | build:
42 | runs-on: ubuntu-latest
43 | steps:
44 | - name: Checkout code
45 | uses: actions/checkout@v5
46 |
47 | - name: Install node
48 | uses: actions/setup-node@v6
49 | with:
50 | node-version: ${{ env.node_version }}
51 |
52 | - name: Cache Node.js modules
53 | uses: actions/cache@v4
54 | with:
55 | path: .npm
56 | key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }}
57 | restore-keys: |
58 | ${{ runner.OS }}-node-
59 | ${{ runner.OS }}-
60 |
61 | - name: Install dependencies
62 | run: npm ci --cache .npm --prefer-offline
63 |
64 | - name: Build
65 | run: npm run build
66 |
--------------------------------------------------------------------------------
/src/fonts/_licenses.md:
--------------------------------------------------------------------------------
1 | # Licensing
2 |
3 | The following fonts are owned by Pixel Sagas, check out their [website](http://www.pixelsagas.com/):
4 |
5 | - Barazhad
6 | - Celestial
7 | - Daedra
8 | - Davek
9 | - Dethek
10 | - Espruar
11 | - HighDrowic
12 | - Kargi
13 | - Iokharic
14 | - MageScript
15 | - MarasEye
16 | - OldeEspruar
17 | - OldeThorass
18 | - Ophidian
19 | - Qijomi
20 | - Reanaarian
21 | - Rellanic
22 | - Semphari
23 | - Thorass
24 |
25 | The following font was created by TenkaDigi:
26 |
27 | - Infernal (Fan Art)
28 |
29 | The follow font was created by Helena Jole:
30 |
31 | - ScrapbookChinese
32 |
33 | The following font was created by Levi:
34 |
35 | - Aztec
36 |
37 | The following font is under [1001Fonts Free For Personal Use License (FFP)](https://www.1001fonts.com/licenses/ffp.html):
38 |
39 | - Dragon Alphabet
40 |
41 | The following font is under [GNU GENERAL PUBLIC LICENSE v3](https://www.gnu.org/licenses/gpl-3.0.en.html):
42 |
43 | - KremlinPremier
44 |
45 | The following font is under [SIL OPEN FONT LICENSE Version 1.1](https://scripts.sil.org/cms/scripts/page.php?item_id=OFL_web):
46 |
47 | - [MusiQwik](https://www.fontspace.com/musiqwik-font-f3722). Copyright (c) 2003, Robert Allgeyer.
48 | - [Ny Stormning](https://www.fontspace.com/ny-stormning-font-f23289). Copyright (c) 2016, Mew Too, Robert Jablonski (Cannot Into Space Fonts) (cannotintospacefonts@gmail.com).
49 |
50 | The following are under [CC BY-SA 3](https://creativecommons.org/licenses/by-sa/3.0/):
51 |
52 | - [Ar Ciela](http://hymmnoserver.uguu.ca/). Hymmnos and HYMMNOSERVER were created by Akira Tsuchiya.
53 | - Elder Futhark FS
54 |
55 | The following does not accompanied license terms, were OPL or their license have expired:
56 |
57 | - AnglosaxonRunes
58 | - DarkEldar
59 | - Eltharin
60 | - FingerAlphabet
61 | - Floki
62 | - HighschoolRunes
63 | - JungleSlang
64 | - MeroiticDemotic
65 | - MiroslavNormal
66 | - Pulsian (Fan Art by Echiceroo)
67 | - Skaven
68 | - Tengwar (Greifswalder)
69 | - OldeEnglish
70 | - Oriental
71 | - OrkGlyphs
72 | - Thassilonian (Fan Art)
73 | - Tuzluca
74 | - Valmaric
--------------------------------------------------------------------------------
/src/module.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "polyglot",
3 | "title": "Polyglot",
4 | "description": "Talk to others using a language you can speak and scrambles text you can't understand, in several fantasy scripts.",
5 | "authors": [
6 | {
7 | "name": "Matheus Clemente",
8 | "discord": "mclemente#5524",
9 | "ko-fi": "mclemente"
10 | }
11 | ],
12 | "compatibility": {
13 | "minimum": "13.347",
14 | "verified": "13"
15 | },
16 | "esmodules": ["module/polyglot.js"],
17 | "scripts": ["lib/tom-select/tom-select.complete.min.js"],
18 | "styles": ["lib/tom-select/tom-select.min.css", "styles/fonts.css", "styles/polyglot.css"],
19 | "languages": [
20 | {
21 | "lang": "en",
22 | "name": "English",
23 | "path": "lang/en.json"
24 | },
25 | {
26 | "lang": "pt-BR",
27 | "name": "Português (Brasil)",
28 | "path": "lang/pt-BR.json"
29 | },
30 | {
31 | "lang": "es",
32 | "name": "Español",
33 | "path": "lang/es.json"
34 | },
35 | {
36 | "lang": "ko",
37 | "name": "Korean",
38 | "path": "lang/ko.json"
39 | },
40 | {
41 | "lang": "fr",
42 | "name": "French",
43 | "path": "lang/fr.json"
44 | },
45 | {
46 | "lang": "cs",
47 | "name": "Česky",
48 | "path": "lang/cs.json"
49 | },
50 | {
51 | "lang": "ja",
52 | "name": "日本語",
53 | "path": "lang/ja.json"
54 | },
55 | {
56 | "lang": "pl",
57 | "name": "Polski",
58 | "path": "lang/pl.json"
59 | },
60 | {
61 | "lang": "it",
62 | "name": "Italiano",
63 | "path": "lang/it.json"
64 | },
65 | {
66 | "lang": "fi",
67 | "name": "Suomi",
68 | "path": "lang/fi.json"
69 | },
70 | {
71 | "lang": "sv",
72 | "name": "Svenska",
73 | "path": "lang/sv.json"
74 | },
75 | {
76 | "lang": "de",
77 | "name": "Deutsch",
78 | "path": "lang/de.json"
79 | },
80 | {
81 | "lang": "cn",
82 | "name": "中文",
83 | "path": "lang/zh_Hans.json"
84 | }
85 | ],
86 | "url": "This is auto replaced",
87 | "version": "This is auto replaced",
88 | "manifest": "This is auto replaced",
89 | "download": "This is auto replaced"
90 | }
91 |
--------------------------------------------------------------------------------
/src/module/providers/uesrpg-d100.js:
--------------------------------------------------------------------------------
1 | import LanguageProvider from "./templates/Base.js";
2 |
3 | export default class uesrpgLanguageProvider extends LanguageProvider {
4 | languages = {
5 | cyrodilic: {
6 | font: "Thorass",
7 | },
8 | aldmeri: {
9 | font: "Espruar",
10 | },
11 | ayleidoon: {
12 | font: "Espruar",
13 | },
14 | bosmeri: {
15 | font: "Mage Script",
16 | },
17 | daedric: {
18 | font: "Daedra",
19 | },
20 | dovah: {
21 | font: "Dragon Alphabet",
22 | },
23 | dunmeri: {
24 | font: "High Drowic",
25 | },
26 | dwemeris: {
27 | font: "Dethek",
28 | },
29 | falmer: {
30 | font: "Ar Ciela",
31 | },
32 | jel: {
33 | font: "Ophidian",
34 | },
35 | nordic: {
36 | font: "Ny Stormning",
37 | },
38 | taagra: {
39 | font: "Jungle Slang",
40 | },
41 | yoku: {
42 | font: "Oriental",
43 | },
44 | };
45 |
46 | getSystemDefaultLanguage() {
47 | return "cyrodilic";
48 | }
49 |
50 | async getLanguages() {
51 | const languagesSetting = game.settings.get("polyglot", "Languages");
52 | const langs = {};
53 | if (this.replaceLanguages) {
54 | CONFIG.UESRPG.languages = {};
55 | }
56 | Object.keys(CONFIG.UESRPG.languages).forEach((key) => {
57 | const label = CONFIG.UESRPG.languages[key];
58 | if (label) {
59 | langs[key] = {
60 | label,
61 | font: languagesSetting[key]?.font || this.languages[key]?.font || this.defaultFont,
62 | rng: languagesSetting[key]?.rng ?? "default",
63 | };
64 | }
65 | });
66 | this.languages = langs;
67 | }
68 |
69 | getUserLanguages(actor) {
70 | let knownLanguages = new Set();
71 | let literateLanguages = new Set();
72 | for (let item of actor.items) {
73 | if (item.type === "language") {
74 | if (item.system.speak) knownLanguages.add(item.name.trim().toLowerCase());
75 | if (item.system.readWrite) literateLanguages.add(item.name.trim().toLowerCase());
76 | }
77 | }
78 | return [knownLanguages, literateLanguages];
79 | }
80 |
81 | conditions(lang) {
82 | return game.polyglot.literateLanguages.has(lang);
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/module/providers/_module.js:
--------------------------------------------------------------------------------
1 |
2 | export { default as LanguageProvider } from "./templates/Base.js";
3 | export { default as GenericLanguageProvider } from "./templates/Generic.js";
4 |
5 | export { default as a5eLanguageProvider } from "./a5e.js";
6 | export { default as ariaLanguageProvider } from "./aria.js";
7 | export { default as arsLanguageProvider } from "./ars.js";
8 | export { default as coc7LanguageProvider } from "./coc7.js";
9 | export { default as cyberpunkRedLanguageProvider } from "./cyberpunk-red-core.js";
10 | export { default as d35eLanguageProvider } from "./d35e.js";
11 | export { default as darkHeresyLanguageProvider } from "./dark-heresy.js";
12 | export { default as dccLanguageProvider } from "./dcc.js";
13 | export { default as demonlordLanguageProvider } from "./demonlord.js";
14 | export { default as dnd4eLanguageProvider } from "./dnd4e.js";
15 | export { default as dnd5eLanguageProvider } from "./dnd5e.js";
16 | export { default as drawSteelLanguageProvider } from "./draw-steel.js";
17 | export { default as dsa5LanguageProvider } from "./dsa5.js";
18 | export { default as earthdawn4eLanguageProvider } from "./earthdawn4e.js";
19 | export { default as fggLanguageProvider } from "./fgg.js";
20 | export { default as gurpsLanguageProvider } from "./gurps.js";
21 | export { default as oseLanguageProvider } from "./ose.js";
22 | export { default as pf1LanguageProvider } from "./pf1.js";
23 | export { default as pf2eLanguageProvider } from "./pf2e.js";
24 | export { default as sfrpgLanguageProvider } from "./sfrpg.js";
25 | export { default as shadowrun5eLanguageProvider } from "./shadowrun5e.js";
26 | export { default as splittermondLanguageProvider } from "./splittermond.js";
27 | export { default as sw5eLanguageProvider } from "./sw5e.js";
28 | export { default as swadeLanguageProvider } from "./swade.js";
29 | export { default as tormenta20LanguageProvider } from "./tormenta20.js";
30 | export { default as uesrpgLanguageProvider } from "./uesrpg-d100.js";
31 | export { default as wfrp4eLanguageProvider } from "./wfrp4e.js";
32 | export { default as wwnLanguageProvider } from "./wwn.js";
33 |
34 |
--------------------------------------------------------------------------------
/src/module/providers/a5e.js:
--------------------------------------------------------------------------------
1 | import LanguageProvider from "./templates/Base.js";
2 |
3 | export default class a5eLanguageProvider extends LanguageProvider {
4 | languages = {
5 | aarakocra: {
6 | font: "Olde Thorass",
7 | },
8 | abyssal: {
9 | font: "Infernal",
10 | },
11 | aquan: {
12 | font: "Dethek",
13 | },
14 | auran: {
15 | font: "Dethek",
16 | },
17 | celestial: {
18 | font: "Celestial",
19 | },
20 | common: {
21 | font: "Thorass",
22 | },
23 | deep: {
24 | font: "Ar Ciela",
25 | },
26 | draconic: {
27 | font: "Iokharic",
28 | },
29 | druidic: {
30 | font: "Jungle Slang",
31 | },
32 | dwarvish: {
33 | font: "Dethek",
34 | },
35 | elvish: {
36 | font: "Espruar",
37 | },
38 | giant: {
39 | font: "Dethek",
40 | },
41 | gith: {
42 | font: "Pulsian",
43 | },
44 | gnoll: {
45 | font: "Kargi",
46 | },
47 | gnomish: {
48 | font: "Dethek",
49 | },
50 | goblin: {
51 | font: "Dethek",
52 | },
53 | halfling: {
54 | font: "Thorass",
55 | },
56 | ignan: {
57 | font: "Dethek",
58 | },
59 | infernal: {
60 | font: "Infernal",
61 | },
62 | orc: {
63 | font: "Dethek",
64 | },
65 | primordial: {
66 | font: "Dethek",
67 | },
68 | sylvan: {
69 | font: "Olde Espruar",
70 | },
71 | terran: {
72 | font: "Dethek",
73 | },
74 | cant: {
75 | font: "Thorass",
76 | },
77 | undercommon: {
78 | font: "High Drowic",
79 | },
80 | };
81 |
82 | /**
83 | * Get an actor's languages
84 | * @param {Document} actor
85 | * @returns [Set, Set]
86 | */
87 | getUserLanguages(actor) {
88 | const knownLanguages = new Set();
89 | const literateLanguages = new Set();
90 |
91 | const langs = actor.system.proficiencies?.languages;
92 | if (!langs) return [knownLanguages, literateLanguages];
93 |
94 | langs.forEach((lang) => {
95 | if (this.languages[lang]) knownLanguages.add(lang);
96 | });
97 |
98 | return [knownLanguages, literateLanguages];
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/templates/LanguageSettings.hbs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/module/providers/dark-heresy.js:
--------------------------------------------------------------------------------
1 | import LanguageProvider from "./templates/Base.js";
2 |
3 | export default class darkHeresyLanguageProvider extends LanguageProvider {
4 | languages = {
5 | lowGothic: {
6 | font: "Infernal",
7 | },
8 | chapterRunes: {
9 | font: "",
10 | },
11 | chaosMarks: {
12 | font: "",
13 | },
14 | eldar: {
15 | font: "",
16 | },
17 | highGothic: {
18 | font: "Infernal",
19 | },
20 | imperialCodes: {
21 | font: "",
22 | },
23 | mercenary: {
24 | font: "",
25 | },
26 | necrontyr: {
27 | font: "",
28 | },
29 | ork: {
30 | font: "Ork Glyphs",
31 | },
32 | technaLingua: {
33 | font: "",
34 | },
35 | tau: {
36 | font: "",
37 | },
38 | underworld: {
39 | font: "",
40 | },
41 | xenosMarkings: {
42 | font: "",
43 | },
44 | };
45 |
46 | getSystemDefaultLanguage() {
47 | return "lowGothic";
48 | }
49 |
50 | async getLanguages() {
51 | if (this.replaceLanguages) {
52 | this.languages = {};
53 | } else {
54 | const originalLanguages = {
55 | chapterRunes: "Chapter Runes",
56 | chaosMarks: "Chaos Marks",
57 | eldar: "Eldar",
58 | highGothic: "High Gothic",
59 | imperialCodes: "Imperial Codes",
60 | lowGothic: "Low Gothic",
61 | mercenary: "Mercenary",
62 | necrontyr: "Necrontyr",
63 | ork: "Ork",
64 | tau: "Tau",
65 | technaLingua: "Techna-Lingua",
66 | underworld: "Underworld",
67 | xenosMarkings: "Xenos Markings",
68 | };
69 | const langs = {};
70 | const languagesSetting = game.settings.get("polyglot", "Languages");
71 | for (let lang in originalLanguages) {
72 | langs[lang] = {
73 | label: originalLanguages[lang],
74 | font: languagesSetting[lang]?.font || this.languages[lang]?.font || this.defaultFont,
75 | rng: languagesSetting[lang]?.rng ?? "default",
76 | };
77 | }
78 | this.languages = langs;
79 | }
80 | }
81 |
82 | getUserLanguages(actor) {
83 | let knownLanguages = new Set();
84 | let literateLanguages = new Set();
85 | for (let lang in actor.system.skills.linguistics.specialities) {
86 | if (actor.system.skills.linguistics.specialities[lang].advance >= 0) knownLanguages.add(lang);
87 | }
88 | return [knownLanguages, literateLanguages];
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/module/providers/wwn.js:
--------------------------------------------------------------------------------
1 | import LanguageProvider from "./templates/Base.js";
2 |
3 | export default class wwnLanguageProvider extends LanguageProvider {
4 | get settings() {
5 | return {
6 | // System has a built-in setting to handle languages.
7 | replaceLanguages: {
8 | polyglotHide: true,
9 | ...game.settings.settings.get("polyglot.replaceLanguages"),
10 | },
11 | customLanguages: {
12 | polyglotHide: true,
13 | ...game.settings.settings.get("polyglot.customLanguages"),
14 | },
15 | };
16 | }
17 |
18 | getSystemDefaultLanguage() {
19 | return Object.keys(this.languages)[0];
20 | }
21 |
22 | addLanguage(lang) {
23 | if (!lang) return;
24 | let languages = game.settings.get("wwn", "languageList");
25 | const languagesSetting = game.settings.get("polyglot", "Languages");
26 | if (!languages.includes(lang)) {
27 | if (languages.endsWith(",")) languages += lang;
28 | else languages += `,${lang}`;
29 | game.settings.set("wwn", "languageList", languages);
30 | }
31 | lang = lang.trim();
32 | const key = lang.slugify({ replacement: "_" });
33 | this.languages[key] = {
34 | label: lang,
35 | font: languagesSetting[key]?.font ?? this.defaultFont,
36 | rng: languagesSetting[key]?.rng ?? "default",
37 | };
38 | }
39 |
40 | removeLanguage(lang) {
41 | if (!lang) return;
42 | let languages = game.settings.get("wwn", "languageList");
43 | if (languages.includes(lang)) {
44 | languages.replace(new RegExp(`,\\s*${lang}`), "");
45 | game.settings.set("wwn", "languageList", languages);
46 | }
47 | const key = lang.slugify({ replacement: "_" });
48 | delete this.languages[key];
49 | }
50 |
51 | async getLanguages() {
52 | const languagesSetting = game.settings.get("polyglot", "Languages");
53 | for (let lang of game.settings.get("wwn", "languageList").split(",")) {
54 | const key = lang.slugify({ replacement: "_" });
55 | this.languages[key] = {
56 | label: lang,
57 | font: languagesSetting[key]?.font || this.defaultFont,
58 | rng: languagesSetting[key]?.rng ?? "default",
59 | };
60 | }
61 | }
62 |
63 | getUserLanguages(actor) {
64 | let knownLanguages = new Set();
65 | let literateLanguages = new Set();
66 | if (actor.system.languages) {
67 | for (let lang of actor.system.languages.value) {
68 | knownLanguages.add(lang.toLowerCase());
69 | }
70 | }
71 | return [knownLanguages, literateLanguages];
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/module/providers/swade.js:
--------------------------------------------------------------------------------
1 | import LanguageProvider from "./templates/Base.js";
2 |
3 | export default class swadeLanguageProvider extends LanguageProvider {
4 | get settings() {
5 | return {
6 | LanguageRegex: {
7 | type: String,
8 | default: game.i18n.localize("POLYGLOT.SWADE.LanguageSkills"),
9 | },
10 | "SWADE.AdditionalLanguageStat": {
11 | hint: game.i18n.format("POLYGLOT.SWADE.AdditionalLanguageStat.hint", {
12 | setting: game.i18n.localize("POLYGLOT.LanguageRegex.title"),
13 | }),
14 | type: String,
15 | default: "",
16 | },
17 | "SWADE.AdditionalLiterateStat": {
18 | hint: game.i18n.format("POLYGLOT.SWADE.AdditionalLiterateStat.hint", {
19 | setting: game.i18n.localize("POLYGLOT.SWADE.AdditionalLanguageStat.title"),
20 | }),
21 | type: String,
22 | default: "",
23 | },
24 | };
25 | }
26 |
27 | getUserLanguages(actor) {
28 | let knownLanguages = new Set();
29 | let literateLanguages = new Set();
30 | const additionalLanguageStat = game.settings.get("polyglot", "SWADE.AdditionalLanguageStat");
31 | const additionalLiterateStat = game.settings.get("polyglot", "SWADE.AdditionalLiterateStat");
32 | if (!additionalLanguageStat) {
33 | const languageRegex = game.settings.get("polyglot", "LanguageRegex");
34 | let myRegex = new RegExp(`${languageRegex} \\((.+)\\)`, "i");
35 | for (let item of actor.items) {
36 | const name = item?.flags?.babele?.originalName || item.name;
37 | if (myRegex.test(name)) knownLanguages.add(name.match(myRegex)[1].trim().toLowerCase());
38 | }
39 | } else {
40 | const languages = actor.system?.additionalStats?.[additionalLanguageStat]?.value.split(/[,;]/) ?? [];
41 | for (let lang of languages) {
42 | lang = lang.trim();
43 | knownLanguages.add(lang.toLowerCase());
44 | this.addLanguage(lang);
45 | }
46 | }
47 | if (additionalLiterateStat) {
48 | const languages = actor.system?.additionalStats?.[additionalLiterateStat]?.value.split(/[,;]/) ?? [];
49 | for (let lang of languages) {
50 | lang = lang.trim();
51 | literateLanguages.add(lang.toLowerCase());
52 | this.addLanguage(lang);
53 | }
54 | }
55 | return [knownLanguages, literateLanguages];
56 | }
57 |
58 | conditions(lang) {
59 | if (game.settings.get("polyglot", "SWADE.AdditionalLiterateStat")) return game.polyglot.literateLanguages.has(lang);
60 | return game.polyglot.knownLanguages.has(lang);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/fonts/licenses/infernal.txt:
--------------------------------------------------------------------------------
1 | DUNGEONS & DRAGONS, D&D, Wizards of the Coast, Forgotten Realms, the dragon ampersand, all other Wizards of the Coast product names, and their respective logos are trademarks of Wizards of the Coast in the USA and other countries.
2 |
3 | This font is a fanmade, unofficial resource derived from the version of the Infernal script provided in the Dungeons & Dragons 5th Edition module "Baldur's Gate: Descent into Avernus" on page 256.
4 |
5 | This font was created in memory of Neale Davidson, a fantastic contributor to the online community of Dungeons & Dragons who created several popular versions of scripts provided in previous edition materials. If you appreciate this font, I would encourage you to donate to his wife's PayPal, which can be found on pixelsagas.com/
6 |
7 | Shareware Usage Terms
8 |
9 | The Infernal font is free to use for personal, non-commercial purposes. No payment is necessary to use the Infernal font for personal use, and there is no limit to the amount of prints, pages, or other medium to be produced using them. However, you cannot offer the font for commercial sale, or offer for direct download. The inclusion othe font name and/or site URL in the credits or documentation when it is used is appreciated, but this is not mandatory.
10 |
11 | Payment
12 |
13 | Payment is not required for the use of the Infernal font.
14 |
15 | Support
16 |
17 | No support is provided for this font, questions or comments may be directed to Tenka Digi on DeviantArt ( https://www.deviantart.com/tenkadigi ), though response is not guarunteed.
18 |
19 | Tenka Digi expressly disclaims any warranty for the font. The font and any related documentation is provided "as is" without warranty of any kind, either express or implied, including, without limitation, the implied warranties or merchantability, fitness for a particular purpose, or non-infringement. The entire risk arising out of use or performance of the font remains with the user.
20 |
21 | No Liability For Consequential Damages.
22 |
23 | In no event shall Tenka Digi be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or any other pecuniary loss) arising out of the use of or inability to use this product, even if Tenka Digi has been advised of the possibility of such damages.
24 |
25 | 3) MISCELLANEOUS
26 |
27 | Should the user have any questions concerning this document or you desire to contact Neale Davidson for any reason, please email tenkadigi@hotmail.com .
28 |
29 | Governing Law
30 |
31 | This agreement is governed by and subject to the laws of the United States of America.
32 |
--------------------------------------------------------------------------------
/src/fonts/licenses/dragon alphabet.txt:
--------------------------------------------------------------------------------
1 | 1001Fonts Free For Personal Use License (FFP)
2 |
3 | Preamble
4 | In this license, 'dragon_alphabet' refers to the given .zip file, which may contain one or numerous fonts. These fonts can be of any type (.ttf, .otf, ...) and together they form a 'font family' or in short a 'typeface'.
5 |
6 | 1. Copyright
7 | dragon_alphabet is the intellectual property of its respective author, provided it is original, and is protected by copyright laws in many parts of the world.
8 |
9 | 2. Personal Use
10 | dragon_alphabet may be downloaded and used free of charge for personal use, as long as the usage is not racist or illegal. Personal use refers to all usage that does not generate financial income in a business manner, for instance:
11 |
12 | - personal scrapbooking for yourself
13 | - recreational websites and blogs for friends and family
14 | - prints such as flyers, posters, t-shirts for churches, charities, and non-profit organizations
15 |
16 | 3. Commercial Use
17 | Commercial use is not allowed without prior written permission from the respective author. Please contact the author to ask for commercial licensing. Commercial use refers to usage in a business environment, including:
18 |
19 | - business cards, logos, advertising, websites, mobile apps for companies
20 | - t-shirts, books, apparel that will be sold for money
21 | - flyers, posters for events that charge admission
22 | - freelance graphic design work
23 | - anything that will generate direct or indirect income
24 |
25 | 4. Modification
26 | dragon_alphabet may not be modified, altered, adapted or built upon without written permission by its respective author. This pertains all files within the downloadable font zip-file.
27 |
28 | 5. Conversion
29 | dragon_alphabet may be converted to other formats such as WOFF, SVG or EOT webfonts, as long as the font is not modified in any other way, such as changing names or altering individual glyphs.
30 |
31 | 6. Distribution
32 | While dragon_alphabet may freely be copied and passed along to other individuals for private use as its original downloadable zip-file, it may not be sold or published without written permission by its respective author.
33 |
34 | 7. Embedding
35 | dragon_alphabet may be embedded into an application such as a web- or mobile app, as long as the application is of personal use and does not distribute dragon_alphabet, such as offering it as a download.
36 |
37 | 8. Disclaimer
38 | dragon_alphabet is offered 'as is' without any warranty. 1001fonts.com and the respective author of dragon_alphabet shall not be liable for any damage derived from using this typeface. By using dragon_alphabet you agree to the terms of this license.
--------------------------------------------------------------------------------
/src/module/providers/earthdawn4e.js:
--------------------------------------------------------------------------------
1 | import LanguageProvider from "./templates/Base.js";
2 |
3 | export default class earthdawn4eLanguageProvider extends LanguageProvider {
4 | languages = {
5 | human: {
6 | font: "Thorass",
7 | },
8 | dwarven: {
9 | font: "Dethek",
10 | },
11 | elven: {
12 | font: "Espruar",
13 | },
14 | windling: {
15 | font: "Olde Thorass",
16 | },
17 | obsidiman: {
18 | font: "Dethek",
19 | },
20 | troll: {
21 | font: "Jungle Slang",
22 | },
23 | ork: {
24 | font: "Dethek",
25 | },
26 | tskrang: {
27 | font: "Iokharic",
28 | },
29 | };
30 |
31 | get settings() {
32 | return {
33 | LanguageRegex: {
34 | type: String,
35 | default: game.i18n.localize("POLYGLOT.Generic.Language"),
36 | },
37 | LiteracyRegex: {
38 | type: String,
39 | default: game.i18n.localize("POLYGLOT.Generic.Read"),
40 | },
41 | };
42 | }
43 |
44 | async getLanguages() {
45 | const languagesSetting = game.settings.get("polyglot", "Languages");
46 | for (let lang in this.languages) {
47 | this.languages[lang] = {
48 | label: game.i18n.localize(`earthdawn.l.language${lang.capitalize()}`),
49 | font: languagesSetting[lang]?.font || this.languages[lang]?.font || this.defaultFont,
50 | rng: languagesSetting[lang]?.rng ?? "default",
51 | };
52 | }
53 | }
54 |
55 | getUserLanguages(actor) {
56 | let knownLanguages = new Set();
57 | let literateLanguages = new Set();
58 | for (let lang in actor.system.speak.languages) {
59 | if (actor.system.speak.languages[lang]) knownLanguages.add(lang);
60 | }
61 | for (let lang in actor.system.languages.write) {
62 | if (actor.system.write.languages[lang]) literateLanguages.add(lang);
63 | }
64 | if (actor.system.languages.other) {
65 | const languageRegex = game.settings.get("polyglot", "LanguageRegex");
66 | const literacyRegex = game.settings.get("polyglot", "LiteracyRegex");
67 | for (let lang of actor.system.languages.other.split(/[,;]/)) {
68 | const languageMatch = lang.match(`${languageRegex} \\((.+)\\)`, "i");
69 | const literacyMatch = lang.match(`${literacyRegex} \\((.+)\\)`, "i");
70 | if (languageMatch || literacyMatch) {
71 | if (languageMatch) knownLanguages.add(languageMatch[1].trim().toLowerCase());
72 | else if (literacyMatch) literateLanguages.add(literacyMatch[1].trim().toLowerCase());
73 | } else {
74 | knownLanguages.add(lang.trim().toLowerCase());
75 | literateLanguages.add(lang.trim().toLowerCase());
76 | }
77 | }
78 | }
79 | return [knownLanguages, literateLanguages];
80 | }
81 |
82 | conditions(lang) {
83 | return game.polyglot.literateLanguages.has(lang);
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/module/providers/demonlord.js:
--------------------------------------------------------------------------------
1 | import LanguageProvider from "./templates/Base.js";
2 |
3 | export default class demonlordLanguageProvider extends LanguageProvider {
4 | languages = {
5 | "Common Tongue": {
6 | font: "Thorass",
7 | },
8 | "Dark Speech": {
9 | font: "Infernal",
10 | },
11 | "High Archaic": {
12 | font: "Mage Script",
13 | },
14 | Elvish: {
15 | font: "Espruar",
16 | },
17 | Dwarfish: {
18 | font: "Dethek",
19 | },
20 | "Dead Languages": {
21 | font: "Olde Thorass",
22 | },
23 | "Secret Language": {
24 | font: "Thassilonian",
25 | },
26 | Trollish: {
27 | font: "Ar Ciela",
28 | },
29 | Centauri: {
30 | font: "High Drowic",
31 | },
32 | Gnomish: {
33 | font: "High Drowic",
34 | },
35 | Amrin: {
36 | font: "Thorass",
37 | },
38 | Balgrennish: {
39 | font: "Tengwar",
40 | },
41 | Bhali: {
42 | font: "Tengwar",
43 | },
44 | Edene: {
45 | font: "Thorass",
46 | },
47 | Erath: {
48 | font: "Thorass",
49 | },
50 | Grennish: {
51 | font: "Tengwar",
52 | },
53 | Kalasan: {
54 | font: "Thorass",
55 | },
56 | Woad: {
57 | font: "Jungle Slang",
58 | },
59 | Sylphen: {
60 | font: "High Drowic",
61 | },
62 | Molekin: {
63 | font: "Barazhad",
64 | },
65 | Naga: {
66 | font: "Barazhad",
67 | },
68 | Yerath: {
69 | font: "Barazhad",
70 | },
71 | };
72 |
73 | requiresReady = true;
74 |
75 | getSystemDefaultLanguage() {
76 | return "Common Tongue";
77 | }
78 |
79 | async getLanguages() {
80 | if (this.replaceLanguages) {
81 | this.languages = {};
82 | return;
83 | }
84 | const demonlordPack = game.packs.get("demonlord.languages");
85 | const demonlordItemList = await demonlordPack.getIndex();
86 | const languagesSetting = game.settings.get("polyglot", "Languages");
87 | for (let item of demonlordItemList) {
88 | const originalName = item?.flags?.babele?.originalName || item.name;
89 | this.languages[originalName] = {
90 | label: item.name,
91 | font: languagesSetting[originalName]?.font || this.languages[originalName]?.font || this.defaultFont,
92 | rng: languagesSetting[originalName]?.rng ?? "default",
93 | };
94 | }
95 | }
96 |
97 | getUserLanguages(actor) {
98 | let knownLanguages = new Set();
99 | let literateLanguages = new Set();
100 | for (let item of actor.items) {
101 | if (item.type === "language") {
102 | const name = item?.flags?.babele?.originalName || item.name;
103 | if (item.system.speak) knownLanguages.add(name);
104 | if (item.system.read) literateLanguages.add(name);
105 | }
106 | }
107 | return [knownLanguages, literateLanguages];
108 | }
109 |
110 | conditions(lang) {
111 | return game.polyglot.literateLanguages.has(lang);
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/src/module/libs/libWrapper.js:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | // Copyright © 2021 fvtt-lib-wrapper Rui Pinheiro
3 |
4 | "use strict";
5 |
6 | // A shim for the libWrapper library
7 | export let libWrapper = undefined;
8 |
9 | export const VERSIONS = [1, 12, 2];
10 | export const TGT_SPLIT_RE = new RegExp("([^.[]+|\\[('([^'\\\\]|\\\\.)+?'|\"([^\"\\\\]|\\\\.)+?\")\\])", "g");
11 | export const TGT_CLEANUP_RE = new RegExp("(^\\['|'\\]$|^\\[\"|\"\\]$)", "g");
12 |
13 | // Main shim code
14 | Hooks.once("init", () => {
15 | // Check if the real module is already loaded - if so, use it
16 | if (globalThis.libWrapper && !(globalThis.libWrapper.is_fallback ?? true)) {
17 | libWrapper = globalThis.libWrapper;
18 | return;
19 | }
20 |
21 | // Fallback implementation
22 | libWrapper = class {
23 | static get is_fallback() {
24 | return true;
25 | }
26 |
27 | static get WRAPPER() {
28 | return "WRAPPER";
29 | }
30 |
31 | static get MIXED() {
32 | return "MIXED";
33 | }
34 |
35 | static get OVERRIDE() {
36 | return "OVERRIDE";
37 | }
38 |
39 | static register(package_id, target, fn, type = "MIXED", { chain = undefined, bind = [] } = {}) {
40 | const is_setter = target.endsWith("#set");
41 | target = !is_setter ? target : target.slice(0, -4);
42 | const split = target.match(TGT_SPLIT_RE).map((x) => x.replace(/\\(.)/g, "$1").replace(TGT_CLEANUP_RE, ""));
43 | const root_nm = split.splice(0, 1)[0];
44 |
45 | let obj; let fn_name;
46 | if (split.length === 0) {
47 | obj = globalThis;
48 | fn_name = root_nm;
49 | } else {
50 | const _eval = eval;
51 | fn_name = split.pop();
52 | obj = split.reduce((x, y) => x[y], globalThis[root_nm] ?? _eval(root_nm));
53 | }
54 |
55 | let iObj = obj;
56 | let descriptor = null;
57 | while (iObj) {
58 | descriptor = Object.getOwnPropertyDescriptor(iObj, fn_name);
59 | if (descriptor) break;
60 | iObj = Object.getPrototypeOf(iObj);
61 | }
62 | if (!descriptor || descriptor?.configurable === false) throw new Error(
63 | `libWrapper Shim: '${target}' does not exist, could not be found, or has a non-configurable descriptor.`,
64 | );
65 |
66 | let original = null;
67 | const wrapper =
68 | chain ?? (type.toUpperCase?.() !== "OVERRIDE" && type !== 3)
69 | ? function (...args) {
70 | return fn.call(this, original.bind(this), ...bind, ...args);
71 | }
72 | : function (...args) {
73 | return fn.call(this, ...bind, ...args);
74 | };
75 | if (!is_setter) {
76 | if (descriptor.value) {
77 | original = descriptor.value;
78 | descriptor.value = wrapper;
79 | } else {
80 | original = descriptor.get;
81 | descriptor.get = wrapper;
82 | }
83 | } else {
84 | if (!descriptor.set) throw new Error(`libWrapper Shim: '${target}' does not have a setter`);
85 | original = descriptor.set;
86 | descriptor.set = wrapper;
87 | }
88 |
89 | descriptor.configurable = true;
90 | Object.defineProperty(obj, fn_name, descriptor);
91 | }
92 | };
93 | });
94 |
--------------------------------------------------------------------------------
/src/lang/ja.json:
--------------------------------------------------------------------------------
1 | {
2 | "POLYGLOT": {
3 | "DefaultAlphabet": "標準文字",
4 | "FontSettings": "フォント設定",
5 | "LanguageSettings": "言語設定",
6 | "ChatSettings": "チャット設定",
7 | "Languages.title": "言語",
8 | "Languages.hint": "言語のアルファベットを変更します。セーブ後に再読み込みが必要です。デフォルトに戻すと自動で再読み込みされます。",
9 | "Fonts": "フォント",
10 | "CustomLanguages.title": "カスタム言語",
11 | "CustomLanguages.hint": "システムに追加するカスタム言語のリストをカンマ区切りで指定します。",
12 | "ComprehendLanguages.title": "コンプリヘンド・ランゲージズ呪文",
13 | "ComprehendLanguages.hint": "D&Dにおけるコンプリヘンド・ランゲージズに相当する呪文。設定済のカスタム言語を入力します。その習得者は話したり書いたりはできませんが、すべての言語が理解できるようになります。",
14 | "Truespeech.title": "タンズ呪文",
15 | "Truespeech.hint": "D&Dにおけるタンズに相当する呪文。設定済のカスタム言語を入力します。その話者はすべての“話し言葉”を理解し(つまり資料は読めない)、すべてのクリーチャーが理解できる発言が行えるようになります。",
16 | "DefaultLanguage.title": "デフォルトの言語",
17 | "DefaultLanguage.hint": "デフォルト選択される言語の名称を入力します。空にすると、システムのデフォルトが使用されます。",
18 | "ReplaceLanguages.title": "システム言語を置き換える",
19 | "ReplaceLanguages.hint": "システムのデフォルト言語をカスタム言語に置き換えます。リストの最初の言語が新しいデフォルト言語になります。",
20 | "ScrambleGM.title": "GMもスクランブル化する",
21 | "ScrambleGM.hint": "無効にすると、GMはテキストの内容を常に確認できるようになります。選択したコマが言語を理解しているかは、翻訳アイコン(地球儀マーク)の色を確認する必要があります。",
22 | "enableAllFonts.title": "言語設定ですべてのフォントを追加する",
23 | "enableAllFonts.hint": "言語設定でPolyglotフォントが使用できるようなります。",
24 | "RandomizeRunes.title": "ルーンのランダム化",
25 | "RandomizeRunes.hint": "有効にすると、同じメッセージを繰り返し発言したとしても、スクランブル後のテキストが別の文字列になります。",
26 | "ExportFonts.title": "フォントを使用可能にする",
27 | "ExportFonts.hint": "PolyglotフォントをFoundryのシステム(例えば図形描画ツールなど)で使用できるようなります。",
28 | "DisplayTranslated.title": "翻訳ボックスを表示する",
29 | "DisplayTranslated.hint": "チャットログ内で翻訳が行われるとき、翻訳文と原文が併記されるようになります。",
30 | "HideTranslation.title": "翻訳アイコンと翻訳元の表示を隠す",
31 | "HideTranslation.hint": "チャットに表示される翻訳アイコン(地球儀マーク)と、翻訳ボックス内に表示される「翻訳元」の表示をプレイヤーに隠します。何の言語を話しているかをプレイヤーに伏せたいときに適しています。",
32 | "AllowOOC.title": "OOCチャットのスクランブル化",
33 | "AllowOOC.hint": "キャラクターの発言ではないメッセージ(OOC:Out Of Character)であっても、GMは言語をスクランブルできるようになります。",
34 | "AllowOOCOptions": {
35 | "a": "全員",
36 | "b": "GMのみ",
37 | "c": "プレイヤーのみ",
38 | "d": "なし"
39 | },
40 | "LanguageProvider": {
41 | "name": "言語設定の提供元",
42 | "hint": "アルファベットや言語情報の提供元を選択できるようになりました。ゲームシステムやインストールされたモジュールによって、より多くの提供元が利用できます。以下のオプションは、ここで選択した言語の提供元によって変化します。⚠️提供元を変更したときは、保存後に再度設定を開き直す必要があります。",
43 | "choices": {
44 | "module": "[モジュール] {name}",
45 | "native": "標準設定",
46 | "system": "[システム] {name}"
47 | }
48 | },
49 | "Translation": "翻訳",
50 | "TranslatedFrom": "翻訳元:",
51 | "LanguageLabel": "言語",
52 | "AlphabetLabel": "文字体系",
53 | "LatinAlphabet": "ラテン文字",
54 | "ToggleRunes": "ルーンの切替",
55 | "Runes": "ルーン",
56 | "Generic": {
57 | "Language": "言語"
58 | },
59 | "UESRPG.Language": "言語",
60 | "COC7": {
61 | "LanguageOwn": "言語",
62 | "LanguageAny": "言語",
63 | "LanguageOther": "言語",
64 | "LanguageSpec": "言語"
65 | },
66 | "SWADE": {
67 | "LanguageSkills": "言語"
68 | },
69 | "WFRP4E": {
70 | "LanguageSkills": "言語"
71 | },
72 | "enableAllFonts": {
73 | "choices": {
74 | "1": "Polyglotのフォント",
75 | "2": "コアの追加フォント",
76 | "0": "なし",
77 | "3": "両方"
78 | }
79 | },
80 | "FontSize": "フォントサイズ(%)",
81 | "Font": "フォント"
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/lang/ko.json:
--------------------------------------------------------------------------------
1 | {
2 | "POLYGLOT": {
3 | "DefaultAlphabet": "기본 문자",
4 | "FontSettings": "글꼴 설정",
5 | "LanguageSettings": "언어 설정",
6 | "ChatSettings": "채팅 설정",
7 | "Languages.title": "언어",
8 | "Languages.hint": "언어에 사용될 알파벳을 변경한다. 기본값으로 재설정하면 새로고침된다.",
9 | "Fonts": "글꼴",
10 | "CustomLanguages.title": "사용자 지정 언어",
11 | "CustomLanguages.hint": "시스템에 추가할 사용자 정의 언어. 쉼표(,)로 구분하여 목록을 정의한다.",
12 | "ComprehendLanguages.title": "언어 변환 주문",
13 | "ComprehendLanguages.hint": "D&D의 언어 변환 주문과 같이, 설정한 사용자 지정 언어를 입력하면 말하거나 쓰진 못하지만 다른 언어를 이해할 수 있게 해준다.",
14 | "Truespeech.title": "언어 구사 주문",
15 | "Truespeech.hint": "D&D의 언어 구사 주문과 같이, 설정한 사용자 지정 언어를 입력하면 화자는 언어를 듣고 이해할 수 있으며(저널은 읽지 못함), 모든 생물의 언어를 이해할 수 있다.",
16 | "JournalHighlight.title": "저널 하이라이트 불투명도(%)",
17 | "JournalHighlight.hint": "저널의 글씨 위 하이라이트 표시의 불투명도를 정의한다.",
18 | "logographicalFontToggle.title": "로고그래픽 폰트",
19 | "logographicalFontToggle.hint": "로고그래픽 폰트(e.g.:일본어, 한자)를 사용하여 구절의 크기를 절반으로 줄인다.",
20 | "DefaultLanguage.title": "기본 언어",
21 | "DefaultLanguage.hint": "선택할 기본 언어의 이름이다. 시스템 기본값을 사용하려면 비워둘 것.",
22 | "ReplaceLanguages.title": "시스템 언어 대체",
23 | "ReplaceLanguages.hint": "시스템의 기본 언어를 사용자 지정 언어로 바꾼다. 목록의 첫번째 언어가 새 기본 언어가 된다.",
24 | "ScrambleGM.title": "GM에게 스크램블",
25 | "ScrambleGM.hint": "GM에게 텍스트를 항상 표시하려면 이 옵션을 비활성화한다. 토큰이 이해하는지는 지구본 색 참조.",
26 | "enableAllFonts.title": "모든 글꼴 사용",
27 | "enableAllFonts.hint": "언어 설정에서 Polyglot 글꼴을 사용가능하게 한다.",
28 | "RandomizeRunes.title": "룬 임의화",
29 | "RandomizeRunes.hint": "이 옵션을 활성화하면 동일한 메시지가 반복되더라도 스크램블 텍스트가 다르게 나타난다.",
30 | "RandomizeRunesOptions": {
31 | "a": "기본값",
32 | "b": "고유 문구",
33 | "c": "없음 ⚠️"
34 | },
35 | "ExportFonts.title": "글꼴 사용 가능",
36 | "ExportFonts.hint": "Polyglot 글꼴을 Foundry에서 사용할 수 있도록 한다(예: 그리기 도구).",
37 | "DisplayTranslated.title": "번역 상자 표시",
38 | "DisplayTranslated.hint": "채팅창에서 번역된 언어의 경우 원본 텍스트 밑에 번역을 아래에 표시한다.",
39 | "HideTranslation.title": "지구본을 숨기고 \"다음 언어로부터 번역됨\" 텍스트를 플레이어에게 보임",
40 | "HideTranslation.hint": "지구본을 숨기고 \"다음 언어로부터 번역됨\" 채팅 메시지를 플레이어에게 보여준다. 플레이어에게 어떤 언어를 사용하는지 보여주고 싶지 않을 때 이상적이다.",
41 | "AllowOOC.title": "OOC 채팅 메시지 스크램블",
42 | "AllowOOC.hint": "GM이 OOC 메시지를 보낼 때 스크램블 할 수 있도록 한다.",
43 | "AllowOOCOptions": {
44 | "a": "모두",
45 | "b": "GM만",
46 | "c": "PL만",
47 | "d": "없음"
48 | },
49 | "LanguageProvider": {
50 | "name": "언어 설정 공급자",
51 | "hint": "문자 및 언어 정보를 제공하는 공급자를 선택한다. 게임 시스템과 설치된 모듈을 통해 더 많은 언어 공급자를 이용할 수 있다. 아래 옵션은 여기서 선택한 언어 공급자에 따라 달라진다. ⚠️공급자를 변경할 경우 설정을 저장하고 다시 열어야 한다.",
52 | "choices": {
53 | "module": "[모듈] {name}",
54 | "native": "일반적",
55 | "system": "[시스템] {name}"
56 | }
57 | },
58 | "Translation": "번역",
59 | "TranslatedFrom": "다음 언어로부터 번역됨: ",
60 | "LanguageLabel": "언어",
61 | "AlphabetLabel": "문자",
62 | "LatinAlphabet": "라틴 알파벳",
63 | "ToggleRunes": "룬 토글",
64 | "Runes": "룬",
65 | "Generic": {
66 | "Language": "언어"
67 | },
68 | "UESRPG.Language": "언어",
69 | "COC7": {
70 | "LanguageOwn": "언어",
71 | "LanguageAny": "언어",
72 | "LanguageOther": "언어",
73 | "LanguageSpec": "언어"
74 | },
75 | "SWADE": {
76 | "LanguageSkills": "언어"
77 | },
78 | "WFRP4E": {
79 | "LanguageSkills": "언어"
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/module/providers/ose.js:
--------------------------------------------------------------------------------
1 | import LanguageProvider from "./templates/Base.js";
2 |
3 | export default class oseLanguageProvider extends LanguageProvider {
4 | languages = {
5 | Common: {
6 | label: "Common",
7 | font: "Thorass",
8 | rng: "default",
9 | },
10 | Lawful: {
11 | label: "Lawful",
12 | font: "Celestial",
13 | rng: "default",
14 | },
15 | Chaotic: {
16 | label: "Chaotic",
17 | font: "Barazhad",
18 | rng: "default",
19 | },
20 | Neutral: {
21 | label: "Neutral",
22 | font: "Infernal",
23 | rng: "default",
24 | },
25 | Bugbear: {
26 | label: "Bugbear",
27 | font: "Dethek",
28 | rng: "default",
29 | },
30 | Doppelgänger: {
31 | label: "Doppelgänger",
32 | font: "Pulsian",
33 | rng: "default",
34 | },
35 | Dragon: {
36 | label: "Dragon",
37 | font: "Iokharic",
38 | rng: "default",
39 | },
40 | Dwarvish: {
41 | label: "Dwarvish",
42 | font: "Dethek",
43 | rng: "default",
44 | },
45 | Elvish: {
46 | label: "Elvish",
47 | font: "Espruar",
48 | rng: "default",
49 | },
50 | Gargoyle: {
51 | label: "Gargoyle",
52 | font: "High Drowic",
53 | rng: "default",
54 | },
55 | Gnoll: {
56 | label: "Gnoll",
57 | font: "Kargi",
58 | rng: "default",
59 | },
60 | Gnomish: {
61 | label: "Gnomish",
62 | font: "Tengwar",
63 | rng: "default",
64 | },
65 | Goblin: {
66 | label: "Goblin",
67 | font: "Dethek",
68 | rng: "default",
69 | },
70 | Halfling: {
71 | label: "Halfling",
72 | rng: "default",
73 | },
74 | Harpy: {
75 | label: "Harpy",
76 | font: "Olde Thorass",
77 | rng: "default",
78 | },
79 | Hobgoblin: {
80 | label: "Hobgoblin",
81 | font: "Dethek",
82 | rng: "default",
83 | },
84 | Kobold: {
85 | label: "Kobold",
86 | font: "Iokharic",
87 | rng: "default",
88 | },
89 | "Lizard Man": {
90 | label: "Lizard Man",
91 | font: "Iokharic",
92 | rng: "default",
93 | },
94 | Medusa: {
95 | label: "Medusa",
96 | font: "High Drowic",
97 | rng: "default",
98 | },
99 | Minotaur: {
100 | label: "Minotaur",
101 | font: "Olde Espruar",
102 | rng: "default",
103 | },
104 | Ogre: {
105 | label: "Ogre",
106 | font: "Meroitic Demotic",
107 | rng: "default",
108 | },
109 | Orcish: {
110 | label: "Orcish",
111 | font: "Dethek",
112 | rng: "default",
113 | },
114 | Pixie: {
115 | label: "Pixie",
116 | font: "Olde Espruar",
117 | rng: "default",
118 | },
119 | };
120 |
121 | async getLanguages() {
122 | if (this.replaceLanguages) {
123 | this.languages = {};
124 | return;
125 | }
126 | const languagesSetting = game.settings.get("polyglot", "Languages");
127 | CONFIG.OSE.languages.forEach((key) => {
128 | this.languages[key] = {
129 | label: key,
130 | font: languagesSetting[key]?.font || this.languages[key]?.font || this.defaultFont,
131 | rng: languagesSetting[key]?.rng ?? "default",
132 | };
133 | });
134 | }
135 |
136 | getUserLanguages(actor) {
137 | let knownLanguages = new Set();
138 | let literateLanguages = new Set();
139 | for (let lang of actor.system.languages.value) knownLanguages.add(lang);
140 | return [knownLanguages, literateLanguages];
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/src/module/providers/gurps.js:
--------------------------------------------------------------------------------
1 | import LanguageProvider from "./templates/Base.js";
2 |
3 | export default class gurpsLanguageProvider extends LanguageProvider {
4 | get settings() {
5 | return {
6 | LanguageRegex: {
7 | type: String,
8 | default: game.i18n.localize("POLYGLOT.Generic.Language"),
9 | },
10 | };
11 | }
12 |
13 | /**
14 | * Search through all of the advantages (including recursing into containers) looking for "Language" or translation.
15 | * Depending on the source, it can be two different patterns, Language: NAME (optionals) or Language (NAME) (optionals)
16 | * and the advantage names may or may not be translated, so we must search for both
17 | */
18 | getUserLanguages(actor) {
19 | let knownLanguages = new Set();
20 | let literateLanguages = new Set();
21 | if (GURPS) {
22 | const languageRegex = game.settings.get("polyglot", "LanguageRegex");
23 | // window.GURPS set when the GURPS game system is loaded
24 | let npat1 = ": +(?[^\\(]+)";
25 | let npat2 = " +\\((?[^\\)]+)\\)";
26 | GURPS.recurselist(actor.system.ads, (advantage) => {
27 | if (!this.updateForPattern(
28 | advantage,
29 | new RegExp(languageRegex + npat1, "i"),
30 | knownLanguages,
31 | literateLanguages
32 | )) if (!this.updateForPattern(
33 | advantage,
34 | new RegExp(languageRegex + npat2, "i"),
35 | knownLanguages,
36 | literateLanguages
37 | )) if (!this.updateForPattern(
38 | advantage,
39 | new RegExp(game.i18n.localize("GURPS.language") + npat1, "i"),
40 | knownLanguages,
41 | literateLanguages,
42 | true
43 | )) this.updateForPattern(
44 | advantage,
45 | new RegExp(game.i18n.localize("GURPS.language") + npat2, "i"),
46 | knownLanguages,
47 | literateLanguages,
48 | true
49 | );
50 | });
51 | }
52 | return [knownLanguages, literateLanguages];
53 | }
54 |
55 | /**
56 | If we match on the Language name, search the name (or the notes)
57 | for indicators of spoken or written levels of comprehension in English, or translated
58 | */
59 | updateForPattern(advantage, regex, knownLanguages, literateLanguages, langDetected = false) {
60 | let match = advantage.name.match(regex);
61 | if (match) {
62 | const lang = match.groups.name.trim().toLowerCase();
63 | const wpat = new RegExp(game.i18n.localize("GURPS.written"), "i");
64 | const spat = new RegExp(game.i18n.localize("GURPS.spoken"), "i");
65 | let written = advantage.name.match(/written/i) || advantage.notes?.match(/written/i);
66 | if (!written) written = advantage.name.match(wpat) || advantage.notes?.match(wpat);
67 | let spoken = advantage.name.match(/spoken/i) || advantage.notes?.match(/spoken/i);
68 | if (!spoken) spoken = advantage.name.match(spat) || advantage.notes?.match(spat);
69 | if (written && spoken) {
70 | knownLanguages.add(lang);
71 | literateLanguages.add(lang);
72 | return true;
73 | } else if (written) {
74 | literateLanguages.add(lang);
75 | return true;
76 | } else if (spoken) {
77 | knownLanguages.add(lang);
78 | return true;
79 | } else if (langDetected) { // neither is specificaly identified, assume both if "Language" detected
80 | knownLanguages.add(lang);
81 | literateLanguages.add(lang);
82 | return true;
83 | }
84 | }
85 | return false;
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/styles/fonts.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family:'ArCiela';
3 | src:url('../fonts/ArCiela.ttf');
4 | }
5 | @font-face {
6 | font-family:'Barazhad';
7 | src:url('../fonts/Barazhad.otf');
8 | }
9 | @font-face {
10 | font-family:'Celestial';
11 | src:url('../fonts/Celestial.ttf');
12 | }
13 | @font-face {
14 | font-family:'DarkEldar';
15 | src:url('../fonts/DarkEldar.ttf');
16 | }
17 | @font-face {
18 | font-family:'Dethek';
19 | src:url('../fonts/Dethek.otf');
20 | }
21 | @font-face {
22 | font-family:'ElderFuthark';
23 | src:url('../fonts/ElderFutharkFS.ttf');
24 | }
25 | @font-face {
26 | font-family:'Eltharin';
27 | src:url('../fonts/Eltharin.ttf');
28 | }
29 | @font-face {
30 | font-family:'Espruar';
31 | src:url('../fonts/Espruar.otf');
32 | }
33 | @font-face {
34 | font-family:'Floki';
35 | src:url('../fonts/Floki.ttf');
36 | }
37 | @font-face {
38 | font-family:'FingerAlphabet';
39 | src:url('../fonts/FingerAlphabet.ttf');
40 | }
41 | @font-face {
42 | font-family:'HighDrowic';
43 | src:url('../fonts/HighDrowic.otf');
44 | }
45 | @font-face {
46 | font-family:'HighschoolRunes';
47 | src:url('../fonts/HighschoolRunes.ttf');
48 | }
49 | @font-face {
50 | font-family:'Infernal';
51 | src:url('../fonts/Infernal.ttf');
52 | }
53 | @font-face {
54 | font-family:'Iokharic';
55 | src:url('../fonts/Iokharic.otf');
56 | }
57 | @font-face {
58 | font-family:'JungleSlang';
59 | src:url('../fonts/JungleSlang.ttf');
60 | }
61 | @font-face {
62 | font-family:'Kargi';
63 | src:url('../fonts/Kargi.ttf');
64 | }
65 | @font-face {
66 | font-family:'MarasEye';
67 | src:url('../fonts/MarasEye.otf');
68 | }
69 | @font-face {
70 | font-family:'MeroiticDemotic';
71 | src:url('../fonts/MeroiticDemotic.ttf');
72 | }
73 | @font-face {
74 | font-family:'MiroslavNormal';
75 | src:url('../fonts/MiroslavNormal.ttf');
76 | }
77 | @font-face {
78 | font-family:'OldeEspruar';
79 | src:url('../fonts/OldeEspruar.otf');
80 | }
81 | @font-face {
82 | font-family:'OldeThorass';
83 | src:url('../fonts/OldeThorass.otf');
84 | }
85 | @font-face {
86 | font-family:'Ophidian';
87 | src:url('../fonts/Ophidian.otf');
88 | }
89 | @font-face {
90 | font-family:'Pulsian';
91 | src:url('../fonts/Pulsian.ttf');
92 | }
93 | @font-face {
94 | font-family:'Oriental';
95 | src:url('../fonts/Oriental.ttf');
96 | }
97 | @font-face {
98 | font-family:'OrkGlyphs';
99 | src:url('../fonts/OrkGlyphs.ttf');
100 | }
101 | @font-face {
102 | font-family:'Qijomi';
103 | src:url('../fonts/Qijomi.otf');
104 | }
105 | @font-face {
106 | font-family:'Reanaarian';
107 | src:url('../fonts/Reanaarian.otf');
108 | }
109 | @font-face {
110 | font-family:'Saurian';
111 | src:url('../fonts/Saurian.ttf');
112 | }
113 | @font-face {
114 | font-family:'Semphari';
115 | src:url('../fonts/Semphari.otf');
116 | }
117 | @font-face {
118 | font-family:'Skaven';
119 | src:url('../fonts/Skaven.ttf');
120 | }
121 | @font-face {
122 | font-family:'Tengwar';
123 | src:url('../fonts/Tengwar.ttf');
124 | }
125 | @font-face {
126 | font-family:'Thassilonian';
127 | src:url('../fonts/Thassilonian.ttf');
128 | }
129 | @font-face {
130 | font-family:'Thorass';
131 | src:url('../fonts/Thorass.otf');
132 | }
133 | @font-face {
134 | font-family:'Tuzluca';
135 | src:url('../fonts/Tuzluca.ttf');
136 | }
137 | @font-face {
138 | font-family:'Valmaric';
139 | src:url('../fonts/Valmaric.ttf');
140 | }
--------------------------------------------------------------------------------
/src/fonts/licenses/pixel sagas.txt:
--------------------------------------------------------------------------------
1 | Font License
2 | Shareware/ Font License
3 |
4 | Pixel Sagas Freeware Fonts EULA (End User License Agreement) and Software Inclusion Agreement
5 |
6 | “Purchaser” and “User” may be used interchangeably in this agreement.
7 |
8 | “Pixel Sagas” and “Neale Davidson” may be used interchangeably in this agreement. These all refer to the intellectual and legal property of Neale Davidson.
9 |
10 | Usage
11 |
12 | Pixel Saga’s Shareware Fonts are free to use for personal, non-commercial purposes. No payment is necessary to use Pixel Saga’s Freeware Fonts for personal use, and there is no limit to the amount of prints, pages, or other medium to be produced using them. However, you cannot offer the font for commercial sale, or offer for direct download. The inclusion of the font name and/or site URL in the credits or documentation when it is used is appreciated, but this is not mandatory.
13 |
14 | Payment
15 |
16 | Payment is not required for the use of Pixel Saga’s Shareware Fonts. Commercial use requires a modest fee which can be paid through the pixelsagas.com web site through Paypal.com’s services. The transaction receipt for any shareware “commercial license” purchase will suffice as proof of license.
17 |
18 | Support
19 |
20 | Font installation help is available at http://www.pixelsagas.com. If you experience problems with any Pixel Saga’s Freeware font (such as spacing issues or missing characters), please verify that you have the correct and current version of the fonts. In the case of Freeware fonts, downloading the font directly from the Pixel Sagas site will ensure that the font files have not been altered.
21 |
22 | Software Inclusion Agreement
23 |
24 | Pixel Saga’s software products are protected by copyright laws and International copyright treaties, as well as other intellectual property laws and treaties. All Pixel Saga’s software products are licensed, not sold.
25 |
26 | 1) GRANT OF LICENSE
27 |
28 | This document grants the user the following rights:
29 |
30 | Installation and Use. The user may install and use an unlimited number of copies of the software product. The user may not offer Pixel Sagas freeware fonts for direct download unless the user has received explicit, written permission from Neale Davidson. Otherwise please direct users to the http://www.pixelsagas.com website. Pixel Sagas freeware fonts may, however, be embedded for web, publication, or general software use.
31 |
32 | 2) WARRANTIES
33 |
34 | None
35 |
36 | Pixel Sagas expressly disclaims any warranty for the software product. The software product and any related documentation is provided “as is” without warranty of any kind, either express or implied, including, without limitation, the implied warranties or merchantability, fitness for a particular purpose, or non-infringement. The entire risk arising out of use or performance of the software product remains with the user.
37 |
38 | No Liability For Consequential Damages.
39 |
40 | In no event shall Neale Davidson or Pixel Sagas be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or any other pecuniary loss) arising out of the use of or inability to use this product, even if Pixel Sagas has been advised of the possibility of such damages.
41 |
42 | 3) MISCELLANEOUS
43 |
44 | Should the user have any questions concerning this document or you desire to contact Neale Davidson for any reason, please email jaynz@pixelsagas.com .
45 |
46 | Governing Law
47 |
48 | This agreement is governed by and subject to the laws of the United States of America.
--------------------------------------------------------------------------------
/src/module/providers/wfrp4e.js:
--------------------------------------------------------------------------------
1 | import LanguageProvider from "./templates/Base.js";
2 |
3 | export default class wfrp4eLanguageProvider extends LanguageProvider {
4 | languages = {
5 | reikspiel: {
6 | font: "Infernal",
7 | },
8 | wastelander: {
9 | font: "Infernal",
10 | },
11 | classical: {
12 | font: "Infernal",
13 | },
14 | cathan: {
15 | font: "Oriental",
16 | },
17 | tilean: {
18 | font: "Thorass",
19 | },
20 | estalian: {
21 | font: "Tengwar",
22 | },
23 | gospodarinyi: {
24 | font: "Miroslav Normal",
25 | },
26 | albion: {
27 | font: "Elder Futhark",
28 | },
29 | norse: {
30 | font: "Elder Futhark",
31 | },
32 | bretonnian: {
33 | font: "Elder Futhark",
34 | },
35 | druhir: {
36 | font: "Dark Eldar",
37 | },
38 | elthárin: {
39 | font: "Eltharin",
40 | },
41 | orcish: {
42 | font: "Ork Glyphs",
43 | },
44 | queekish: {
45 | font: "Skaven",
46 | },
47 | slaan: {
48 | font: "Saurian",
49 | },
50 | khazalid: {
51 | font: "Floki",
52 | },
53 | magick: {
54 | font: "Eltharin",
55 | },
56 | };
57 |
58 | requiresReady = true;
59 |
60 | get settings() {
61 | return {
62 | LanguageRegex: {
63 | type: String,
64 | default: game.i18n.localize("POLYGLOT.WFRP4E.LanguageSkills"),
65 | },
66 | ReadWrite: {
67 | name: game.i18n.localize("POLYGLOT.WFRP4E.ReadWrite.title"),
68 | hint: game.i18n.localize("POLYGLOT.WFRP4E.ReadWrite.hint"),
69 | type: String,
70 | default: game.i18n.localize("POLYGLOT.WFRP4E.ReadWrite.default"),
71 | },
72 | };
73 | }
74 |
75 | getSystemDefaultLanguage() {
76 | return "reikspiel";
77 | }
78 |
79 | async getLanguages() {
80 | if (this.replaceLanguages) {
81 | this.languages = {};
82 | return;
83 | }
84 | const wfrp4ePack = game.packs.get("wfrp4e-core.items") || game.packs.get("wfrp4e.basic");
85 | const wfrp4eItemList = await wfrp4ePack.getIndex();
86 | const languagesSetting = game.settings.get("polyglot", "Languages");
87 | const myRegex = new RegExp(`(?:Language|${game.settings.get("polyglot", "LanguageRegex")})\\s*\\((.+)\\)`, "i");
88 | const langs = {};
89 | for (let item of wfrp4eItemList) {
90 | if (myRegex.test(item.name)) {
91 | let label = item.name.match(myRegex)[1].trim();
92 | let key = label.toLowerCase();
93 | if (!label) continue;
94 | langs[key] = {
95 | label,
96 | font: languagesSetting[key]?.font || this.languages[key]?.font || this.defaultFont,
97 | rng: languagesSetting[key]?.rng ?? "default",
98 | };
99 | }
100 | }
101 | this.languages = langs;
102 | }
103 |
104 | getUserLanguages(actor) {
105 | let knownLanguages = new Set();
106 | let literateLanguages = new Set();
107 | const readWrite = game.settings.get("polyglot", "ReadWrite");
108 | const isLiterate = actor.items.find((item) => item.name === readWrite && item.type === "talent") != null;
109 | let myRegex = new RegExp(`${game.settings.get("polyglot", "LanguageRegex")}\\s*\\((.+)\\)`, "i");
110 | for (let item of actor.items) {
111 | // adding only the descriptive language name, not "Language (XYZ)"
112 | if (myRegex.test(item.name)) {
113 | let language = item.name.match(myRegex)[1].trim().toLowerCase();
114 | knownLanguages.add(language);
115 | if (isLiterate) literateLanguages.add(language);
116 | }
117 | }
118 | return [knownLanguages, literateLanguages];
119 | }
120 |
121 | conditions(lang) {
122 | return game.polyglot.literateLanguages.has(lang);
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Development
2 |
3 | ## Building
4 |
5 | ### Prerequisites
6 |
7 | In order to build this module, recent versions of `node` and `npm` are
8 | required. Most likely, using `yarn` also works, but only `npm` is officially
9 | supported. We recommend using the latest lts version of `node`. If you use `nvm`
10 | to manage your `node` versions, you can simply run
11 |
12 | ```
13 | nvm install
14 | ```
15 |
16 | in the project's root directory.
17 |
18 | You also need to install the project's dependencies. To do so, run
19 |
20 | ```
21 | npm install
22 | ```
23 |
24 | ### Building
25 |
26 | You can build the project by running
27 |
28 | ```
29 | npm run build
30 | ```
31 |
32 | Alternatively, you can run
33 |
34 | ```
35 | npm run build:watch
36 | ```
37 |
38 | to watch for changes and automatically build as necessary.
39 |
40 | ### Linking the built project to Foundry VTT
41 |
42 | In order to provide a fluent development experience, it is recommended to link
43 | the built module to your local Foundry VTT installation's data folder. In
44 | order to do so, first add a file called `foundryconfig.json` to the project root
45 | with the following content:
46 |
47 | ```
48 | {
49 | "dataPath": ["/absolute/path/to/your/FoundryVTT"]
50 | }
51 | ```
52 |
53 | (if you are using Windows, make sure to use `\` as a path separator instead of
54 | `/`)
55 |
56 | Then run
57 |
58 | ```
59 | npm run link-project
60 | ```
61 |
62 | On Windows, creating symlinks requires administrator privileges, so
63 | unfortunately you need to run the above command in an administrator terminal for
64 | it to work.
65 |
66 | You can also link to multiple data folders by specifying multiple paths in the
67 | `dataPath` array.
68 |
69 | ## System Support
70 |
71 | If you want to add support for a system, be sure to check the [API page](../../wiki/API).
72 |
73 | The guide assumes you're contributing the code to another module or system. If you want to contribute to this project, you will still need to create a subclass, but you should add it to [LanguageProvider.js](/module/LanguageProvider.js) and its name to the import list on [api.js](src/module/api.js).
74 |
75 | # Translations
76 |
77 |
78 |
79 |
80 |
81 | Polyglot is available in the following languages:
82 |
83 | - Czech, thanks to [KarelZavicak](https://github.com/KarelZavicak)
84 | - English
85 | - Finnish, thanks to [Demian Wright](https://github.com/DemianWright)
86 | - French, thanks to [sladecraven](https://github.com/sladecraven)
87 | - German, thanks to [Nyhles](https://github.com/Nyhles)
88 | - Italian, thanks to [EldritchTranslator](https://github.com/EldritchTranslator)
89 | - Japanese, thanks to [BrotherSharper](https://github.com/BrotherSharper)
90 | - Korean, thanks to [drdwing](https://github.com/drdwing)
91 | - Polish, thanks to [MichalGolaszewski](https://github.com/MichalGolaszewski)
92 | - Portuguese (Brazil)
93 | - Spanish, thanks to [juanfrank](https://github.com/juanfrank), [lozalojo](https://github.com/lozalojo), [GoR](github.com/Git-GoR)
94 | - Swedish, thanks to [Jonas Karlsson](https://github.com/xdy)
95 |
96 | ## Contributing
97 |
98 | If you want to contribute with any translation, check out [Polyglot's Weblate page](https://weblate.foundryvtt-hub.com/engage/polyglot/).
99 |
100 | ### System Specific Translations
101 |
102 | Some translations are specific to a system (e.g. `COC7`, `SWADE`, and `WFRP4E`. When in doubt about its translation, check up with other translators of the system or the Babele module's translation.
103 |
--------------------------------------------------------------------------------
/src/module/providers/draw-steel.js:
--------------------------------------------------------------------------------
1 | import LanguageProvider from "./templates/Base.js";
2 |
3 | export default class drawSteelLanguageProvider extends LanguageProvider {
4 | languages = {
5 | // ancestry languages
6 | caelian: { // common
7 | font: "Meroitic Demotic",
8 | },
9 | anjali: {
10 | font: "High Drowic",
11 | },
12 | axiomatic: {
13 | font: "Miroslav Normal",
14 | },
15 | filliaric: {
16 | font: "Kargi",
17 | },
18 | highKuric: {
19 | font: "Maras Eye",
20 | },
21 | hyrallic: {
22 | font: "Ar Ciela",
23 | },
24 | illyvric: {
25 | font: "Ar Ciela",
26 | },
27 | kalliak: {
28 | font: "Kargi",
29 | },
30 | kethaic: {
31 | font: "Semphari",
32 | },
33 | khelt: {
34 | font: "Barazhad",
35 | },
36 | khoursirian: {
37 | font: "Meroitic Demotic",
38 | },
39 | lowKuric: {
40 | font: "Ork Glyphs",
41 | },
42 | mindspeech: {
43 | font: "Saurian",
44 | },
45 | protoCtholl: {
46 | font: "Tengwar",
47 | },
48 | szetch: {
49 | font: "Kargi",
50 | },
51 | theFirstLanguage: {
52 | font: "Mage Script",
53 | },
54 | tholl: {
55 | font: "Tengwar",
56 | },
57 | urollialic: {
58 | font: "Skaven",
59 | },
60 | variac: {
61 | font: "Skaven",
62 | },
63 | vastariax: {
64 | font: "Rellanic",
65 | },
66 | vhoric: {
67 | font: "Maras Eye",
68 | },
69 | voll: {
70 | font: "Celestial",
71 | },
72 | yllyric: {
73 | font: "Ar Ciela",
74 | },
75 | zahariax: {
76 | font: "Dark Eldar",
77 | },
78 | zaliac: {
79 | font: "Floki",
80 | },
81 | // Human languages. Khoursirian already covered
82 | higaran: {
83 | font: "Meroitic Demotic",
84 | },
85 | khemharic: {
86 | font: "Meroitic Demotic",
87 | },
88 | oaxuatl: {
89 | font: "Meroitic Demotic",
90 | },
91 | phaedran: {
92 | font: "Meroitic Demotic",
93 | },
94 | riojan: {
95 | font: "Meroitic Demotic",
96 | },
97 | uvalic: {
98 | font: "Meroitic Demotic",
99 | },
100 | vaniric: {
101 | font: "Meroitic Demotic",
102 | },
103 | vasloria: {
104 | font: "Meroitic Demotic",
105 | },
106 | // Dead languages
107 | highRhyvian: {
108 | font: "Ar Ciela",
109 | },
110 | khamish: {
111 | font: "Jungle Slang",
112 | },
113 | kheltivari: {
114 | font: "Barazhad",
115 | },
116 | lowRhivian: {
117 | font: "Ar Ciela",
118 | },
119 | oldVariac: {
120 | font: "Skaven",
121 | },
122 | phorialtic: {
123 | font: "Ork Glyphs",
124 | },
125 | rallarian: {
126 | font: "Floki",
127 | },
128 | ullorvic: {
129 | font: "Ar Ciela",
130 | },
131 | };
132 |
133 | async getLanguages() {
134 | if (this.replaceLanguages) {
135 | this.languages = {};
136 | return;
137 | }
138 | const languagesSetting = game.settings.get("polyglot", "Languages");
139 | this.languages = Object.keys(CONFIG.DRAW_STEEL.languages).reduce((outputLangs, lang) => {
140 | outputLangs[lang] = {
141 | label: CONFIG.DRAW_STEEL.languages[lang].label,
142 | font: languagesSetting[lang]?.font || this.languages[lang]?.font || this.defaultFont,
143 | rng: languagesSetting[lang]?.rng ?? "default",
144 | };
145 | return outputLangs;
146 | }, {});
147 | }
148 |
149 | getUserLanguages(actor) {
150 | let known_languages = new Set();
151 | let literate_languages = new Set();
152 |
153 | const actorLangs = Array.from(actor.system.biography?.languages);
154 |
155 | if (actorLangs) {
156 | known_languages = new Set(actorLangs);
157 | }
158 |
159 | return [known_languages, literate_languages];
160 | }
161 |
162 | getSystemDefaultLanguage() {
163 | return "caelian";
164 | }
165 |
166 | addToConfig(key, lang) {
167 | if (CONFIG.DRAW_STEEL.languages) {
168 | CONFIG.DRAW_STEEL.languages[key] = { label: lang };
169 | }
170 | }
171 |
172 | removeFromConfig(key) {
173 | if (CONFIG.DRAW_STEEL.languages) delete CONFIG.DRAW_STEEL.languages[key];
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/src/module/providers/pf1.js:
--------------------------------------------------------------------------------
1 | import LanguageProvider from "./templates/Base.js";
2 |
3 | export default class pf1LanguageProvider extends LanguageProvider {
4 | languages = {
5 | common: {
6 | font: "Thorass",
7 | },
8 | aboleth: {
9 | font: "Ar Ciela",
10 | },
11 | abyssal: {
12 | font: "Barazhad",
13 | },
14 | aklo: {
15 | font: "Ophidian",
16 | },
17 | algollthu: {
18 | font: "Ar Ciela",
19 | },
20 | anadi: {
21 | font: "Jungle Slang",
22 | },
23 | aquan: {
24 | font: "Olde Thorass",
25 | },
26 | arboreal: {
27 | font: "Olde Espruar",
28 | },
29 | auran: {
30 | font: "Olde Thorass",
31 | },
32 | azlanti: {
33 | font: "Tengwar",
34 | },
35 | boggard: {
36 | font: "Semphari",
37 | },
38 | caligni: {
39 | font: "High Drowic",
40 | },
41 | celestial: {
42 | font: "Celestial",
43 | },
44 | cyclops: {
45 | font: "Meroitic Demotic",
46 | },
47 | daemonic: {
48 | font: "Infernal",
49 | },
50 | dark: {
51 | font: "High Drowic",
52 | },
53 | destrachan: {
54 | font: "Ar Ciela",
55 | },
56 | draconic: {
57 | font: "Iokharic",
58 | },
59 | drowsign: {
60 | font: "Finger Alphabet",
61 | },
62 | druidic: {
63 | font: "Jungle Slang",
64 | },
65 | dwarven: {
66 | font: "Dethek",
67 | },
68 | dziriak: {
69 | font: "Pulsian",
70 | },
71 | elven: {
72 | font: "Espruar",
73 | },
74 | erutaki: {
75 | font: "Tuzluca",
76 | },
77 | garundi: {
78 | font: "Qijomi",
79 | },
80 | giant: {
81 | font: "Meroitic Demotic",
82 | },
83 | gnoll: {
84 | font: "Kargi",
85 | },
86 | gnome: {
87 | font: "Dethek",
88 | },
89 | gnomish: {
90 | font: "Dethek",
91 | },
92 | goblin: {
93 | font: "Kargi",
94 | },
95 | grippli: {
96 | font: "Semphari",
97 | },
98 | hallit: {
99 | font: "Tengwar",
100 | },
101 | ignan: {
102 | font: "Dethek",
103 | },
104 | iruxi: {
105 | font: "Semphari",
106 | },
107 | jistkan: {
108 | font: "Valmaric",
109 | },
110 | jotun: {
111 | font: "Meroitic Demotic",
112 | },
113 | jyoti: {
114 | font: "Celestial",
115 | },
116 | infernal: {
117 | font: "Infernal",
118 | },
119 | kelish: {
120 | font: "Highschool Runes",
121 | },
122 | mwangi: {
123 | font: "Tengwar",
124 | },
125 | necril: {
126 | font: "High Drowic",
127 | },
128 | orc: {
129 | font: "Dethek",
130 | },
131 | orcish: {
132 | font: "Dethek",
133 | },
134 | polyglot: {
135 | font: "Tengwar",
136 | },
137 | protean: {
138 | font: "Barazhad",
139 | },
140 | requian: {
141 | font: "Reanaarian",
142 | },
143 | shoanti: {
144 | font: "Tengwar",
145 | },
146 | skald: {
147 | font: "Valmaric",
148 | },
149 | sphinx: {
150 | font: "Reanaarian",
151 | },
152 | strix: {
153 | font: "Infernal",
154 | },
155 | sylvan: {
156 | font: "Olde Espruar",
157 | },
158 | shoony: {
159 | font: "Dethek",
160 | },
161 | taldane: {
162 | font: "Tengwar",
163 | },
164 | tengu: {
165 | font: "Oriental",
166 | },
167 | terran: {
168 | font: "Dethek",
169 | },
170 | thassilonian: {
171 | font: "Thassilonian",
172 | },
173 | tien: {
174 | font: "Oriental",
175 | },
176 | treant: {
177 | font: "Olde Espruar",
178 | },
179 | undercommon: {
180 | font: "High Drowic",
181 | },
182 | utopian: {
183 | font: "Maras Eye",
184 | },
185 | varisian: {
186 | font: "Tengwar",
187 | },
188 | vegepygmy: {
189 | font: "Kargi",
190 | },
191 | vudrani: {
192 | font: "Qijomi",
193 | },
194 | };
195 |
196 | getUserLanguages(actor) {
197 | let knownLanguages = new Set();
198 | let literateLanguages = new Set();
199 | if (actor.system?.traits?.languages) {
200 | for (let lang of actor.system.traits.languages.total) {
201 | knownLanguages.add(lang);
202 | }
203 | if (actor.system.traits.languages.customTotal) {
204 | for (let lang of actor.system.traits.languages.customTotal) {
205 | const key = lang.trim().toLowerCase();
206 | knownLanguages.add(key);
207 | }
208 | }
209 | }
210 | return [knownLanguages, literateLanguages];
211 | }
212 | }
213 |
--------------------------------------------------------------------------------
/src/module/api.js:
--------------------------------------------------------------------------------
1 | import * as providers from "./providers/_module.js";
2 | import { providerKeys } from "./providers/_shared.js";
3 | import { addSetting } from "./settings.js";
4 |
5 | export class PolyglotAPI {
6 | constructor() {
7 | this.providers = {};
8 | this.polyglot = null;
9 | }
10 |
11 | init() {
12 | // Assumes the first class in the file is the actual LanguageProvider class. This is better than adding an if-clause in the loop
13 | const supportedSystems = Object.keys(providers)
14 | .filter((provider) => provider !== "LanguageProvider")
15 | .map((provider) => provider.replace("LanguageProvider", ""))
16 | .join("|");
17 | const systemsRegex = new RegExp(`^(${supportedSystems})$`);
18 | let providerString = game.system.id;
19 | if (!systemsRegex.test(game.system.id)) {
20 | providerString = providerKeys[game.system.id] || "Generic";
21 | }
22 |
23 | const providerId = `native${providerString !== "Generic" ? `.${providerString}` : ""}`;
24 | this.providers[providerId] = new providers[`${providerString}LanguageProvider`](providerId);
25 | }
26 |
27 | get languageProvider() {
28 | return this.polyglot.languageProvider;
29 | }
30 |
31 | /**
32 | * @param {String} provider
33 | */
34 | set languageProvider(provider) {
35 | this.polyglot.languageProvider = this.providers[provider];
36 | }
37 |
38 | attach() {
39 | game.polyglot.api = this;
40 | this.polyglot = game.polyglot;
41 | }
42 |
43 | defaultProvider() {
44 | /** providerIds should always be sorted the same way so this should achieve a stable default. */
45 | const providerIds = Object.keys(this.providers);
46 | let defaultValue = providerIds[0];
47 |
48 | const module = providerIds.find((key) => key.startsWith("module."));
49 | if (module) defaultValue = module;
50 |
51 | const gameSystem = providerIds.find((key) => key.startsWith("system.") || key.includes(game.system.id));
52 | if (gameSystem) defaultValue = gameSystem;
53 |
54 | addSetting("languageProvider", {
55 | // Has no name or hint
56 | config: false,
57 | type: String,
58 | default: defaultValue,
59 | onChange: (s) => {
60 | this.languageProvider = this.providers[s];
61 | },
62 | });
63 | }
64 |
65 | updateProvider() {
66 | // If the configured provider is registered use that one. If not use the default provider
67 | const configuredProvider = game.settings.get("polyglot", "languageProvider");
68 | const fallbackProvider = game.settings.settings.get("polyglot.languageProvider").default;
69 | this.polyglot.languageProvider = this.providers[configuredProvider] || this.providers[fallbackProvider];
70 | this.polyglot.omniglot = game.settings.get("polyglot", "omniglot");
71 | this.polyglot.comprehendLanguages = game.settings.get("polyglot", "comprehendLanguages");
72 | this.polyglot.truespeech = game.settings.get("polyglot", "truespeech");
73 | }
74 |
75 | /**
76 | * @param {String} moduleId
77 | * @param {providers.LanguageProvider} languageProvider
78 | */
79 | registerModule(moduleId, languageProvider) {
80 | const module = game.modules.get(moduleId);
81 | if (!module) {
82 | console.warn(
83 | `Polyglot | A module tried to register with the id "${moduleId}". However no active module with this id was found. This api registration call was ignored. If you are the author of that module please check that the id passed to "registerModule" matches the id in your manifest exactly.`,
84 | );
85 | return;
86 | }
87 | if (moduleId === "polyglot") {
88 | console.warn(
89 | `Polyglot | A module tried to register with the id "${moduleId}", which is not allowed. This api registration call was ignored. If you're the author of the module please use the id of your own module as it's specified in your manifest to register to this api.`,
90 | );
91 | return;
92 | }
93 |
94 | this.#register(`module.${module.id}`, languageProvider);
95 | }
96 |
97 | /**
98 | * @param {providers.LanguageProvider} languageProvider
99 | */
100 | registerSystem(languageProvider) {
101 | this.#register(`system.${game.system.id}`, languageProvider);
102 | }
103 |
104 | /**
105 | * @param {String} id
106 | * @param {providers.LanguageProvider} languageProvider
107 | */
108 | #register(id, languageProvider) {
109 | const providerInstance = new languageProvider(id);
110 | this.providers[providerInstance.id] = providerInstance;
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/src/fonts/licenses/ny stormning.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016, Mew Too, Robert Jablonski (Cannot Into Space Fonts) (cannotintospacefonts@gmail.com),
2 | with Reserved Font Name Ny Stormning.
3 |
4 | This Font Software is licensed under the SIL Open Font License, Version 1.1.
5 | This license is copied below, and is also available with a FAQ at:
6 | http://scripts.sil.org/OFL
7 |
8 |
9 | -----------------------------------------------------------
10 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
11 | -----------------------------------------------------------
12 |
13 | PREAMBLE
14 | The goals of the Open Font License (OFL) are to stimulate worldwide
15 | development of collaborative font projects, to support the font creation
16 | efforts of academic and linguistic communities, and to provide a free and
17 | open framework in which fonts may be shared and improved in partnership
18 | with others.
19 |
20 | The OFL allows the licensed fonts to be used, studied, modified and
21 | redistributed freely as long as they are not sold by themselves. The
22 | fonts, including any derivative works, can be bundled, embedded,
23 | redistributed and/or sold with any software provided that any reserved
24 | names are not used by derivative works. The fonts and derivatives,
25 | however, cannot be released under any other type of license. The
26 | requirement for fonts to remain under this license does not apply
27 | to any document created using the fonts or their derivatives.
28 |
29 | DEFINITIONS
30 | "Font Software" refers to the set of files released by the Copyright
31 | Holder(s) under this license and clearly marked as such. This may
32 | include source files, build scripts and documentation.
33 |
34 | "Reserved Font Name" refers to any names specified as such after the
35 | copyright statement(s).
36 |
37 | "Original Version" refers to the collection of Font Software components as
38 | distributed by the Copyright Holder(s).
39 |
40 | "Modified Version" refers to any derivative made by adding to, deleting,
41 | or substituting -- in part or in whole -- any of the components of the
42 | Original Version, by changing formats or by porting the Font Software to a
43 | new environment.
44 |
45 | "Author" refers to any designer, engineer, programmer, technical
46 | writer or other person who contributed to the Font Software.
47 |
48 | PERMISSION & CONDITIONS
49 | Permission is hereby granted, free of charge, to any person obtaining
50 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
51 | redistribute, and sell modified and unmodified copies of the Font
52 | Software, subject to the following conditions:
53 |
54 | 1) Neither the Font Software nor any of its individual components,
55 | in Original or Modified Versions, may be sold by itself.
56 |
57 | 2) Original or Modified Versions of the Font Software may be bundled,
58 | redistributed and/or sold with any software, provided that each copy
59 | contains the above copyright notice and this license. These can be
60 | included either as stand-alone text files, human-readable headers or
61 | in the appropriate machine-readable metadata fields within text or
62 | binary files as long as those fields can be easily viewed by the user.
63 |
64 | 3) No Modified Version of the Font Software may use the Reserved Font
65 | Name(s) unless explicit written permission is granted by the corresponding
66 | Copyright Holder. This restriction only applies to the primary font name as
67 | presented to the users.
68 |
69 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
70 | Software shall not be used to promote, endorse or advertise any
71 | Modified Version, except to acknowledge the contribution(s) of the
72 | Copyright Holder(s) and the Author(s) or with their explicit written
73 | permission.
74 |
75 | 5) The Font Software, modified or unmodified, in part or in whole,
76 | must be distributed entirely under this license, and must not be
77 | distributed under any other license. The requirement for fonts to
78 | remain under this license does not apply to any document created
79 | using the Font Software.
80 |
81 | TERMINATION
82 | This license becomes null and void if any of the above conditions are
83 | not met.
84 |
85 | DISCLAIMER
86 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
87 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
88 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
89 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
90 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
91 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
92 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
93 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
94 | OTHER DEALINGS IN THE FONT SOFTWARE.
95 |
--------------------------------------------------------------------------------
/src/lang/sv.json:
--------------------------------------------------------------------------------
1 | {
2 | "POLYGLOT": {
3 | "Languages.hint": "Ändrar alfabetet som används för språken. Återställning till standardinställningarna laddar om.",
4 | "enableAllFonts": {
5 | "choices": {
6 | "0": "Ingen",
7 | "1": "Polyglot's Teckensnitt",
8 | "2": "Foundry's Extrafonter",
9 | "3": "Bägge"
10 | },
11 | "title": "Lägg till teckensnitt i teckensnitts- och språkinställningarna",
12 | "hint": "Lägg till teckensnitt i teckensnitts- och språkinställningarna."
13 | },
14 | "LanguageProvider": {
15 | "choices": {
16 | "module": "[Modul] {name}",
17 | "native": "Generisk",
18 | "system": "[System] {name}"
19 | },
20 | "name": "Provider av språkinställningar",
21 | "hint": "Välj vem som tillhandahåller språkinformation för alfabet och språk. Fler språkleverantörer kan göras tillgängliga via spelsystem och installerade moduler. Alternativen nedan beror på vilken språkleverantör som väljs här. ⚠️ Om du byter leverantör har du för att spara och öppna dessa inställningar igen."
22 | },
23 | "UESRPG.Language": "Språk",
24 | "COC7": {
25 | "LanguageOwn": "Språk",
26 | "LanguageAny": "Språk",
27 | "LanguageOther": "Språk",
28 | "LanguageSpec": "Språk"
29 | },
30 | "DND5E": {
31 | "SpecialLanguages.title": "Ersätt specialspråk",
32 | "SpecialLanguages.hint": "Namnet på språket som kommer att ersätta \"språk\" som \"alla språk det kunde i livet\"."
33 | },
34 | "SWADE": {
35 | "LanguageSkills": "Språk"
36 | },
37 | "WFRP4E": {
38 | "LanguageSkills": "Språk"
39 | },
40 | "Runes": "Runor",
41 | "Generic": {
42 | "Language": "Språk"
43 | },
44 | "DefaultAlphabet": "Standardalfabet",
45 | "FontSettings": "Teckensnittsinställningar",
46 | "LanguageSettings": "Språkinställningar",
47 | "ChatSettings": "Chatinställningar",
48 | "Languages.title": "Språk",
49 | "Font": "Teckensnitt",
50 | "Fonts": "Teckensnitt",
51 | "FontSize": "Teckenstorlek (%)",
52 | "CustomLanguages.title": "Anpassade språk",
53 | "CustomLanguages.hint": "Definiera en lista över anpassade, kommaseparerade språk att lägga till i systemet.",
54 | "ComprehendLanguages.title": "Magiformeln Förstå Språk",
55 | "ComprehendLanguages.hint": "Sätt ett språk vars talare förstår alla andra språk, men som inte kan talas eller skrivas.",
56 | "Truespeech.title": "Tala i tungor",
57 | "Truespeech.hint": "Sätt ett språk vars talare förstår alla talade språk (kan inte läsa jJurnaler) och som förstås av alla varelser.",
58 | "JournalHighlight.title": "Journalmarkering Opacitet (%)",
59 | "JournalHighlight.hint": "Definierar opaciteten för markeringen över teckensnitt på journalen.",
60 | "logographicalFontToggle.title": "Logografiska teckensnitt",
61 | "logographicalFontToggle.hint": "Halverar storleken på fraser med hjälp av logografiska teckensnitt (t.ex. japanska, kinesiska tecken).",
62 | "DefaultLanguage.title": "Standardspråk",
63 | "DefaultLanguage.hint": "Namnet på standardspråket att välja. Lämna tomt för att använda systemets standard.",
64 | "ReplaceLanguages.title": "Ersätt systemets språk",
65 | "ReplaceLanguages.hint": "Ersätter systemets standardspråk med dina anpassade språk. Det första språket på listan blir det nya standardspråket.",
66 | "ScrambleGM.title": "Förvräng meddelanden för SL",
67 | "ScrambleGM.hint": "Översätt inte texten för SL (se globens färg för att se vad spelfigur förstår). Kräver omladdning.",
68 | "RandomizeRunes.title": "Randomisera runor",
69 | "RandomizeRunes.hint": "Detta avgör vilken typ av slumpgenerator som används för att generera en fras. ⚠️ Alternativet \"Ingen\" stöder endast alfanumeriska tecken (inga accenter).",
70 | "RandomizeRunesOptions": {
71 | "a": "Standard",
72 | "b": "Unika fraser",
73 | "c": "Inga ⚠️"
74 | },
75 | "ExportFonts.title": "Lägg till Polyglots teckensnitt till Foundry",
76 | "ExportFonts.hint": "Lägg till Polyglots teckensnitt till Foundry meny för ytterligare teckensnitt.",
77 | "DisplayTranslated.title": "Visa översättningar",
78 | "DisplayTranslated.hint": "För språk som är översatta i chattfönstret, visa originaltexten och en översättning nedan.",
79 | "HideTranslation.title": "Dölj indikatorer från spelare",
80 | "AllowOOC.title": "Förvräng OOC Chat Messages",
81 | "AllowOOC.hint": "Välj vems användare som ska få sina meddelanden förvrängda. OOC = Utan karaktär.",
82 | "AllowOOCOptions": {
83 | "a": "Alla",
84 | "b": "Endast GM",
85 | "c": "Endast spelare",
86 | "d": "Ingen"
87 | },
88 | "LanguageRegex": {
89 | "title": "Språkregex",
90 | "hint": "Du kan använda detta för att ändra termen som söks på objekt från \"Språk\" till något annat, som \"Tungomål\". Den här inställningen är mer användbar för icke-engelsktalande."
91 | },
92 | "Translation": "Översättning",
93 | "TranslatedFrom": "Översatt från ",
94 | "LanguageLabel": "Språk",
95 | "LatinAlphabet": "Latinska alfabetet",
96 | "ToggleRunes": "Växla runor",
97 | "HideTranslation.hint": "Döljer globen och texten \"Översatt från\" i chattmeddelanden till spelare. Perfekt för när du inte vill visa spelare vilket språk du talar. Kräver omladdning.",
98 | "AlphabetLabel": "Alfabet"
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/lang/it.json:
--------------------------------------------------------------------------------
1 | {
2 | "POLYGLOT": {
3 | "LanguageSettings": "Impostazioni lingua",
4 | "ChatSettings": "Impostazioni chat",
5 | "Languages.title": "Lingue",
6 | "FontSize": "Dimensione dei caratteri (%)",
7 | "CustomLanguages.title": "Lingue personalizzate",
8 | "CustomLanguages.hint": "Definisci una lista di lingue personalizzate, separate da virgole, da aggiungere al sistema.",
9 | "ComprehendLanguages.title": "Incantesimo Comprensione dei Linguaggi",
10 | "source": {
11 | "data": "Dati",
12 | "s3": "S3",
13 | "forgevtt": "Forge"
14 | },
15 | "Truespeech.title": "Incantesimo Lingue",
16 | "Truespeech.hint": "Determina una lingua che fa capire a chi la conosce tutte le lingue parlate (non fa leggere i Diari) e che può essere capita da tutte le creature.",
17 | "JournalHighlight.title": "Opacità dell'evidenziatore nei Diari (%)",
18 | "DefaultLanguage.title": "Lingua predefinita",
19 | "DefaultLanguage.hint": "Nome del linguaggio predefinito da selezionare. Se vuoto, usa il predefinito di sistema.",
20 | "ReplaceLanguages.title": "Sostituisci le lingue di sistema",
21 | "ScrambleGM.title": "Rimescola i messaggi per il GM",
22 | "ScrambleGM.hint": "Non tradurre i testi per il GM (fai riferimento al colore del mappamondo per capire se il token comprende). Richiede il ricaricamento.",
23 | "enableAllFonts": {
24 | "hint": "Aggiungi i font alle impostazioni di font e lingua.",
25 | "choices": {
26 | "0": "Nessuno",
27 | "2": "Font aggiuntivi di base",
28 | "3": "Entrambi",
29 | "1": "Font di Polyglot"
30 | },
31 | "title": "Aggiungi font alle impostazioni di font e lingua"
32 | },
33 | "logographicalFontToggle.hint": "Dimezza la dimensione di frasi che usano font logografici (esempio: giapponese, cinese).",
34 | "logographicalFontToggle.title": "Font logografici",
35 | "directory": {
36 | ".hint": "Indica una cartella al di fuori della cartella \"modules\" che contiene i file dei font.",
37 | "name": "Cartella dei font personalizzati"
38 | },
39 | "Fonts": "Font",
40 | "Font": "Font",
41 | "FontSettings": "Impostazioni font",
42 | "RandomizeRunes.title": "Randomizza le rune",
43 | "RandomizeRunesOptions": {
44 | "a": "Default",
45 | "b": "Frasi uniche",
46 | "c": "Nessuno ⚠️"
47 | },
48 | "ExportFonts.title": "Aggiungi i font di Polyglot a quelli base",
49 | "ExportFonts.hint": "Aggiungi i font di Polyglot al menù di Font Addizionali.",
50 | "DisplayTranslated.title": "Mostra traduzioni",
51 | "HideTranslation.title": "Nascondi indicatori ai Giocatori",
52 | "HideTranslation.hint": "Nasconde il Mappamondo e il testo \"Tradotto da\" nei messaggi in chat ai giocatori. Perfetto per quando vuoi nascondere loro che lingua stai parlando.",
53 | "AllowOOC.title": "Rimescola i messaggi OOC in chat",
54 | "AllowOOC.hint": "Scegli che utenti hanno i messaggi rimescolati. OOC = Fuori personaggio (Out of Character).",
55 | "AllowOOCOptions": {
56 | "a": "Tutti",
57 | "b": "Solo GM",
58 | "c": "Solo Giocatori",
59 | "d": "Nessuno"
60 | },
61 | "LanguageProvider": {
62 | "name": "Fonte delle impostazioni delle lingue",
63 | "choices": {
64 | "module": "[Modulo] {name}",
65 | "native": "Generico",
66 | "system": "[Sistema] {name}"
67 | },
68 | "hint": "Seleziona la fonte delle informazioni per gli alfabeti e le lingue. Altre fonti possono essere rese disponibili tramite sistemi e moduli installati. Le opzioni sottostanti dipendono dalla fonte stabilita qui. ⚠️ Se cambi la fonte, devi salvare e riaprire queste impostazioni."
69 | },
70 | "LanguageRegex": {
71 | "title": "RegEx lingua",
72 | "hint": "Puoi usare questa impostazione per cambiare il termine cercato tra gli oggetti da \"Lingua\" a qualcos'altro, come \"Linguaggio\"."
73 | },
74 | "Translation": "Traduzione",
75 | "DefaultAlphabet": "Alfabeto predefinito",
76 | "Languages.hint": "Cambia l'alfabeto usato per le lingue. Ripristinare le impostazioni predefinite ricaricherà la pagina.",
77 | "ComprehendLanguages.hint": "Determina una lingua che fa comprendere a chi la conosce tutte le altre lingue, ma che non può essere parlata o scritta.",
78 | "JournalHighlight.hint": "Definisci l'opacità dell'evidenziamento in un Dario.",
79 | "ReplaceLanguages.hint": "Sostituisce le lingue predefinite del sistema con le tue lingue personalizzate. La prima della lista diventerà la nuova lingua predefinita.",
80 | "RandomizeRunes.hint": "Questo determina che tipo di RNG viene usato per generare una frase. ⚠️ L'opzione \"Nessuno\" supporta solo caratteri alfanumerici (no accenti).",
81 | "DisplayTranslated.hint": "Per le lingue che sono tradotte nella chat, mostra il testo originale con la traduzione sotto.",
82 | "Generic": {
83 | "Language": "Lingua"
84 | },
85 | "UESRPG.Language": "Lingua",
86 | "Runes": "Rune",
87 | "ToggleRunes": "Attiva / disattiva rune",
88 | "LatinAlphabet": "Alfabeto latino",
89 | "AlphabetLabel": "Alfabeto",
90 | "LanguageLabel": "Lingua",
91 | "TranslatedFrom": "Tradotto dal ",
92 | "SWADE": {
93 | "LanguageSkills": "Lingua"
94 | },
95 | "DND5E": {
96 | "SpecialLanguages.hint": "Nome della lingua che rimpiazzerà \"lingue\" come \"tutte le lingue conosciute in vita\".",
97 | "SpecialLanguages.title": "Sostituisci lingue speciali"
98 | },
99 | "COC7": {
100 | "LanguageSpec": "Lingua",
101 | "LanguageOther": "Lingua",
102 | "LanguageAny": "Lingua",
103 | "LanguageOwn": "Lingua"
104 | },
105 | "WFRP4E": {
106 | "LanguageSkills": "Lingua"
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/src/module/tour.js:
--------------------------------------------------------------------------------
1 |
2 | class PolyglotTour extends foundry.nue.Tour {
3 | async _preStep() {
4 | await super._preStep();
5 |
6 | if (this.currentStep.actions) await this.performActions(this.currentStep.actions);
7 |
8 | // If there's tab info, switch to that tab
9 | if (this.currentStep.tab) await this.switchTab(this.currentStep.tab);
10 | }
11 |
12 | async performActions(actions) {
13 | for (const action of actions) {
14 | switch (action) {
15 | case "chat-message": {
16 | await ChatMessage.create({ content: "Polyglot Test Message", flags: { polyglot: { language: "test" } } });
17 | break;
18 | }
19 | case "user-config": {
20 | await game.user.sheet.render(true);
21 | break;
22 | }
23 | case "end": {
24 | this.configurator?.close();
25 | game.user.sheet.close();
26 | break;
27 | }
28 | }
29 | }
30 | }
31 |
32 | async switchTab(tab) {
33 | switch (tab.parent) {
34 | case "sidebar":
35 | ui.sidebar.activateTab(tab.id);
36 | break;
37 | case "settings": {
38 | const app = game.settings.sheet;
39 | await app._render(true);
40 | app.activateTab(tab.id);
41 | break;
42 | }
43 | case "general": {
44 | if (!this.configurator) {
45 | const configurator = game.settings.menus.get("polyglot.GeneralSettings");
46 | this.configurator = new configurator.type();
47 | }
48 | await this.configurator._render(true);
49 | this.configurator.activateTab(tab.id);
50 | break;
51 | }
52 | }
53 | }
54 | }
55 |
56 | export function registerTours() {
57 | game.tours.register("polyglot", "test", new PolyglotTour(
58 | {
59 | title: "POLYGLOT.TOURS.Main.title",
60 | description: "POLYGLOT.TOURS.Main.desc",
61 | restricted: true,
62 | display: game.settings.get("polyglot", "enableChatFeatures"),
63 | canBeResumed: true,
64 | steps: [
65 | {
66 | id: "canvas",
67 | title: "POLYGLOT.TOURS.Main.Canvas.Title",
68 | content: "POLYGLOT.TOURS.Main.Canvas.Content",
69 | tab: { parent: "sidebar", id: "chat" }
70 | },
71 | {
72 | id: "language-selector",
73 | selector: ".polyglot-lang-select",
74 | title: "POLYGLOT.TOURS.Main.LanguageSelector.Title",
75 | content: "POLYGLOT.TOURS.Main.LanguageSelector.Content"
76 | },
77 | {
78 | id: "language-selector-dropdown",
79 | selector: ".polyglot-lang-select .ts-wrapper",
80 | title: "POLYGLOT.TOURS.Main.LanguageSelectorSelect.Title",
81 | content: "POLYGLOT.TOURS.Main.LanguageSelectorSelect.Content"
82 | },
83 | {
84 | id: "language-selector-dropdown",
85 | selector: ".polyglot-lang-select .ts-wrapper",
86 | title: "POLYGLOT.TOURS.Main.LanguageSelectorSelect2.Title",
87 | content: "POLYGLOT.TOURS.Main.LanguageSelectorSelect2.Content"
88 | },
89 | {
90 | id: "language-selector-pips",
91 | selector: ".polyglot-lang-select .ts-wrapper",
92 | title: "POLYGLOT.TOURS.Main.LanguageSelectorPips.Title",
93 | content: "POLYGLOT.TOURS.Main.LanguageSelectorPips.Content",
94 | actions: ["chat-message"]
95 | },
96 | {
97 | id: "chat-message",
98 | selector: ".chat-log .chat-message:last-of-type",
99 | title: "POLYGLOT.TOURS.Main.ChatMessage.Title",
100 | content: "POLYGLOT.TOURS.Main.ChatMessage.Content",
101 | },
102 | {
103 | id: "chat-message-scrambled",
104 | selector: ".chat-log .chat-message:last-of-type .polyglot-original-text",
105 | title: "POLYGLOT.TOURS.Main.ChatMessageScrambled.Title",
106 | content: "POLYGLOT.TOURS.Main.ChatMessageScrambled.Content",
107 | },
108 | {
109 | id: "chat-message-translation",
110 | selector: ".chat-log .chat-message:last-of-type .polyglot-translation-text",
111 | title: "POLYGLOT.TOURS.Main.ChatMessageTranslation.Title",
112 | content: "POLYGLOT.TOURS.Main.ChatMessageTranslation.Content",
113 | },
114 | {
115 | id: "chat-message-globe",
116 | selector: ".chat-log .chat-message:last-of-type .polyglot-message-language",
117 | title: "POLYGLOT.TOURS.Main.ChatMessageGlobe.Title",
118 | content: "POLYGLOT.TOURS.Main.ChatMessageGlobe.Content",
119 | },
120 | {
121 | id: "chat-message-ending",
122 | selector: ".chat-log .chat-message:last-of-type",
123 | title: "POLYGLOT.TOURS.Main.ChatMessageEnding.Title",
124 | content: "POLYGLOT.TOURS.Main.ChatMessageEnding.Content",
125 | },
126 | {
127 | id: "players-list",
128 | selector: "#ui-left aside#players #players-active",
129 | title: "POLYGLOT.TOURS.Main.PlayersList.Title",
130 | content: "POLYGLOT.TOURS.Main.PlayersList.Content"
131 | },
132 | {
133 | id: "user-config",
134 | selector: ".application.user-config",
135 | title: "POLYGLOT.TOURS.Main.UserConfig.Title",
136 | content: "POLYGLOT.TOURS.Main.UserConfig.Content",
137 | actions: ["user-config"]
138 | },
139 | {
140 | id: "user-config-select-character",
141 | selector: ".application.user-config fieldset:has(.form-group.character)",
142 | title: "POLYGLOT.TOURS.Main.UserConfigSelectCharacter.Title",
143 | content: "POLYGLOT.TOURS.Main.UserConfigSelectCharacter.Content",
144 | actions: ["user-config"]
145 | },
146 | {
147 | id: "actor-ownership",
148 | selector: "#sidebar #actors",
149 | title: "POLYGLOT.TOURS.Main.ActorOwnership.Title",
150 | content: "POLYGLOT.TOURS.Main.ActorOwnership.Content",
151 | tab: { parent: "sidebar", id: "actors" }
152 | },
153 | {
154 | id: "end",
155 | title: "POLYGLOT.TOURS.Main.End.Title",
156 | content: "POLYGLOT.TOURS.Main.End.Content",
157 | actions: ["end"]
158 | }
159 | ]
160 | }
161 | ));
162 | }
163 |
--------------------------------------------------------------------------------
/src/module/forms/FontSettings.js:
--------------------------------------------------------------------------------
1 | const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
2 |
3 | export class PolyglotFontSettings extends HandlebarsApplicationMixin(ApplicationV2) {
4 | static get classes() {
5 | const classes = ["sheet", "polyglot", "polyglot-font-settings"];
6 | if (game.system?.id === "wfrp4e") {
7 | classes.push(game.system.id);
8 | }
9 | return classes;
10 | }
11 |
12 | static DEFAULT_OPTIONS = {
13 | id: "polyglot-font-form",
14 | classes: this.classes,
15 | actions: {
16 | reset: PolyglotFontSettings.reset
17 | },
18 | form: {
19 | handler: PolyglotFontSettings.#onSubmit,
20 | closeOnSubmit: true,
21 | },
22 | position: {
23 | width: 780,
24 | height: 680,
25 | },
26 | tag: "form",
27 | window: {
28 | icon: "fas fa-font",
29 | title: "Font Settings",
30 | contentClasses: ["standard-form"],
31 | resizable: true,
32 | }
33 | };
34 |
35 | get title() {
36 | return `Polyglot: ${game.i18n.localize(this.options.window.title)}`;
37 | }
38 |
39 | static PARTS = {
40 | form: {
41 | template: "./modules/polyglot/templates/FontSettings.hbs"
42 | },
43 | footer: {
44 | template: "templates/generic/form-footer.hbs",
45 | },
46 | };
47 |
48 | _prepareContext() {
49 | const fonts = game.settings.get("polyglot", "Alphabets");
50 | this.fonts = {};
51 |
52 | for (let key in fonts) {
53 | this.fonts[key] = {
54 | label: key,
55 | family: fonts[key].fontFamily,
56 | size: game.polyglot.CustomFontSizes[key] || "100",
57 | alphabeticOnly: fonts[key]?.alphabeticOnly || false,
58 | logographical: fonts[key]?.logographical || false,
59 | };
60 | }
61 |
62 | return {
63 | fonts: this.fonts,
64 | fields: game.settings.settings.get("polyglot.Alphabets").type.element.fields,
65 | buttons: [
66 | { type: "submit", icon: "fa-solid fa-save", label: "SETTINGS.Save" },
67 | { type: "reset", action: "reset", icon: "fa-solid fa-undo", label: "SETTINGS.Reset" },
68 | ]
69 | };
70 | }
71 |
72 | _onRender(context, options) {
73 | super._onRender(context, options);
74 |
75 | const changeFontSize = async (event) => {
76 | event.preventDefault();
77 | if (!event.target.hasFocus) return;
78 | let size = event.target.value;
79 | if (event.type !== "change") {
80 | const multiplier = event.deltaY / Math.abs(event.deltaY); // 1 or -1
81 | const step = Number(event.target.step) || 10;
82 | size = Math.floor(size - (multiplier * step));
83 | }
84 | if (size < 50) return;
85 | event.target.value = size;
86 | const parent = event.target.parentElement;
87 | const font = parent.previousElementSibling.textContent;
88 | parent.nextElementSibling.nextElementSibling.nextElementSibling.style.fontSize = `${size}%`;
89 | this.fonts[font].size = size;
90 | };
91 | const changeFontAlphabetic = async (event) => {
92 | const parent = event.target.parentElement;
93 | const font = parent.previousElementSibling.previousElementSibling.textContent;
94 | this.fonts[font].alphabeticOnly = event.target.checked;
95 | };
96 | const changeFontLogographical = async (event) => {
97 | const parent = event.target.parentElement;
98 | const font = parent.previousElementSibling.previousElementSibling.previousElementSibling.textContent;
99 | this.fonts[font].logographical = event.target.checked;
100 | };
101 |
102 | this.element.querySelectorAll(".alphabeticOnly").forEach((el) => el.addEventListener("change", changeFontAlphabetic));
103 | this.element.querySelectorAll(".logographical").forEach((el) => el.addEventListener("change", changeFontLogographical));
104 |
105 | this.element.querySelectorAll(".selectatr").forEach((el) => el.addEventListener("focus", (event) => {
106 | event.target.hasFocus = true;
107 | }));
108 | this.element.querySelectorAll(".selectatr").forEach((el) => el.addEventListener("blur", (event) => {
109 | event.target.hasFocus = false;
110 | }));
111 | this.element.querySelectorAll(".selectatr").forEach((el) => el.addEventListener("change", changeFontSize));
112 | this.element.querySelectorAll(".selectatr").forEach((el) => el.addEventListener("wheel", changeFontSize));
113 | }
114 |
115 | static async reset() {
116 | const defaultAlphabets = new game.polyglot.languageProvider.constructor().fonts;
117 | game.polyglot.languageProvider.fonts = defaultAlphabets;
118 | await game.settings.set("polyglot", "Alphabets", game.polyglot.languageProvider.fonts);
119 | const defaultCustomFontSizes = game.settings.settings.get("polyglot.CustomFontSizes").default;
120 | await game.settings.set("polyglot", "CustomFontSizes", defaultCustomFontSizes);
121 | this.close();
122 | SettingsConfig.reloadConfirm({ world: true });
123 | }
124 |
125 | static async #onSubmit() {
126 | const customFontSizes = {};
127 | for (const [key, font] of Object.entries(this.fonts)) {
128 | customFontSizes[key] = font.size;
129 | game.polyglot.languageProvider.fonts[key].alphabeticOnly = font.alphabeticOnly;
130 | game.polyglot.languageProvider.fonts[key].logographical = font.logographical;
131 | }
132 | let current = game.settings.get("polyglot", "Alphabets");
133 | await game.settings.set("polyglot", "Alphabets", game.polyglot.languageProvider.fonts);
134 | current = game.settings.get("polyglot", "CustomFontSizes");
135 | game.polyglot.CustomFontSizes = customFontSizes;
136 | await game.settings.set("polyglot", "CustomFontSizes", game.polyglot.CustomFontSizes);
137 | const changes = !foundry.utils.isEmpty(foundry.utils.diffObject(current, game.polyglot.languageProvider.fonts))
138 | || !foundry.utils.isEmpty(foundry.utils.diffObject(current, customFontSizes));
139 | if (changes) SettingsConfig.reloadConfirm({ world: true });
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/gulpfile.mjs:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: 2022 Johannes Loher
2 | // SPDX-FileCopyrightText: 2022 David Archibald
3 | //
4 | // SPDX-License-Identifier: MIT
5 |
6 | import fs from "fs-extra";
7 | import gulp from "gulp";
8 | import prefix from "gulp-autoprefixer";
9 | import sass from "gulp-dart-sass";
10 | import sourcemaps from "gulp-sourcemaps";
11 | import path from "node:path";
12 | import buffer from "vinyl-buffer";
13 | import source from "vinyl-source-stream";
14 | import yargs from "yargs";
15 | import { hideBin } from "yargs/helpers";
16 |
17 | import rollupStream from "@rollup/stream";
18 |
19 | import rollupConfig from "./rollup.config.mjs";
20 |
21 | /********************/
22 | /* CONFIGURATION */
23 | /********************/
24 |
25 | const packageId = "polyglot";
26 | const sourceDirectory = "./src";
27 | const distDirectory = "./dist";
28 | const stylesDirectory = `${sourceDirectory}/styles`;
29 | const stylesExtension = "scss";
30 | const sourceFileExtension = "js";
31 | const staticFiles = ["assets", "fonts", "lang", "lib", "packs", "styles/fonts.css", "templates", "module.json"];
32 |
33 | /********************/
34 | /* BUILD */
35 | /********************/
36 |
37 | let cache;
38 |
39 | /**
40 | * Build the distributable JavaScript code
41 | */
42 | function buildCode() {
43 | return rollupStream({ ...rollupConfig(), cache })
44 | .on("bundle", (bundle) => {
45 | cache = bundle;
46 | })
47 | .pipe(source(`${packageId}.js`))
48 | .pipe(buffer())
49 | .pipe(sourcemaps.init({ loadMaps: true }))
50 | .pipe(sourcemaps.write("."))
51 | .pipe(gulp.dest(`${distDirectory}/module`));
52 | }
53 |
54 | /**
55 | * Build style sheets
56 | */
57 | function buildStyles() {
58 | return gulp.src([`${stylesDirectory}/**/*.${stylesExtension}`], { base: `${stylesDirectory}/` })
59 | .pipe(sourcemaps.init({ loadMaps: true }))
60 | .pipe(sass({ outputStyle: "compressed" }).on("error", sass.logError))
61 | .pipe(prefix({ cascade: false }))
62 | .pipe(sourcemaps.write("."))
63 | .pipe(gulp.dest(`${distDirectory}/styles`));
64 | }
65 |
66 | /**
67 | * Copy static files
68 | */
69 | async function copyFiles() {
70 | for (const file of staticFiles) {
71 | if (fs.existsSync(`${sourceDirectory}/${file}`)) {
72 | await fs.copy(`${sourceDirectory}/${file}`, `${distDirectory}/${file}`);
73 | }
74 | }
75 | }
76 |
77 | function tomSelect() {
78 | return gulp.src([
79 | "node_modules/tom-select/dist/js/tom-select.complete.min.js",
80 | "node_modules/tom-select/dist/js/tom-select.complete.min.js.map",
81 | "node_modules/tom-select/dist/css/tom-select.min.css",
82 | "node_modules/tom-select/dist/css/tom-select.min.css.map",
83 | ]).pipe(gulp.dest("dist/lib/tom-select"));;
84 | }
85 |
86 | /**
87 | * Watch for changes for each build step
88 | */
89 | export function watch() {
90 | tomSelect();
91 | gulp.watch(`${sourceDirectory}/**/*.${sourceFileExtension}`, { ignoreInitial: false }, buildCode);
92 | gulp.watch(`${stylesDirectory}/**/*.${stylesExtension}`, { ignoreInitial: false }, buildStyles);
93 | gulp.watch(
94 | staticFiles.map((file) => `${sourceDirectory}/${file}`),
95 | { ignoreInitial: false },
96 | copyFiles,
97 | );
98 | }
99 |
100 | export const build = gulp.series(clean, gulp.parallel(buildCode, buildStyles, tomSelect, copyFiles));
101 |
102 | /********************/
103 | /* CLEAN */
104 | /********************/
105 |
106 | /**
107 | * Remove built files from `dist` folder while ignoring source files
108 | */
109 | export async function clean() {
110 | const files = [...staticFiles, "styles", "module"];
111 |
112 | console.log(" ", "Files to clean:");
113 | console.log(" ", files.join("\n "));
114 |
115 | for (const filePath of files) {
116 | await fs.remove(`${distDirectory}/${filePath}`);
117 | }
118 | }
119 |
120 | /********************/
121 | /* LINK */
122 | /********************/
123 |
124 | /**
125 | * Get the data paths of Foundry VTT based on what is configured in `foundryconfig.json`
126 | */
127 | function getDataPaths() {
128 | const config = fs.readJSONSync("foundryconfig.json");
129 | const dataPath = config?.dataPath;
130 |
131 | if (dataPath) {
132 | const dataPaths = Array.isArray(dataPath) ? dataPath : [dataPath];
133 |
134 | return dataPaths.map((dataPath) => {
135 | if (typeof dataPath !== "string") {
136 | throw new Error(`Property dataPath in foundryconfig.json is expected to be a string or an array of strings, but found ${dataPath}`);
137 | }
138 | if (!fs.existsSync(path.resolve(dataPath))) {
139 | throw new Error(`The dataPath ${dataPath} does not exist on the file system`);
140 | }
141 | return path.resolve(dataPath);
142 | });
143 | } else {
144 | throw new Error("No dataPath defined in foundryconfig.json");
145 | }
146 | }
147 |
148 | /**
149 | * Link build to User Data folder
150 | */
151 | export async function link() {
152 | let destinationDirectory;
153 | if (fs.existsSync(path.resolve(sourceDirectory, "module.json"))) {
154 | destinationDirectory = "modules";
155 | } else {
156 | throw new Error("Could not find module.json");
157 | }
158 |
159 | const linkDirectories = getDataPaths().map((dataPath) => path.resolve(dataPath, "Data", destinationDirectory, packageId));
160 |
161 | const argv = yargs(hideBin(process.argv)).option("clean", {
162 | alias: "c",
163 | type: "boolean",
164 | default: false,
165 | }).argv;
166 | const clean = argv.c;
167 |
168 | for (const linkDirectory of linkDirectories) {
169 | if (clean) {
170 | console.log(`Removing build in ${linkDirectory}.`);
171 |
172 | await fs.remove(linkDirectory);
173 | } else if (!fs.existsSync(linkDirectory)) {
174 | console.log(`Linking dist to ${linkDirectory}.`);
175 | await fs.ensureDir(path.resolve(linkDirectory, ".."));
176 | await fs.symlink(path.resolve(distDirectory), linkDirectory);
177 | } else {
178 | console.log(`Skipped linking to ${linkDirectory}, as it already exists.`);
179 | }
180 | }
181 | }
182 |
--------------------------------------------------------------------------------
/src/module/providers/cyberpunk-red-core.js:
--------------------------------------------------------------------------------
1 | import LanguageProvider from "./templates/Base.js";
2 |
3 | export default class cyberpunkRedLanguageProvider extends LanguageProvider {
4 | defaultFont = "Olde English";
5 |
6 | languages = {
7 | streetslang: {
8 | font: "Olde English",
9 | },
10 | arabic: {
11 | font: "Ar Ciela",
12 | },
13 | bengali: {
14 | font: "Olde English",
15 | },
16 | berber: {
17 | font: "Olde English",
18 | },
19 | burmese: {
20 | font: "Ar Ciela",
21 | },
22 | cantonese: {
23 | font: "Oriental",
24 | },
25 | chinese: {
26 | font: "Oriental",
27 | },
28 | cree: {
29 | font: "Olde English",
30 | },
31 | creole: {
32 | font: "Olde English",
33 | },
34 | dari: {
35 | font: "Olde English",
36 | },
37 | dutch: {
38 | font: "Olde English",
39 | },
40 | english: {
41 | font: "Olde English",
42 | },
43 | farsi: {
44 | font: "Ar Ciela",
45 | },
46 | filipino: {
47 | font: "Ar Ciela",
48 | },
49 | finnish: {
50 | font: "Kremlin Premier",
51 | },
52 | french: {
53 | font: "Olde English",
54 | },
55 | german: {
56 | font: "Miroslav Normal",
57 | },
58 | guarani: {
59 | font: "Olde English",
60 | },
61 | hausa: {
62 | font: "Olde English",
63 | },
64 | hawaiian: {
65 | font: "Olde English",
66 | },
67 | hebrew: {
68 | font: "Olde English",
69 | },
70 | hindi: {
71 | font: "Ar Ciela",
72 | },
73 | indonesian: {
74 | font: "Ar Ciela",
75 | },
76 | italian: {
77 | font: "Olde English",
78 | },
79 | japanese: {
80 | font: "Oriental",
81 | },
82 | khmer: {
83 | font: "Ar Ciela",
84 | },
85 | korean: {
86 | font: "Oriental",
87 | },
88 | lingala: {
89 | font: "Olde English",
90 | },
91 | malayan: {
92 | font: "Ar Ciela",
93 | },
94 | mandarin: {
95 | font: "Oriental",
96 | },
97 | maori: {
98 | font: "Olde English",
99 | },
100 | mayan: {
101 | font: "Olde English",
102 | },
103 | mongolian: {
104 | font: "Ar Ciela",
105 | },
106 | navajo: {
107 | font: "Olde English",
108 | },
109 | nepali: {
110 | font: "Ar Ciela",
111 | },
112 | norwegian: {
113 | font: "Miroslav Normal",
114 | },
115 | oromo: {
116 | font: "Olde English",
117 | },
118 | pamanyungan: {
119 | font: "Olde English",
120 | },
121 | polish: {
122 | font: "Kremlin Premier",
123 | },
124 | portuguese: {
125 | font: "Olde English",
126 | },
127 | quechua: {
128 | font: "Olde English",
129 | },
130 | romanian: {
131 | font: "Kremlin Premier",
132 | },
133 | russian: {
134 | font: "Kremlin Premier",
135 | },
136 | sinhalese: {
137 | font: "Olde English",
138 | },
139 | spanish: {
140 | font: "Olde English",
141 | },
142 | swahili: {
143 | font: "Olde English",
144 | },
145 | tahitian: {
146 | font: "Olde English",
147 | },
148 | tamil: {
149 | font: "Olde English",
150 | },
151 | turkish: {
152 | font: "Ar Ciela",
153 | },
154 | twi: {
155 | font: "Olde English",
156 | },
157 | ukrainian: {
158 | font: "Kremlin Premier",
159 | },
160 | urdu: {
161 | font: "Ar Ciela",
162 | },
163 | vietnamese: {
164 | font: "Ar Ciela",
165 | },
166 | yoruba: {
167 | font: "Olde English",
168 | },
169 | };
170 |
171 | get settings() {
172 | return {
173 | LanguageRegex: {
174 | type: String,
175 | default: game.i18n.localize("POLYGLOT.Generic.Language"),
176 | },
177 | };
178 | }
179 |
180 | async getLanguages() {
181 | const originalLanguages = {
182 | streetslang: "Streetslang",
183 | arabic: "Arabic",
184 | bengali: "Bengali",
185 | berber: "Berber",
186 | burmese: "Burmese",
187 | cantonese: "Cantonese",
188 | chinese: "Scrapbook Chinese",
189 | cree: "Cree",
190 | creole: "Creole",
191 | dari: "Dari",
192 | dutch: "Dutch",
193 | english: "English",
194 | farsi: "Farsi",
195 | filipino: "Filipino",
196 | finnish: "Finnish",
197 | french: "French",
198 | german: "German",
199 | guarani: "Guarani",
200 | hausa: "Hausa",
201 | hawaiian: "Hawaiian",
202 | hebrew: "Hebrew",
203 | hindi: "Hindi",
204 | indonesian: "Indonesian",
205 | italian: "Italian",
206 | japanese: "Japanese",
207 | khmer: "Khmer",
208 | korean: "Korean",
209 | lingala: "Lingala",
210 | malayan: "Malayan",
211 | mandarin: "Mandarin",
212 | maori: "Maori",
213 | mayan: "Mayan",
214 | mongolian: "Mongolian",
215 | navajo: "Navajo",
216 | nepali: "Nepali",
217 | norwegian: "Norwegian",
218 | oromo: "Oromo",
219 | pamanyungan: "Pama-nyungan",
220 | polish: "Polish",
221 | portuguese: "Portuguese",
222 | quechua: "Quechua",
223 | romanian: "Romanian",
224 | russian: "Russian",
225 | sinhalese: "Sinhalese",
226 | spanish: "Spanish",
227 | swahili: "Swahili",
228 | tahitian: "Tahitian",
229 | tamil: "Tamil",
230 | turkish: "Turkish",
231 | twi: "Twi",
232 | ukrainian: "Ukrainian",
233 | urdu: "Urdu",
234 | vietnamese: "Vietnamese",
235 | yoruba: "Yoruba",
236 | };
237 | const langs = {};
238 | const languagesSetting = game.settings.get("polyglot", "Languages");
239 | for (let lang in originalLanguages) {
240 | const label = originalLanguages[lang];
241 | if (!label) continue;
242 | langs[lang] = {
243 | label,
244 | font: languagesSetting[lang]?.font || this.languages[lang]?.font || this.defaultFont,
245 | rng: languagesSetting[lang]?.rng ?? "default",
246 | };
247 | }
248 | this.languages = this.replaceLanguages ? {} : langs;
249 | }
250 |
251 | getUserLanguages(actor) {
252 | let knownLanguages = new Set();
253 | let literateLanguages = new Set();
254 | const languageRegex = game.settings.get("polyglot", "LanguageRegex");
255 | let myRegex = new RegExp(`${languageRegex}\\s*\\((.+)\\)`, "i");
256 | for (let item of actor.items) {
257 | if (item.type === "skill") {
258 | if (myRegex.test(item.name)) {
259 | knownLanguages.add(item.name.match(myRegex)[1].trim().toLowerCase());
260 | }
261 | }
262 | }
263 | return [knownLanguages, literateLanguages];
264 | }
265 | }
266 |
--------------------------------------------------------------------------------
/src/module/providers/dnd5e.js:
--------------------------------------------------------------------------------
1 | import LanguageProvider from "./templates/Base.js";
2 |
3 | export default class dnd5eLanguageProvider extends LanguageProvider {
4 | languages = {
5 | aarakocra: {
6 | font: "Olde Thorass",
7 | },
8 | abyssal: {
9 | font: "Infernal",
10 | },
11 | aquan: {
12 | font: "Dethek",
13 | },
14 | auran: {
15 | font: "Dethek",
16 | },
17 | celestial: {
18 | font: "Celestial",
19 | },
20 | common: {
21 | font: "Thorass",
22 | },
23 | deep: {
24 | font: "Ar Ciela",
25 | },
26 | draconic: {
27 | font: "Iokharic",
28 | },
29 | druidic: {
30 | font: "Jungle Slang",
31 | },
32 | dwarvish: {
33 | font: "Dethek",
34 | },
35 | elvish: {
36 | font: "Espruar",
37 | },
38 | giant: {
39 | font: "Dethek",
40 | },
41 | gith: {
42 | font: "Pulsian",
43 | },
44 | gnoll: {
45 | font: "Kargi",
46 | },
47 | gnomish: {
48 | font: "Dethek",
49 | },
50 | goblin: {
51 | font: "Dethek",
52 | },
53 | halfling: {
54 | font: "Thorass",
55 | },
56 | ignan: {
57 | font: "Dethek",
58 | },
59 | infernal: {
60 | font: "Infernal",
61 | },
62 | orc: {
63 | font: "Dethek",
64 | },
65 | primordial: {
66 | font: "Dethek",
67 | },
68 | sylvan: {
69 | font: "Olde Espruar",
70 | },
71 | terran: {
72 | font: "Dethek",
73 | },
74 | cant: {
75 | font: "Thorass",
76 | },
77 | undercommon: {
78 | font: "High Drowic",
79 | },
80 | };
81 |
82 | get settings() {
83 | return {
84 | "DND5E.SpecialLanguages": {
85 | type: String,
86 | default: game.i18n.localize("DND5E.Language.Language.Common"),
87 | }
88 | };
89 | }
90 |
91 | languageRarities = ["standard", "exotic"];
92 |
93 | multiLanguages = {
94 | primordial: {
95 | parent: "exotic"
96 | }
97 | };
98 |
99 | async getLanguages() {
100 | const languagesSetting = game.settings.get("polyglot", "Languages");
101 | const langs = {};
102 | if (this.replaceLanguages) {
103 | CONFIG.DND5E.languages = {};
104 | this.languageRarities = [];
105 | this.multiLanguages = {};
106 | }
107 | const systemLanguages = CONFIG.DND5E.languages;
108 | const getLang = (key, target) => {
109 | const processLanguage = (label) => {
110 | if (label) {
111 | langs[key] = {
112 | label,
113 | font: languagesSetting[key]?.font || this.languages[key]?.font || this.defaultFont,
114 | rng: languagesSetting[key]?.rng ?? "default",
115 | };
116 | }
117 | };
118 |
119 | if (key in this.multiLanguages) {
120 | processLanguage(game.i18n.localize(target[key].label));
121 | }
122 | if (target[key].children) {
123 | Object.keys(target[key].children).forEach((kkey) => {
124 | getLang(kkey, target[key].children);
125 | });
126 | } else {
127 | processLanguage(game.i18n.localize(target[key]));
128 | }
129 | };
130 | Object.keys(systemLanguages).forEach((key) => {
131 | if (this.languageRarities.includes(key)) {
132 | Object.keys(systemLanguages[key].children).forEach((kkey) => {
133 | getLang(kkey, systemLanguages[key].children);
134 | });
135 | } else {
136 | getLang(key, systemLanguages);
137 | }
138 | });
139 | this.languages = langs;
140 | }
141 |
142 | getUserLanguages(actor) {
143 | let knownLanguages = new Set();
144 | let literateLanguages = new Set();
145 | if (actor.system?.traits?.languages) {
146 | for (let lang of actor.system.traits.languages.value) {
147 | if (this.languageRarities.includes(lang)) {
148 | for (let l in CONFIG.DND5E.languages[lang].children) {
149 | knownLanguages.add(l.trim().replace(/[\s']/g, "_"));
150 | }
151 | } else {
152 | knownLanguages.add(lang.trim().replace(/[\s']/g, "_"));
153 | }
154 | if (lang in this.multiLanguages) {
155 | const parent = this.multiLanguages[lang].parent;
156 | let languages;
157 | if (parent) {
158 | const parentChildren = CONFIG.DND5E.languages[parent].children;
159 | languages = parentChildren[lang].children;
160 | } else {
161 | languages = CONFIG.DND5E.languages[lang].children;
162 | }
163 | for (let l in languages) {
164 | knownLanguages.add(l.trim().replace(/[\s']/g, "_"));
165 | }
166 | }
167 | }
168 | if (actor.system.traits.languages.custom) {
169 | const defaultSpecialLanguage = game.settings
170 | .get("polyglot", "DND5E.SpecialLanguages")
171 | .trim()
172 | .toLowerCase();
173 | // eslint-disable-next-line no-unsafe-optional-chaining
174 | for (let lang of actor.system.traits.languages?.custom.split(/[;]/)) {
175 | let key = lang.trim().toLowerCase();
176 | try {
177 | if (/(usually common)|(in life)|(its creator)|(?<=any)(.*)(?=language)/i.test(key)) {
178 | knownLanguages.add(defaultSpecialLanguage);
179 | } else if (/(?<=usually)(.*)(?=\))/g.test(key)) {
180 | key = key.match(/(?<=usually)(.*)(?=\))/g)[0].trim();
181 | knownLanguages.add(key);
182 | } else if (/(?<=understands)(.*)(?=but can't speak it)/g.test(key)) {
183 | key = key.match(/(?<=understands)(.*)(?=but can't speak it)/g)[0].trim();
184 | knownLanguages.add(key);
185 | } else if (/(.*)(?=plus)/.test(key)) {
186 | key = key.match(/(.*)(?=plus)/)[0].trim();
187 | knownLanguages.add(key);
188 | } else {
189 | knownLanguages.add(key);
190 | }
191 | } catch(err) {
192 | console.error(
193 | `Polyglot | Failed to get custom language "${key}" from actor "${actor.name}".`,
194 | err
195 | );
196 | }
197 | }
198 | }
199 | }
200 | return [knownLanguages, literateLanguages];
201 | }
202 |
203 | filterUsers(ownedActors) {
204 | const filtered = super.filterUsers(ownedActors);
205 | const party = game.settings.get("dnd5e", "primaryParty")?.actor;
206 | if (party?.system?.members.length) {
207 | const members = Array.from(party.system.members.ids);
208 | const users = filtered.filter((u) => ownedActors.some((actor) => members.includes(actor.id) && actor.testUserPermission(u, "OWNER")));
209 | return users;
210 | }
211 | return filtered;
212 | }
213 | }
214 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2022 Johannes Loher
2 | #
3 | # SPDX-License-Identifier: MIT
4 |
5 | name: Release
6 |
7 | on:
8 | release:
9 | types: [published]
10 |
11 | env:
12 | package_type: module
13 | node_version: 22
14 |
15 | jobs:
16 | lint:
17 | runs-on: ubuntu-latest
18 | steps:
19 | - name: Checkout code
20 | uses: actions/checkout@v5
21 |
22 | - name: Install node
23 | uses: actions/setup-node@v6
24 | with:
25 | node-version: ${{ env.node_version }}
26 |
27 | - name: Cache Node.js modules
28 | uses: actions/cache@v4
29 | with:
30 | path: .npm
31 | key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }}
32 | restore-keys: |
33 | ${{ runner.OS }}-node-
34 | ${{ runner.OS }}-
35 |
36 | - name: Install dependencies
37 | run: npm ci --cache .npm --prefer-offline
38 |
39 | - name: Lint
40 | run: npm run lint
41 |
42 | build:
43 | runs-on: ubuntu-latest
44 | steps:
45 | - name: Checkout code
46 | uses: actions/checkout@v5
47 |
48 | - name: Install node
49 | uses: actions/setup-node@v6
50 | with:
51 | node-version: ${{ env.node_version }}
52 |
53 | - name: Cache Node.js modules
54 | uses: actions/cache@v4
55 | with:
56 | path: .npm
57 | key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }}
58 | restore-keys: |
59 | ${{ runner.OS }}-node-
60 | ${{ runner.OS }}-
61 |
62 | - name: Install dependencies
63 | run: npm ci --cache .npm --prefer-offline
64 |
65 | - name: Extract tag version number
66 | id: get_version
67 | uses: battila7/get-version-action@v2
68 |
69 | - name: Substitute Manifest and Download Links For Versioned Ones
70 | id: sub_manifest_link_version
71 | uses: microsoft/variable-substitution@v1
72 | with:
73 | files: "src/${{ env.package_type }}.json"
74 | env:
75 | version: ${{ steps.get_version.outputs.version-without-v }}
76 | url: https://github.com/${{ github.repository }}
77 | manifest: https://github.com/${{ github.repository }}/releases/latest/download/${{ env.package_type }}.json
78 | download: https://github.com/${{ github.repository }}/releases/download/${{ github.event.release.tag_name }}/${{ env.package_type }}.zip
79 |
80 | - name: Build
81 | run: npm run build
82 |
83 | - name: Archive production artifacts
84 | uses: actions/upload-artifact@v4
85 | with:
86 | name: dist
87 | path: dist
88 |
89 | publish:
90 | needs:
91 | - lint
92 | - build
93 | runs-on: ubuntu-latest
94 | steps:
95 | - name: Checkout code
96 | uses: actions/checkout@v5
97 |
98 | - name: Download production artifacts for publication
99 | uses: actions/download-artifact@v5
100 | with:
101 | name: dist
102 | path: dist
103 |
104 | - name: Create zip file
105 | working-directory: ./dist
106 | run: zip -r ../${{ env.package_type }}.zip .
107 |
108 | - name: Create release
109 | id: create_version_release
110 | uses: ncipollo/release-action@v1
111 | with:
112 | allowUpdates: true
113 | name: ${{ github.event.release.name }}
114 | token: ${{ secrets.GITHUB_TOKEN }}
115 | artifacts: "./dist/${{ env.package_type }}.json, ./${{ env.package_type }}.zip"
116 | tag: ${{ github.event.release.tag_name }}
117 | body: ${{ github.event.release.body }}
118 |
119 | - name: Get Module ID
120 | id: moduleID
121 | uses: notiz-dev/github-action-json-property@release
122 | with:
123 | path: "./dist/${{ env.package_type }}.json"
124 | prop_path: "id"
125 |
126 | - name: Get mininum
127 | id: minimum
128 | uses: notiz-dev/github-action-json-property@release
129 | with:
130 | path: "./dist/${{ env.package_type }}.json"
131 | prop_path: "compatibility.minimum"
132 |
133 | - name: Get verified
134 | id: verified
135 | uses: notiz-dev/github-action-json-property@release
136 | with:
137 | path: "./dist/${{ env.package_type }}.json"
138 | prop_path: "compatibility.verified"
139 |
140 | - name: Extract tag version number
141 | id: get_version
142 | uses: battila7/get-version-action@v2
143 |
144 | - name: Foundry Release API
145 | uses: fjogeleit/http-request-action@v1
146 | with:
147 | url: "https://api.foundryvtt.com/_api/packages/release_version"
148 | method: "POST"
149 | customHeaders: '{"Content-Type": "application/json", "Authorization" : "${{ secrets.FOUNDRY_KEY }}"}'
150 | data: '{"id": "${{ steps.moduleID.outputs.prop }}", "release": {"version": "${{ steps.get_version.outputs.version-without-v }}", "manifest": "https://github.com/${{ github.repository }}/releases/download/${{ github.event.release.tag_name }}/${{ env.package_type }}.json", "notes": "https://github.com/${{ github.repository }}/releases/tag/${{ github.event.release.tag_name }}/", "compatibility" : {"minimum": "${{ steps.minimum.outputs.prop }}", "verified": "${{ steps.verified.outputs.prop }}"}}}'
151 | preventFailureOnNoResponse: true
152 |
--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: 2022 Johannes Loher
2 | // SPDX-FileCopyrightText: 2022 David Archibald
3 | //
4 | // SPDX-License-Identifier: MIT
5 |
6 | module.exports = {
7 | parserOptions: {
8 | ecmaVersion: 13,
9 | extraFileExtensions: [".cjs", ".mjs"],
10 | sourceType: "module",
11 | },
12 |
13 | env: {
14 | browser: true,
15 | es6: true,
16 | jquery: true,
17 | },
18 |
19 | extends: ["eslint:recommended", "@typhonjs-fvtt/eslint-config-foundry.js/0.8.0"],
20 |
21 | plugins: [],
22 |
23 | rules: {
24 | "array-bracket-spacing": ["warn", "never"],
25 | "array-callback-return": "warn",
26 | "arrow-spacing": "warn",
27 | "brace-style": "warn",
28 | "comma-dangle": ["warn", "only-multiline"],
29 | "comma-style": "warn",
30 | "computed-property-spacing": "warn",
31 | "constructor-super": "error",
32 | "default-param-last": "warn",
33 | "dot-location": ["warn", "property"],
34 | "eol-last": ["error", "always"],
35 | eqeqeq: ["warn", "smart"],
36 | "func-call-spacing": "warn",
37 | "func-names": ["warn", "never"],
38 | "getter-return": "warn",
39 | indent: ["warn", "tab", { SwitchCase: 1 }],
40 | "lines-between-class-members": "warn",
41 | "new-parens": ["warn", "always"],
42 | "no-alert": "warn",
43 | "no-array-constructor": "warn",
44 | "no-class-assign": "warn",
45 | "no-compare-neg-zero": "warn",
46 | "no-cond-assign": "warn",
47 | "no-const-assign": "error",
48 | "no-constant-condition": "warn",
49 | "no-constructor-return": "warn",
50 | "no-delete-var": "warn",
51 | "no-dupe-args": "warn",
52 | "no-dupe-class-members": "warn",
53 | "no-dupe-keys": "warn",
54 | "no-duplicate-case": "warn",
55 | "no-duplicate-imports": ["warn", { includeExports: true }],
56 | "no-else-return": "warn",
57 | "no-empty": ["warn", { allowEmptyCatch: true }],
58 | "no-empty-character-class": "warn",
59 | "no-empty-pattern": "warn",
60 | "no-func-assign": "warn",
61 | "no-global-assign": "warn",
62 | "no-implicit-coercion": ["warn", { allow: ["!!"] }],
63 | "no-implied-eval": "warn",
64 | "no-import-assign": "warn",
65 | "no-invalid-regexp": "warn",
66 | "no-irregular-whitespace": "warn",
67 | "no-iterator": "warn",
68 | "no-lone-blocks": "warn",
69 | "no-lonely-if": "warn",
70 | "no-misleading-character-class": "warn",
71 | "no-mixed-operators": "warn",
72 | "no-multi-str": "warn",
73 | "no-multiple-empty-lines": ["warn", { max: 1 }],
74 | "no-new-func": "warn",
75 | "no-new-object": "warn",
76 | "no-new-symbol": "warn",
77 | "no-new-wrappers": "warn",
78 | "no-nonoctal-decimal-escape": "warn",
79 | "no-obj-calls": "warn",
80 | "no-octal": "warn",
81 | "no-octal-escape": "warn",
82 | "no-promise-executor-return": "warn",
83 | "no-proto": "warn",
84 | "no-regex-spaces": "warn",
85 | "no-script-url": "warn",
86 | "no-self-assign": "warn",
87 | "no-self-compare": "warn",
88 | "no-setter-return": "warn",
89 | "no-sequences": "warn",
90 | "no-template-curly-in-string": "warn",
91 | "no-this-before-super": "error",
92 | "no-unexpected-multiline": "warn",
93 | "no-unmodified-loop-condition": "warn",
94 | "no-unneeded-ternary": "warn",
95 | "no-unreachable": "warn",
96 | "no-unreachable-loop": "warn",
97 | "no-unsafe-negation": ["warn", { enforceForOrderingRelations: true }],
98 | "no-unsafe-optional-chaining": ["warn", { disallowArithmeticOperators: true }],
99 | "no-unused-expressions": "warn",
100 | "no-useless-backreference": "warn",
101 | "no-useless-call": "warn",
102 | "no-useless-catch": "warn",
103 | "no-useless-computed-key": ["warn", { enforceForClassMembers: true }],
104 | "no-useless-concat": "warn",
105 | "no-useless-constructor": "warn",
106 | "no-useless-rename": "warn",
107 | "no-useless-return": "warn",
108 | "no-var": "warn",
109 | "no-void": "warn",
110 | "no-whitespace-before-property": "warn",
111 | "prefer-numeric-literals": "warn",
112 | "prefer-object-spread": "warn",
113 | "prefer-regex-literals": "warn",
114 | "prefer-spread": "warn",
115 | "rest-spread-spacing": ["warn", "never"],
116 | "semi-spacing": "warn",
117 | "semi-style": ["warn", "last"],
118 | "space-unary-ops": ["warn", { words: true, nonwords: false }],
119 | "switch-colon-spacing": "warn",
120 | "symbol-description": "warn",
121 | "template-curly-spacing": ["warn", "never"],
122 | "unicode-bom": ["warn", "never"],
123 | "use-isnan": ["warn", { enforceForSwitchCase: true, enforceForIndexOf: true }],
124 | "valid-typeof": ["warn", { requireStringLiterals: true }],
125 | "wrap-iife": ["warn", "inside"],
126 |
127 | "arrow-parens": ["warn", "always"],
128 | "comma-spacing": "warn",
129 | "dot-notation": "warn",
130 | "key-spacing": "warn",
131 | "keyword-spacing": ["warn", { overrides: { catch: { before: true, after: false } } }],
132 | "max-len": [
133 | "warn",
134 | {
135 | code: 120,
136 | ignoreComments: true,
137 | ignoreTrailingComments: true,
138 | ignoreUrls: true,
139 | ignoreStrings: true,
140 | ignoreTemplateLiterals: true,
141 | ignoreRegExpLiterals: true,
142 | },
143 | ],
144 | "no-extra-boolean-cast": ["warn", { enforceForLogicalOperands: true }],
145 | "no-extra-semi": "warn",
146 | "no-multi-spaces": ["warn", { ignoreEOLComments: true }],
147 | "no-throw-literal": "error",
148 | "no-trailing-spaces": "warn",
149 | "no-useless-escape": "warn",
150 | "no-unused-vars": ["warn", { args: "none" }],
151 | "nonblock-statement-body-position": ["warn", "beside"],
152 | "one-var": ["warn", "never"],
153 | "operator-linebreak": [
154 | "warn",
155 | "before",
156 | {
157 | overrides: { "=": "after", "+=": "after", "-=": "after" },
158 | },
159 | ],
160 | "prefer-template": "warn",
161 | "quote-props": ["warn", "as-needed", { keywords: false }],
162 | quotes: ["warn", "double", { avoidEscape: true, allowTemplateLiterals: false }],
163 | semi: "warn",
164 | "space-before-blocks": ["warn", "always"],
165 | "space-before-function-paren": [
166 | "warn",
167 | {
168 | anonymous: "always",
169 | named: "never",
170 | asyncArrow: "always",
171 | },
172 | ],
173 | "spaced-comment": "warn",
174 | },
175 |
176 | globals: {
177 | globalThis: false,
178 | GURPS: false,
179 | JournalTextPageSheet: false,
180 | ProseMirror: false,
181 | TomSelect: false,
182 | Tour: false,
183 | },
184 |
185 | overrides: [
186 | {
187 | files: ["./*.js", "./*.cjs", "./*.mjs"],
188 | env: {
189 | node: true,
190 | },
191 | },
192 | ],
193 | };
194 |
--------------------------------------------------------------------------------
/src/module/forms/LanguageSettings.js:
--------------------------------------------------------------------------------
1 | import { providerKeys } from "../providers/_shared.js";
2 |
3 | export class PolyglotLanguageSettings extends FormApplication {
4 | /**
5 | * Default Options for this FormApplication
6 | */
7 | static get defaultOptions() {
8 | const classes = ["sheet", "polyglot", "polyglot-language-settings"];
9 | if (game.system.id === "wfrp4e") {
10 | classes.push(game.system.id);
11 | }
12 | return foundry.utils.mergeObject(super.defaultOptions, {
13 | id: "polyglot-language-form",
14 | title: "Polyglot Language Settings",
15 | template: "./modules/polyglot/templates/LanguageSettings.hbs",
16 | classes,
17 | width: 600,
18 | height: 680,
19 | closeOnSubmit: true,
20 | resizable: true,
21 | });
22 | }
23 |
24 | getData() {
25 | const data = {};
26 | const selectedProvider = game.polyglot.languageProvider.id;
27 | // Insert all speed providers into the template data
28 | data.providers = Object.values(game.polyglot.api.providers).map((languageProvider) => {
29 | const provider = {};
30 | provider.id = languageProvider.id;
31 | let dotPosition = provider.id.indexOf(".");
32 | if (dotPosition === -1) dotPosition = provider.id.length;
33 | const type = provider.id.substring(0, dotPosition);
34 | const id = provider.id.substring(dotPosition + 1);
35 | if (type === "native") {
36 | let title = id === game.system.id || id === providerKeys[game.system.id] ? game.system.title : id;
37 | provider.selectTitle = (`${game.i18n.localize("POLYGLOT.LanguageProvider.choices.native")} ${title}`).trim();
38 | } else {
39 | const name = type === "module" ? game.modules.get(id).title : game.system.title;
40 | provider.selectTitle = game.i18n.format(`POLYGLOT.LanguageProvider.choices.${type}`, { name });
41 | }
42 | provider.isSelected = provider.id === selectedProvider;
43 | return provider;
44 | });
45 |
46 | data.providerSelection = {
47 | id: "languageProvider",
48 | name: game.i18n.localize("POLYGLOT.LanguageProvider.name"),
49 | hint: game.i18n.localize("POLYGLOT.LanguageProvider.hint"),
50 | type: String,
51 | choices: data.providers.reduce((choices, provider) => {
52 | choices[provider.id] = provider.selectTitle;
53 | return choices;
54 | }, {}),
55 | value: selectedProvider,
56 | isCheckbox: false,
57 | isSelect: true,
58 | isRange: false,
59 | };
60 |
61 | this.languageProvider = data.providerSelection.value;
62 |
63 | function prepSetting(key) {
64 | const { name, hint } = game.settings.settings.get(`polyglot.${key}`);
65 | const value = game.settings.get("polyglot", `${key}`);
66 | return { value, name, hint };
67 | }
68 |
69 | const { name, hint, type } = game.settings.settings.get("polyglot.Languages");
70 | const value = Object.fromEntries(
71 | Object.entries(game.settings.get("polyglot", "Languages"))
72 | .sort()
73 | .filter(([key]) =>
74 | ![game.polyglot.omniglot, game.polyglot.comprehendLanguages, game.polyglot.truespeech].includes(key)
75 | )
76 | );
77 |
78 | const languages = {
79 | name,
80 | hint,
81 | value,
82 | fields: type.element.fields
83 | };
84 |
85 | const alphabets = prepSetting("Alphabets");
86 |
87 | return {
88 | data,
89 | languages,
90 | alphabets,
91 | rng: {
92 | default: "POLYGLOT.RandomizeRunesOptions.a",
93 | unique: "POLYGLOT.RandomizeRunesOptions.b",
94 | none: "POLYGLOT.RandomizeRunesOptions.c"
95 | }
96 | };
97 | }
98 |
99 | async activateListeners(html) {
100 | super.activateListeners(html);
101 | html.find(".polyglot-languageProvider").on("change", (event) => {
102 | const languagesList = html.find(".polyglot-languages-list")[0];
103 | const languagesWarning = html.find(".polyglot-languages-warn")[0];
104 | const shouldDisplayLanguages = this.languageProvider === event.target.value;
105 | languagesList.style.display = shouldDisplayLanguages ? "block" : "none";
106 | languagesWarning.style.display = shouldDisplayLanguages ? "none" : "block";
107 | });
108 | html.find(".polyglot-alphabet").each(function () {
109 | const font = this.previousSibling.previousSibling.children[0].value; // selectatr's value
110 | this.style.font = game.polyglot.languageProvider.fonts[font];
111 | });
112 | html.find(".selectatr").on("change", (event) => {
113 | const font = event.target.value;
114 | const parentElement = event.target.parentElement;
115 | const nextSibling = parentElement.nextSibling;
116 | if (nextSibling && nextSibling.nextSibling) {
117 | const elementToChange = nextSibling.nextSibling;
118 | const alphabet = game.polyglot.languageProvider.fonts[font];
119 | elementToChange.style.font = alphabet;
120 | }
121 | });
122 | html.find("button").on("click", async (event) => {
123 | if (event.currentTarget?.dataset?.action === "reset") {
124 | const current = game.settings.get("polyglot", "Languages");
125 | await game.settings.set("polyglot", "Languages", {});
126 | const defaultProvider = new game.polyglot.languageProvider.constructor();
127 | defaultProvider.getLanguages();
128 | const diff = foundry.utils.diffObject(defaultProvider.languages, current);
129 | await game.settings.set("polyglot", "Languages", defaultProvider.languages);
130 | if (Object.keys(diff).length) SettingsConfig.reloadConfirm({ world: true });
131 | this.close();
132 | }
133 | });
134 | }
135 |
136 | /**
137 | * Executes on form submission
138 | * @param {Event} ev - the form submission event
139 | * @param {Object} formData - the form data
140 | */
141 | async _updateObject(ev, formData) {
142 | const languageProvider = game.settings.get("polyglot", "languageProvider");
143 | if (languageProvider !== formData.languageProvider) {
144 | await game.settings.set("polyglot", "languageProvider", formData.languageProvider);
145 | game.polyglot.api.updateProvider();
146 | await game.settings.set("polyglot", "Alphabets", game.polyglot.languageProvider.fonts);
147 | await game.settings.set("polyglot", "Languages", game.polyglot.languageProvider.languages);
148 | } else {
149 | const languages = foundry.utils.expandObject(formData).languages;
150 | const current = game.settings.get("polyglot", "Languages");
151 | const diff = foundry.utils.diffObject(current, languages);
152 | if (!Object.keys(diff).length) return;
153 | game.polyglot.languageProvider.languages = languages;
154 | await game.settings.set("polyglot", "Languages", languages);
155 | }
156 | SettingsConfig.reloadConfirm({ world: true });
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/src/lang/es.json:
--------------------------------------------------------------------------------
1 | {
2 | "I18N": {
3 | "LANGUAGE": "Español",
4 | "MAINTAINERS": "@Viriato139ac#0342, Juanfrank"
5 | },
6 | "POLYGLOT": {
7 | "DefaultAlphabet": "Alfabeto por defecto",
8 | "FontSettings": "Ajustes de fuentes",
9 | "LanguageSettings": "Ajustes de idiomas",
10 | "ChatSettings": "Ajustes del chat",
11 | "Languages.title": "Idiomas",
12 | "Languages.hint": "Cambia el alfabeto de los idiomas.",
13 | "Font": "Fuente",
14 | "Fonts": "Fuentes",
15 | "FontSize": "Tamaño de fuente (%)",
16 | "AllowOOC.hint": "Determina qué usuarios tendrán sus mensajes codificados al utilizar el chat como jugador. OOC = Out of character (como jugador, o fuera del personaje).",
17 | "AllowOOC.title": "Codificar mensajes OOC del chat",
18 | "AllowOOCOptions": {
19 | "a": "Todos",
20 | "b": "Solo GM",
21 | "c": "Solo jugadores",
22 | "d": "Ninguno"
23 | },
24 | "ComprehendLanguages.hint": "Define un idioma que permite al hablante entender todos los idiomas, pero que no puede ser escrito ni hablado.",
25 | "ComprehendLanguages.title": "Hechizo Comprender Idiomas",
26 | "CustomLanguages.hint": "Define una lista de idiomas personalizados, separados mediante coma, para que sean añadidos al sistema.",
27 | "CustomLanguages.title": "Idiomas personalizados",
28 | "DefaultLanguage.hint": "Nombre del idioma que se selecciona por defecto. Dejar en blanco para utilizar el valor por defecto del sistema.",
29 | "DefaultLanguage.title": "Idioma por defecto",
30 | "DisplayTranslated.hint": "Para los idiomas que se traducen en el chat, muestra el texto original y a continuación la traducción.",
31 | "DisplayTranslated.title": "Mostrar traducciones",
32 | "enableAllFonts": {
33 | "choices": {
34 | "0": "Ninguno",
35 | "1": "Fuentes de Polyglot",
36 | "2": "Fuentes adicionales del programa Base",
37 | "3": "Ambos"
38 | },
39 | "hint": "Añade las fuentes de las opciones seleccionadas a los Ajustes de Fuente e Idioma.",
40 | "title": "Añadir fuentes a los ajustes de los módulos"
41 | },
42 | "ExportFonts.hint": "Añade las fuentes de Polyglot al menú de Fuentes Adicionales del programa Base. Si se desactiva esta opción, se eliminarán todas las fuentes de Polyglot del menú.",
43 | "ExportFonts.title": "Añade las fuentes de Polyglot al programa Base",
44 | "HideTranslation.hint": "Oculta el globo y el texto \"Traducido del\" en el chat a los jugadores. Útil para cuando no se quiere que los jugadores sepan qué idioma se está hablando. Requiere recargar la página.",
45 | "HideTranslation.title": "Ocultar a los jugadores los globos y el texto \"Traducido del\"",
46 | "IgnoreJournalFontSize": {
47 | "title": "Diario: Usar tamaño de fuente normal",
48 | "hint": "Ignora el tamaño de las fuentes de Polyglot en los diarios, haciendo que tengan el mismo tamaño que tendría el texto normal. Útil para ocasiones en las que el formato del diario es importante."
49 | },
50 | "JournalHighlight": {
51 | "hint": "Define la opacidad del resaltado de las fuentes en el diario.",
52 | "title": "Opacidad del resaltado en los diarios (%)"
53 | },
54 | "JournalHighlightColor": {
55 | "hint": "Define el color de resaltado de las fuentes en el diario.",
56 | "title": "Color de resaltado de los disarios"
57 | },
58 | "LanguageProvider": {
59 | "name": "Proveedor de ajustes de idioma",
60 | "hint": "Seleccione quien provee información de alfabetos e idiomas. Se pueden habilitar más proveedores instalando módulos y sistemas. Las opciones que aparecen más abajo dependerán del proveedor seleccionado. ⚠️ Si cambia el proveedor, deberá guardar los cambios y volver a abrir la ventana de configuración.",
61 | "choices": {
62 | "module": "[Módulo] {name}",
63 | "native": "Genérico",
64 | "system": "[Sistema] {name}"
65 | }
66 | },
67 | "languageDataPath": {
68 | "title": "Ruta de idioma",
69 | "hint": "Si el sistema tiene idiomas configurados en los datos de los actores que no se cargan bien, es posible que estén usando otra ruta. Introduzca la ruta en los datos al atributo correcto (p.e. actor.system.languages o actor.system.speak). Este ajuste tiene prioridad sobre los ajustes de RegEx de idioma. Requiere reinicio."
70 | },
71 | "literacyDataPath": {
72 | "title": "Ruta de alfabetización",
73 | "hint": "Lo mismo que el ajuste de la ruta de idioma, pero aplicado a la lectura de diarios. Se necesita rellenar el ajuste de ruta de idioma. Requiere reinicio."
74 | },
75 | "LanguageRegex": {
76 | "title": "RegEx de idioma",
77 | "hint": "Se puede usar para cambiar el término de búsqueda en los objetos de \"Idioma\" a otro diferente, como \"Lengua\"."
78 | },
79 | "logographicalFontToggle.hint": "Reduce a la mitad el tamaño de las frases que usen fuentes logográficas (p. ej. caracteres japoneses o chinos).",
80 | "logographicalFontToggle.title": "Fuentes logográficas",
81 | "RandomizeRunes.hint": "Determina el tipo de aleatoriedad (RNG) utilizada para generar una frase. ⚠️ La opción \"Ninguno\" solamente admite caracteres alfanuméricos (sin acentos).",
82 | "RandomizeRunes.title": "Aleatorizar las runas",
83 | "RandomizeRunesOptions": {
84 | "a": "Por defecto",
85 | "b": "Frases únicas",
86 | "c": "Ninguna ⚠️"
87 | },
88 | "ReplaceLanguages.hint": "Reemplaza el idioma por defecto del sistema por sus idiomas personalizados. El primer idioma personalizado de la lista se convertirá en el nuevo idioma por defecto.",
89 | "ReplaceLanguages.title": "Reemplazar idiomas del sistema",
90 | "RuneRegex": {
91 | "title": "Aleatorizar solo alfanuméricos",
92 | "hint": "Hace que la aleatoriedad ignore los caracteres no alfanuméricos (p. ej. !,.;:?#$\"'). Esto puede causar que algunos de estos caracteres se muestren como un cuadrado (□) en algunas fuentes."
93 | },
94 | "ScrambleGM.title": "Codificar para el GM",
95 | "ScrambleGM.hint": "No traducir el texto para el DJ (remítase al color del globo para ver la perspectiva del icono). Requiere recargar la página.",
96 | "Truespeech.title": "Hechizo Idiomas",
97 | "Truespeech.hint": "Define un idioma que permite al hablante entender todos los idiomas hablados (no puede leer Diarios), y que es entendido por todas las criaturas.",
98 | "Translation": "Traducción",
99 | "TranslatedFrom": "Traducido del ",
100 | "LanguageLabel": "Idioma",
101 | "AlphabetLabel": "Alfabeto",
102 | "LatinAlphabet": "Alfabeto latino",
103 | "ToggleRunes": "Activar/desactivar runas",
104 | "Runes": "Runas",
105 | "UESRPG.Language": "Idioma",
106 | "Generic": {
107 | "Language": "Idioma"
108 | },
109 | "COC7": {
110 | "LanguageOwn": "Lengua propia",
111 | "LanguageAny": "Otras lenguas",
112 | "LanguageOther": "Otras lenguas",
113 | "LanguageSpec": "Lengua"
114 | },
115 | "DND5E": {
116 | "SpecialLanguages.title": "Reemplazar idiomas especiales",
117 | "SpecialLanguages.hint": "Nombre del idioma que reemplazará \"idiomas\" tales como \"todos los idiomas que supo en vida\"."
118 | },
119 | "SWADE": {
120 | "LanguageSkills": "Idioma"
121 | },
122 | "WFRP4E": {
123 | "LanguageSkills": "Idioma"
124 | }
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/src/module/forms/GeneralSettings.js:
--------------------------------------------------------------------------------
1 | export class PolyglotGeneralSettings extends FormApplication {
2 | static get defaultOptions() {
3 | const classes = ["sheet", "polyglot", "polyglot-general-settings"];
4 | if (game.system.id === "wfrp4e") {
5 | classes.push(game.system.id);
6 | }
7 | return foundry.utils.mergeObject(super.defaultOptions, {
8 | id: "polyglot-general-form",
9 | title: "Polyglot General Settings",
10 | template: "./modules/polyglot/templates/GeneralSettings.hbs",
11 | classes,
12 | tabs: [{ navSelector: ".tabs", contentSelector: ".content", initial: "font" }],
13 | width: 600,
14 | height: "auto",
15 | closeOnSubmit: true,
16 | });
17 | }
18 |
19 | _prepSetting(key, flag = false) {
20 | const settingData = game.settings.settings.get(`polyglot.${key}`);
21 | if (!flag && settingData.polyglotHide) return;
22 |
23 | const { button, choices, default: def, hasTextarea, hint, isColor, name, range, type } = settingData;
24 | let select = [];
25 | if (choices !== undefined) {
26 | const type = foundry.utils.getType(choices);
27 | if (type === "Object") select = Object.entries(choices).map(([key, value]) => ({ key, value }));
28 | else if (type === "Array") select = choices;
29 | }
30 |
31 | let settingType = type.name;
32 | if (button) {
33 | settingType = "Button";
34 | } else if (range) {
35 | settingType = "Range";
36 | } else if (choices) {
37 | settingType = "Select";
38 | } else if (isColor) {
39 | settingType = "Color";
40 | } else if (hasTextarea) {
41 | settingType = "Textarea";
42 | }
43 |
44 | return {
45 | id: key,
46 | value: flag ? (game.user.flags?.polyglot?.[key] ?? def) : game.settings.get("polyglot", key),
47 | name,
48 | hint,
49 | type: settingType,
50 | range,
51 | select,
52 | };
53 | }
54 |
55 | _prepFlag(key) {
56 | return this._prepSetting(key, true);
57 | }
58 |
59 | async resetToDefault(key) {
60 | const defaultValue = game.settings.settings.get(`polyglot.${key}`).default;
61 | await game.settings.set("polyglot", key, defaultValue);
62 | }
63 |
64 | getData() {
65 | const isGM = game.user.isGM;
66 | let data = {};
67 | if (isGM) {
68 | data = {
69 | tabs: {
70 | font: {
71 | icon: "fas fa-cogs",
72 | name: "POLYGLOT.Fonts",
73 | },
74 | journal: {
75 | icon: "fas fa-book-open",
76 | name: "SIDEBAR.TabJournal",
77 | },
78 | languages: {
79 | icon: "fas fa-globe",
80 | name: "POLYGLOT.Languages.title",
81 | },
82 | chat: {
83 | icon: "fas fa-comments",
84 | name: "CHAT.Chat",
85 | },
86 | },
87 | settings: {
88 | font: {
89 | // Font Settings
90 | RuneRegex: this._prepSetting("RuneRegex"),
91 | enableAllFonts: this._prepSetting("enableAllFonts"),
92 | exportFonts: this._prepSetting("exportFonts"),
93 | },
94 | journal: {
95 | // Journal
96 | IgnoreJournalFontSize: this._prepSetting("IgnoreJournalFontSize"),
97 | JournalHighlightColor: this._prepSetting("JournalHighlightColor"),
98 | JournalHighlight: this._prepSetting("JournalHighlight"),
99 | },
100 | languages: {
101 | // Languages
102 | replaceLanguages: this._prepSetting("replaceLanguages"),
103 | defaultLanguage: this._prepSetting("defaultLanguage"),
104 | customLanguages: this._prepSetting("customLanguages"),
105 | omniglot: this._prepSetting("omniglot"),
106 | comprehendLanguages: this._prepSetting("comprehendLanguages"),
107 | truespeech: this._prepSetting("truespeech"),
108 | },
109 | chat: {
110 | // Chat
111 | enableChatFeatures: this._prepSetting("enableChatFeatures")
112 | },
113 | },
114 | };
115 | if (game.settings.get("polyglot", "enableChatFeatures")) {
116 | data.settings.chat = {
117 | ...data.settings.chat,
118 | "display-translated": this._prepSetting("display-translated"),
119 | hideTranslation: this._prepSetting("hideTranslation"),
120 | allowOOC: this._prepSetting("allowOOC"),
121 | runifyGM: this._prepSetting("runifyGM"),
122 | };
123 | }
124 | } else {
125 | data = {
126 | tabs: {
127 | languages: {
128 | icon: "fas fa-globe",
129 | name: "POLYGLOT.Languages.title",
130 | },
131 | },
132 | settings: {
133 | languages: {
134 | defaultLanguage: this._prepFlag("defaultLanguage"),
135 | },
136 | },
137 | };
138 | }
139 |
140 | for (const s in data.settings) {
141 | // eslint-disable-next-line no-unused-vars
142 | data.settings[s] = Object.fromEntries(
143 | Object.entries(data.settings[s]).filter(([key, value]) => value !== undefined),
144 | );
145 | }
146 |
147 | return data;
148 | }
149 |
150 | async activateListeners(html) {
151 | super.activateListeners(html);
152 | html.find("button").on("click", async (event) => {
153 | const dataset = event.currentTarget?.dataset;
154 | if (dataset?.action === "reset") {
155 | let keys = [
156 | "defaultLanguage"
157 | ];
158 | if (game.user.isGM) {
159 | keys = [
160 | "RuneRegex",
161 | "enableAllFonts",
162 | "exportFonts",
163 | "IgnoreJournalFontSize",
164 | "JournalHighlightColor",
165 | "JournalHighlight",
166 | "replaceLanguages",
167 | "defaultLanguage",
168 | "customLanguages",
169 | "omniglot",
170 | "comprehendLanguages",
171 | "truespeech",
172 | "enableChatFeatures",
173 | "display-translated",
174 | "hideTranslation",
175 | "allowOOC",
176 | "runifyGM",
177 | ];
178 | await Promise.all(
179 | keys.map(async (key) => {
180 | await this.resetToDefault(key);
181 | }),
182 | );
183 | } else {
184 | await Promise.all(
185 | keys.map(async (key) => {
186 | await game.user.unsetFlag("polyglot", key);
187 | }),
188 | );
189 | }
190 | this.close();
191 | } else if (dataset?.key) {
192 | const key = dataset.key;
193 | game.polyglot.languageProvider.settings?.[key].button?.(event);
194 | }
195 | });
196 | html.find(".form-group button[name]").on("click", async (event) => {
197 | const name = event.currentTarget.name;
198 | game.polyglot.languageProvider.settings?.[name].button?.(event);
199 | });
200 | }
201 |
202 | async _updateObject(event, formData) {
203 | let requiresClientReload = false;
204 | let requiresWorldReload = false;
205 | for (let [k, v] of Object.entries(foundry.utils.flattenObject(formData))) {
206 | let s = game.settings.settings.get(`polyglot.${k}`);
207 | let current = game.user.isGM ? game.settings.get(s.namespace, s.key) : game.user.getFlag("polyglot", k);
208 | if (v === current) continue;
209 | requiresClientReload ||= (s.scope !== CONST.SETTING_SCOPES.WORLD) && s.requiresReload;
210 | requiresWorldReload ||= (s.scope === CONST.SETTING_SCOPES.WORLD) && s.requiresReload;
211 | if (game.user.isGM) {
212 | await game.settings.set(s.namespace, s.key, v);
213 | } else {
214 | await game.user.setFlag("polyglot", k, v);
215 | }
216 | }
217 | if (requiresClientReload || requiresWorldReload) {
218 | SettingsConfig.reloadConfirm({ world: requiresWorldReload });
219 | }
220 | }
221 | }
222 |
--------------------------------------------------------------------------------
/src/module/providers/sw5e.js:
--------------------------------------------------------------------------------
1 | import LanguageProvider from "./templates/Base.js";
2 |
3 | export default class sw5eLanguageProvider extends LanguageProvider {
4 | languages = {
5 | basic: {
6 | font: "Celestial",
7 | },
8 | abyssin: {
9 | font: "Barazhad",
10 | },
11 | aleena: {
12 | font: "Jungle Slang",
13 | },
14 | antarian: {
15 | font: "Ar Ciela",
16 | },
17 | anzellan: {
18 | font: "Valmaric",
19 | },
20 | aqualish: {
21 | font: "Floki",
22 | },
23 | arconese: {
24 | font: "Ork Glyphs",
25 | },
26 | ardennian: {
27 | font: "Thorass",
28 | },
29 | arkanian: {
30 | font: "Celestial",
31 | },
32 | balosur: {
33 | font: "Ar Ciela",
34 | },
35 | barabel: {
36 | font: "Dark Eldar",
37 | },
38 | besalisk: {
39 | font: "Barazhad",
40 | },
41 | binary: {
42 | font: "Celestial",
43 | },
44 | bith: {
45 | font: "Skaven",
46 | },
47 | bocce: {
48 | font: "Tuzluca",
49 | },
50 | bothese: {
51 | font: "Infernal",
52 | },
53 | catharese: {
54 | font: "Espruar",
55 | },
56 | cerean: {
57 | font: "Olde Espruar",
58 | },
59 | "chadra-fan": {
60 | font: "Infernal",
61 | },
62 | chagri: {
63 | font: "Ophidian",
64 | },
65 | cheunh: {
66 | font: "Ar Ciela",
67 | },
68 | chevin: {
69 | font: "Eltharin",
70 | },
71 | chironan: {
72 | font: "Saurian",
73 | },
74 | clawdite: {
75 | font: "Reanaarian",
76 | },
77 | codruese: {
78 | font: "Meroitic Demotic",
79 | },
80 | colicoid: {
81 | font: "Thassilonian",
82 | },
83 | dashadi: {
84 | font: "Iokharic",
85 | },
86 | defel: {
87 | font: "Dark Eldar",
88 | },
89 | devaronese: {
90 | font: "Iokharic",
91 | },
92 | dosh: {
93 | font: "Iokharic",
94 | },
95 | draethos: {
96 | font: "Pulsian",
97 | },
98 | durese: {
99 | font: "Reanaarian",
100 | },
101 | dug: {
102 | font: "Qijomi",
103 | },
104 | ewokese: {
105 | font: "Skaven",
106 | },
107 | falleen: {
108 | font: "Tengwar",
109 | },
110 | felucianese: {
111 | font: "Skaven",
112 | },
113 | gamorrese: {
114 | font: "Highschool Runes",
115 | },
116 | gand: {
117 | font: "Reanaarian",
118 | },
119 | geonosian: {
120 | font: "Maras Eye",
121 | },
122 | givin: {
123 | font: "High Drowic",
124 | },
125 | gran: {
126 | font: "Qijomi",
127 | },
128 | gungan: {
129 | font: "Highschool Runes",
130 | },
131 | hapan: {
132 | font: "Valmaric",
133 | },
134 | harchese: {
135 | font: "Thassilonian",
136 | },
137 | herglese: {
138 | font: "Ophidian",
139 | },
140 | honoghran: {
141 | font: "Tuzluca",
142 | },
143 | huttese: {
144 | font: "Thassilonian",
145 | },
146 | iktotchese: {
147 | font: "Iokharic",
148 | },
149 | ithorese: {
150 | font: "Dethek",
151 | },
152 | jawaese: {
153 | font: "Valmaric",
154 | },
155 | kaleesh: {
156 | font: "Infernal",
157 | },
158 | kaminoan: {
159 | font: "Ar Ciela",
160 | },
161 | karkaran: {
162 | font: "Ophidian",
163 | },
164 | keldor: {
165 | font: "Meroitic Demotic",
166 | },
167 | kharan: {
168 | font: "Ar Ciela",
169 | },
170 | killik: {
171 | font: "Thassilonian",
172 | },
173 | klatooinian: {
174 | font: "Thassilonian",
175 | },
176 | kubazian: {
177 | font: "Olde Thorass",
178 | },
179 | kushiban: {
180 | font: "Thorass",
181 | },
182 | kyuzo: {
183 | font: "Barazhad",
184 | },
185 | lannik: {
186 | font: "Semphari",
187 | },
188 | lasat: {
189 | font: "Floki",
190 | },
191 | lowickese: {
192 | font: "Qijomi",
193 | },
194 | lurmese: {
195 | font: "Jungle Slang",
196 | },
197 | mandoa: {
198 | font: "Kargi",
199 | },
200 | miralukese: {
201 | font: "Miroslav Normal",
202 | },
203 | mirialan: {
204 | font: "Miroslav Normal",
205 | },
206 | moncal: {
207 | font: "Dark Eldar",
208 | },
209 | mustafarian: {
210 | font: "Ork Glyphs",
211 | },
212 | muun: {
213 | font: "Tengwar",
214 | },
215 | nautila: {
216 | font: "Ophidian",
217 | },
218 | ortolan: {
219 | font: "Thorass",
220 | },
221 | pakpak: {
222 | font: "Olde Thorass",
223 | },
224 | pyke: {
225 | font: "Meroitic Demotic",
226 | },
227 | quarrenese: {
228 | font: "Ophidian",
229 | },
230 | rakata: {
231 | font: "Iokharic",
232 | },
233 | rattataki: {
234 | font: "Infernal",
235 | },
236 | rishii: {
237 | font: "Maras Eye",
238 | },
239 | rodese: {
240 | font: "Meroitic Demotic",
241 | },
242 | ryn: {
243 | font: "Espruar",
244 | },
245 | selkatha: {
246 | font: "Ophidian",
247 | },
248 | semblan: {
249 | font: "Finger Alphabet",
250 | },
251 | shistavanen: {
252 | font: "Pulsian",
253 | },
254 | shyriiwook: {
255 | font: "Olde Espruar",
256 | },
257 | sith: {
258 | font: "High Drowic",
259 | },
260 | squibbian: {
261 | font: "Valmaric",
262 | },
263 | sriluurian: {
264 | font: "Jungle Slang",
265 | },
266 | "ssi-ruuvi": {
267 | font: "Maras Eye",
268 | },
269 | sullustese: {
270 | font: "Highschool Runes",
271 | },
272 | talzzi: {
273 | font: "Olde Thorass",
274 | },
275 | tarasinese: {
276 | font: "Olde Espruar",
277 | },
278 | thisspiasian: {
279 | font: "Ar Ciela",
280 | },
281 | togorese: {
282 | font: "Floki",
283 | },
284 | togruti: {
285 | font: "Pulsian",
286 | },
287 | toydarian: {
288 | font: "Espruar",
289 | },
290 | tusken: {
291 | font: "Semphari",
292 | },
293 | "twi'leki": {
294 | font: "Tuzluca",
295 | },
296 | ugnaught: {
297 | font: "Floki",
298 | },
299 | umbaran: {
300 | font: "Jungle Slang",
301 | },
302 | utapese: {
303 | font: "Eltharin",
304 | },
305 | verpine: {
306 | font: "Thassilonian",
307 | },
308 | vong: {
309 | font: "Valmaric",
310 | },
311 | voss: {
312 | font: "Iokharic",
313 | },
314 | yevethan: {
315 | font: "High Drowic",
316 | },
317 | zabraki: {
318 | font: "Maras Eye",
319 | },
320 | zygerrian: {
321 | font: "Floki",
322 | },
323 | };
324 |
325 | languageRarities = ["standard", "exotic"];
326 |
327 | async getLanguages() {
328 | const languagesSetting = game.settings.get("polyglot", "Languages");
329 | const langs = {};
330 | if (this.replaceLanguages) {
331 | CONFIG.SW5E.languages = {};
332 | }
333 | const systemLanguages = CONFIG.SW5E.languages;
334 | const getLang = (key, target) => {
335 | const processLanguage = (label) => {
336 | if (label) {
337 | langs[key] = {
338 | label,
339 | font: languagesSetting[key]?.font || this.languages[key]?.font || this.defaultFont,
340 | rng: languagesSetting[key]?.rng ?? "default",
341 | };
342 | }
343 | };
344 |
345 | if (target[key].children) {
346 | Object.keys(target[key].children).forEach((kkey) => {
347 | getLang(kkey, target[key].children);
348 | });
349 | } else {
350 | processLanguage(game.i18n.localize(target[key]));
351 | }
352 | };
353 | Object.keys(systemLanguages).forEach((key) => {
354 | if (this.languageRarities.includes(key)) {
355 | Object.keys(systemLanguages[key].children).forEach((kkey) => {
356 | getLang(kkey, systemLanguages[key].children);
357 | });
358 | } else {
359 | getLang(key, systemLanguages);
360 | }
361 | });
362 | this.languages = langs;
363 | }
364 |
365 | getSystemDefaultLanguage() {
366 | return "basic";
367 | }
368 | }
369 |
--------------------------------------------------------------------------------
/src/lang/fi.json:
--------------------------------------------------------------------------------
1 | {
2 | "POLYGLOT": {
3 | "LanguageSettings": "Kielten asetukset",
4 | "ChatSettings": "Keskusteluasetukset",
5 | "CustomLanguages.title": "Mukautetut kielet",
6 | "ComprehendLanguages.title": "Kaikkitietävä kieli",
7 | "ComprehendLanguages.hint": "Aseta kieli, jonka puhuja ymmärtää kaikkia muita kieliä, mutta jota ei voi puhua eikä kirjoittaa.",
8 | "directory": {
9 | "name": "Mukautettu fonttikansio",
10 | ".hint": "Valitse fonttitiedostoja sisältävä kansio, joka ei ole modules-kansiossa."
11 | },
12 | "source": {
13 | "s3": "S3",
14 | "forgevtt": "Forge"
15 | },
16 | "Truespeech.title": "Kaikkipuheen kieli",
17 | "JournalHighlight.title": "Korostuksen peitto (%)",
18 | "JournalHighlight.hint": "Määrittää muistiinpanon fonttien päälle tulevan korostuksen peiton.",
19 | "logographicalFontToggle.title": "Logografiset fontit",
20 | "logographicalFontToggle.hint": "Puolittaa logografisia fontteja (esim. japanilaiset, kiinalaiset merkit) käyttävien lauseiden pituuden.",
21 | "DefaultLanguage.title": "Oletuskieli",
22 | "DefaultLanguage.hint": "Valittavan oletuskielen nimi. Pidä tyhjänä, jos haluat käyttää järjestelmän oletusarvoa.",
23 | "ReplaceLanguages.title": "Korvaa järjestelmän kielet",
24 | "ScrambleGM.title": "PJ näkee sekoitetut viestit",
25 | "ScrambleGM.hint": "Älä käännä tekstiä PJ:lle (katso maapallon väristä, mitä pelinappula ymmärtää). Vaatii uudelleenlataamisen.",
26 | "Generic": {
27 | "Language": "Kieli"
28 | },
29 | "enableAllFonts": {
30 | "choices": {
31 | "0": "Ei mitään",
32 | "2": "Ytimen ylimääräiset fontit",
33 | "3": "Molemmat",
34 | "1": "Polyglot fontit"
35 | },
36 | "title": "Lisää Foundryn fontteja {settingMenuLabel} asetuksiin",
37 | "hint": "Lisää Foundryn fontteja kohtiin {setting1} ja {setting2}."
38 | },
39 | "RandomizeRunesOptions": {
40 | "a": "Oletus",
41 | "b": "Uniikit fraasit",
42 | "c": "Ei mitään ⚠️"
43 | },
44 | "ExportFonts.title": "Lisää Polyglotin fontit ytimeen",
45 | "ExportFonts.hint": "Lisää Polyglotin fontit ytimen {settingMenuLabel} -valikkoon. Kytke asetus pois päältä poistaaksesi kaikki Polyglotin fontit valikosta.",
46 | "DisplayTranslated.title": "Näytön käännökset",
47 | "DefaultAlphabet": "Oletusaakkosto",
48 | "FontSettings": "Fonttien asetukset",
49 | "Languages.title": "Kielet",
50 | "Font": "Fontti",
51 | "Fonts": "Fontit",
52 | "FontSize": "Fonttikoko (%)",
53 | "CustomLanguages.hint": "Kirjoita luettelo järjestelmään lisättävistä mukautetuista kielistä. Ne on erotettava toisistaan pilkuilla tai puolipisteillä.",
54 | "Truespeech.hint": "Aseta kieli, jonka puhuja ymmärtää kaikkia puhuttuja kieliä (ei voi lukea muistiinpanoja) ja jota kaikki olennot ymmärtävät.",
55 | "UESRPG.Language": "Kieli",
56 | "ReplaceLanguages.hint": "Korvaa järjestelmän oletuskielet mukauttamallasi kielillä. Luettelon ensimmäisestä kielestä tulee uusi oletuskieli.",
57 | "RandomizeRunes.hint": "Tämä määrittää, minkä tyyppistä satunnaislukugeneraattoria käytetään fraasin luomiseen. ⚠️ Vaihtoehto \"Ei mitään\" tukee vain aakkosnumeerisia merkkejä (ei aksentteja).",
58 | "SWADE": {
59 | "LanguageSkills": "Kieli",
60 | "AdditionalLanguageStat": {
61 | "hint": "On mahdollista kohdistaa lisäominaisuuteen (joka asetetaan SWADE Settings Configuratorissa). Sinun on syötettävä Stat-avain (merkkikokoriippuvainen). Huomaa, että tämä asetus ohittaa asetuksen {setting}.",
62 | "title": "Kielen Stat-avain"
63 | },
64 | "AdditionalLiterateStat": {
65 | "title": "Lukutaidon Stat-avain",
66 | "hint": "Muistiinpanoja on mahdollista rajoittaa lisäämällä lisäominaisuus. Sinun on kirjoitettava Stat-avain (merkkikokoriippuvainen). Tämä asetus on ei riipu asetuksesta {setting}."
67 | }
68 | },
69 | "WFRP4E": {
70 | "LanguageSkills": "Kieli"
71 | },
72 | "DND5E": {
73 | "SpecialLanguages.title": "Korvaa erikoiset kielet",
74 | "SpecialLanguages.hint": "Kielen nimi, joka korvaa \"kielet\" kuten \"kaikki kielet, jotka se osasi elämässään\"."
75 | },
76 | "COC7": {
77 | "LanguageSpec": "Kieli",
78 | "LanguageOwn": "Kieli",
79 | "LanguageAny": "Kieli",
80 | "LanguageOther": "Kieli"
81 | },
82 | "DisplayTranslated.hint": "Näytä alkuperäinen teksti ja käännös sen alapuolella keskusteluikkunassa käännetyille kielille.",
83 | "HideTranslation.title": "Piilota ilmaisimet pelaajilta",
84 | "AllowOOCOptions": {
85 | "b": "Vain PJ",
86 | "c": "Vain pelaajat",
87 | "d": "Ei mitään",
88 | "a": "Kaikki"
89 | },
90 | "LanguageProvider": {
91 | "choices": {
92 | "module": "[Moduuli] {name}",
93 | "native": "Yleinen",
94 | "system": "[Järjestelmä] {name}"
95 | },
96 | "name": "Kieliasetusten tarjoaja",
97 | "hint": "Valitse, kuka tarjoaa kielitietoja aakkosista ja kielistä. Pelijärjestelmät ja asennetut moduulit voivat tarjota lisää kielipalvelujen tarjoajia. Alla olevat vaihtoehdot riippuvat tässä valitusta kielipalveluntarjoajasta. ⚠️ Jos vaihdat palveluntarjoajaa, sinun on tallennettava ja avattava nämä asetukset uudelleen."
98 | },
99 | "LanguageRegex": {
100 | "title": "Kielen RegEx",
101 | "hint": "Tällä voit vaihtaa esineissä käytetyn termin \"Kieli\" joksikin muuksi, kuten \"Puhe\"."
102 | },
103 | "LanguageLabel": "Kieli",
104 | "AlphabetLabel": "Aakkosto",
105 | "LatinAlphabet": "Latinalaiset aakkoset",
106 | "HideTranslation.hint": "Piilottaa maapallon ja Käännetty kielestä -tekstin pelaajille lähetetyistä keskusteluviesteistä. Hyödyllinen silloin, kun et halua näyttää pelaajille, mitä kieltä puhut. Vaatii uudelleenlatauksen.",
107 | "Languages.hint": "Muuttaa kielissä käytettävää aakkostoa.",
108 | "TranslatedFrom": "Käännetty kielestä ",
109 | "Translation": "Käännös",
110 | "AllowOOC.hint": "Valitse, minkä käyttäjien viestit salataan. PUP = pelin ulkopuolinen puhe.",
111 | "AllowOOC.title": "Salaa PUP-viestit",
112 | "GeneralSettings": "Yleiset asetukset",
113 | "languageDataPath": {
114 | "hint": "Jos järjestelmässäsi on asetettuja kieliä hahmojen tietoihin ja niitä ei ladata oikein, se saattaa käyttää toista resurssipolkua. Syötä resurssipolku oikeaan attribuuttiin (esim. actor.system.languages tai actor.system.speak). Tämä asetus on ensisijainen {setting}-asetukseen nähden. Vaatii uudelleenlatauksen.",
115 | "title": "Kielen resurssipolku"
116 | },
117 | "RuneRegex": {
118 | "hint": "Jättää muut kuin aakkosnumeeriset merkit (esim. !,.;:?#$\"') huomioimatta satunnaistamisessa. Tämä saattaa aiheuttaa sen, että jotkin näistä merkeistä näkyvät neliönä (□) joissakin fonteissa.",
119 | "title": "Satunnaista vain aakkosnumeeriset merkit"
120 | },
121 | "General": "Yleinen",
122 | "Omniglot": {
123 | "title": "Kaikkikielen kieli",
124 | "hint": "Aseta kieli, jonka puhuja ymmärtää ja puhuu kaikkia muita kieliä."
125 | },
126 | "IgnoreJournalFontSize": {
127 | "hint": "Jättää huomiotta Polyglotin fonttien koon muistiinpanoissa, jolloin niiden koko on sama kuin normaalin tekstin. Hyödyllinen silloin, kun muistiinpanon muotoilulla on merkitystä.",
128 | "title": "Käytä tavallista fonttikokoa"
129 | },
130 | "JournalHighlightColor": {
131 | "hint": "Määrittää muistiinpanon fonttien päälle tulevan korostuksen peiton.",
132 | "title": "Korostusväri"
133 | },
134 | "literacyDataPath": {
135 | "title": "Lukutaidon resurssipolku",
136 | "hint": "Sama kuin asetus {setting}, mutta muistiinpanojen lukemista varten. Tämä asetus edellyttää asetusta {setting}. Vaatii uudelleenlatauksen."
137 | },
138 | "RandomizeRunes.title": "Satunnaista riimut",
139 | "ToggleRunes": "Vaihda riimut päälle/pois",
140 | "Runes": "Riimut",
141 | "AlphabeticOnly": "Vain aakkoselliset",
142 | "Logographical": "Logografinen"
143 | }
144 | }
145 |
--------------------------------------------------------------------------------