lang
This commit is contained in:
@@ -5,7 +5,11 @@
|
||||
|
||||
set(DUSK_GAME_ASSETS_DIR "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
||||
|
||||
add_subdirectory(palette)# Palette asset needs to be added before any images.
|
||||
# Palette asset needs to be added before any images.
|
||||
add_subdirectory(palette)
|
||||
|
||||
# Languages need to be added before anything that uses text.
|
||||
add_subdirectory(locale)
|
||||
|
||||
add_subdirectory(entity)
|
||||
add_subdirectory(map)
|
||||
|
||||
6
assets/locale/CMakeLists.txt
Normal file
6
assets/locale/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
add_asset(LANGUAGE en_US.po)
|
||||
10
assets/locale/en_US.po
Normal file
10
assets/locale/en_US.po
Normal file
@@ -0,0 +1,10 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Language: us\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "test.test"
|
||||
msgstr "Hello this is a test."
|
||||
@@ -16,9 +16,14 @@ typedef enum {
|
||||
ASSET_TYPE_COUNT,
|
||||
} assettype_t;
|
||||
|
||||
typedef enum {
|
||||
ASSET_LOAD_STRAT_ENTIRE,
|
||||
} assetloadstrat_t;
|
||||
|
||||
typedef struct {
|
||||
const char_t *header;
|
||||
const size_t dataSize;
|
||||
const assetloadstrat_t loadStrategy;
|
||||
errorret_t (*load)(void *data, void *output);
|
||||
} assettypedef_t;
|
||||
|
||||
@@ -29,12 +34,14 @@ static const assettypedef_t ASSET_TYPE_DEFINITIONS[ASSET_TYPE_COUNT] = {
|
||||
|
||||
[ASSET_TYPE_PALETTE_IMAGE] = {
|
||||
.header = "DPI",
|
||||
.loadStrategy = ASSET_LOAD_STRAT_ENTIRE,
|
||||
.dataSize = sizeof(assetpaletteimage_t),
|
||||
.load = assetPaletteImageLoad
|
||||
},
|
||||
|
||||
[ASSET_TYPE_ALPHA_IMAGE] = {
|
||||
.header = "DAI",
|
||||
.loadStrategy = ASSET_LOAD_STRAT_ENTIRE,
|
||||
.dataSize = sizeof(assetalphaimage_t),
|
||||
.load = assetAlphaImageLoad
|
||||
},
|
||||
|
||||
23
src/asset/type/assetlanguage.h
Normal file
23
src/asset/type/assetlanguage.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "locale/language/keys.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint32_t chunk;
|
||||
uint32_t offset;
|
||||
uint32_t length;
|
||||
} assetlanguagestring_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
assetlanguagestring_t strings[LANG_KEY_COUNT];
|
||||
} assetlanguageheader_t;
|
||||
#pragma pack(pop)
|
||||
18
src/locale/language/languagechunk.h
Normal file
18
src/locale/language/languagechunk.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
#define LANG_CHUNK_STRING_COUNT 64
|
||||
#define LANG_CHUNK_STRING_MAX_LENGTH DUSK_LANG_STRING_MAX_LENGTH
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
char_t
|
||||
} languagechunk_t;
|
||||
#pragma pack(pop)
|
||||
@@ -74,7 +74,7 @@ int32_t stringFormatVA(
|
||||
char_t *dest,
|
||||
const size_t destSize,
|
||||
const char_t *format,
|
||||
const va_list args
|
||||
va_list args
|
||||
) {
|
||||
assertNotNull(format, "format must not be NULL");
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ int32_t stringFormatVA(
|
||||
char_t *dest,
|
||||
const size_t destSize,
|
||||
const char_t *format,
|
||||
const va_list args
|
||||
va_list args
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,6 +3,7 @@ from args import inputAssets, args
|
||||
from processasset import processAsset
|
||||
from processpalette import processPaletteList
|
||||
from processtileset import processTilesetList
|
||||
from processlanguage import processLanguageList
|
||||
from assethelpers import getBuiltAssetsRelativePath
|
||||
import zipfile
|
||||
|
||||
@@ -31,6 +32,7 @@ with zipfile.ZipFile(outputFileName, 'w') as zipf:
|
||||
# Generate additional headers.
|
||||
processPaletteList()
|
||||
processTilesetList()
|
||||
processLanguageList()
|
||||
|
||||
# Finalize build
|
||||
if args.build_type == 'header':
|
||||
|
||||
@@ -4,6 +4,7 @@ from processimage import processImage
|
||||
from processpalette import processPalette
|
||||
from processtileset import processTileset
|
||||
from processmap import processMap
|
||||
from processlanguage import processLanguage
|
||||
|
||||
processedAssets = []
|
||||
|
||||
@@ -22,6 +23,8 @@ def processAsset(asset):
|
||||
return processTileset(asset)
|
||||
elif t == 'map':
|
||||
return processMap(asset)
|
||||
elif t == 'language':
|
||||
return processLanguage(asset)
|
||||
else:
|
||||
print(f"Error: Unknown asset type '{asset['type']}' for path '{asset['path']}'")
|
||||
sys.exit(1)
|
||||
73
tools/assetstool/processlanguage.py
Normal file
73
tools/assetstool/processlanguage.py
Normal file
@@ -0,0 +1,73 @@
|
||||
import sys
|
||||
import os
|
||||
from args import args
|
||||
from assetcache import assetCache, assetGetCache
|
||||
from assethelpers import getAssetRelativePath
|
||||
import polib
|
||||
import re
|
||||
|
||||
LANGUAGE_DATA = {}
|
||||
LANGUAGE_KEYS = []
|
||||
|
||||
def processLanguageList():
|
||||
# Language keys header data
|
||||
headerKeys = "// Auto-generated language keys header file.\n"
|
||||
headerKeys += "#pragma once\n"
|
||||
headerKeys += "#include \"dusk.h\"\n\n"
|
||||
|
||||
keyIndex = 0
|
||||
for key in LANGUAGE_KEYS:
|
||||
headerKeys += f"#define {getLanguageVariableName(key)} {keyIndex}\n"
|
||||
keyIndex += 1
|
||||
|
||||
for lang in LANGUAGE_DATA:
|
||||
if key not in LANGUAGE_DATA[lang]:
|
||||
print(f"Warning: Missing translation for key '{key}' in language '{lang}'")
|
||||
sys.exit(1)
|
||||
|
||||
headerKeys += f"\n#define LANG_KEY_COUNT {len(LANGUAGE_KEYS)}\n"
|
||||
|
||||
# Write out the language keys header file
|
||||
outputFile = os.path.join(args.headers_dir, "locale", "language", "keys.h")
|
||||
os.makedirs(os.path.dirname(outputFile), exist_ok=True)
|
||||
with open(outputFile, "w") as f:
|
||||
f.write(headerKeys)
|
||||
|
||||
def getLanguageVariableName(languageKey):
|
||||
# Take the language key, prepend LANG_, uppercase, replace any non symbols
|
||||
# with _
|
||||
key = languageKey.strip().upper()
|
||||
key = re.sub(r'[^A-Z0-9]', '_', key)
|
||||
return f"LANG_{key}"
|
||||
|
||||
def processLanguage(asset):
|
||||
cache = assetGetCache(asset['path'])
|
||||
if cache is not None:
|
||||
return cache
|
||||
|
||||
# Load PO File
|
||||
po = polib.pofile(asset['path'])
|
||||
|
||||
langName = po.metadata.get('Language')
|
||||
if langName not in LANGUAGE_DATA:
|
||||
LANGUAGE_DATA[langName] = {}
|
||||
|
||||
for entry in po:
|
||||
key = entry.msgid
|
||||
val = entry.msgstr
|
||||
|
||||
if key not in LANGUAGE_KEYS:
|
||||
LANGUAGE_KEYS.append(key)
|
||||
|
||||
if key not in LANGUAGE_DATA[langName]:
|
||||
LANGUAGE_DATA[langName][key] = val
|
||||
else:
|
||||
print(f"Error: Duplicate translation key '{key}' in language '{langName}'")
|
||||
sys.exit(1)
|
||||
|
||||
outLanguageData = {
|
||||
'data': po,
|
||||
'path': asset['path'],
|
||||
'files': []
|
||||
}
|
||||
return assetCache(asset['path'], outLanguageData)
|
||||
Reference in New Issue
Block a user