logo

You can see an example here. Or see how it is build below.

Format:

Project.xml

- source
  |_ PlayState.hx
  |_ Main.hx

- assets
  |_ data
    |_ lang
      |_ ar.json
      |_ de.json
      |_ en.json
      |_ es.json
      |_ fr.json
      |_ it.json
      |_ pt.json
      |_ ru.json
      |_ zh.json

Project.xml

<?xml version="1.0" encoding="utf-8"?>
<project xmlns="http://lime.software/project/1.0.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://lime.software/project/1.0.2 http://lime.software/xsd/project-1.0.2.xsd">

    <!-- _________________________ Application Settings _________________________ -->

    <app title="LangExample" file="LangExample" main="Main" version="0.0.1" company="SantiagoCalebe" />

    <!--The flixel preloader is not accurate in Chrome. You can use it regularly if you embed the swf into a html file
        or you can set the actual size of your file manually at "FlxPreloaderBase-onUpdate-bytesTotal"-->
    <app preloader="flixel.system.FlxPreloader" />

    <!--Minimum without FLX_NO_GAMEPAD: 11.8, without FLX_NO_NATIVE_CURSOR: 11.2-->
    <set name="SWF_VERSION" value="11.8" />

    <!-- ____________________________ Window Settings ___________________________ -->

    <!--These window settings apply to all targets-->
    <window width="640" height="360" fps="60" background="#000000" hardware="true" vsync="false" />

    <!--HTML5-specific-->
    <window if="html5" resizable="false" />

    <!--Desktop-specific-->
    <window if="desktop" orientation="landscape" fullscreen="false" resizable="true" />

    <!--Mobile-specific-->
    <window if="mobile" orientation="landscape" fullscreen="true" width="0" height="0" />

    <!-- _____________________________ Path Settings ____________________________ -->

    <set name="BUILD_DIR" value="export" />
    <source path="source" />
    <assets path="assets" />
    <assets path="assets/data/lang" rename="assets/data/lang" include="*.json" />

    <!-- _______________________________ Libraries ______________________________ -->

    <haxelib name="flixel" />
    <haxelib name="flixel-addons" />
    <haxelib name="hxLang" />

    <!--In case you want to use the ui package-->
    <!--<haxelib name="flixel-ui" />-->

    <!--In case you want to use nape with flixel-->
    <!--<haxelib name="nape-haxe4" />-->

    <!-- ______________________________ Haxedefines _____________________________ -->

    <!--Enable the Flixel core recording system-->
    <!--<haxedef name="FLX_RECORD" />-->

    <!--Disable the right and middle mouse buttons-->
    <!--<haxedef name="FLX_NO_MOUSE_ADVANCED" />-->

    <!--Disable the native cursor API on Flash-->
    <!--<haxedef name="FLX_NO_NATIVE_CURSOR" />-->

    <!--Optimise inputs, be careful you will get null errors if you don't use conditionals in your game-->
    <haxedef name="FLX_NO_MOUSE" if="mobile" />
    <haxedef name="FLX_NO_KEYBOARD" if="mobile" />
    <haxedef name="FLX_NO_TOUCH" if="desktop" />
    <!--<haxedef name="FLX_NO_GAMEPAD" />-->

    <!--Disable the Flixel core sound tray-->
    <!--<haxedef name="FLX_NO_SOUND_TRAY" />-->

    <!--Disable the Flixel sound management code-->
    <!--<haxedef name="FLX_NO_SOUND_SYSTEM" />-->

    <!--Disable the Flixel core focus lost screen-->
    <!--<haxedef name="FLX_NO_FOCUS_LOST_SCREEN" />-->

    <!--Disable the Flixel core debugger. Automatically gets set whenever you compile in release mode!-->
    <haxedef name="FLX_NO_DEBUG" unless="debug" />

    <!--Enable this for Nape release builds for a serious peformance improvement-->
    <haxedef name="NAPE_RELEASE_BUILD" unless="debug" />

    <!-- _________________________________ Custom _______________________________ -->

    <!--Place custom nodes like icons here (higher priority to override the HaxeFlixel icon)-->
</project>

source/Main.hx

package;

import flixel.FlxGame;
import flixel.FlxG;
import flixel.FlxState;
import openfl.display.Sprite;
import PlayState;
import hxLang.Lang;

class Main extends Sprite
{
    public var languages:Array<String> = ["en", "es", "fr", "de", "pt", "it", "ru", "zh", "ja", "ar"];
    public function new()
    {
        super();

        Lang.init("assets/data/lang", languages, true);
        Lang.setDefaultLang("en");

        var game = new FlxGame(640, 480, PlayState, 60, 60);
        addChild(game);
    }
}

source/PlayState.hx

package;

import flixel.FlxState;
import flixel.text.FlxText;
import flixel.FlxSprite;
import flixel.FlxG;
import hxLang.Lang;

class PlayState extends FlxState {
    var langFields:Array<FlxSprite> = [];
    var langLabels:Array<FlxText> = [];
    var quoteField:FlxText;
    var footerText:FlxText;
    var languages = Lang.langs();

    var selectedIndex:Int = 0;

    override public function create():Void {
        super.create();

        Lang.switchLanguage(languages[selectedIndex]);
        quoteField = new FlxText(0, 0, 400, Lang.get("quote"));
        quoteField.wordWrap = true;
        quoteField.setFormat(null, 18, 0xFFFFFFFF, "left");
        quoteField.screenCenter();
        quoteField.x += 100;
        add(quoteField);

        for (i in 0...languages.length) {
            var lang = languages[i];

            var bg = new FlxSprite(0, 30 + i * 35);
            bg.makeGraphic(150, 30, 0xFF444444);
            bg.alpha = (i == selectedIndex) ? 1 : 0.5;
            add(bg);
            langFields.push(bg);

            var langStr = Std.string(lang);
            var label = new FlxText(bg.x + 5, bg.y + 5, 140, langStr.toUpperCase());
            label.setFormat(null, 20, (i == selectedIndex) ? 0xFFFFFFFF : 0xFF888888, "left");
            add(label);
            langLabels.push(label);
        }

        footerText = new FlxText(0, 0, FlxG.width, "© SantiagoCalebe - hxLang (2025 -)", 16);
        footerText.setFormat(null, 16, 0xFFFFFFFF, "center");
        footerText.y = FlxG.height - footerText.height - 10;
        footerText.scrollFactor.set();
        add(footerText);
    }

    override public function update(elapsed:Float):Void {
        super.update(elapsed);

        var hoveredIndex:Int = -1;
        for (i in 0...langFields.length) {
            if (FlxG.mouse.overlaps(langFields[i])) {
                hoveredIndex = i;
                break;
            }
        }

        for (i in 0...langFields.length) {
            var isSelected = (i == selectedIndex);
            var isHovered = (i == hoveredIndex);

            if (isHovered) {
                langFields[i].alpha = 1;
                langFields[i].makeGraphic(150, 30, 0xFFFFFFFF);
                langLabels[i].color = 0xFFFFFFFF;

                if (FlxG.mouse.justPressed) {
                    if (selectedIndex != i) {
                        selectedIndex = i;
                        var lang = languages[i];
                        if (Lang.switchLanguage(lang)) {
                            quoteField.text = Lang.get("quote");
                        }
                    }
                }
            } else if (isSelected) {
                langFields[i].alpha = 1;
                langFields[i].makeGraphic(150, 30, 0xFFFFFFFF);
                langLabels[i].color = 0xFF000000;
            } else {
                langFields[i].alpha = 0.5;
                langFields[i].makeGraphic(150, 30, 0xFF444444);
                langLabels[i].color = 0xFF888888;
            }
        }
    }
}

And also, in assets/data/lang/, there is 10 JSON files with the languages.

assets/json/data/ar.json

{
  "currentLanguage": "Arabic",
  "quote": "Nahnu mahkumuna bi'an nakuna ahraran."
}

assets/json/data/de.json

{
  "currentLanguage": "Deutsch",
  "quote": "Wir sind dazu verurteilt, frei zu sein."
}

assets/json/data/en.json

{
  "currentLanguage": "English",
  "quote": "We are condemned to be free."
}

assets/json/data/es.json

{
  "currentLanguage": "Español",
  "quote": "Estamos condenados a ser libres."
}

assets/json/data/fr.json

{
  "currentLanguage": "Français",
  "quote": "Nous sommes condamnés à être libres."
}

assets/json/data/it.json

{
  "currentLanguage": "Italiano",
  "quote": "Siamo condannati a essere liberi."
}

assets/json/data/pt.json

{
  "currentLanguage": "Português",
  "quote": "Estamos condenados a ser livres."
}

assets/json/data/ru.json

{
  "currentLanguage": "Russian",
  "quote": "My obrecheny byt' svobodnymi."
}

assets/json/data/zh.json

{
  "currentLanguage": "Chinese",
  "quote": "Women zhuding yao ziyou."
}

Deploy of the example:

Click Here