├── assets
├── i18n
│ ├── es
│ │ └── translation.json
│ └── en
│ │ └── translation.json
└── bitmapfonts
│ ├── iceicebaby.png
│ ├── helvetica_regular.png
│ ├── iceicebaby.xml
│ └── helvetica_regular.xml
├── test
├── README.md
├── entry.ts
└── com
│ └── koreez
│ └── plugin
│ └── plugin.test.ts
├── static
├── assets
│ ├── i18n
│ │ ├── en
│ │ │ └── translation.json
│ │ └── es
│ │ │ └── translation.json
│ └── bitmapfonts
│ │ ├── helvetica_regular.png
│ │ └── helvetica_regular.xml
├── styles
│ └── main.css
├── index.html
└── manifest.json
├── src
├── com
│ └── koreez
│ │ └── plugin
│ │ ├── i18n
│ │ ├── I18nScene.ts
│ │ ├── textExtensions.ts
│ │ └── Ii18n.ts
│ │ └── I18nPlugin.ts
└── index.ts
├── CHANGELOG.md
├── .prettierrc
├── tslint.test.json
├── tsconfig.test.json
├── .gitignore
├── .publishrc
├── .editorconfig
├── config
├── .eslintrc.js
├── webpack.parts.config.js
└── webpack.config.js
├── .npmignore
├── .travis.yml
├── tsconfig.json
├── LICENSE
├── .istanbul.yml
├── .github
├── ISSUE_TEMPLATE.md
└── PULL_REQUEST_TEMPLATE.md
├── webpack.example.config.js
├── CONTRIBUTING.md
├── tslint.json
├── example
└── index.ts
├── webpack.config.js
├── karma.conf.js
├── CODE_OF_CONDUCT.md
├── package.json
└── README.md
/assets/i18n/es/translation.json:
--------------------------------------------------------------------------------
1 | {
2 | "hello": "Hola",
3 | "world": "Mundo"
4 | }
5 |
--------------------------------------------------------------------------------
/test/README.md:
--------------------------------------------------------------------------------
1 | # Plugin Testing
2 |
3 | Unit tests are written using Mocha, Chai and Sinon.
--------------------------------------------------------------------------------
/static/assets/i18n/en/translation.json:
--------------------------------------------------------------------------------
1 | {
2 | "hello": "Hello",
3 | "world": "World"
4 | }
5 |
--------------------------------------------------------------------------------
/static/assets/i18n/es/translation.json:
--------------------------------------------------------------------------------
1 | {
2 | "hello": "Hola",
3 | "world": "Mundo"
4 | }
5 |
--------------------------------------------------------------------------------
/assets/bitmapfonts/iceicebaby.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/koreezgames/phaser3-i18n-plugin/HEAD/assets/bitmapfonts/iceicebaby.png
--------------------------------------------------------------------------------
/assets/bitmapfonts/helvetica_regular.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/koreezgames/phaser3-i18n-plugin/HEAD/assets/bitmapfonts/helvetica_regular.png
--------------------------------------------------------------------------------
/assets/i18n/en/translation.json:
--------------------------------------------------------------------------------
1 | {
2 | "hello": "Hello",
3 | "world": "World",
4 | "interpolations": "Interpolations: {{0}}"
5 | }
6 |
--------------------------------------------------------------------------------
/src/com/koreez/plugin/i18n/I18nScene.ts:
--------------------------------------------------------------------------------
1 | import { Ii18n } from "./Ii18n";
2 |
3 | export interface I18nScene extends Phaser.Scene {
4 | i18n: Ii18n;
5 | }
6 |
--------------------------------------------------------------------------------
/static/assets/bitmapfonts/helvetica_regular.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/koreezgames/phaser3-i18n-plugin/HEAD/static/assets/bitmapfonts/helvetica_regular.png
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Phaser3 i18n Plugin:
2 |
3 | ## Phaser3 i18n Plugin 2.0.6
4 |
5 | ### v2.0.6
6 |
7 | - fixed dynamic bitmap text bug
8 |
9 | ### v2.0.5
10 |
11 | - added i18next export
12 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 140,
3 | "tabWidth": 4,
4 | "useTabs": false,
5 | "semi": true,
6 | "singleQuote": false,
7 | "trailingComma": "none",
8 | "bracketSpacing": true
9 | }
10 |
--------------------------------------------------------------------------------
/test/entry.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | import "bluebird/js/browser/bluebird";
5 | import "es6-map/implement";
6 | import "es6-symbol/implement";
7 |
--------------------------------------------------------------------------------
/tslint.test.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "./tslint.json"
4 | ],
5 | "rules": {
6 | "no-implicit-dependencies": false,
7 | "no-reference": false,
8 | "no-submodule-imports": false
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/tsconfig.test.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "lib-test"
5 | },
6 | "include": ["./src/**/*.ts", "./test/**/*.ts"],
7 | "files": ["./types/phaser.d.ts"]
8 | }
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .nyc_output
3 | coverage
4 | dist/lib
5 | dist-test
6 | lib
7 | lib-test
8 | node_modules
9 | *.as
10 | *.iml
11 | src/**/*.js
12 | src/**/*.js.map
13 | test/**/*.js
14 | test/**/*.js.map
15 | npm-debug.log
16 | yarn-error.log
17 | .DS_Store
18 |
--------------------------------------------------------------------------------
/static/styles/main.css:
--------------------------------------------------------------------------------
1 | html {
2 | width: 100%;
3 | height: 100%;
4 | margin: 0px;
5 | padding: 0px;
6 | }
7 |
8 | body {
9 | height: inherit;
10 | width: inherit;
11 | margin: 0px;
12 | display: flex;
13 | justify-content: center;
14 | align-items: center;
15 | }
16 |
--------------------------------------------------------------------------------
/static/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Phaser Boilerplate
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.publishrc:
--------------------------------------------------------------------------------
1 | {
2 | "validations": {
3 | "vulnerableDependencies": true,
4 | "uncommittedChanges": true,
5 | "untrackedFiles": true,
6 | "sensitiveData": false,
7 | "branch": "master",
8 | "gitTag": true
9 | },
10 | "confirm": true,
11 | "publishTag": "latest --access public",
12 | "prePublishScript": false,
13 | "postPublishScript": false
14 | }
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | end_of_line = lf
5 | charset = utf-8
6 | trim_trailing_whitespace = true
7 | indent_style = space
8 | indent_size = 4
9 |
10 | [*.{ts}]
11 | indent_style = space
12 | indent_size = 4
13 |
14 | [*.{js,json}]
15 | indent_style = space
16 | indent_size = 2
17 |
18 | [{.codeclimate.yml,.eslintignore,.eslintrc,.istanbul.yml,.publishrc,.travis.yml}]
19 | indent_style = space
20 | indent_size = 2
21 |
--------------------------------------------------------------------------------
/config/.eslintrc.js:
--------------------------------------------------------------------------------
1 | const settings = {
2 | env: {
3 | browser: false,
4 | node: true,
5 | },
6 | extends: 'standard',
7 | rules: {
8 | 'comma-dangle': [
9 | 'error',
10 | {
11 | arrays: 'always-multiline',
12 | objects: 'always-multiline',
13 | imports: 'always-multiline',
14 | exports: 'always-multiline',
15 | functions: 'always-multiline',
16 | },
17 | ],
18 | },
19 | }
20 |
21 | module.exports = settings
22 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | /.idea
2 | /.nyc_output
3 | /.vscode
4 | /coverage
5 | /dist
6 | /dist-test
7 | /docs
8 | /lib-test
9 | /not-ported-extensions
10 | /src
11 | /test
12 | /transpiled-code
13 | /typings
14 | CODE_OF_CONDUCT.md
15 | CONTRIBUTING.md
16 | ISSUE_TEMPLATE.md
17 | PULL_REQUEST_TEMPLATE.md
18 | karma.conf.js
19 | tsconfig.json
20 | tsconfig.test.json
21 | tslint.json
22 | tslint.test.json
23 | webpack.config.js
24 | yarn.lock
25 | .editorconfig
26 | .gitignore
27 | .istanbul.yml
28 | .npmignore
29 | .prettierrc
30 | .publishrc
31 | .travis.yml
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------------
2 | // Copyright (c) 2018 Koreez LLC. All Rights Reserved.
3 | //
4 | // NOTICE: You are permitted to use, modify, and distribute this file
5 | // in accordance with the terms of the license agreement accompanying it.
6 | // ------------------------------------------------------------------------------
7 |
8 | /**
9 | * I18nPlugin
10 | */
11 | import i18next from "i18next";
12 | export { I18nScene } from "./com/koreez/plugin/i18n/I18nScene";
13 | export { I18nPlugin } from "./com/koreez/plugin/I18nPlugin";
14 | export { i18next };
15 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - stable
4 | env:
5 | global:
6 | - CC_TEST_REPORTER_ID=71e455189fdcb3925ba38e620c090f72e7734ab75219b2a39fbaaad0021daab7
7 | before_install:
8 | - export CHROME_BIN=chromium-browser
9 | - export DISPLAY=:99.0
10 | - sh -e /etc/init.d/xvfb start
11 | - yarn config set registry "https://registry.npmjs.org"
12 | - yarn global add greenkeeper-lockfile@1
13 | - yarn global add codeclimate-test-reporter
14 | before_script:
15 | - greenkeeper-lockfile-update
16 | script:
17 | - yarn test
18 | after_script:
19 | - greenkeeper-lockfile-upload
20 | after_success:
21 | - codeclimate-test-reporter < coverage/lcov.info
22 |
--------------------------------------------------------------------------------
/static/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Your Game",
3 | "short_name": "Your Game",
4 | "start_url": "index.html",
5 | "display": "standalone",
6 | "orientation": "landscape",
7 | "icons": [
8 | {
9 | "src": "icon.png",
10 | "sizes": "512x512",
11 | "type": "image/png"
12 | },
13 | {
14 | "src": "launcher-icon-2x.png",
15 | "sizes": "96x96",
16 | "type": "image/png"
17 | },
18 | {
19 | "src": "launcher-icon-3x.png",
20 | "sizes": "144x144",
21 | "type": "image/png"
22 | },
23 | {
24 | "src": "launcher-icon-4x.png",
25 | "sizes": "192x192",
26 | "type": "image/png"
27 | }
28 | ]
29 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "outDir": "lib",
4 | "target": "es5",
5 | "lib": ["es7", "dom"],
6 | "sourceMap": true,
7 | "inlineSources": true,
8 | "module": "commonjs",
9 | "moduleResolution": "node",
10 | "experimentalDecorators": true,
11 | "emitDecoratorMetadata": true,
12 | "removeComments": true,
13 | "strict": false,
14 | "noImplicitAny": true,
15 | "strictNullChecks": false,
16 | "noImplicitThis": false,
17 | "alwaysStrict": true,
18 | "noUnusedLocals": true,
19 | "noUnusedParameters": false,
20 | "noImplicitReturns": true,
21 | "noFallthroughCasesInSwitch": true
22 | },
23 | "include": ["./src/**/*", "./types/**/*", "./plugins/**/*"]
24 | }
25 |
--------------------------------------------------------------------------------
/config/webpack.parts.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack')
2 | const CleanWebpackPlugin = require('clean-webpack-plugin')
3 | const GitRevisionPlugin = require('git-revision-webpack-plugin')
4 |
5 | exports.cleanup = paths => ({
6 | plugins: [
7 | new CleanWebpackPlugin(paths, { root: process.cwd(), verbose: false }),
8 | ],
9 | })
10 |
11 | exports.loadJs = ({ options }) => ({
12 | module: {
13 | rules: [
14 | {
15 | test: /\.ts?$/,
16 | exclude: ['/node_modules/', '/lib/'],
17 | use: [
18 | {
19 | loader: 'ts-loader',
20 | options: options,
21 | },
22 | ],
23 | },
24 | ],
25 | },
26 | })
27 |
28 | exports.sourceMaps = method => ({
29 | devtool: method,
30 | })
31 |
32 | exports.attachRevision = () => ({
33 | plugins: [
34 | new webpack.BannerPlugin({
35 | banner: new GitRevisionPlugin().version(),
36 | }),
37 | ],
38 | })
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Koreez LLC
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.
--------------------------------------------------------------------------------
/.istanbul.yml:
--------------------------------------------------------------------------------
1 | verbose: false
2 | instrumentation:
3 | root: lib
4 | extensions:
5 | - .ts
6 | # default-excludes: true
7 | # excludes: []
8 | # variable: __coverage__
9 | # compact: true
10 | # preserve-comments: false
11 | # complete-copy: false
12 | # save-baseline: false
13 | # baseline-file: ./coverage/coverage-baseline.raw.json
14 | # include-all-sources: false
15 | # include-pid: false
16 | # es-modules: true
17 | # auto-wrap: true
18 | # reporting:
19 | # print: summary
20 | # reports:
21 | # - lcov
22 | # dir: ./coverage
23 | # summarizer: pkg
24 | # report-config: {}
25 | # watermarks:
26 | # statements: [50, 80]
27 | # functions: [50, 80]
28 | # branches: [50, 80]
29 | # lines: [50, 80]
30 | # hooks:
31 | # hook-run-in-context: false
32 | # post-require-hook: null
33 | # handle-sigint: false
34 | # check:
35 | # global:
36 | # statements: 0
37 | # lines: 0
38 | # branches: 0
39 | # functions: 0
40 | # excludes: []
41 | # each:
42 | # statements: 0
43 | # lines: 0
44 | # branches: 0
45 | # functions: 0
46 | # excludes: []
47 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Expected Behavior
4 |
5 |
6 |
7 | ## Current Behavior
8 |
9 |
10 |
11 | ## Possible Solution
12 |
13 |
14 |
15 | ## Steps to Reproduce (for bugs)
16 |
17 |
18 | 1.
19 | 2.
20 | 3.
21 | 4.
22 |
23 | ## Context
24 |
25 |
26 |
27 | ## Your Environment
28 |
29 | * Version used:
30 | * Environment name and version (e.g. Chrome 39, node.js 5.4):
31 | * Operating System and version (desktop or mobile):
32 | * Link to your project:
33 |
34 | # Stack trace
35 |
36 |
--------------------------------------------------------------------------------
/webpack.example.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require("webpack");
2 | const path = require("path");
3 | const HtmlWebpackPlugin = require("html-webpack-plugin");
4 | const ConcatPlugin = require("webpack-concat-plugin");
5 |
6 | const concatPluginConfigGenerator = (name, files) => {
7 | return {
8 | uglify: false,
9 | sourceMap: false,
10 | name: name,
11 | fileName: "[name].js",
12 | filesToConcat: files,
13 | injectType: "none"
14 | };
15 | };
16 |
17 | module.exports = (function(options) {
18 | return {
19 | mode: "development",
20 |
21 | entry: {
22 | main: path.resolve("example/index.ts")
23 | },
24 |
25 | output: {
26 | path: __dirname + "/dist",
27 | filename: "bundle.js"
28 | },
29 |
30 | devtool: "source-map",
31 |
32 | module: {
33 | rules: [{ test: /\.ts$/, loader: "ts-loader" }]
34 | },
35 |
36 | plugins: [
37 | new HtmlWebpackPlugin({
38 | template: path.resolve("static/index.html"),
39 | inject: false
40 | }),
41 |
42 | new ConcatPlugin(concatPluginConfigGenerator("phaser", [path.resolve(__dirname, "./node_modules/phaser/dist/phaser.js")]))
43 | ],
44 |
45 | resolve: {
46 | extensions: [".ts", ".js", ".json"]
47 | }
48 | };
49 | })();
50 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to phaser3-i18n-plugin
2 |
3 | ## Setup
4 |
5 | 1 - Clone your fork of the repository:
6 |
7 | ```
8 | $ git clone https://github.com/koreezgames/phaser3-i18n-plugin.git
9 | ```
10 |
11 | 2 - Install npm dependencies using yarn:
12 |
13 | ```
14 | $ yarn install
15 | ```
16 |
17 | 3 - Run start process
18 |
19 | ```
20 | $ yarn run start
21 | ```
22 |
23 | 4 - Run test process
24 |
25 | ```
26 | $ yarn test
27 | ```
28 |
29 | ## Guidelines
30 |
31 | - Please try to [combine multiple commits before
32 | pushing](http://stackoverflow.com/questions/6934752/combining-multiple-commits-before-pushing-in-git).
33 |
34 | - Please use `TDD` when fixing bugs. This means that you should write a unit
35 | test that fails because it reproduces the issue, then fix the issue and finally run
36 | the test to ensure that the issue has been resolved. This helps us to prevent
37 | fixed bugs from happening again in the future.
38 |
39 | - Always format your code using `yarn run autoformat`.
40 |
41 | - Please keep the test coverage at 100%. Write additional unit test if
42 | necessary.
43 |
44 | - Please create an issue before sending a PR if your commit is going to change the
45 | public interface of the package or it includes significant architecture
46 | changes.
47 |
48 | - Feel free to ask for help from other members of the Koreez team via the
49 | [github issues](https://github.com/koreezgames/phaser3-i18n-plugin/issues).
50 |
--------------------------------------------------------------------------------
/config/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const merge = require('webpack-merge')
3 | const packagejson = require('../package.json')
4 | const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin')
5 |
6 | const parts = require('./webpack.parts.config')
7 |
8 | let main = packagejson.main
9 | main = main.replace(/^.*[\\/]/, '')
10 |
11 | const libraryName = main.substring(0, main.lastIndexOf('.'))
12 |
13 | const paths = {
14 | base: path.resolve('src'),
15 | app: path.resolve('src/index.ts'),
16 | dist: path.resolve('lib'),
17 | }
18 |
19 | const libConfig = merge([
20 | {
21 | target: 'web',
22 | context: paths.base,
23 | entry: {
24 | app: paths.app,
25 | },
26 | output: {
27 | library: libraryName,
28 | filename: libraryName + '.js',
29 | libraryExport: 'default',
30 | libraryTarget: 'umd',
31 | umdNamedDefine: true,
32 | path: paths.dist,
33 | },
34 | externals: {
35 | phaser: 'phaser',
36 | },
37 | resolve: {
38 | modules: [path.resolve('./node_modules'), path.resolve('./src')],
39 | extensions: ['.json', '.js', '.ts'],
40 | },
41 | plugins: [new CaseSensitivePathsPlugin()],
42 | },
43 |
44 | parts.loadJs({}),
45 |
46 | parts.sourceMaps('source-map'),
47 |
48 | parts.cleanup([paths.dist]),
49 |
50 | parts.attachRevision(),
51 | ])
52 |
53 | module.exports = env => {
54 | const config = merge(libConfig)
55 |
56 | return config
57 | }
58 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["tslint:latest", "tslint-config-prettier"],
3 | "rules": {
4 | "ban-types": [false],
5 | "class-name": true,
6 | "comment-format": [true, "check-space"],
7 | "curly": true,
8 | "forin": true,
9 | "label-position": true,
10 | "member-access": true,
11 | "member-ordering": [
12 | true,
13 | {
14 | "order": [
15 | "static-field",
16 | "instance-field",
17 | "constructor",
18 | "public-instance-method",
19 | "protected-instance-method",
20 | "private-instance-method"
21 | ]
22 | }
23 | ],
24 | "no-angle-bracket-type-assertion": false,
25 | "no-arg": true,
26 | "no-bitwise": true,
27 | "no-console": [true, "debug", "info", "time", "timeEnd", "trace"],
28 | "no-construct": true,
29 | "no-debugger": true,
30 | "no-duplicate-variable": true,
31 | "no-empty": false,
32 | "no-eval": true,
33 | "no-inferrable-types": false,
34 | "no-shadowed-variable": true,
35 | "no-string-literal": true,
36 | "no-switch-case-fall-through": false,
37 | "no-this-assignment": false,
38 | "no-unused-expression": true,
39 | "no-use-before-declare": true,
40 | "no-var-keyword": true,
41 | "object-literal-sort-keys": true,
42 | "ordered-imports": false,
43 | "only-arrow-functions": [false],
44 | "prefer-const": false,
45 | "radix": true,
46 | "trailing-comma": [false],
47 | "triple-equals": [true, "allow-null-check"],
48 | "variable-name": false
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Description
4 |
5 |
6 |
7 | ## Related Issue
8 |
9 |
10 |
11 |
12 |
13 |
14 | ## Motivation and Context
15 |
16 |
17 |
18 | ## How Has This Been Tested?
19 |
20 |
21 |
22 |
23 |
24 | ## Types of changes
25 |
26 |
27 |
28 | - [ ] Updated docs / Refactor code / Added a tests case (non-breaking change)
29 | - [ ] Bug fix (non-breaking change which fixes an issue)
30 | - [ ] New feature (non-breaking change which adds functionality)
31 | - [ ] Breaking change (fix or feature that would cause existing functionality to change)
32 |
33 | ## Checklist:
34 |
35 |
36 |
37 |
38 | - [ ] My code follows the code style of this project.
39 | - [ ] My change requires a change to the documentation.
40 | - [ ] I have updated the documentation accordingly.
41 | - [ ] I have read the **CONTRIBUTING** document.
42 | - [ ] I have added tests to cover my changes.
43 | - [ ] All new and existing tests passed.
44 |
--------------------------------------------------------------------------------
/example/index.ts:
--------------------------------------------------------------------------------
1 | ///
2 | import "phaser";
3 | import { I18nPlugin } from "../src/com/koreez/plugin/I18nPlugin";
4 |
5 | export default class Game extends Phaser.Game {
6 | public centerX: number;
7 | public centerY: number;
8 | constructor(config: GameConfig) {
9 | super(config);
10 | }
11 | }
12 |
13 | function preload() {
14 | this.load.bitmapFont("helvetica_regular", "assets/bitmapfonts/helvetica_regular.png", "assets/bitmapfonts/helvetica_regular.xml");
15 | this.load.bitmapFont("iceicebaby", "assets/bitmapfonts/iceicebaby.png", "assets/bitmapfonts/iceicebaby.xml");
16 | }
17 |
18 | function create() {
19 | console.log("create");
20 | this.i18n.initialize(
21 | {
22 | debug: false,
23 | fallbackLng: "en",
24 | loadPath: "assets/i18n/{{lng}}/{{ns}}.json"
25 | },
26 | () => {
27 | this.make.text({ x: 0, y: 0, text: "hello" }, true);
28 | this.add.text(60, 0, "world");
29 | this.add.text(60, 60, "interpolations", null, { 0: "is working" });
30 | this.add.bitmapText(100, 100, "helvetica_regular", "hello", 50);
31 | this.add.dynamicBitmapText(100, 200, "iceicebaby", "hello", 50);
32 | setTimeout(() => {
33 | this.i18n.changeLanguage("es");
34 | }, 5000);
35 | }
36 | );
37 | }
38 |
39 | document.onreadystatechange = () => {
40 | if (document.readyState === "complete") {
41 | const config = {
42 | height: 600,
43 | plugins: {
44 | scene: [
45 | {
46 | key: "i18nPlugin",
47 | mapping: "i18n",
48 | plugin: I18nPlugin
49 | }
50 | ]
51 | },
52 | scene: {
53 | create,
54 | preload
55 | },
56 | type: Phaser.AUTO,
57 | width: 400
58 | };
59 | (window as any).game = new Game(config);
60 | }
61 | };
62 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require("webpack");
2 | const path = require("path");
3 | const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
4 |
5 | module.exports = env => {
6 | if (!env) env = { production: false, karma: false };
7 |
8 | let mode = env.production ? "production" : "development";
9 | let tsconfig = !env.karma ? "tsconfig.json" : "tsconfig.test.json";
10 | let output = env.production ? "dist" : "dist-test";
11 | let filename = env.production ? "i18n.min.js" : "i18n.js";
12 |
13 | return {
14 | mode: mode,
15 |
16 | entry: {
17 | main: path.join(__dirname, "src/index.ts")
18 | },
19 |
20 | output: {
21 | path: path.join(__dirname, output),
22 | filename: filename,
23 |
24 | libraryTarget: "var",
25 | library: "phaser3i18n"
26 | },
27 |
28 | devtool: env.production ? undefined : "inline-source-map",
29 |
30 | module: {
31 | rules: [
32 | {
33 | test: /\.ts$/,
34 | loader: "ts-loader?configFile=" + tsconfig
35 | },
36 | {
37 | test: env.production /* disable this loader for production builds */ ? /^$/ : /^(.(?!\.test))*\.ts$/,
38 | loader: "istanbul-instrumenter-loader",
39 | query: {
40 | embedSource: true
41 | },
42 | enforce: "post"
43 | }
44 | ]
45 | },
46 |
47 | plugins: env.production ? [] : [new webpack.SourceMapDevToolPlugin({ test: /\.ts$/i })],
48 |
49 | optimization: env.production
50 | ? {
51 | concatenateModules: true,
52 | minimize: true,
53 | minimizer: [
54 | new UglifyJsPlugin({
55 | cache: true,
56 | parallel: 4,
57 | uglifyOptions: {
58 | output: {
59 | comments: false
60 | }
61 | }
62 | })
63 | ]
64 | }
65 | : {},
66 | resolve: {
67 | extensions: [".ts", ".js", ".json"]
68 | }
69 | };
70 | };
71 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | process.env.TEST = true;
2 | process.env.NODE_ENV = "test";
3 |
4 | const webpackConfig = require("./webpack.config.js")({ production: false, karma: true });
5 |
6 | delete webpackConfig.entry;
7 |
8 | module.exports = config => {
9 | var configuration = {
10 | captureConsole: true,
11 | // proxies: {
12 | // "/static/assets/i18n/en/translation.json": "/assets/i18n/en/translation.json",
13 | // "/static/assets/i18n/es/translation.json": "/assets/i18n/es/translation.json"
14 | // },
15 | basePath: "",
16 | frameworks: ["mocha", "chai", "sinon", "es6-shim"],
17 | files: [
18 | { pattern: "node_modules/bluebird/js/browser/bluebird.js", include: true },
19 | { pattern: "node_modules/phaser/dist/phaser.js", include: true },
20 | { pattern: "./test/**/**/**.test.ts", include: true },
21 | { pattern: "**/*.map", served: true, included: false, watched: true },
22 | { pattern: "assets/**/*.json", watched: false, included: false, served: true }
23 | ],
24 | preprocessors: {
25 | "./**/**/**/**.ts": ["sourcemap"],
26 | "./test/**/**/**.test.ts": ["webpack"]
27 | },
28 | webpack: webpackConfig,
29 | webpackMiddleware: {
30 | noInfo: true
31 | },
32 | plugins: [
33 | "karma-webpack",
34 | "karma-sourcemap-writer",
35 | "karma-sourcemap-loader",
36 | "karma-remap-istanbul",
37 | "karma-mocha-reporter",
38 | "karma-mocha",
39 | "karma-chai",
40 | "karma-sinon",
41 | "karma-es6-shim",
42 | "karma-coverage-istanbul-reporter"
43 | ],
44 | reporters: config.singleRun ? ["dots", "mocha", "coverage-istanbul"] : ["dots", "mocha"],
45 | coverageIstanbulReporter: {
46 | reports: ["html", "lcov", "lcovonly", "text-summary"],
47 | dir: "coverage",
48 | fixWebpackSourcePaths: true,
49 | "report-config": {
50 | html: {
51 | subdir: "html-report"
52 | }
53 | }
54 | },
55 | port: 9876,
56 | colors: true,
57 | logLevel: config.LOG_INFO,
58 | autoWatch: true,
59 | browsers: []
60 | };
61 |
62 | if (process.env.TRAVIS) {
63 | configuration.browsers.push("PhantomJS");
64 | configuration.plugins.push("karma-phantomjs-launcher");
65 | } else {
66 | configuration.browsers.push("PhantomJS");
67 | configuration.plugins.push("karma-phantomjs-launcher");
68 | }
69 |
70 | config.set(configuration);
71 | };
72 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | - Using welcoming and inclusive language
12 | - Being respectful of differing viewpoints and experiences
13 | - Gracefully accepting constructive criticism
14 | - Focusing on what is best for the community
15 | - Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | - The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | - Trolling, insulting/derogatory comments, and personal or political attacks
21 | - Public or private harassment
22 | - Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | - Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hello@koreez.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44 |
45 | [homepage]: http://contributor-covenant.org
46 | [version]: http://contributor-covenant.org/version/1/4/
47 |
--------------------------------------------------------------------------------
/test/com/koreez/plugin/plugin.test.ts:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------------
2 | // Copyright (c) 2018 Koreez LLC. All Rights Reserved.
3 | //
4 | // NOTICE: You are permitted to use, modify, and distribute this file
5 | // in accordance with the terms of the license agreement accompanying it.
6 | // ------------------------------------------------------------------------------
7 |
8 | import { expect } from "chai";
9 | import { i18next } from "../../../../src/";
10 | import { I18nPlugin } from "../../../../src/com/koreez/plugin/I18nPlugin";
11 | import "../../../entry";
12 |
13 | describe("i18n Plugin", () => {
14 | it("plugin_is_properly_installing", done => {
15 | const config = {
16 | banner: false,
17 | height: 10,
18 | plugins: {
19 | scene: [
20 | {
21 | key: "plugin_is_properly_installing",
22 | mapping: "i18n",
23 | plugin: I18nPlugin,
24 | start: true
25 | }
26 | ]
27 | },
28 | scene: {
29 | create
30 | },
31 | type: Phaser.AUTO,
32 | width: 10
33 | };
34 | function create() {
35 | expect(this.i18n).instanceOf(I18nPlugin);
36 | done();
37 | }
38 | (window as any).game = new Phaser.Game(config);
39 | });
40 |
41 | it("plugin_is_properly_working", done => {
42 | const config = {
43 | banner: false,
44 | height: 10,
45 | plugins: {
46 | scene: [
47 | {
48 | key: "plugin_is_properly_working",
49 | mapping: "i18n",
50 | plugin: I18nPlugin
51 | }
52 | ]
53 | },
54 | scene: {
55 | create
56 | },
57 | type: Phaser.AUTO,
58 | width: 10
59 | };
60 | function create() {
61 | this.i18n.initialize(
62 | {
63 | debug: false,
64 | fallbackLng: "en",
65 | loadPath: "base/assets/i18n/{{lng}}/{{ns}}.json"
66 | },
67 | () => {
68 | const textObject = this.add.text(0, 0, "hello");
69 | expect(textObject.text).equal("Hello");
70 | this.i18n.on("languageChanged", () => {
71 | expect(textObject.text).equal("Hola");
72 | done();
73 | });
74 | this.i18n.changeLanguage("es");
75 | }
76 | );
77 | }
78 | (window as any).game = new Phaser.Game(config);
79 | });
80 |
81 | it("plugin_i18next", done => {
82 | const config = {
83 | banner: false,
84 | height: 10,
85 | plugins: {
86 | scene: [
87 | {
88 | key: "plugin_i18next",
89 | mapping: "i18n",
90 | plugin: I18nPlugin
91 | }
92 | ]
93 | },
94 | scene: {
95 | create
96 | },
97 | type: Phaser.AUTO,
98 | width: 10
99 | };
100 | function create() {
101 | this.i18n.initialize(
102 | {
103 | debug: false,
104 | fallbackLng: "en",
105 | loadPath: "base/assets/i18n/{{lng}}/{{ns}}.json"
106 | },
107 | () => {
108 | const textObject = this.add.text(0, 0, "hello");
109 | expect(textObject.text).equal("Hello");
110 | expect(i18next.t("hello")).equal("Hello");
111 | this.i18n.on("languageChanged", () => {
112 | expect(textObject.text).equal("Hola");
113 | expect(i18next.t("hello")).equal("Hola");
114 | done();
115 | });
116 | this.i18n.changeLanguage("es");
117 | }
118 | );
119 | }
120 | (window as any).game = new Phaser.Game(config);
121 | });
122 | });
123 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@koreez/phaser3-i18n",
3 | "version": "2.0.6",
4 | "description": "Internationalization for phaser done right. Using the i18next i18n ecosystem.",
5 | "main": "lib/index.js",
6 | "typings": "lib/index.d.ts",
7 | "scripts": {
8 | "start": "webpack-dev-server --config ./webpack.example.config.js",
9 | "test": "karma start --single-run",
10 | "mocha": "mocha test/**/*.test.ts --require ts-node/register",
11 | "autoformat": "prettier --config .prettierrc --write {src,test}{/,/**/}{*,*.test}.ts",
12 | "tslint-check:src": "tslint-config-prettier-check ./tslint.json",
13 | "tslint-check:test": "tslint-config-prettier-check ./tslint.test.json",
14 | "tslint:src": "tslint --project tsconfig.json",
15 | "tslint:test": "tslint --config tslint.test.json --project tsconfig.test.json",
16 | "tslint": "npm run tslint-check:src && npm run tslint-check:test && npm run tslint:src && npm run tslint:test",
17 | "clean-up": "rimraf .nyc_output && rimraf coverage && rimraf lib && rimraf lib-test && rimraf dist-test",
18 | "compile:src": "tsc -d --importHelpers",
19 | "compile:test": "tsc -p tsconfig.test.json -d --importHelpers",
20 | "dev": "webpack",
21 | "build": "webpack --env.production",
22 | "prepare": "npm run clean-up && npm run compile:src",
23 | "prepublishOnly": "publish-please guard",
24 | "publish-please": "npm run tslint && npm run autoformat && npm run clean-up && npm run test && publish-please"
25 | },
26 | "repository": {
27 | "type": "git",
28 | "url": "git@github.com:koreezgames/phaser3-i18n-plugin.git"
29 | },
30 | "publishConfig": {
31 | "registry": "https://registry.npmjs.org"
32 | },
33 | "keywords": [
34 | "Phaser3",
35 | "Phaser",
36 | "internationalization",
37 | "localization",
38 | "i18next",
39 | "i18n"
40 | ],
41 | "author": "Koreez LLC",
42 | "contributors": [
43 | "Sargis Sargsyan "
44 | ],
45 | "license": "MIT",
46 | "bugs": {
47 | "url": "https://github.com/koreezgames/phaser3-i18n-plugin/issues"
48 | },
49 | "homepage": "https://github.com/koreezgames/phaser3-i18n-plugin#readme",
50 | "dependencies": {
51 | "i18next": "^15.0.2",
52 | "i18next-xhr-backend": "^2.0.0"
53 | },
54 | "peerDependencies": {
55 | "phaser": "^3.12.0"
56 | },
57 | "devDependencies": {
58 | "@types/bluebird": "^3.5.25",
59 | "@types/chai": "^4.1.7",
60 | "@types/i18next": "^12.1.0",
61 | "@types/i18next-xhr-backend": "^1.4.1",
62 | "@types/mocha": "^5.2.1",
63 | "@types/sinon": "^7.0.5",
64 | "bluebird": "^3.5.3",
65 | "browserify-versionify": "^1.0.6",
66 | "chai": "^4.2.0",
67 | "es6-map": "^0.1.5",
68 | "es6-symbol": "^3.1.1",
69 | "glslify": "^7.0.0",
70 | "html-webpack-plugin": "^3.2.0",
71 | "imports-loader": "^0.8.0",
72 | "istanbul": "^0.4.5",
73 | "istanbul-instrumenter-loader": "^3.0.1",
74 | "karma": "^4.0.0",
75 | "karma-chai": "^0.1.0",
76 | "karma-chai-sinon": "^0.1.5",
77 | "karma-chrome-launcher": "^2.2.0",
78 | "karma-coverage-istanbul-reporter": "^2.0.4",
79 | "karma-es6-shim": "^1.0.0",
80 | "karma-mocha": "^1.3.0",
81 | "karma-mocha-reporter": "^2.2.5",
82 | "karma-phantomjs-launcher": "^1.0.4",
83 | "karma-remap-istanbul": "^0.6.0",
84 | "karma-sinon": "^1.0.5",
85 | "karma-sourcemap-loader": "^0.3.7",
86 | "karma-sourcemap-writer": "^0.1.2",
87 | "karma-webpack": "^3.0.5",
88 | "mocha": "^5.2.0",
89 | "phaser": "^3.16.2",
90 | "prettier": "^1.16.4",
91 | "publish-please": "^5.4.3",
92 | "remap-istanbul": "^0.13.0",
93 | "rimraf": "^2.6.3",
94 | "sinon": "^7.2.3",
95 | "sinon-chai": "^3.3.0",
96 | "ts-loader": "^5.3.3",
97 | "ts-node": "^8.0.2",
98 | "tslint": "^5.12.1",
99 | "tslint-config-prettier": "^1.18.0",
100 | "typescript": "^3.3.3",
101 | "uglifyjs-webpack-plugin": "^2.1.1",
102 | "webpack": "^4.29.3",
103 | "webpack-cli": "^3.2.3",
104 | "webpack-concat-plugin": "^3.0.0",
105 | "webpack-dev-server": "^3.1.14"
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Phaser3 i18n Plugin
2 |
3 | [](https://github.com/koreezgames/phaser3-i18n-plugin/blob/master/LICENSE)
4 | [](https://travis-ci.org/koreezgames/phaser3-i18n-plugin)
5 | [](https://codebeat.co/projects/github-com-koreezgames-phaser-i18next-master)
6 | [](https://codeclimate.com/github/koreezgames/phaser3-i18n-plugin/test_coverage)
7 | [](https://badge.fury.io/js/%40koreez%2Fphaser3-i18n)
8 | [](https://greenkeeper.io/)
9 | [](https://github.com/prettier/prettier)
10 |
11 | Phaser3 i18n is a plugin for Phaser 3 that allows you to have seamless translations in your game. It uses **[i18next](https://github.com/i18next/i18next)** as it's source for translations management, which is widely adopted by the JS community in other projects as well.
12 |
13 | Key features:
14 |
15 | - Support for translations namespaces
16 | - Simple key/value JSON
17 | - Seamless switching of languages
18 | - No extra function calls for translating strings, directly build into Phaser's Text object
19 |
20 | ## Getting Started
21 |
22 | ### Installation
23 |
24 | [](https://www.npmjs.com/package/@koreez/phaser3-i18n)
25 |
26 | ```shell
27 | $ npm i -g npm
28 | $ npm i --save @koreez/phaser3-i18n
29 | ```
30 |
31 | ## Usage
32 |
33 | ### Import the plugin
34 |
35 | ```javascript
36 | import { I18nPlugin } from "@koreez/phaser3-i18n";
37 | ```
38 |
39 | ### Load the plugin
40 |
41 | You need to load the plugin in your game. This is done just like any other plugin in Phaser 3.
42 | So, to load the plugin, include it in plugins config.
43 |
44 | ```javascript
45 | const config = {
46 | type: Phaser.AUTO,
47 | parent: "phaser-example",
48 | width: 800,
49 | height: 600,
50 | plugins: {
51 | scene: [
52 | {
53 | key: "i18nPlugin",
54 | plugin: I18nPlugin,
55 | mapping: "i18n"
56 | }
57 | ]
58 | },
59 | scene: {
60 | create: create
61 | }
62 | };
63 | ```
64 |
65 | ### Initialize the plugin
66 |
67 | After plugin has been loaded you need to initialize it.
68 |
69 | ```javascript
70 | create () {
71 | this.i18n.initialize(
72 | {
73 | fallbackLng: 'en',
74 | loadPath: 'assets/i18n/{{lng}}/{{ns}}.json',
75 | debug: false,
76 | },
77 | function () {
78 | console.log('I18nPlugin initialized!')
79 | },
80 | )
81 | }
82 | ```
83 |
84 | The plugin will patch _add.text, add.bitmapText and add.dynamicBitmapText / make.text, make.bitmapText and make.dynamicBitmapText_ methods with additional functionality.
85 |
86 | ### Create localized texts
87 |
88 | ```javascript
89 | // x - any
90 | // y - any
91 | // font - bitmap font
92 | // text - should be translation key
93 | // size - font size
94 | // interpolations - interpolation for translation (for example { 0: "value0", 1: "value1" }), note this is not required parameter
95 | this.add.bitmapText(x, y, font, text, size, interpolations);
96 | ```
97 |
98 | ##### **_or via config_**
99 |
100 | ```javascript
101 | var config = {
102 | x: 100,
103 | y: 100,
104 | text: "translationKey",
105 | font: "atari-classic",
106 | size: 64,
107 | interpolations: { 0: "value0", 1: "value1" }
108 | };
109 | this.make.dynamicBitmapText(config);
110 | ```
111 |
112 | ## Manage translations
113 |
114 | When you're all done and set up for translations and have your key value file, next up is starting to translate them. For smaller games this is fairly simple and still manageable by editing your translations in a text file.
115 | But when you start with bigger games and more translations (and translation namespaces) you want to manage your translations better, and maybe even use external translator services.
116 |
117 | Two of those service you could use are [locize](https://locize.com/) and/or [Poeditor](https://poeditor.com). Both these services allow you to online edit key value JSON translations that are used in i18next.
118 | The advantage of using such tools is that it's easier to allow external people work on your translations and they aggregate the statistics of your projects (translation completion, languages managed, etc.)
119 |
120 | ## Credits
121 |
122 | Big thanks to this great repo:
123 |
124 | https://github.com/orange-games/phaser-i18next
125 |
126 | ## License
127 |
128 | [MIT](LICENSE)
129 |
--------------------------------------------------------------------------------
/src/com/koreez/plugin/i18n/textExtensions.ts:
--------------------------------------------------------------------------------
1 | import i18next from "i18next";
2 |
3 | const setText: (value: string) => any = function(value: string): any {
4 | if (value !== this._i18nKey) {
5 | this._i18nKey = value.toString() || "";
6 | }
7 | return this._setText(i18next.t(this._i18nKey, this._interpolations) || "");
8 | };
9 |
10 | const interpolations: any = {
11 | get(): any {
12 | return this._interpolations;
13 | },
14 |
15 | set(value: any): void {
16 | this._interpolations = value;
17 | this.setText(this._i18nKey);
18 | }
19 | };
20 |
21 | const setTranslationParameter: (key: string, value: any) => void = function(key: string, value: any): void {
22 | if (!this._interpolations) {
23 | this._interpolations = {};
24 | }
25 | this._interpolations[key] = value;
26 | this.setText(this._i18nKey);
27 | };
28 |
29 | const clearTranslationParameter: (key: string) => void = function(key: string): void {
30 | if (key in this._interpolations) {
31 | delete this._interpolations[key];
32 | }
33 | this.setText(this._i18nKey);
34 | };
35 |
36 | const commonExtend: (clazz: any, prop: string) => void = (clazz: any, prop: string): void => {
37 | if (clazz.prototype.setText !== setText) {
38 | clazz.prototype._setText = clazz.prototype.setText;
39 |
40 | clazz.prototype.setText = setText;
41 |
42 | Object.defineProperty(clazz.prototype, "interpolations", interpolations);
43 |
44 | clazz.prototype.setTranslationParameter = setTranslationParameter;
45 |
46 | clazz.prototype.clearTranslationParameter = clearTranslationParameter;
47 | }
48 |
49 | const creator: any = Phaser.GameObjects.GameObjectCreator;
50 | if (creator) {
51 | const textCreator: string = creator.prototype[prop];
52 | if (textCreator) {
53 | delete creator.prototype[prop];
54 | creator.register(`_${prop}`, textCreator);
55 | creator.register(prop, function(config: any, addToScene: boolean = false): Phaser.GameObjects.GameObject {
56 | const _text: Phaser.GameObjects.GameObject = this.scene.make[`_${prop}`](config, addToScene);
57 | (_text as any).interpolations = config.interpolations;
58 | return _text;
59 | });
60 | }
61 | }
62 |
63 | const factory: any = Phaser.GameObjects.GameObjectFactory;
64 | if (factory) {
65 | const textFactory: string = factory.prototype[prop];
66 | if (textFactory) {
67 | delete factory.prototype[prop];
68 | factory.register(`_${prop}`, textFactory);
69 | }
70 | }
71 | };
72 |
73 | const textExtensions: any = {
74 | extendText: () => {
75 | const text: any = Phaser.GameObjects.Text;
76 | if (text) {
77 | commonExtend(text, "text");
78 | }
79 | const gameObjectFactory: any = Phaser.GameObjects.GameObjectFactory;
80 | if (!gameObjectFactory) {
81 | return;
82 | }
83 | gameObjectFactory.register("text", function(
84 | x: any,
85 | y: any,
86 | str: any,
87 | style: any,
88 | theInterpolations: any
89 | ): Phaser.GameObjects.GameObject {
90 | const aText: Phaser.GameObjects.GameObject = this.scene.add._text(x, y, str, style);
91 | (aText as any).interpolations = theInterpolations;
92 | return aText;
93 | });
94 | },
95 |
96 | extendBitmapText: () => {
97 | const bitmapText: any = Phaser.GameObjects.BitmapText;
98 | if (bitmapText) {
99 | commonExtend(bitmapText, "bitmapText");
100 | }
101 | const gameObjectFactory: any = Phaser.GameObjects.GameObjectFactory;
102 | if (!gameObjectFactory) {
103 | return;
104 | }
105 | gameObjectFactory.register("bitmapText", function(
106 | x: any,
107 | y: any,
108 | font: any,
109 | str: any,
110 | size: any,
111 | theInterpolations: any
112 | ): Phaser.GameObjects.GameObject {
113 | const aText: Phaser.GameObjects.GameObject = this.scene.add._bitmapText(x, y, font, str, size);
114 | (aText as any).interpolations = theInterpolations;
115 | return aText;
116 | });
117 | },
118 |
119 | extendDynamicBitmapText: () => {
120 | const dynamicBitmapText: any = Phaser.GameObjects.DynamicBitmapText;
121 | if (dynamicBitmapText) {
122 | commonExtend(dynamicBitmapText, "dynamicBitmapText");
123 | }
124 | const gameObjectFactory: any = Phaser.GameObjects.GameObjectFactory;
125 | if (!gameObjectFactory) {
126 | return;
127 | }
128 | gameObjectFactory.register("dynamicBitmapText", function(
129 | x: any,
130 | y: any,
131 | font: any,
132 | str: any,
133 | size: any,
134 | theInterpolations: any
135 | ): Phaser.GameObjects.GameObject {
136 | const aText: Phaser.GameObjects.GameObject = this.scene.add._dynamicBitmapText(x, y, font, str, size);
137 | (aText as any).interpolations = theInterpolations;
138 | return aText;
139 | });
140 | }
141 | };
142 |
143 | export default textExtensions;
144 |
--------------------------------------------------------------------------------
/src/com/koreez/plugin/i18n/Ii18n.ts:
--------------------------------------------------------------------------------
1 | import i18next from "i18next";
2 |
3 | export interface Ii18n {
4 | /**
5 | * List of modules used
6 | */
7 | modules: i18next.Modules;
8 |
9 | /**
10 | * Internal container for all used plugins and implementation details like languageUtils, pluralResolvers, etc.
11 | */
12 | services: i18next.Services;
13 |
14 | /**
15 | * Uses similar args as the t function and returns true if a key exists.
16 | */
17 | exists: i18next.ExistsFunction;
18 |
19 | /**
20 | * Is set to the current detected or set language.
21 | * If you need the primary used language depending on your configuration (whilelist, load) you will prefer using i18next.languages[0].
22 | */
23 | language: string;
24 |
25 | /**
26 | * Is set to an array of language-codes that will be used it order to lookup the translation value.
27 | */
28 | languages: string[];
29 |
30 | /**
31 | * Exposes interpolation.format function added on init.
32 | */
33 | format: i18next.FormatFunction;
34 |
35 | /**
36 | * Current options
37 | */
38 | options: i18next.InitOptions;
39 |
40 | /**
41 | * Is initialized
42 | */
43 | isInitialized: boolean;
44 |
45 | loadResources(callback?: (err: any) => void): void;
46 |
47 | /**
48 | * Returns a t function that defaults to given language or namespace.
49 | * Both params could be arrays of languages or namespaces and will be treated as fallbacks in that case.
50 | * On the returned function you can like in the t function override the languages or namespaces by passing them in options or by prepending namespace.
51 | */
52 | getFixedT(lng: string | string[], ns?: string | string[]): i18next.TFunction;
53 | getFixedT(lng: null, ns: string | string[]): i18next.TFunction;
54 |
55 | /**
56 | * Changes the language. The callback will be called as soon translations were loaded or an error occurs while loading.
57 | * HINT: For easy testing - setting lng to 'cimode' will set t function to always return the key.
58 | */
59 | changeLanguage(lng: string, callback?: i18next.Callback): Promise;
60 |
61 | /**
62 | * Loads additional namespaces not defined in init options.
63 | */
64 | loadNamespaces(ns: string | string[], callback?: i18next.Callback): Promise;
65 |
66 | /**
67 | * Loads additional languages not defined in init options (preload).
68 | */
69 | loadLanguages(lngs: string | string[], callback?: i18next.Callback): Promise;
70 |
71 | /**
72 | * Reloads resources on given state. Optionally you can pass an array of languages and namespaces as params if you don't want to reload all.
73 | */
74 | reloadResources(lngs?: string | string[], ns?: string | string[], callback?: () => void): Promise;
75 | reloadResources(lngs: null, ns: string | string[], callback?: () => void): Promise;
76 |
77 | /**
78 | * Changes the default namespace.
79 | */
80 | setDefaultNamespace(ns: string): void;
81 |
82 | /**
83 | * Returns rtl or ltr depending on languages read direction.
84 | */
85 | dir(lng?: string): "ltr" | "rtl";
86 |
87 | /**
88 | * Will return a new i18next instance.
89 | * Please read the options page for details on configuration options.
90 | * Providing a callback will automatically call init.
91 | * The callback will be called after all translations were loaded or with an error when failed (in case of using a backend).
92 | */
93 | createInstance(options?: i18next.InitOptions, callback?: i18next.Callback): i18next.i18n;
94 |
95 | /**
96 | * Creates a clone of the current instance. Shares store, plugins and initial configuration.
97 | * Can be used to create an instance sharing storage but being independent on set language or namespaces.
98 | */
99 | cloneInstance(options?: i18next.InitOptions, callback?: i18next.Callback): i18next.i18n;
100 |
101 | /**
102 | * Gets fired after initialization.
103 | */
104 | on(event: "initialized", callback: (options: i18next.InitOptions) => void): void;
105 |
106 | /**
107 | * Gets fired on loaded resources.
108 | */
109 | on(event: "loaded", callback: (loaded: boolean) => void): void;
110 |
111 | /**
112 | * Gets fired if loading resources failed.
113 | */
114 | on(event: "failedLoading", callback: (lng: string, ns: string, msg: string) => void): void;
115 |
116 | /**
117 | * Gets fired on accessing a key not existing.
118 | */
119 | on(event: "missingKey", callback: (lngs: string[], namespace: string, key: string, res: string) => void): void;
120 |
121 | /**
122 | * Gets fired when resources got added or removed.
123 | */
124 | on(event: "added" | "removed", callback: (lng: string, ns: string) => void): void;
125 |
126 | /**
127 | * Gets fired when changeLanguage got called.
128 | */
129 | on(event: "languageChanged", callback: (lng: string) => void): void;
130 |
131 | /**
132 | * Event listener
133 | */
134 | on(event: string, listener: (...args: any[]) => void): void;
135 |
136 | /**
137 | * Remove event listener
138 | */
139 | off(event: string, listener: (...args: any[]) => void): void;
140 |
141 | /**
142 | * Gets one value by given key.
143 | */
144 | getResource(lng: string, ns: string, key: string, options?: { keySeparator?: string }): any;
145 |
146 | /**
147 | * Adds one key/value.
148 | */
149 | addResource(lng: string, ns: string, key: string, value: string, options?: { keySeparator?: string; silent?: boolean }): void;
150 |
151 | /**
152 | * Adds multiple key/values.
153 | */
154 | addResources(lng: string, ns: string, resources: any): void;
155 |
156 | /**
157 | * Adds a complete bundle.
158 | * Setting deep param to true will extend existing translations in that file.
159 | * Setting overwrite to true it will overwrite existing translations in that file.
160 | */
161 | addResourceBundle(lng: string, ns: string, resources: any, deep?: boolean, overwrite?: boolean): void;
162 |
163 | /**
164 | * Checks if a resource bundle exists.
165 | */
166 | hasResourceBundle(lng: string, ns: string): boolean;
167 |
168 | /**
169 | * Returns a resource bundle.
170 | */
171 | getResourceBundle(lng: string, ns: string): any;
172 |
173 | /**
174 | * Removes an existing bundle.
175 | */
176 | removeResourceBundle(lng: string, ns: string): void;
177 | }
178 |
--------------------------------------------------------------------------------
/src/com/koreez/plugin/I18nPlugin.ts:
--------------------------------------------------------------------------------
1 | import i18next from "i18next";
2 | import * as XHR from "i18next-xhr-backend";
3 | import { Ii18n } from "./i18n/Ii18n";
4 | import textExtensions from "./i18n/textExtensions";
5 |
6 | export class I18nPlugin extends Phaser.Plugins.ScenePlugin implements Ii18n {
7 | public static staticConstructor(): any {
8 | textExtensions.extendText();
9 |
10 | textExtensions.extendBitmapText();
11 |
12 | textExtensions.extendDynamicBitmapText();
13 | }
14 |
15 | public get modules(): i18next.Modules {
16 | return i18next.modules;
17 | }
18 |
19 | public get services(): i18next.Services {
20 | return i18next.services;
21 | }
22 |
23 | private languageChangedBound: any;
24 |
25 | // Called when the Plugin is booted by the PluginManager.
26 | // If you need to reference other systems in the Scene (like the Loader or DisplayList) then set-up those references now, not in the constructor.
27 | public boot(): void {
28 | const eventEmitter: Phaser.Events.EventEmitter = this.systems.events;
29 |
30 | // Listening to the following events is entirely optional, although we would recommend cleanly shutting down and destroying at least.
31 | // If you don't need any of these events then remove the listeners and the relevant methods too.
32 |
33 | eventEmitter.on("shutdown", this.shutdown, this);
34 | eventEmitter.on("shutdown", this.shutdown, this);
35 | this.languageChangedBound = this.languageChanged.bind(this);
36 | this.on("languageChanged", this.languageChangedBound);
37 | }
38 |
39 | /**
40 | * @param options - Initial options.
41 | * @param callback - will be called after all translations were loaded or with an error when failed (in case of using a backend).
42 | */
43 | public initialize(options: any, callback?: i18next.Callback): void {
44 | i18next.use(new XHR(null, options));
45 | if (options) {
46 | i18next.init(options, callback);
47 | return;
48 | }
49 | i18next.init(callback);
50 | }
51 |
52 | /**
53 | * The use function is there to load additional plugins to i18next.
54 | * For available module see the plugins page and don't forget to read the documentation of the plugin.
55 | */
56 | public use(module: any): i18next.i18n {
57 | return i18next.use(module);
58 | }
59 |
60 | public t<
61 | TResult extends string | object | Array | undefined = string,
62 | TKeys extends string = string,
63 | TValues extends object = object
64 | >(key: TKeys | TKeys[], options?: i18next.TOptions): TResult {
65 | return i18next.t(key, options);
66 | }
67 |
68 | public exists(key: string | string[], options?: i18next.InterpolationOptions): boolean {
69 | return i18next.exists(key, options);
70 | }
71 |
72 | public loadResources(callback?: (err: any) => void): void {
73 | i18next.loadResources(callback);
74 | }
75 |
76 | public createInstance(options?: i18next.InitOptions, callback?: i18next.Callback): i18next.i18n {
77 | return i18next.createInstance(options, callback);
78 | }
79 |
80 | public cloneInstance(options?: i18next.InitOptions, callback?: i18next.Callback): i18next.i18n {
81 | return i18next.cloneInstance(options, callback);
82 | }
83 |
84 | /**
85 | * Returns a t function that defaults to given language or namespace.
86 | * Both params could be arrays of languages or namespaces and will be treated as fallbacks in that case.
87 | * On the returned function you can like in the t function override the languages or namespaces by passing them in options or by prepending namespace.
88 | */
89 | public getFixedT(lng: string | string[], ns?: string | string[]): i18next.TFunction {
90 | return i18next.getFixedT(lng, ns);
91 | }
92 |
93 | /**
94 | * Changes the language. The callback will be called as soon translations were loaded or an error occurs while loading.
95 | * HINT: For easy testing - setting lng to 'cimode' will set t function to always return the key.
96 | */
97 | public changeLanguage(lng: string, callback?: i18next.Callback): Promise {
98 | return i18next.changeLanguage(lng, callback);
99 | }
100 |
101 | /**
102 | * Is set to the current detected or set language.
103 | * If you need the primary used language depending on your configuration (whilelist, load) you will prefer using i18next.languages[0].
104 | */
105 | public get language(): string {
106 | return i18next.language;
107 | }
108 |
109 | /**
110 | * Is set to an array of language-codes that will be used it order to lookup the translation value.
111 | */
112 | public get languages(): string[] {
113 | return i18next.languages;
114 | }
115 |
116 | /**
117 | * Loads additional namespaces not defined in init options.
118 | */
119 | public loadNamespaces(ns: string | string[], callback: i18next.Callback): Promise {
120 | return i18next.loadNamespaces(ns, callback);
121 | }
122 |
123 | /**
124 | * Loads additional languages not defined in init options (preload).
125 | */
126 | public loadLanguages(lngs: string | string[], callback: i18next.Callback): Promise {
127 | return i18next.loadLanguages(lngs, callback);
128 | }
129 |
130 | /**
131 | * Reloads resources on given state. Optionally you can pass an array of languages and namespaces as params if you don't want to reload all.
132 | */
133 | public reloadResources(lngs?: string[], ns?: string[]): Promise {
134 | return i18next.reloadResources(lngs, ns);
135 | }
136 |
137 | /**
138 | * Changes the default namespace.
139 | */
140 | public setDefaultNamespace(ns: string): void {
141 | i18next.setDefaultNamespace(ns);
142 | }
143 |
144 | /**
145 | * Returns rtl or ltr depending on languages read direction.
146 | */
147 | public dir(lng?: string): "ltr" | "rtl" {
148 | return i18next.dir(lng);
149 | }
150 |
151 | /**
152 | * Exposes interpolation.format function added on init.
153 | */
154 | public get format(): i18next.FormatFunction {
155 | return i18next.format;
156 | }
157 |
158 | /**
159 | * Event listener
160 | */
161 | public on(event: string, listener: (...args: any[]) => void): void {
162 | i18next.on(event, listener);
163 | }
164 |
165 | /**
166 | * Remove event listener
167 | */
168 | public off(event: string, listener: (...args: any[]) => void): void {
169 | i18next.off(event, listener);
170 | }
171 |
172 | /**
173 | * Gets one value by given key.
174 | */
175 | public getResource(
176 | lng: string,
177 | ns: string,
178 | key: string,
179 | options?: {
180 | keySeparator?: string;
181 | }
182 | ): any {
183 | i18next.getResource(lng, ns, key, options);
184 | }
185 |
186 | /**
187 | * Adds one key/value.
188 | */
189 | public addResource(
190 | lng: string,
191 | ns: string,
192 | key: string,
193 | value: string,
194 | options?: {
195 | keySeparator?: string;
196 | silent?: boolean;
197 | }
198 | ): void {
199 | i18next.addResource(lng, ns, key, value, options);
200 | }
201 |
202 | /**
203 | * Adds multiple key/values.
204 | */
205 | public addResources(lng: string, ns: string, resources: any): void {
206 | i18next.addResources(lng, ns, resources);
207 | }
208 |
209 | /**
210 | * Adds a complete bundle.
211 | * Setting deep param to true will extend existing translations in that file.
212 | * Setting overwrite to true it will overwrite existing translations in that file.
213 | */
214 | public addResourceBundle(lng: string, ns: string, resources: any, deep?: boolean, overwrite?: boolean): void {
215 | i18next.addResourceBundle(lng, ns, resources, deep, overwrite);
216 | }
217 |
218 | /**
219 | * Checks if a resource bundle exists.
220 | */
221 | public hasResourceBundle(lng: string, ns: string): boolean {
222 | return i18next.hasResourceBundle(lng, ns);
223 | }
224 |
225 | /**
226 | * Returns a resource bundle.
227 | */
228 | public getResourceBundle(lng: string, ns: string): any {
229 | return i18next.getResourceBundle(lng, ns);
230 | }
231 |
232 | /**
233 | * Removes an existing bundle.
234 | */
235 | public removeResourceBundle(lng: string, ns: string): void {
236 | i18next.removeResourceBundle(lng, ns);
237 | }
238 |
239 | /**
240 | * Current options
241 | */
242 | public get options(): i18next.InitOptions {
243 | return i18next.options;
244 | }
245 |
246 | /**
247 | * Is initialized
248 | */
249 | public get isInitialized(): boolean {
250 | return i18next.isInitialized;
251 | }
252 |
253 | public recursiveUpdateText(obj: any): void {
254 | if (
255 | obj instanceof Phaser.GameObjects.Text ||
256 | obj instanceof Phaser.GameObjects.BitmapText ||
257 | obj instanceof Phaser.GameObjects.DynamicBitmapText
258 | ) {
259 | (obj as any).setText((obj as any)._i18nKey);
260 | return;
261 | }
262 | if (obj instanceof Phaser.GameObjects.Container) {
263 | obj.list.forEach((child: any) => {
264 | this.recursiveUpdateText(child);
265 | });
266 | return;
267 | }
268 |
269 | if (obj.children && obj.children.length > 0) {
270 | obj.children.each((child: any) => {
271 | this.recursiveUpdateText(child);
272 | });
273 | }
274 | }
275 |
276 | private shutdown(): void {
277 | this.off("languageChanged", this.languageChangedBound);
278 | const eventEmitter: Phaser.Events.EventEmitter = this.systems.events;
279 | eventEmitter.off("shutdown", this.shutdown, this, false);
280 | eventEmitter.off("shutdown", this.shutdown, this, false);
281 | this.scene = null;
282 | }
283 |
284 | private languageChanged(): void {
285 | this.recursiveUpdateText(this.scene);
286 | }
287 | }
288 |
289 | I18nPlugin.staticConstructor();
290 |
--------------------------------------------------------------------------------
/assets/bitmapfonts/iceicebaby.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/assets/bitmapfonts/helvetica_regular.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/static/assets/bitmapfonts/helvetica_regular.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------