mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-16 05:13:58 -07:00
Delete obsolete non-working i18n code
This was SVN commit r8527.
This commit is contained in:
parent
ec5d4a9f9e
commit
818ea52c3b
72 changed files with 3 additions and 5360 deletions
|
|
@ -57,9 +57,6 @@ lodbias = 0
|
|||
|
||||
profile = default
|
||||
|
||||
; Language selection: (currently "english" or "pseudogreek")
|
||||
language = english
|
||||
|
||||
; Font mappings:
|
||||
|
||||
font.console = console
|
||||
|
|
|
|||
|
|
@ -1,394 +0,0 @@
|
|||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Spreadsheet::ParseExcel;
|
||||
use Encode;
|
||||
|
||||
opendir my $root, '.' or die "Error opening current directory: $!";
|
||||
for my $d (grep { /^[a-z]+$/ and -d $_ } readdir $root) {
|
||||
opendir my $dir, $d or die "Error opening directory '$d': $!";
|
||||
for (grep /\.xls$/, readdir $dir) {
|
||||
/(.*)\.xls$/;
|
||||
print "* Converting $d/$1.xls\n";
|
||||
convert("$d/$1");
|
||||
}
|
||||
}
|
||||
print "* Completed\n\n";
|
||||
|
||||
sub convert {
|
||||
|
||||
my $filename_in = "$_[0].xls";
|
||||
my $filename_base = $_[0];
|
||||
|
||||
$_[0] =~ /([^\/]+)$/;
|
||||
my $table_name = $1;
|
||||
|
||||
my $workbook = Spreadsheet::ParseExcel::Workbook->Parse($filename_in);
|
||||
die unless $workbook;
|
||||
my $worksheet = $workbook->{Worksheet}[0];
|
||||
|
||||
my @data;
|
||||
|
||||
my %encodings = (
|
||||
# Excel name => Encode name
|
||||
ucs2 => 'ucs2-be',
|
||||
ascii => 'ascii',
|
||||
);
|
||||
|
||||
for my $r ($worksheet->{MinRow} .. $worksheet->{MaxRow}) {
|
||||
push @data, [];
|
||||
for my $c ($worksheet->{MinCol} .. $worksheet->{MaxCol}) {
|
||||
my $cell = $worksheet->{Cells}[$r][$c];
|
||||
if ($cell) {
|
||||
my $code = defined $cell->{Code} ? $cell->{Code} : 'ascii';
|
||||
if (not exists $encodings{$code}) {
|
||||
die "Unrecognised encoding '$code'";
|
||||
}
|
||||
push @{$data[-1]}, decode($encodings{$code}, $cell->{Val});
|
||||
} else {
|
||||
push @{$data[-1]}, '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (@data < 3) {
|
||||
die "Too few rows of data";
|
||||
}
|
||||
|
||||
# Remove the top line
|
||||
shift @data;
|
||||
|
||||
if (1 != grep length, @{$data[0]}) {
|
||||
die "Second row must contain a single cell, either 'phrases' or the name of the word-table (e.g. 'nouns')";
|
||||
}
|
||||
|
||||
my $title = (shift @data)->[0];
|
||||
|
||||
# Remove blank lines
|
||||
while (@data and not grep length, @{$data[0]}) {
|
||||
shift @data;
|
||||
}
|
||||
|
||||
if ($title eq 'phrases') {
|
||||
convert_phrases($filename_base, \@data);
|
||||
} else {
|
||||
convert_words($filename_base, $title, \@data);
|
||||
}
|
||||
}
|
||||
|
||||
sub convert_words {
|
||||
|
||||
my $filename_out = "$_[0].wrd";
|
||||
my $title = $_[1];
|
||||
my @data = @{$_[2]};
|
||||
|
||||
my @keys = map lc, @{ shift @data };
|
||||
# Remove the English name from the list of keys
|
||||
shift @keys;
|
||||
|
||||
=pod
|
||||
|
||||
struct {
|
||||
u8 TitleLength;
|
||||
u16* Title;
|
||||
|
||||
u8 PropCount;
|
||||
struct {
|
||||
u8 KeyLength;
|
||||
u16* Key;
|
||||
}* PropNames;
|
||||
|
||||
u16 ValueCount;
|
||||
struct {
|
||||
u8 WordLength;
|
||||
u16* Word;
|
||||
struct {
|
||||
u8 PropLength;
|
||||
u16* Property;
|
||||
} Properties[ProprCount];
|
||||
} Words[ValueCount];
|
||||
}
|
||||
|
||||
=cut
|
||||
|
||||
open my $o, '>', $filename_out or die "Error opening $filename_out: $!";
|
||||
binmode $o;
|
||||
|
||||
print $o pack 'C/a*', encode('utf16-le', $title);
|
||||
|
||||
print $o pack 'C', scalar @keys;
|
||||
print $o pack 'C/a*', encode('utf16-le', $_) for @keys;
|
||||
|
||||
print $o pack 'S', scalar @data;
|
||||
for (@data) {
|
||||
print $o pack 'C/a*', encode('utf16-le', $_) for @$_[0..@keys]; # 1 more than @keys, because the first 'property' is the English name
|
||||
}
|
||||
|
||||
close $o;
|
||||
}
|
||||
|
||||
sub convert_phrases {
|
||||
|
||||
my $filename_out = "$_[0].lng";
|
||||
my @data = @{$_[1]};
|
||||
|
||||
# Allow simple error reporting
|
||||
our $errors = 0;
|
||||
sub error($) { print STDERR "$_[0]\n"; ++$errors; }
|
||||
|
||||
# Split the input file on "--" lines, and store an array ref
|
||||
# for each section containing the lines
|
||||
|
||||
my @phrase_lines;
|
||||
my $line_no = 3;
|
||||
for (@data) {
|
||||
push @phrase_lines, [ [ $line_no, $_->[0] ], [ $line_no, $_->[1] ] ];
|
||||
++$line_no;
|
||||
}
|
||||
|
||||
# Build phrase_data, being a list of [ raw key, parsed key, parsed translation ]
|
||||
|
||||
my @phrase_data;
|
||||
|
||||
for (@phrase_lines) {
|
||||
next unless @$_;
|
||||
my $key = shift @$_;
|
||||
if (not @$_) {
|
||||
error "Error in line $key->[0]: no translation specified for key '$key->[1]'";
|
||||
next;
|
||||
}
|
||||
my $translation = join "\n", map $_->[1], @$_;
|
||||
|
||||
push @phrase_data, [ $key->[1], parse_translation($key->[1], $translation) ];
|
||||
}
|
||||
|
||||
if ($errors) {
|
||||
die "ABORTING: $::errors errors found\n";
|
||||
}
|
||||
|
||||
#use Data::Dumper; print Dumper \@phrase_data; exit;
|
||||
|
||||
=pod
|
||||
|
||||
Disk format:
|
||||
|
||||
file {
|
||||
u16 phrase_count
|
||||
phrase* phrases;
|
||||
}
|
||||
|
||||
phrase {
|
||||
u16 key_length;
|
||||
u16* key_string; // not null-terminated
|
||||
|
||||
u8 variable_count; // just for validating its use
|
||||
|
||||
u8 section_count;
|
||||
translation_section* sections;
|
||||
}
|
||||
|
||||
translation_section {
|
||||
u8 type;
|
||||
|
||||
// Type 0: (string)
|
||||
u16 length;
|
||||
u16* text; // not null-terminated
|
||||
|
||||
// OR Type 1: (variable)
|
||||
u8 id; // referring to the position in the key phrase
|
||||
|
||||
// OR Type 2: (function)
|
||||
u8 namelength;
|
||||
u8* name;
|
||||
u8 paramcount;
|
||||
func_param* params;
|
||||
}
|
||||
|
||||
func_param {
|
||||
u8 type;
|
||||
|
||||
// Type 0: (string)
|
||||
u8 length;
|
||||
u16* text;
|
||||
|
||||
// OR Type 1: (variable)
|
||||
u8 id; // referring to the position in the key phrase
|
||||
|
||||
// OR Type 2: (int)
|
||||
u32 value;
|
||||
|
||||
// (doubles/etc will just be stringified)
|
||||
}
|
||||
|
||||
=cut
|
||||
|
||||
# Output the language file to disk
|
||||
|
||||
open my $o, '>', $filename_out or die "Error opening $filename_out: $!";
|
||||
binmode $o;
|
||||
|
||||
print $o pack 'S', scalar @phrase_data;
|
||||
for (@phrase_data) {
|
||||
# $_ eq [ key, var count, [ sections... ] ]
|
||||
|
||||
my $key = encode('utf16-le', $_->[0]);
|
||||
print $o pack 'S/a*C', $key, $_->[1];
|
||||
|
||||
print $o pack 'C', scalar @{ $_->[2] };
|
||||
|
||||
for (@{ $_->[2] }) {
|
||||
# $_ eq [ type, data... ]
|
||||
|
||||
if ($_->[0] eq 'str') {
|
||||
print $o pack 'CS/a*', 0, encode('utf16-le', $_->[1]);
|
||||
|
||||
} elsif ($_->[0] eq 'var') {
|
||||
print $o pack 'CC', 1, $_->[1];
|
||||
|
||||
} elsif ($_->[0] eq 'code') {
|
||||
my ($name, @params) = @{$_->[1]};
|
||||
print $o pack 'CC/a*C', 2, $name, scalar @params;
|
||||
|
||||
for (@params) {
|
||||
|
||||
if ($_->[0] eq 'str') {
|
||||
print $o pack 'CC/a*', 0, encode('utf16-le', $_->[1]);
|
||||
|
||||
} elsif ($_->[0] eq 'var') {
|
||||
print $o pack 'CC', 1, $_->[1];
|
||||
|
||||
} elsif ($_->[0] eq 'int') {
|
||||
print $o pack 'Cl', 2, $_->[1];
|
||||
|
||||
} else {
|
||||
die "Invalid func param type $_->[0]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
die "Invalid sec type $_->[0]";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub parse_basic {
|
||||
# Parse "\$[a-zA-Z0-9_]+" (allowing "$$" to represent "$")
|
||||
my @parts;
|
||||
for (split /(\$(?:\$|[a-zA-Z0-9_]+))/, $_[0]) {
|
||||
if (/\$([a-zA-Z0-9_]+)/) {
|
||||
push @parts, [ var => $1 ];
|
||||
} else {
|
||||
$_ = '$' if $_ eq '$$';
|
||||
if (@parts and $parts[-1][0] eq 'str') {
|
||||
$parts[-1][1] .= $_;
|
||||
} else {
|
||||
push @parts, [ str => $_ ];
|
||||
}
|
||||
}
|
||||
}
|
||||
return \@parts;
|
||||
}
|
||||
|
||||
sub parse_complex {
|
||||
# Parse "\$[a-zA-Z0-9_]+" (allowing "$$" to represent "$")
|
||||
# as well as [...] code lumps
|
||||
|
||||
my @chars = split //, $_[0];
|
||||
my @parts = [ str => '' ];
|
||||
|
||||
while (@chars) {
|
||||
$_ = shift @chars;
|
||||
if ($_ eq '$') {
|
||||
if (@chars==0 or $chars[0] eq '$') {
|
||||
$parts[-1][1] .= '$';
|
||||
} else {
|
||||
my $varname = '';
|
||||
while (@chars and $chars[0] =~ /[a-zA-Z0-9_]/) {
|
||||
$varname .= shift @chars;
|
||||
}
|
||||
push @parts, [ var => $varname ];
|
||||
push @parts, [ str => '' ];
|
||||
}
|
||||
} elsif ($_ eq '[') {
|
||||
my $codetext;
|
||||
while (@chars and $chars[0] ne ']') {
|
||||
$codetext .= shift @chars;
|
||||
}
|
||||
shift @chars;
|
||||
push @parts, [ code => parse_code($codetext) ];
|
||||
push @parts, [ str => '' ];
|
||||
|
||||
} else {
|
||||
$parts[-1][1] .= $_;
|
||||
}
|
||||
}
|
||||
|
||||
@parts = grep $_->[1] ne '', @parts;
|
||||
return \@parts;
|
||||
}
|
||||
|
||||
|
||||
sub parse_code {
|
||||
my @rawparts = split /,\s*/, $_[0];
|
||||
my $name = shift @rawparts;
|
||||
my @parts;
|
||||
for (@rawparts) {
|
||||
if (/^\d+$/) {
|
||||
push @parts, [ 'int' => $_ ];
|
||||
} elsif (/^\$(.*)/) {
|
||||
push @parts, [ 'var' => $1 ];
|
||||
} else {
|
||||
push @parts, [ 'str' => $_ ];
|
||||
}
|
||||
}
|
||||
return [ $name, @parts ];
|
||||
}
|
||||
|
||||
|
||||
sub parse_translation {
|
||||
my ($key, $str) = @_;
|
||||
|
||||
# Parse key to extract the variable sections
|
||||
$key = parse_basic($key);
|
||||
|
||||
# Fill variables with ( var0 => 0, var1 => 1, var2 => 2 )
|
||||
my %variables;
|
||||
for (@$key) {
|
||||
$variables{$_->[1]} = scalar keys %variables if $_->[0] eq 'var';
|
||||
}
|
||||
my %unused_variables = %variables;
|
||||
|
||||
# Parse the translated string for
|
||||
$str = parse_complex($str);
|
||||
|
||||
# Replace variable strings with the appropriate numbers
|
||||
for (@$str) {
|
||||
if ($_->[0] eq 'var') {
|
||||
if (not exists $variables{$_->[1]}) {
|
||||
die "Unrecognised variable '$_->[1]'\n";
|
||||
}
|
||||
delete $unused_variables{$_->[1]};
|
||||
$_->[1] = $variables{$_->[1]};
|
||||
|
||||
} elsif ($_->[0] eq 'code') {
|
||||
|
||||
for (@{$_->[1]}[1 .. $#{$_->[1]}]) {
|
||||
|
||||
if ($_->[0] eq 'var') {
|
||||
if (not exists $variables{$_->[1]}) {
|
||||
die "Unrecognised variable '$_->[1]'\n";
|
||||
}
|
||||
delete $unused_variables{$_->[1]};
|
||||
$_->[1] = $variables{$_->[1]};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (keys %unused_variables) {
|
||||
warn "Warning: variable '$_' unreferenced in translated string\n";
|
||||
}
|
||||
|
||||
return (scalar keys %variables, $str);
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -480,19 +480,6 @@ function setup_all_libs ()
|
|||
setup_static_lib_package("graphics", source_dirs, extern_libs, {})
|
||||
|
||||
|
||||
-- internationalization = i18n
|
||||
-- note: this package isn't large, but is separate because it may be
|
||||
-- useful for other projects.
|
||||
source_dirs = {
|
||||
"i18n"
|
||||
}
|
||||
extern_libs = {
|
||||
"spidermonkey",
|
||||
"boost"
|
||||
}
|
||||
setup_static_lib_package("i18n", source_dirs, extern_libs, {})
|
||||
|
||||
|
||||
source_dirs = {
|
||||
"tools/atlas/GameInterface",
|
||||
"tools/atlas/GameInterface/Handlers"
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ GUI utilities
|
|||
#include "GUI.h"
|
||||
#include "GUIManager.h"
|
||||
#include "ps/Parser.h"
|
||||
#include "ps/i18n.h"
|
||||
|
||||
extern int g_yres;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,160 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "BufferVariable.h"
|
||||
|
||||
#include "DataTypes.h"
|
||||
#include "CLocale.h"
|
||||
|
||||
// Hashing functions are currently 32-bit only
|
||||
cassert(sizeof(int) == 4);
|
||||
cassert(sizeof(double) == 8);
|
||||
// (TODO: the hashing here is quite rubbish)
|
||||
|
||||
using namespace I18n;
|
||||
|
||||
namespace I18n {
|
||||
// These bits don't seem to work without the explicit namespace{}
|
||||
|
||||
template<> BufferVariable* NewBufferVariable<int>(int v) { return new BufferVariable_int(v); }
|
||||
template<> BufferVariable* NewBufferVariable<float>(float v) { return new BufferVariable_double(v); }
|
||||
template<> BufferVariable* NewBufferVariable<double>(double v) { return new BufferVariable_double(v); }
|
||||
template<> BufferVariable* NewBufferVariable<Noun>(Noun v) { return new BufferVariable_string(v.value); }
|
||||
template<> BufferVariable* NewBufferVariable<Name>(Name v) { return new BufferVariable_rawstring(v.value); }
|
||||
|
||||
//
|
||||
// Don't allow plain strings -- people *must* specify whether it's going
|
||||
// to be automatically translated (I18n::Noun) or not (I18n::Name/Raw)
|
||||
//
|
||||
}
|
||||
|
||||
StrImW BufferVariable_int::ToString(CLocale*)
|
||||
{
|
||||
wchar_t buffer[50];
|
||||
swprintf_s(buffer, ARRAY_SIZE(buffer), L"%d", value);
|
||||
return buffer;
|
||||
}
|
||||
u32 BufferVariable_int::Hash()
|
||||
{
|
||||
return (u32)value;
|
||||
}
|
||||
|
||||
|
||||
StrImW BufferVariable_double::ToString(CLocale*)
|
||||
{
|
||||
wchar_t buffer[50];
|
||||
swprintf_s(buffer, ARRAY_SIZE(buffer), L"%f", value);
|
||||
return buffer;
|
||||
}
|
||||
u32 BufferVariable_double::Hash()
|
||||
{
|
||||
// Add the two four-bytes of the double
|
||||
union {
|
||||
u32 i[2];
|
||||
double d;
|
||||
} u;
|
||||
u.d = value;
|
||||
return u.i[0]+u.i[1];
|
||||
}
|
||||
|
||||
|
||||
StrImW BufferVariable_string::ToString(CLocale* locale)
|
||||
{
|
||||
// Attempt noun translations
|
||||
const Str nouns = L"nouns";
|
||||
const Str wordname (value.str());
|
||||
const CLocale::LookupType* word = locale->LookupWord(nouns, wordname);
|
||||
// Couldn't find; just return the original word
|
||||
if (! word)
|
||||
return value;
|
||||
|
||||
const Str propname = L"singular";
|
||||
Str ret;
|
||||
if (! locale->LookupProperty(word, propname, ret))
|
||||
{
|
||||
delete word;
|
||||
return value;
|
||||
}
|
||||
delete word;
|
||||
return ret.c_str();
|
||||
}
|
||||
u32 BufferVariable_string::Hash()
|
||||
{
|
||||
// Do nothing very clever
|
||||
int hash = 0;
|
||||
const wchar_t* str = value.str();
|
||||
size_t len = wcslen(str);
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
hash += str[i];
|
||||
return hash;
|
||||
}
|
||||
|
||||
StrImW BufferVariable_rawstring::ToString(CLocale*)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
u32 BufferVariable_rawstring::Hash()
|
||||
{
|
||||
int hash = 0;
|
||||
const wchar_t* str = value.str();
|
||||
size_t len = wcslen(str);
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
hash += str[i];
|
||||
return hash;
|
||||
}
|
||||
|
||||
bool I18n::operator== (BufferVariable& a, BufferVariable& b)
|
||||
{
|
||||
if (a.Type != b.Type)
|
||||
return false;
|
||||
|
||||
switch (a.Type)
|
||||
{
|
||||
case vartype_int:
|
||||
return *static_cast<BufferVariable_int*>(&a) == *static_cast<BufferVariable_int*>(&b);
|
||||
case vartype_double:
|
||||
return *static_cast<BufferVariable_double*>(&a) == *static_cast<BufferVariable_double*>(&b);
|
||||
case vartype_string:
|
||||
return *static_cast<BufferVariable_string*>(&a) == *static_cast<BufferVariable_string*>(&b);
|
||||
case vartype_rawstring:
|
||||
return *static_cast<BufferVariable_rawstring*>(&a) == *static_cast<BufferVariable_rawstring*>(&b);
|
||||
}
|
||||
debug_warn(L"Invalid buffer variable vartype");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BufferVariable_int::operator== (BufferVariable_int& a)
|
||||
{
|
||||
return a.value == this->value;
|
||||
}
|
||||
|
||||
bool BufferVariable_double::operator== (BufferVariable_double& a)
|
||||
{
|
||||
return a.value == this->value;
|
||||
}
|
||||
|
||||
bool BufferVariable_string::operator== (BufferVariable_string& a)
|
||||
{
|
||||
return a.value == this->value;
|
||||
}
|
||||
|
||||
bool BufferVariable_rawstring::operator== (BufferVariable_rawstring& a)
|
||||
{
|
||||
return a.value == this->value;
|
||||
}
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
BufferVariable stores the parameters that have been passed to a StringBuffer,
|
||||
providing hashes and strings on request.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_I18N_BUFFERVARIABLE
|
||||
#define INCLUDED_I18N_BUFFERVARIABLE
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include "StrImmutable.h"
|
||||
|
||||
|
||||
|
||||
namespace I18n
|
||||
{
|
||||
class CLocale;
|
||||
|
||||
enum {
|
||||
vartype_int,
|
||||
vartype_double,
|
||||
vartype_string,
|
||||
vartype_rawstring // won't be translated automatically
|
||||
};
|
||||
|
||||
class BufferVariable
|
||||
{
|
||||
public:
|
||||
char Type;
|
||||
virtual StrImW ToString(CLocale*) = 0;
|
||||
virtual u32 Hash() = 0;
|
||||
virtual ~BufferVariable() {};
|
||||
};
|
||||
|
||||
// Factory constructor type thing, sort of
|
||||
template<typename T>
|
||||
BufferVariable* NewBufferVariable(T v);
|
||||
|
||||
class BufferVariable_int : public BufferVariable
|
||||
{
|
||||
public:
|
||||
int value;
|
||||
BufferVariable_int(int v) : value(v) { Type = vartype_int; }
|
||||
StrImW ToString(CLocale*);
|
||||
u32 Hash();
|
||||
// Equality testing is required by the cache
|
||||
bool operator== (BufferVariable_int&);
|
||||
};
|
||||
|
||||
class BufferVariable_double : public BufferVariable
|
||||
{
|
||||
public:
|
||||
double value;
|
||||
BufferVariable_double(double v) : value(v) { Type = vartype_double; }
|
||||
StrImW ToString(CLocale*);
|
||||
u32 Hash();
|
||||
bool operator== (BufferVariable_double&);
|
||||
};
|
||||
|
||||
class BufferVariable_string : public BufferVariable
|
||||
{
|
||||
public:
|
||||
StrImW value;
|
||||
BufferVariable_string(StrImW v) : value(v) { Type = vartype_string; }
|
||||
StrImW ToString(CLocale*);
|
||||
u32 Hash();
|
||||
bool operator== (BufferVariable_string&);
|
||||
};
|
||||
|
||||
class BufferVariable_rawstring : public BufferVariable
|
||||
{
|
||||
public:
|
||||
StrImW value;
|
||||
BufferVariable_rawstring(StrImW v) : value(v) { Type = vartype_rawstring; }
|
||||
StrImW ToString(CLocale*);
|
||||
u32 Hash();
|
||||
bool operator== (BufferVariable_rawstring&);
|
||||
};
|
||||
|
||||
// BufferVariable==BufferVariable compares their Types, and then
|
||||
// uses the appropriate operator== if they're the same
|
||||
bool operator== (BufferVariable&, BufferVariable&);
|
||||
}
|
||||
|
||||
#endif // INCLUDED_I18N_BUFFERVARIABLE
|
||||
|
|
@ -1,464 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "CLocale.h"
|
||||
#include "TSComponent.h"
|
||||
#include "ps/StringConvert.h"
|
||||
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "ps/CLogger.h"
|
||||
#define LOG_CATEGORY L"i18n"
|
||||
|
||||
using namespace I18n;
|
||||
|
||||
// Vaguely useful utility function for deleting stuff
|
||||
template<typename T> void delete_fn(T* v) { delete v; }
|
||||
|
||||
// These could be optimised for little-endian sizeof(wchar_t)==2 systems:
|
||||
static inline void ReadWString8_(const char*& data, Str& str)
|
||||
{
|
||||
u8 length = *(u8*)data;
|
||||
data += 1;
|
||||
StringConvert::ucs2le_to_wstring(data, data+length, str);
|
||||
data += length;
|
||||
}
|
||||
static inline void ReadWString16_(const char*& data, Str& str)
|
||||
{
|
||||
u16 length = *(u16*)data;
|
||||
data += 2;
|
||||
StringConvert::ucs2le_to_wstring(data, data+length, str);
|
||||
data += length;
|
||||
}
|
||||
|
||||
#define ReadWString8(s) Str s; ReadWString8_(data, s);
|
||||
#define ReadWString16(s) Str s; ReadWString16_(data, s);
|
||||
|
||||
|
||||
bool CLocale::LoadStrings(const char* data)
|
||||
{
|
||||
// TODO: More robust file format (so errors can be detected in a
|
||||
// nicer way than watching for access violations)
|
||||
|
||||
u16 PhraseCount = *(u16*)data;
|
||||
data += 2;
|
||||
|
||||
for (int i = 0; i < PhraseCount; ++i)
|
||||
{
|
||||
ReadWString16(Key);
|
||||
|
||||
u8 VarCount = *(u8*)data;
|
||||
data += 1;
|
||||
|
||||
// Get the relevant entry in the string hash, creating it if it doesn't exist
|
||||
TranslatedString* String = Strings[Key];
|
||||
if (! String)
|
||||
String = Strings[Key] = new TranslatedString;
|
||||
// If this is a redefined string, make sure it's empty
|
||||
String->Parts.clear();
|
||||
// Store the number of variables, so translate(x)<<y<<z can check for validity
|
||||
String->VarCount = VarCount;
|
||||
|
||||
u8 SectionCount = *(u8*)data;
|
||||
data += 1;
|
||||
|
||||
for (int j = 0; j < SectionCount; ++j)
|
||||
{
|
||||
u8 SectionType = *(u8*)data;
|
||||
data += 1;
|
||||
|
||||
switch (SectionType)
|
||||
{
|
||||
case 0: // Constant string
|
||||
{
|
||||
ReadWString16(StringText);
|
||||
|
||||
String->Parts.push_back(new TSComponentString(StringText.c_str()));
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: // Variable
|
||||
{
|
||||
u8 VarID = *(u8*)data;
|
||||
data += 1;
|
||||
|
||||
String->Parts.push_back(new TSComponentVariable(VarID));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: // Function
|
||||
{
|
||||
u8 NameLength = *(u8*)data;
|
||||
data += 1;
|
||||
|
||||
std::string NameText ((const char*)data, (const char*)(data + NameLength));
|
||||
data += NameLength;
|
||||
|
||||
u8 ParamCount = *(u8*)data;
|
||||
data += 1;
|
||||
|
||||
TSComponentFunction* Func = new TSComponentFunction(NameText.c_str());
|
||||
|
||||
for (int k = 0; k < ParamCount; ++k)
|
||||
{
|
||||
u8 ParamType = *(u8*)data;
|
||||
data += 1;
|
||||
|
||||
switch (ParamType)
|
||||
{
|
||||
case 0: // String
|
||||
{
|
||||
ReadWString8(StrText);
|
||||
|
||||
Func->AddParam(new ScriptValueString(Script, StrText.c_str()));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: // Variable
|
||||
{
|
||||
u8 ID = *(u8*)data;
|
||||
data += 1;
|
||||
|
||||
Func->AddParam(new ScriptValueVariable(Script, ID));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: // Integer
|
||||
{
|
||||
u32 Num = *(u32*)data;
|
||||
data += 4;
|
||||
|
||||
Func->AddParam(new ScriptValueInteger(Script, Num));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: // Argh!
|
||||
debug_warn(L"Invalid function parameter type");
|
||||
}
|
||||
}
|
||||
|
||||
String->Parts.push_back(Func);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: // Argh!
|
||||
debug_warn(L"Invalid translation string section type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CLocale::LoadFunctions(const char* data, size_t len, const char* filename)
|
||||
{
|
||||
// Insist on little-endian UTF16 files containing a BOM (e.g. as generated
|
||||
// by Notepad when saving in Unicode format)
|
||||
|
||||
// TODO: Support more Unicode file formats
|
||||
|
||||
if (len < 2)
|
||||
{
|
||||
LOG(CLogger::Error, LOG_CATEGORY, L"I18n: Functions file '%hs' is too short", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*(jschar*)data != 0xFEFF)
|
||||
{
|
||||
LOG(CLogger::Error, LOG_CATEGORY, L"I18n: Functions file '%hs' has invalid Unicode format (lacking little-endian BOM)", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! Script.ExecuteCode((jschar*)(data+2), len/2, filename))
|
||||
{
|
||||
LOG(CLogger::Error, LOG_CATEGORY, L"I18n: JS errors in functions file '%hs'", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CLocale::LoadDictionary(const char* data)
|
||||
{
|
||||
ReadWString8(DictName);
|
||||
|
||||
u8 PropertyCount = *(u8*)data;
|
||||
data += 1;
|
||||
|
||||
DictData& dict = Dictionaries[DictName];
|
||||
|
||||
if (dict.DictProperties.size() && PropertyCount != dict.DictProperties.size())
|
||||
{
|
||||
LOG(CLogger::Error, LOG_CATEGORY, L"I18n: Multiple dictionary files loaded with the name ('%ls') and different properties", DictName.c_str());
|
||||
return false;
|
||||
// TODO: Check headings to make sure they're identical (or handle them more cleverly)
|
||||
}
|
||||
|
||||
// Read the names of the properties
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < PropertyCount; ++i)
|
||||
{
|
||||
ReadWString8(Property);
|
||||
dict.DictProperties[Property] = i;
|
||||
}
|
||||
|
||||
u16 ValueCount = *(u16*)data;
|
||||
data += 2;
|
||||
|
||||
// Read each 'value' (word + properties)
|
||||
|
||||
for (i = 0; i < ValueCount; ++i)
|
||||
{
|
||||
ReadWString8(Word);
|
||||
|
||||
std::vector<std::wstring>& props = dict.DictWords[Word];
|
||||
|
||||
for (int j = 0; j < PropertyCount; ++j)
|
||||
{
|
||||
ReadWString8(Value);
|
||||
props.push_back(Value);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CLocale::UnloadDictionaries()
|
||||
{
|
||||
Dictionaries.clear();
|
||||
}
|
||||
|
||||
|
||||
const CLocale::LookupType* CLocale::LookupWord(const Str& dictname, const Str& word)
|
||||
{
|
||||
std::map<Str, DictData>::const_iterator dictit = Dictionaries.find(dictname);
|
||||
if (dictit == Dictionaries.end())
|
||||
{
|
||||
LOG(CLogger::Warning, LOG_CATEGORY, L"I18n: Non-loaded dictionary '%ls' accessed", dictname.c_str());
|
||||
return NULL;
|
||||
}
|
||||
std::map<Str, std::vector<Str> >::const_iterator wordit = dictit->second.DictWords.find(word);
|
||||
if (wordit == dictit->second.DictWords.end())
|
||||
{
|
||||
// Word not found. Respond quietly, so JS code can handle missing
|
||||
// words in a more appropriate way.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Return some data that can later be passed to LookupProperty
|
||||
return new LookupType(&dictit->second, &wordit->second);
|
||||
}
|
||||
|
||||
bool CLocale::LookupProperty(const LookupType* data, const Str& property, Str& result)
|
||||
{
|
||||
std::map<Str, int>::const_iterator propit = data->first->DictProperties.find(property);
|
||||
if (propit == data->first->DictProperties.end())
|
||||
return false;
|
||||
|
||||
// Return the appropriate string
|
||||
result = (*data->second)[propit->second];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
const StrImW CLocale::CallFunction(const char* name, const std::vector<BufferVariable*>& vars, const std::vector<ScriptValue*>& params)
|
||||
{
|
||||
return Script.CallFunction(name, vars, params);
|
||||
}
|
||||
|
||||
|
||||
|
||||
StringBuffer CLocale::Translate(const wchar_t* id)
|
||||
{
|
||||
if (++CacheAge > CacheAgeLimit)
|
||||
{
|
||||
CacheAge = 0;
|
||||
ClearCache();
|
||||
}
|
||||
|
||||
StringsType::iterator TransStr = Strings.find(Str(id));
|
||||
if (TransStr == Strings.end())
|
||||
{
|
||||
LOG(CLogger::Normal, LOG_CATEGORY, L"I18n: No translation found for string '%ls'", id);
|
||||
|
||||
// Just use the ID string directly, and remember it for the future
|
||||
return StringBuffer(&AddDefaultString(id), this);
|
||||
}
|
||||
|
||||
return StringBuffer((*TransStr).second, this);
|
||||
}
|
||||
|
||||
|
||||
void CLocale::AddToCache(StringBuffer* sb, Str& str)
|
||||
{
|
||||
CacheData& d = TranslationCache[sb->String];
|
||||
|
||||
// Clean up any earlier cache entry
|
||||
std::for_each(d.vars.begin(), d.vars.end(), delete_fn<BufferVariable>);
|
||||
|
||||
// Set the data for the new cache entry
|
||||
d.hash = sb->Hash();
|
||||
d.vars = sb->Variables;
|
||||
d.output = str;
|
||||
}
|
||||
|
||||
bool CLocale::ReadCached(StringBuffer* sb, Str& str)
|
||||
{
|
||||
// Look for a string with the right key in the cache
|
||||
std::map<TranslatedString*, CacheData>::iterator it =
|
||||
TranslationCache.find(sb->String);
|
||||
|
||||
// See if it actually exists
|
||||
if (it == TranslationCache.end())
|
||||
return false;
|
||||
|
||||
// Check quickly whether the hashes match
|
||||
if (sb->Hash() != (*it).second.hash)
|
||||
return false;
|
||||
|
||||
// Check every variable to see whether they're identical
|
||||
debug_assert(sb->Variables.size() == (*it).second.vars.size()); // this should always be true
|
||||
size_t count = sb->Variables.size();
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
if (! ( *sb->Variables[i] == *(*it).second.vars[i] ) )
|
||||
return false;
|
||||
|
||||
str = (*it).second.output;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CLocale::ClearCache()
|
||||
{
|
||||
// Deallocate cached data
|
||||
for (std::map<TranslatedString*, CacheData>::iterator it = TranslationCache.begin(); it != TranslationCache.end(); ++it)
|
||||
std::for_each((*it).second.vars.begin(), (*it).second.vars.end(), delete_fn<BufferVariable>);
|
||||
|
||||
TranslationCache.clear();
|
||||
}
|
||||
|
||||
|
||||
bool is_valid_variable_char(wchar_t c)
|
||||
{
|
||||
// c =~ /[a-zA-Z0-9_]/
|
||||
// (Hurrah for internationalisation.)
|
||||
return
|
||||
(c >= 'a' && c <= 'z')
|
||||
|| (c >= 'A' && c <= 'Z')
|
||||
|| (c >= '0' && c <= '9')
|
||||
|| (c == '_');
|
||||
}
|
||||
|
||||
TranslatedString& CLocale::AddDefaultString(const wchar_t* id)
|
||||
{
|
||||
// Parse a string involving $variables and $$ (=$)
|
||||
|
||||
enum ParseState {
|
||||
st_default,
|
||||
st_afterdollar,
|
||||
st_variable
|
||||
};
|
||||
ParseState state = st_default;
|
||||
|
||||
TranslatedString* str = new TranslatedString;
|
||||
str->VarCount = 0;
|
||||
|
||||
std::wstring tempstr;
|
||||
|
||||
for (const wchar_t* ch = id; *ch != '\0'; ++ch)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case st_default:
|
||||
if (*ch == '$')
|
||||
{
|
||||
state = st_afterdollar;
|
||||
}
|
||||
else
|
||||
{
|
||||
tempstr += *ch;
|
||||
}
|
||||
|
||||
break;
|
||||
case st_afterdollar:
|
||||
if (*ch == '$')
|
||||
{
|
||||
tempstr += '$';
|
||||
state = st_default;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Start of a variable name.
|
||||
// Push the old string onto the component stack
|
||||
if (tempstr.length())
|
||||
{
|
||||
str->Parts.push_back(new TSComponentString(tempstr.c_str()));
|
||||
tempstr.clear();
|
||||
}
|
||||
|
||||
// Set the ID (starting at 0) and increment the count
|
||||
str->Parts.push_back(new TSComponentVariable(str->VarCount++));
|
||||
|
||||
state = st_variable;
|
||||
}
|
||||
break;
|
||||
case st_variable:
|
||||
if (*ch == '$')
|
||||
{
|
||||
state = st_afterdollar;
|
||||
}
|
||||
else if (! is_valid_variable_char(*ch))
|
||||
{
|
||||
state = st_default;
|
||||
tempstr = *ch;
|
||||
}
|
||||
// We don't care about the actual name of the variable, so just ignore it.
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Make sure the last string is added to the parts list
|
||||
if (tempstr.length())
|
||||
str->Parts.push_back(new TSComponentString(tempstr.c_str()));
|
||||
|
||||
Strings[id] = str;
|
||||
|
||||
return *str;
|
||||
}
|
||||
|
||||
|
||||
CLocale::~CLocale()
|
||||
{
|
||||
// Clean up the list of strings
|
||||
for (StringsType::iterator it = Strings.begin(); it != Strings.end(); ++it)
|
||||
delete (*it).second;
|
||||
|
||||
ClearCache();
|
||||
}
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
CLocale contains all the data about a locale (/language).
|
||||
LoadFunctions/LoadStrings/LoadDictionary are used to specify data to be used
|
||||
when translating, and Translate is used to perform translations.
|
||||
|
||||
All other methods are used internally by other I18n components.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_I18N_CLOCALE
|
||||
#define INCLUDED_I18N_CLOCALE
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include "Interface.h"
|
||||
#include "StringBuffer.h"
|
||||
#include "StrImmutable.h"
|
||||
#include "ScriptInterface.h"
|
||||
|
||||
#include "lib/sysdep/stl.h" // STL_HASH_MAP
|
||||
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
||||
struct JSContext;
|
||||
|
||||
namespace I18n
|
||||
{
|
||||
|
||||
class CLocale : public CLocale_interface
|
||||
{
|
||||
friend class StringBuffer;
|
||||
|
||||
private:
|
||||
typedef STL_HASH_MAP<Str, TranslatedString*> StringsType;
|
||||
|
||||
public:
|
||||
StringBuffer Translate(const wchar_t* id);
|
||||
|
||||
bool LoadFunctions(const char* filedata, size_t len, const char* filename);
|
||||
bool LoadStrings(const char* filedata);
|
||||
bool LoadDictionary(const char* filedata);
|
||||
void UnloadDictionaries();
|
||||
|
||||
const StrImW CallFunction(const char* name, const std::vector<BufferVariable*>& vars, const std::vector<ScriptValue*>& params);
|
||||
|
||||
private:
|
||||
struct DictData;
|
||||
public:
|
||||
typedef std::pair<const DictData*, const std::vector<Str>*> LookupType;
|
||||
|
||||
// Returns a new'ed structure. Please remember to delete it.
|
||||
const LookupType* LookupWord(const Str& dictname, const Str& word);
|
||||
|
||||
bool LookupProperty(const LookupType* data, const Str& property, Str& result);
|
||||
|
||||
CLocale(JSContext* context, JSObject* scope) : CacheAge(0), Script(this, context, scope) {}
|
||||
~CLocale();
|
||||
|
||||
void AddToCache(StringBuffer*, Str&);
|
||||
bool ReadCached(StringBuffer*, Str&);
|
||||
void ClearCache();
|
||||
|
||||
private:
|
||||
|
||||
TranslatedString& AddDefaultString(const wchar_t* id);
|
||||
|
||||
StringsType Strings;
|
||||
|
||||
// Incremented by every call to Translate(), with
|
||||
// ClearCache() being run after a certain number of calls.
|
||||
// TODO: Replace with a better caching system.
|
||||
int CacheAge;
|
||||
static const int CacheAgeLimit = 1024;
|
||||
|
||||
struct CacheData
|
||||
{
|
||||
u32 hash;
|
||||
std::vector<BufferVariable*> vars;
|
||||
Str output;
|
||||
};
|
||||
std::map<TranslatedString*, CacheData> TranslationCache;
|
||||
|
||||
struct DictData
|
||||
{
|
||||
std::map< Str /* property name */, int /* property id */ > DictProperties;
|
||||
std::map< Str /* word */, std::vector<Str> /* properties */ > DictWords;
|
||||
};
|
||||
std::map<Str /* dictionary name */, DictData> Dictionaries;
|
||||
|
||||
ScriptObject Script;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif // INCLUDED_I18N_CLOCALE
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Things that are used by most I18n code:
|
||||
|
||||
#ifndef INCLUDED_I18N_COMMON
|
||||
#define INCLUDED_I18N_COMMON
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "ps/Errors.h"
|
||||
|
||||
namespace I18n
|
||||
{
|
||||
// Define an 'internal' string type, for no particular reason
|
||||
typedef std::wstring Str;
|
||||
}
|
||||
|
||||
ERROR_GROUP(I18n);
|
||||
|
||||
// That was exciting.
|
||||
|
||||
#endif // INCLUDED_I18N_COMMON
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_I18N_DATATYPES
|
||||
#define INCLUDED_I18N_DATATYPES
|
||||
|
||||
#include "StrImmutable.h"
|
||||
|
||||
namespace I18n
|
||||
{
|
||||
// Use for names of objects that should be translated, e.g.
|
||||
// translate("Construct $obj")<<I18n::Noun(selectedobject.name)
|
||||
struct Noun
|
||||
{
|
||||
template<typename T> Noun(T d) : value(d) {}
|
||||
StrImW value;
|
||||
};
|
||||
|
||||
// Allow translate("Hello $you")<<I18n::Name(playername), which
|
||||
// won't attempt to translate the player's name.
|
||||
// Templated to allow char* and wchar_t*
|
||||
struct Name
|
||||
{
|
||||
template<typename T> Name(T d) : value(d) {}
|
||||
StrImW value;
|
||||
};
|
||||
|
||||
// Also allow I18n::Raw("english message"), which does the same
|
||||
// non-translation but makes more sense when writing e.g. error messages
|
||||
typedef Name Raw;
|
||||
}
|
||||
|
||||
|
||||
#endif // INCLUDED_I18N_DATATYPES
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Vague overview of the i18n code:
|
||||
(TODO: Improve the documentation)
|
||||
|
||||
CLocale stores all locale-specific (locale==language, roughly) data.
|
||||
Usually there's only going to be one in existence.
|
||||
|
||||
A language needs to define:
|
||||
|
||||
* String files that define translations for phrases.
|
||||
* Dictionary files that translate individual words (usually names of objects),
|
||||
including extra information that the grammar requires (whether to use 'a' or
|
||||
'an' in English, gender in lots of European languages, etc)
|
||||
* .js files containing functions that apply grammatical rules
|
||||
(e.g. choosing singular vs plural depending on a number)
|
||||
|
||||
CLocale::LoadStrings / LoadDictionary / LoadFunctions are used to input the
|
||||
data from the appropriate files. Call multiple times if desired.
|
||||
|
||||
CLocale::Translate is the primary interface. Pass it a unique identifier
|
||||
string, and it'll read the appropriate translated data from the
|
||||
loaded data files. A StringBuffer is returned.
|
||||
|
||||
To allow variables embedded in text, StringBuffer::operator<< is used
|
||||
in a similar way to in cout, storing the variable in the StringBuffer and
|
||||
returning the StringBuffer again.
|
||||
StringBuffer::operator Str() does the final insertion of variables into
|
||||
the translated phrase, either grabbing the final result from a cache or
|
||||
doing all the variable-to-string conversions.
|
||||
|
||||
|
||||
The strings read from disk are each stored as a TranslatedString,
|
||||
containing several TSComponents, which are either static strings or
|
||||
default-formatted variables or functions.
|
||||
|
||||
TSComponentFunction is the most complex of the TSComponents, containing a
|
||||
list of ScriptValues -- these allow numbers, strings and variables to be
|
||||
passed as parameters into a JS function.
|
||||
|
||||
|
||||
StringBuffer::operator<< stores BufferVariable*s in the StringBuffer.
|
||||
These provide access to a hash of the variable (for caching), and can
|
||||
be converted into a string (for display).
|
||||
|
||||
|
||||
StrImW is used in various places, just as a more efficient alternative
|
||||
to std::wstring.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "Interface.h"
|
||||
#include "CLocale.h"
|
||||
|
||||
#include "ps/CLogger.h"
|
||||
#define LOG_CATEGORY L"i18n"
|
||||
|
||||
using namespace I18n;
|
||||
|
||||
struct JSContext;
|
||||
|
||||
CLocale_interface* I18n::NewLocale(JSContext* cx, JSObject* scope)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new CLocale(cx, scope);
|
||||
}
|
||||
catch (PSERROR_I18n& e)
|
||||
{
|
||||
LOG(CLogger::Error, LOG_CATEGORY, L"Error creating locale object ('%hs')", e.what());
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
The only file that external code should need to include.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_I18N_INTERFACE
|
||||
#define INCLUDED_I18N_INTERFACE
|
||||
|
||||
#include "StringBuffer.h"
|
||||
#include "DataTypes.h"
|
||||
|
||||
struct JSContext;
|
||||
struct JSObject;
|
||||
|
||||
namespace I18n
|
||||
{
|
||||
// Use an interface class, so minimal headers are required by
|
||||
// anybody who only wants to make use of Translate()
|
||||
class CLocale_interface
|
||||
{
|
||||
public:
|
||||
virtual StringBuffer Translate(const wchar_t* id) = 0;
|
||||
|
||||
// Load* functions return true for success, false for failure
|
||||
|
||||
// Pass the contents of a UTF-16LE BOMmed .js file.
|
||||
// The filename is just used to give more useful error messages from JS.
|
||||
virtual bool LoadFunctions(const char* filedata, size_t len, const char* filename) = 0;
|
||||
|
||||
// Desires a .lng file, as produced by convert.pl
|
||||
virtual bool LoadStrings(const char* filedata) = 0;
|
||||
|
||||
// Needs .wrd files generated through tables.pl
|
||||
virtual bool LoadDictionary(const char* filedata) = 0;
|
||||
|
||||
virtual void UnloadDictionaries() = 0;
|
||||
|
||||
virtual ~CLocale_interface() {}
|
||||
};
|
||||
|
||||
// Build a CLocale. Returns NULL on failure.
|
||||
CLocale_interface* NewLocale(JSContext* cx, JSObject* scope);
|
||||
}
|
||||
|
||||
#endif // INCLUDED_I18N_INTERFACE
|
||||
|
|
@ -1,485 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "ScriptInterface.h"
|
||||
#include "CLocale.h"
|
||||
#include "ps/StringConvert.h"
|
||||
#include "scripting/SpiderMonkey.h"
|
||||
|
||||
#include "ps/CLogger.h"
|
||||
#define LOG_CATEGORY L"i18n"
|
||||
|
||||
using namespace I18n;
|
||||
|
||||
// LookedupWord JS class:
|
||||
namespace JSI_LookedupWord {
|
||||
|
||||
static JSBool GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
||||
{
|
||||
CLocale::LookupType* lookedup = (CLocale::LookupType*)JS_GetPrivate(cx, obj);
|
||||
debug_assert(lookedup);
|
||||
|
||||
JSObject* parent = JS_GetParent(cx, obj);
|
||||
debug_assert(parent);
|
||||
CLocale* locale = (CLocale*)JS_GetPrivate(cx, parent);
|
||||
debug_assert(locale);
|
||||
|
||||
JSString* prop = JS_ValueToString(cx, id);
|
||||
JSU_ASSERT(prop, "lookup() property failed to convert to string");
|
||||
|
||||
jschar* prop_chars = JS_GetStringChars(prop);
|
||||
|
||||
Str prop_str;
|
||||
StringConvert::jschars_to_wstring(prop_chars, JS_GetStringLength(prop), prop_str);
|
||||
|
||||
Str result;
|
||||
if (! locale->LookupProperty(lookedup, prop_str, result))
|
||||
result = L"(unrecognised property)";
|
||||
|
||||
JSString* result_str = StringConvert::wstring_to_jsstring(cx, result);
|
||||
JSU_ASSERT(result_str, "lookup() property failed to create string");
|
||||
|
||||
*vp = STRING_TO_JSVAL(result_str);
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static void Finalize(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
// Free the LookupType that was allocated when building this object
|
||||
|
||||
CLocale::LookupType* lookedup = (CLocale::LookupType*)JS_GetPrivate(cx, obj);
|
||||
debug_assert(lookedup);
|
||||
delete lookedup;
|
||||
}
|
||||
|
||||
static JSClass JSI_class = {
|
||||
"LookedupWord", JSCLASS_HAS_PRIVATE,
|
||||
JS_PropertyStub, JS_PropertyStub,
|
||||
GetProperty, JS_PropertyStub,
|
||||
JS_EnumerateStub, JS_ResolveStub,
|
||||
JS_ConvertStub, Finalize,
|
||||
NULL, NULL, NULL, NULL
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// 'i18n' JS class:
|
||||
namespace JSI_i18n {
|
||||
|
||||
#define TYPE(x) \
|
||||
static JSBool Create_##x(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval) \
|
||||
{ \
|
||||
/* Set *rval = { type => "Name", value => argv[0] } */ \
|
||||
\
|
||||
JSObject* object = JS_NewObject(cx, NULL, NULL, obj); \
|
||||
JSU_ASSERT(object, "Failed to create i18n value object"); \
|
||||
\
|
||||
/* TODO: More error checking */ \
|
||||
JSU_REQUIRE_PARAMS(1); \
|
||||
jsval type = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, #x)); \
|
||||
jsval value = STRING_TO_JSVAL(JS_ValueToString(cx, argv[0])); \
|
||||
JS_SetProperty(cx, object, "type", &type); \
|
||||
JS_SetProperty(cx, object, "value", &value); \
|
||||
\
|
||||
*rval = OBJECT_TO_JSVAL(object); \
|
||||
\
|
||||
return JS_TRUE; \
|
||||
}
|
||||
TYPE(Name)
|
||||
TYPE(Raw)
|
||||
TYPE(Noun)
|
||||
#undef TYPE
|
||||
|
||||
static JSClass JSI_class = {
|
||||
"JSI_i18n", JSCLASS_HAS_PRIVATE,
|
||||
JS_PropertyStub, JS_PropertyStub,
|
||||
JS_PropertyStub, JS_PropertyStub,
|
||||
JS_EnumerateStub, JS_ResolveStub,
|
||||
JS_ConvertStub, JS_FinalizeStub,
|
||||
NULL, NULL, NULL, NULL
|
||||
};
|
||||
|
||||
#define TYPE(x) {#x, Create_##x, 1, 0, 0}
|
||||
static JSFunctionSpec JSI_funcs[] = {
|
||||
TYPE(Name),
|
||||
TYPE(Raw),
|
||||
TYPE(Noun),
|
||||
{0,0,0,0,0},
|
||||
};
|
||||
#undef TYPE
|
||||
}
|
||||
|
||||
|
||||
static JSBool JSFunc_LookupWord(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
JSU_REQUIRE_PARAMS(2);
|
||||
|
||||
// Get the strings
|
||||
JSString* dictname = JS_ValueToString(cx, argv[0]);
|
||||
JSString* word = JS_ValueToString(cx, argv[1]);
|
||||
JSU_ASSERT(dictname && word, "lookup() failed to convert parameters to strings");
|
||||
|
||||
// and the characters from the strings
|
||||
jschar* dictname_chars = JS_GetStringChars(dictname);
|
||||
jschar* word_chars = JS_GetStringChars(word);
|
||||
// (can't fail)
|
||||
|
||||
// and convert those characters into to wstrings
|
||||
Str dictname_str, word_str;
|
||||
StringConvert::jschars_to_wstring(dictname_chars, JS_GetStringLength(dictname), dictname_str);
|
||||
StringConvert::jschars_to_wstring(word_chars, JS_GetStringLength(word), word_str);
|
||||
|
||||
// Extract the CLocale* from the 'global' object
|
||||
CLocale* locale = (CLocale*)JS_GetPrivate(cx, obj);
|
||||
|
||||
const CLocale::LookupType* lookedup = locale->LookupWord(dictname_str, word_str);
|
||||
if (! lookedup)
|
||||
{
|
||||
// Couldn't find the word in the table
|
||||
*rval = JSVAL_NULL;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
// Create an object to be returned, containing enough data to access properties of the found word
|
||||
JSObject* wordobj = JS_NewObject(cx, &JSI_LookedupWord::JSI_class, NULL, obj);
|
||||
JSU_ASSERT(wordobj, "lookup() failed to create object");
|
||||
|
||||
// Associate the looked-up word data with the JS object
|
||||
JS_SetPrivate(cx, wordobj, (void*)lookedup);
|
||||
|
||||
*rval = OBJECT_TO_JSVAL(wordobj);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool JSFunc_Translate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
JSU_ASSERT(argc >= 1, "Too few parameters to translate() function");
|
||||
|
||||
JSString* phrase_str = JS_ValueToString(cx, argv[0]);
|
||||
JSU_ASSERT(phrase_str, "translate() failed to convert first parameter to string");
|
||||
|
||||
CStrW phrase (JS_GetStringChars(phrase_str));
|
||||
|
||||
jsval locale_objval;
|
||||
JSU_ASSERT(JS_GetProperty(cx, obj, "i18n", &locale_objval), "translate() failed to find i18n object in current scope");
|
||||
CLocale* locale = (CLocale*)JS_GetPrivate(cx, JSVAL_TO_OBJECT(locale_objval));
|
||||
|
||||
StringBuffer sb = locale->Translate(phrase.c_str());
|
||||
for (uintN i=1; i<argc; ++i)
|
||||
{
|
||||
if (JSVAL_IS_INT(argv[i]))
|
||||
{
|
||||
sb << (int) JSVAL_TO_INT(argv[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (JSVAL_IS_DOUBLE(argv[i]))
|
||||
{
|
||||
sb << *JSVAL_TO_DOUBLE(argv[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (JSVAL_IS_OBJECT(argv[i]))
|
||||
{
|
||||
// Check for 'type' and 'value' properties
|
||||
jsval type, value;
|
||||
if (JS_GetProperty(cx, JSVAL_TO_OBJECT(argv[i]), "type", &type)
|
||||
&& type != JSVAL_VOID
|
||||
&& JS_GetProperty(cx, JSVAL_TO_OBJECT(argv[i]), "value", &value)
|
||||
&& value != JSVAL_VOID)
|
||||
{
|
||||
// TODO: More error handling
|
||||
std::string typestr = JS_GetStringBytes(JS_ValueToString(cx, type));
|
||||
|
||||
std::wstring val;
|
||||
if (typestr == "Name")
|
||||
{
|
||||
JSString* s = JS_ValueToString(cx, value);
|
||||
sb << I18n::Name(JS_GetStringChars(s));
|
||||
continue;
|
||||
}
|
||||
else if (typestr == "Raw")
|
||||
{
|
||||
JSString* s = JS_ValueToString(cx, value);
|
||||
sb << I18n::Raw(JS_GetStringChars(s));
|
||||
continue;
|
||||
}
|
||||
else if (typestr == "Noun")
|
||||
{
|
||||
JSString* s = JS_ValueToString(cx, value);
|
||||
sb << I18n::Noun(JS_GetStringChars(s));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JS_ReportError(cx, "Invalid parameter passed to translate() (must be a number or a i18n.something() object)");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
JSString* result_str = StringConvert::wstring_to_jsstring(cx, sb);
|
||||
*rval = STRING_TO_JSVAL(result_str);
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Visible to all JS code:
|
||||
static JSFunctionSpec JSI_i18nInterfaceFunctions[] = {
|
||||
{"translate", JSFunc_Translate, 0, 0, 0},
|
||||
{0,0,0,0,0},
|
||||
};
|
||||
|
||||
// Visible to functions called by the i18n system:
|
||||
static JSFunctionSpec JSI_i18nFunctions[] = {
|
||||
{"lookup", JSFunc_LookupWord, 2, 0, 0},
|
||||
{0,0,0,0,0},
|
||||
};
|
||||
|
||||
// Object under which to run functions called by the i18n system:
|
||||
static JSClass JSI_i18nFunctionScope = {
|
||||
"", JSCLASS_HAS_PRIVATE,
|
||||
JS_PropertyStub, JS_PropertyStub,
|
||||
JS_PropertyStub, JS_PropertyStub,
|
||||
JS_EnumerateStub, JS_ResolveStub,
|
||||
JS_ConvertStub, JS_FinalizeStub,
|
||||
NULL, NULL, NULL, NULL
|
||||
};
|
||||
|
||||
|
||||
ScriptObject::ScriptObject(CLocale* locale, JSContext* cx, JSObject* scope)
|
||||
: Context(cx)
|
||||
{
|
||||
// Don't do much if there's currently no scripting support
|
||||
if (cx == NULL)
|
||||
return;
|
||||
|
||||
// This constructor should, in theory, never fail
|
||||
|
||||
// Create the object [/scope] under which the locale-dependent translation
|
||||
// functions are executed
|
||||
Object = JS_NewObject(Context, &JSI_i18nFunctionScope, NULL, NULL);
|
||||
if (! Object)
|
||||
throw PSERROR_I18n_Script_SetupFailed();
|
||||
|
||||
JS_AddRoot(Context, &Object);
|
||||
// (This will get leaked if the constructor throws, but there will be more
|
||||
// important things to worry about than memory leaks in those situations)
|
||||
|
||||
// Register the functions for use by i18n translations
|
||||
if (! JS_DefineFunctions(Context, Object, JSI_i18nFunctions))
|
||||
throw PSERROR_I18n_Script_SetupFailed();
|
||||
|
||||
// Store the CLocale* in the script-object's private area
|
||||
JS_SetPrivate(Context, Object, locale);
|
||||
|
||||
// Interface setup:
|
||||
|
||||
// Register the interface functions
|
||||
if (! JS_DefineFunctions(Context, scope, JSI_i18nInterfaceFunctions))
|
||||
throw PSERROR_I18n_Script_SetupFailed();
|
||||
|
||||
// Create the 'i18n' interface object
|
||||
JSObject* i18nObject = JS_DefineObject(Context, scope, "i18n", &JSI_i18n::JSI_class, NULL, JSPROP_READONLY | JSPROP_PERMANENT);
|
||||
if (! i18nObject)
|
||||
throw PSERROR_I18n_Script_SetupFailed();
|
||||
|
||||
// Define its functions (i18n.Name() etc)
|
||||
if (! JS_DefineFunctions(Context, i18nObject, JSI_i18n::JSI_funcs))
|
||||
throw PSERROR_I18n_Script_SetupFailed();
|
||||
|
||||
// Store the CLocale* in the i18n object's private area
|
||||
JS_SetPrivate(Context, i18nObject, locale);
|
||||
|
||||
}
|
||||
|
||||
ScriptObject::~ScriptObject()
|
||||
{
|
||||
if (Context)
|
||||
JS_RemoveRoot(Context, &Object);
|
||||
}
|
||||
|
||||
bool ScriptObject::ExecuteCode(const jschar* data, size_t len, const char* filename)
|
||||
{
|
||||
jsval ret;
|
||||
return (JS_EvaluateUCScript(Context, Object, data, (int)len-1, filename, 1, &ret) ? true : false);
|
||||
// use len-1 to stop JS crashing. *shrug* ^^^^^
|
||||
}
|
||||
|
||||
|
||||
const StrImW ScriptObject::CallFunction(const char* name, const std::vector<BufferVariable*>& vars, const std::vector<ScriptValue*>& params)
|
||||
{
|
||||
int argc = (int)params.size();
|
||||
|
||||
// Construct argv, converting each parameter into a jsval
|
||||
jsval* argv = new jsval[argc];
|
||||
for (int i = 0; i < argc; ++i)
|
||||
argv[i] = params[i]->GetJsval(vars);
|
||||
|
||||
jsval rval;
|
||||
bool called = JS_CallFunctionName(Context, Object, name, argc, argv, &rval) ? true : false;
|
||||
|
||||
delete[] argv;
|
||||
|
||||
if (! called)
|
||||
{
|
||||
LOG(CLogger::Error, LOG_CATEGORY, L"I18n: Error executing JS function '%hs'", name);
|
||||
return L"(JS error)";
|
||||
}
|
||||
|
||||
// Convert rval to a string and return
|
||||
|
||||
JSString* str = JS_ValueToString(Context, rval);
|
||||
if (! str)
|
||||
{
|
||||
debug_warn(L"Conversion to string failed");
|
||||
return L"(JS error)";
|
||||
}
|
||||
jschar* chars = JS_GetStringChars(str);
|
||||
if (! chars)
|
||||
{
|
||||
debug_warn(L"GetStringChars failed");
|
||||
return L"(JS error)";
|
||||
}
|
||||
return StrImW(chars, JS_GetStringLength(str));
|
||||
}
|
||||
|
||||
|
||||
ScriptValueString::ScriptValueString(ScriptObject& script, const wchar_t* s)
|
||||
{
|
||||
Context = script.Context;
|
||||
|
||||
JSString* str = StringConvert::wchars_to_jsstring(Context, s);
|
||||
if (!str)
|
||||
{
|
||||
debug_warn(L"Error creating JS string");
|
||||
Value = JSVAL_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
Value = STRING_TO_JSVAL(str);
|
||||
JS_AddRoot(Context, &Value);
|
||||
}
|
||||
}
|
||||
|
||||
jsval ScriptValueString::GetJsval(const std::vector<BufferVariable*>& UNUSED(vars))
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
|
||||
|
||||
ScriptValueString::~ScriptValueString()
|
||||
{
|
||||
if (! JSVAL_IS_NULL(Value))
|
||||
{
|
||||
JS_RemoveRoot(Context, &Value);
|
||||
}
|
||||
}
|
||||
|
||||
/************/
|
||||
|
||||
ScriptValueInteger::ScriptValueInteger(ScriptObject& script, const int v)
|
||||
{
|
||||
Context = script.Context;
|
||||
Value = INT_TO_JSVAL(v);
|
||||
}
|
||||
|
||||
jsval ScriptValueInteger::GetJsval(const std::vector<BufferVariable*>& UNUSED(vars))
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
|
||||
ScriptValueInteger::~ScriptValueInteger()
|
||||
{
|
||||
}
|
||||
|
||||
/************/
|
||||
|
||||
|
||||
ScriptValueVariable::ScriptValueVariable(ScriptObject& script, const unsigned char id)
|
||||
{
|
||||
Context = script.Context;
|
||||
ID = id;
|
||||
GCVal = NULL;
|
||||
}
|
||||
|
||||
jsval ScriptValueVariable::GetJsval(const std::vector<BufferVariable*>& vars)
|
||||
{
|
||||
// Clean up from earlier invocations
|
||||
if (GCVal)
|
||||
{
|
||||
JS_RemoveRoot(Context, &GCVal);
|
||||
GCVal = NULL;
|
||||
}
|
||||
|
||||
switch (vars[ID]->Type)
|
||||
{
|
||||
case vartype_int:
|
||||
{
|
||||
int val = ((BufferVariable_int*)vars[ID])->value;
|
||||
return INT_TO_JSVAL(val);
|
||||
}
|
||||
case vartype_double:
|
||||
{
|
||||
jsdouble* val = JS_NewDouble(Context, ((BufferVariable_double*)vars[ID])->value);
|
||||
if (!val)
|
||||
{
|
||||
debug_warn(L"Error creating JS double");
|
||||
return JSVAL_NULL;
|
||||
}
|
||||
GCVal = (void*)val;
|
||||
JS_AddRoot(Context, &GCVal);
|
||||
return DOUBLE_TO_JSVAL(val);
|
||||
}
|
||||
case vartype_string:
|
||||
{
|
||||
JSString* val = StringConvert::wchars_to_jsstring(Context, ((BufferVariable_string*)vars[ID])->value.str());
|
||||
if (!val)
|
||||
{
|
||||
debug_warn(L"Error creating JS string");
|
||||
return JSVAL_NULL;
|
||||
}
|
||||
GCVal = (void*)val;
|
||||
JS_AddRoot(Context, &GCVal);
|
||||
return STRING_TO_JSVAL(val);
|
||||
}
|
||||
case vartype_rawstring:
|
||||
{
|
||||
JSString* val = StringConvert::wchars_to_jsstring(Context, ((BufferVariable_rawstring*)vars[ID])->value.str());
|
||||
if (!val)
|
||||
{
|
||||
debug_warn(L"Error creating JS string");
|
||||
return JSVAL_NULL;
|
||||
}
|
||||
GCVal = (void*)val;
|
||||
JS_AddRoot(Context, &GCVal);
|
||||
return STRING_TO_JSVAL(val);
|
||||
}
|
||||
default:
|
||||
debug_warn(L"Invalid type");
|
||||
return JSVAL_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ScriptValueVariable::~ScriptValueVariable()
|
||||
{
|
||||
if (GCVal)
|
||||
JS_RemoveRoot(Context, &GCVal);
|
||||
}
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
ScriptObject provides an interface to the JavaScript engine.
|
||||
|
||||
ScriptValues are used to generate jsvals from 'constants' (strings, ints)
|
||||
and 'variables' (dependent on the type passed with "translate(...) <<").
|
||||
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_I18N_SCRIPTINTERFACE
|
||||
#define INCLUDED_I18N_SCRIPTINTERFACE
|
||||
|
||||
#include "Common.h"
|
||||
#include "BufferVariable.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
ERROR_SUBGROUP(I18n, Script);
|
||||
ERROR_TYPE(I18n_Script, SetupFailed);
|
||||
|
||||
typedef intptr_t JSWord;
|
||||
typedef JSWord jsword;
|
||||
typedef jsword jsval;
|
||||
typedef unsigned short jschar;
|
||||
struct JSContext;
|
||||
struct JSObject;
|
||||
|
||||
namespace I18n
|
||||
{
|
||||
|
||||
class ScriptValue;
|
||||
class CLocale;
|
||||
|
||||
class ScriptObject
|
||||
{
|
||||
public:
|
||||
ScriptObject(CLocale* locale, JSContext* cx, JSObject* scope);
|
||||
~ScriptObject();
|
||||
|
||||
bool ExecuteCode(const jschar* data, size_t len, const char* filename);
|
||||
|
||||
const StrImW CallFunction(const char* name, const std::vector<BufferVariable*>& vars, const std::vector<ScriptValue*>& params);
|
||||
|
||||
JSContext* Context;
|
||||
JSObject* Object;
|
||||
};
|
||||
|
||||
// Virtual base class for script values
|
||||
class ScriptValue
|
||||
{
|
||||
public:
|
||||
virtual jsval GetJsval(const std::vector<BufferVariable*>& vars) = 0;
|
||||
virtual ~ScriptValue() {};
|
||||
|
||||
protected:
|
||||
JSContext* Context;
|
||||
};
|
||||
|
||||
// Particular types of script value:
|
||||
|
||||
class ScriptValueString : public ScriptValue
|
||||
{
|
||||
public:
|
||||
ScriptValueString(ScriptObject& script, const wchar_t* s);
|
||||
~ScriptValueString();
|
||||
jsval GetJsval(const std::vector<BufferVariable*>& vars);
|
||||
|
||||
private:
|
||||
jsval Value;
|
||||
};
|
||||
|
||||
class ScriptValueInteger : public ScriptValue
|
||||
{
|
||||
public:
|
||||
ScriptValueInteger(ScriptObject& script, const int v);
|
||||
~ScriptValueInteger();
|
||||
jsval GetJsval(const std::vector<BufferVariable*>& vars);
|
||||
|
||||
private:
|
||||
jsval Value;
|
||||
};
|
||||
|
||||
class ScriptValueVariable : public ScriptValue
|
||||
{
|
||||
public:
|
||||
ScriptValueVariable(ScriptObject& script, const unsigned char id);
|
||||
~ScriptValueVariable();
|
||||
jsval GetJsval(const std::vector<BufferVariable*>& vars);
|
||||
|
||||
private:
|
||||
unsigned char ID;
|
||||
void* GCVal; // something that's being garbage-collected
|
||||
};
|
||||
}
|
||||
|
||||
#endif // INCLUDED_I18N_SCRIPTINTERFACE
|
||||
|
|
@ -1,123 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
A reference-counted immutable string; more efficient than std::wstring
|
||||
when returning strings from functions. (My i18n test program went ~20% faster,
|
||||
which is not insignificant).
|
||||
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_I18N_STRIMMUTABLE
|
||||
#define INCLUDED_I18N_STRIMMUTABLE
|
||||
|
||||
#include <wchar.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lib/sysdep/cpu.h"
|
||||
|
||||
typedef unsigned short jschar;
|
||||
|
||||
namespace I18n
|
||||
{
|
||||
struct strImW_data
|
||||
{
|
||||
int refs;
|
||||
wchar_t* data;
|
||||
strImW_data() : refs(1) {}
|
||||
};
|
||||
|
||||
class StrImW
|
||||
{
|
||||
public:
|
||||
|
||||
// I'm lazy (elsewhere), so allow construction from a variety
|
||||
// of data types:
|
||||
|
||||
StrImW(const wchar_t* s)
|
||||
{
|
||||
ref = new strImW_data;
|
||||
size_t len = wcslen(s)+1;
|
||||
ref->data = new wchar_t[len];
|
||||
memcpy((void*)ref->data, s, len*sizeof(wchar_t));
|
||||
}
|
||||
|
||||
StrImW(const char* s)
|
||||
{
|
||||
ref = new strImW_data;
|
||||
size_t len = strlen(s)+1;
|
||||
ref->data = new wchar_t[len];
|
||||
for (size_t i=0; i<len; ++i)
|
||||
ref->data[i] = s[i];
|
||||
}
|
||||
|
||||
// On non-MSVC, or on MSVC with a native wchar_t type, define jschar separately
|
||||
#if !MSC_VERSION || defined(_NATIVE_WCHAR_T_DEFINED)
|
||||
StrImW(const jschar* s)
|
||||
{
|
||||
ref = new strImW_data;
|
||||
size_t len = 0;
|
||||
while (s[len] != '\0') ++len;
|
||||
++len; // include the \0
|
||||
ref->data = new wchar_t[len];
|
||||
for (size_t i=0; i<len; ++i)
|
||||
ref->data[i] = s[i];
|
||||
}
|
||||
#endif
|
||||
|
||||
StrImW(const jschar* s, size_t len)
|
||||
{
|
||||
ref = new strImW_data;
|
||||
ref->data = new wchar_t[len+1];
|
||||
for (size_t i=0; i<len; ++i)
|
||||
ref->data[i] = s[i];
|
||||
ref->data[len] = 0;
|
||||
}
|
||||
|
||||
~StrImW()
|
||||
{
|
||||
if (--ref->refs == 0)
|
||||
{
|
||||
delete[] ref->data;
|
||||
delete ref;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy constructor
|
||||
StrImW(const StrImW& s)
|
||||
{
|
||||
ref = s.ref;
|
||||
++ref->refs;
|
||||
}
|
||||
|
||||
const wchar_t* str() const
|
||||
{
|
||||
return ref->data;
|
||||
}
|
||||
|
||||
bool operator== (const StrImW& s)
|
||||
{
|
||||
return s.ref==this->ref || wcscmp(s.ref->data, this->ref->data)==0;
|
||||
}
|
||||
|
||||
private:
|
||||
strImW_data* ref;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // INCLUDED_I18N_STRIMMUTABLE
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "CLocale.h"
|
||||
#include "TSComponent.h"
|
||||
#include "StringBuffer.h"
|
||||
|
||||
// Vaguely useful utility function for deleting stuff
|
||||
template<typename T> void delete_fn(T* v) { delete v; }
|
||||
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "ps/CLogger.h"
|
||||
#define LOG_CATEGORY L"i18n"
|
||||
|
||||
using namespace I18n;
|
||||
|
||||
#ifdef I18NDEBUG
|
||||
namespace I18n { bool g_UsedCache; }
|
||||
#endif
|
||||
|
||||
I18n::StringBuffer::operator Str()
|
||||
{
|
||||
#ifdef I18NDEBUG
|
||||
g_UsedCache = false;
|
||||
#endif
|
||||
|
||||
if (Variables.size() != String->VarCount)
|
||||
{
|
||||
LOG(CLogger::Error, LOG_CATEGORY, L"I18n: Incorrect number of parameters passed to Translate");
|
||||
|
||||
// Tidy up
|
||||
std::for_each(Variables.begin(), Variables.end(), delete_fn<BufferVariable>);
|
||||
|
||||
return L"(translation error)";
|
||||
}
|
||||
|
||||
if (String->VarCount == 0)
|
||||
{
|
||||
if (String->Parts.size())
|
||||
return String->Parts[0]->ToString(Locale, Variables).str();
|
||||
else
|
||||
return Str();
|
||||
}
|
||||
|
||||
Str ret;
|
||||
|
||||
if (Locale->ReadCached(this, ret))
|
||||
{
|
||||
// Found in cache
|
||||
|
||||
#ifdef I18NDEBUG
|
||||
g_UsedCache = true;
|
||||
#endif
|
||||
|
||||
// Clean up the current allocated data
|
||||
std::for_each(Variables.begin(), Variables.end(), delete_fn<BufferVariable>);
|
||||
// Return the cached string
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Not in cache - construct the string
|
||||
for (std::vector<const TSComponent*>::iterator it = String->Parts.begin(),
|
||||
end = String->Parts.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
ret += (*it)->ToString(Locale, Variables).str();
|
||||
}
|
||||
|
||||
Locale->AddToCache(this, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 I18n::StringBuffer::Hash()
|
||||
{
|
||||
u32 hash = 0;
|
||||
size_t max = Variables.size();
|
||||
for (size_t i = 0; i < max; ++i)
|
||||
hash += Variables[i]->Hash();
|
||||
return hash;
|
||||
}
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Returned by Translate(), and used to collect variables from the user
|
||||
before converting into a string.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_I18N_STRINGBUFFER
|
||||
#define INCLUDED_I18N_STRINGBUFFER
|
||||
|
||||
#include "Common.h"
|
||||
#include "TranslatedString.h"
|
||||
#include "ps/CStr.h"
|
||||
|
||||
namespace I18n
|
||||
{
|
||||
class CLocale;
|
||||
class BufferVariable;
|
||||
|
||||
template<typename T> BufferVariable* NewBufferVariable(T v);
|
||||
|
||||
class StringBuffer
|
||||
{
|
||||
friend class CLocale;
|
||||
|
||||
public:
|
||||
// Builds and returns the finished string
|
||||
operator Str();
|
||||
operator CStrW() { return CStrW( (Str)*this ); }
|
||||
|
||||
// Stores the variable inside the StringBuffer,
|
||||
// for later conversion into a string
|
||||
template<typename T> StringBuffer& operator<< (T v)
|
||||
{
|
||||
// This BufferVariable is freed by the caching system (yuck)
|
||||
Variables.push_back(NewBufferVariable(v));
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Returns a simple hash of the contents of Variables
|
||||
u32 Hash();
|
||||
|
||||
private:
|
||||
TranslatedString* String;
|
||||
// pointer instead of reference allows assignment.
|
||||
// this class is returned by value, so it's nicer for the
|
||||
// compiler-generated copy ctor to be used.
|
||||
std::vector<BufferVariable*> Variables;
|
||||
CLocale* Locale;
|
||||
|
||||
StringBuffer(TranslatedString* str, CLocale* loc)
|
||||
: String(str), Locale(loc)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // INCLUDED_I18N_STRINGBUFFER
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "TSComponent.h"
|
||||
#include "CLocale.h"
|
||||
|
||||
using namespace I18n;
|
||||
|
||||
// Vaguely useful utility function for deleting stuff
|
||||
template<typename T> void delete_fn(T* v) { delete v; }
|
||||
|
||||
const StrImW TSComponentString::ToString(CLocale* UNUSED(locale), std::vector<BufferVariable*>& UNUSED(vars)) const
|
||||
{
|
||||
return String;
|
||||
}
|
||||
|
||||
/**************/
|
||||
|
||||
const StrImW TSComponentVariable::ToString(CLocale* locale, std::vector<BufferVariable*>& vars) const
|
||||
{
|
||||
// This will never be out-of-bounds -- the number
|
||||
// of parameters has been checked earlier
|
||||
return vars[ID]->ToString(locale);
|
||||
}
|
||||
|
||||
/**************/
|
||||
|
||||
const StrImW TSComponentFunction::ToString(CLocale* locale, std::vector<BufferVariable*>& vars) const
|
||||
{
|
||||
return locale->CallFunction(Name.c_str(), vars, Params);
|
||||
}
|
||||
|
||||
void TSComponentFunction::AddParam(ScriptValue* p)
|
||||
{
|
||||
Params.push_back(p);
|
||||
}
|
||||
|
||||
TSComponentFunction::~TSComponentFunction()
|
||||
{
|
||||
for_each(Params.begin(), Params.end(), delete_fn<ScriptValue>);
|
||||
}
|
||||
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Stores sections of a translated string: constant strings, simple variables,
|
||||
and JS function calls, allowing conversion to strings.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_I18N_TSCOMPONENT
|
||||
#define INCLUDED_I18N_TSCOMPONENT
|
||||
|
||||
#include "StrImmutable.h"
|
||||
#include "BufferVariable.h"
|
||||
#include "ScriptInterface.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace I18n
|
||||
{
|
||||
class CLocale;
|
||||
|
||||
class TSComponent
|
||||
{
|
||||
public:
|
||||
virtual const StrImW ToString(CLocale* locale, std::vector<BufferVariable*>& vars) const = 0;
|
||||
virtual ~TSComponent() {}
|
||||
};
|
||||
|
||||
|
||||
class TSComponentString : public TSComponent
|
||||
{
|
||||
NONCOPYABLE(TSComponentString);
|
||||
public:
|
||||
TSComponentString(const wchar_t* s) : String(s) {}
|
||||
|
||||
const StrImW ToString(CLocale* locale, std::vector<BufferVariable*>& vars) const;
|
||||
|
||||
private:
|
||||
const StrImW String;
|
||||
};
|
||||
|
||||
|
||||
class TSComponentVariable : public TSComponent
|
||||
{
|
||||
NONCOPYABLE(TSComponentVariable);
|
||||
public:
|
||||
TSComponentVariable(unsigned char id) : ID(id) {}
|
||||
|
||||
const StrImW ToString(CLocale* locale, std::vector<BufferVariable*>& vars) const;
|
||||
|
||||
private:
|
||||
unsigned char ID;
|
||||
};
|
||||
|
||||
|
||||
class TSComponentFunction : public TSComponent
|
||||
{
|
||||
NONCOPYABLE(TSComponentFunction);
|
||||
public:
|
||||
TSComponentFunction(const char* name) : Name(name) {}
|
||||
~TSComponentFunction();
|
||||
|
||||
const StrImW ToString(CLocale* locale, std::vector<BufferVariable*>& vars) const;
|
||||
|
||||
// AddParam is called when loading the function, building up the
|
||||
// internal list of parameters (strings / ints / variables)
|
||||
void AddParam(ScriptValue* p);
|
||||
|
||||
private:
|
||||
const std::string Name;
|
||||
std::vector<ScriptValue*> Params;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif // INCLUDED_I18N_TSCOMPONENT
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "TranslatedString.h"
|
||||
#include "TSComponent.h"
|
||||
|
||||
using namespace I18n;
|
||||
|
||||
TranslatedString::~TranslatedString()
|
||||
{
|
||||
for (std::vector<const TSComponent*>::iterator it = Parts.begin(); it != Parts.end(); ++it)
|
||||
delete *it;
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Simple storage for translated phrases, made up of lots of TSComponents
|
||||
(strings / variables / functions)
|
||||
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_I18N_TRANSLATEDSTRING
|
||||
#define INCLUDED_I18N_TRANSLATEDSTRING
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace I18n
|
||||
{
|
||||
class TSComponent;
|
||||
|
||||
class TranslatedString
|
||||
{
|
||||
public:
|
||||
std::vector<const TSComponent*> Parts;
|
||||
unsigned char VarCount;
|
||||
|
||||
~TranslatedString();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // INCLUDED_I18N_TRANSLATEDSTRING
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
class CStr : public std::string {};
|
||||
class CStrW : public std::wstring
|
||||
{
|
||||
public:
|
||||
CStrW(const std::wstring &s) : std::wstring(s) {}
|
||||
};
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "StringConvert.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include "jsapi.h"
|
||||
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
#define ucs2le_to_wchart(ptr) (wchar_t)( (u16) ((u8*)ptr)[0] | (u16) ( ((u8*)ptr)[1] << 8) )
|
||||
#else
|
||||
#define ucs2le_to_wchart(ptr) (wchar_t)(*ptr);
|
||||
#endif
|
||||
|
||||
JSString* StringConvert::wstring_to_jsstring(JSContext* cx, const std::wstring& str)
|
||||
{
|
||||
size_t len = str.length();
|
||||
jschar* data = (jschar*)JS_malloc(cx, len*sizeof(jschar));
|
||||
if (!data)
|
||||
return NULL;
|
||||
for (size_t i=0; i<len; ++i)
|
||||
data[i] = str[i];
|
||||
return JS_NewUCString(cx, data, len);
|
||||
}
|
||||
|
||||
JSString* StringConvert::wchars_to_jsstring(JSContext* cx, const wchar_t* chars)
|
||||
{
|
||||
size_t len = wcslen(chars);
|
||||
jschar* data = (jschar*)JS_malloc(cx, len*sizeof(jschar));
|
||||
if (!data)
|
||||
return NULL;
|
||||
for (size_t i=0; i<len; ++i)
|
||||
data[i] = chars[i];
|
||||
return JS_NewUCString(cx, data, len);
|
||||
}
|
||||
|
||||
void StringConvert::jschars_to_wstring(const jschar* chars, size_t len, std::wstring& result)
|
||||
{
|
||||
assert(result.empty());
|
||||
result.reserve(len);
|
||||
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
result += chars[i];
|
||||
}
|
||||
|
||||
|
||||
void StringConvert::ucs2le_to_wstring(const char* start, const char* end, std::wstring& result)
|
||||
{
|
||||
assert(result.empty());
|
||||
result.reserve(end-start);
|
||||
|
||||
for (const char* pos = start; pos < end; pos += 2)
|
||||
result += ucs2le_to_wchart(pos);
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
typedef unsigned short jschar;
|
||||
typedef unsigned short ucs2char;
|
||||
|
||||
struct JSString;
|
||||
struct JSContext;
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace StringConvert
|
||||
{
|
||||
// A random collection of conversion functions:
|
||||
|
||||
JSString* wstring_to_jsstring(JSContext* cx, const std::wstring& str);
|
||||
JSString* wchars_to_jsstring(JSContext* cx, const wchar_t* chars);
|
||||
|
||||
void jschars_to_wstring(const jschar* chars, size_t len, std::wstring& result);
|
||||
void ucs2le_to_wstring(const char* start, const char* end, std::wstring& result);
|
||||
|
||||
}
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Make sure we have the argument (UNIDOUBLER_HEADER), and that we're not
|
||||
// called from within another unidoubler execution (now that's just asking for
|
||||
// trouble)
|
||||
#if defined(UNIDOUBLER_HEADER) && !defined(IN_UNIDOUBLER)
|
||||
|
||||
#define IN_UNIDOUBLER
|
||||
|
||||
#define _UNICODE
|
||||
#undef CStr
|
||||
#undef CStr_hash_compare
|
||||
#define CStr CStrW
|
||||
// Compat for old code. *Deprecated* CStrW isn't 16-bit - it is "wide"
|
||||
#define CStr16 CStrW
|
||||
#define CStr_hash_compare CStrW_hash_compare
|
||||
#include UNIDOUBLER_HEADER
|
||||
|
||||
// Undef all the Conversion Macros
|
||||
#undef tstring
|
||||
#undef tstringstream
|
||||
#undef _tcout
|
||||
#undef _tstod
|
||||
#undef _ttoi
|
||||
#undef _ttol
|
||||
#undef TCHAR
|
||||
#undef _T
|
||||
#undef _istspace
|
||||
#undef _tsnprintf
|
||||
#undef _totlower
|
||||
#undef _totupper
|
||||
|
||||
// Now include the 8-bit version under the name CStr8
|
||||
#undef _UNICODE
|
||||
#undef CStr
|
||||
#undef CStr_hash_compare
|
||||
#define CStr CStr8
|
||||
#define CStr_hash_compare CStr8_hash_compare
|
||||
#include UNIDOUBLER_HEADER
|
||||
|
||||
#undef IN_UNIDOUBLER
|
||||
#undef UNIDOUBLER_HEADER
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
BufferVariable.cpp
|
||||
BufferVariable.h
|
||||
CLocale.cpp
|
||||
CLocale.h
|
||||
Common.h
|
||||
Interface.cpp
|
||||
Interface.h
|
||||
ScriptInterface.cpp
|
||||
ScriptInterface.h
|
||||
StrImmutable.h
|
||||
StringBuffer.cpp
|
||||
#StringBuffer.h
|
||||
TranslatedString.cpp
|
||||
TranslatedString.h
|
||||
#TSComponent.cpp
|
||||
TSComponent.h
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
del Coverage\*.dyn
|
||||
cd ..\..\..\binaries\system
|
||||
..\..\source\i18n\tests\Coverage\tests
|
||||
cd ..\..\source\i18n\tests\Coverage
|
||||
profmerge
|
||||
codecov -comp ../comp.txt -ccolor #f6f6ff -mname "Philip Taylor" -maddr excors@gmail.com
|
||||
start CODE_COVERAGE.HTML
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SYSDEP_H__
|
||||
#define SYSDEP_H__
|
||||
|
||||
// STL_HASH_MAP, STL_HASH_MULTIMAP
|
||||
#ifdef __GNUC__
|
||||
// GCC
|
||||
# include <ext/hash_map>
|
||||
# define STL_HASH_MAP __gnu_cxx::hash_map
|
||||
# define STL_HASH_MULTIMAP __gnu_cxx::hash_multimap
|
||||
#else // !__GNUC__
|
||||
# include <hash_map>
|
||||
# if defined(_MSC_VER) && (_MSC_VER >= 1300)
|
||||
// VC7 or above
|
||||
# define STL_HASH_MAP stdext::hash_map
|
||||
# define STL_HASH_MULTIMAP stdext::hash_multimap
|
||||
# else
|
||||
// VC6 and anything else (most likely name)
|
||||
# define STL_HASH_MAP std::hash_map
|
||||
# define STL_HASH_MULTIMAP std::hash_multimap
|
||||
# endif // defined(_MSC_VER) && (_MSC_VER >= 1300)
|
||||
#endif // !__GNUC__
|
||||
|
||||
|
||||
#endif // #ifndef SYSDEP_H__
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Hacked version to minimise dependencies
|
||||
|
||||
// convenience type (shorter defs than stdint uintN_t)
|
||||
|
||||
#ifndef __TYPES_H__
|
||||
#define __TYPES_H__
|
||||
|
||||
//#include "posix.h"
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short wchar_t;
|
||||
|
||||
// defines instead of typedefs so we can #undef conflicting decls
|
||||
|
||||
// Workaround: GCC won't parse constructor-casts with multi-word types, while
|
||||
// visual studio will. Define uint/long to a namespaced one-word typedef.
|
||||
typedef unsigned long PS_ulong;
|
||||
typedef unsigned int PS_uint;
|
||||
#define ulong PS_ulong
|
||||
#define uint PS_uint
|
||||
|
||||
#define i8 int8_t
|
||||
#define i16 int16_t
|
||||
#define i32 int32_t
|
||||
#define i64 int64_t
|
||||
|
||||
#define u8 uint8_t
|
||||
#define u16 uint16_t
|
||||
#define u32 uint32_t
|
||||
#define u64 uint64_t
|
||||
|
||||
|
||||
// the standard only guarantees 16 bits.
|
||||
// we use this for memory offsets and ranges, so it better be big enough.
|
||||
#ifdef SIZE_MAX // nested #if to avoid ICC warning if not defined
|
||||
# if SIZE_MAX < 32
|
||||
# error "check size_t and SIZE_MAX - too small?"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#endif // #ifndef __TYPES_H__
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
#include <vector>
|
||||
#include <hash_map>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
/*
|
||||
#include <crtdbg.h>
|
||||
#define new new(_NORMAL_BLOCK ,__FILE__, __LINE__)
|
||||
#define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)
|
||||
#define calloc(c, s) _calloc_dbg(c, s, _NORMAL_BLOCK, __FILE__, __LINE__)
|
||||
#define realloc(p, s) _realloc_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__)
|
||||
#define _expand(p, s) _expand_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__)
|
||||
#define free(p) _free_dbg(p, _NORMAL_BLOCK)
|
||||
*/
|
||||
#endif
|
||||
|
||||
// Random stuff:
|
||||
|
||||
#define SDL_LIL_ENDIAN 1234
|
||||
#define SDL_BIG_ENDIAN 4321
|
||||
|
||||
#define SDL_BYTEORDER SDL_LIL_ENDIAN
|
||||
|
||||
#include <cassert>
|
||||
#define cassert(x) extern char cassert__##__LINE__ [x]
|
||||
#define debug_warn(x) assert(0&&x)
|
||||
#define debug_assert assert
|
||||
|
||||
#define XP_WIN
|
||||
#define MSC_VERSION _MSC_VER
|
||||
#define UNUSED(x)
|
||||
|
||||
#include "ps/Errors.h"
|
||||
|
||||
#include <cstdio>
|
||||
#define swprintf _snwprintf
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
enum {
|
||||
ERROR,
|
||||
WARNING,
|
||||
};
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
static void LOG(int level, const char* cat, const char* fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
vprintf(fmt, va);
|
||||
printf("\n");
|
||||
}
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Auto-generated by errorlist.pl - do not edit.
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "Errors.h"
|
||||
|
||||
class PSERROR_Error : public PSERROR {};
|
||||
class PSERROR_I18n : public PSERROR {};
|
||||
|
||||
class PSERROR_I18n_Script : public PSERROR_I18n {};
|
||||
|
||||
class PSERROR_Error_InvalidError : public PSERROR_Error { public: PSRETURN getCode() const; };
|
||||
class PSERROR_I18n_Script_SetupFailed : public PSERROR_I18n_Script { public: PSRETURN getCode() const; };
|
||||
|
||||
extern const PSRETURN PSRETURN_Error_InvalidError = 0x01000001;
|
||||
extern const PSRETURN PSRETURN_I18n_Script_SetupFailed = 0x02010001;
|
||||
|
||||
extern const PSRETURN MASK__PSRETURN_Error = 0xff000000;
|
||||
extern const PSRETURN CODE__PSRETURN_Error = 0x01000000;
|
||||
extern const PSRETURN MASK__PSRETURN_I18n = 0xff000000;
|
||||
extern const PSRETURN CODE__PSRETURN_I18n = 0x02000000;
|
||||
extern const PSRETURN MASK__PSRETURN_I18n_Script = 0xffff0000;
|
||||
extern const PSRETURN CODE__PSRETURN_I18n_Script = 0x02010000;
|
||||
|
||||
extern const PSRETURN MASK__PSRETURN_Error_InvalidError = 0xffffffff;
|
||||
extern const PSRETURN CODE__PSRETURN_Error_InvalidError = 0x01000001;
|
||||
extern const PSRETURN MASK__PSRETURN_I18n_Script_SetupFailed = 0xffffffff;
|
||||
extern const PSRETURN CODE__PSRETURN_I18n_Script_SetupFailed = 0x02010001;
|
||||
|
||||
PSRETURN PSERROR_Error_InvalidError::getCode() const { return 0x01000001; }
|
||||
PSRETURN PSERROR_I18n_Script_SetupFailed::getCode() const { return 0x02010001; }
|
||||
|
||||
const char* PSERROR::what() const throw ()
|
||||
{
|
||||
return GetErrorString(getCode());
|
||||
}
|
||||
|
||||
const char* GetErrorString(const PSERROR& err)
|
||||
{
|
||||
return GetErrorString(err.getCode());
|
||||
}
|
||||
|
||||
const char* GetErrorString(PSRETURN code)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case 0x01000001: return "Error_InvalidError";
|
||||
case 0x02010001: return "I18n_Script_SetupFailed";
|
||||
|
||||
default: return "Unrecognised error";
|
||||
}
|
||||
}
|
||||
|
||||
void ThrowError(PSRETURN code)
|
||||
{
|
||||
switch (code) // Use 'break' in case someone tries to continue from the exception
|
||||
{
|
||||
case 0x01000001: throw PSERROR_Error_InvalidError(); break;
|
||||
case 0x02010001: throw PSERROR_I18n_Script_SetupFailed(); break;
|
||||
|
||||
default: throw PSERROR_Error_InvalidError(); // Hmm...
|
||||
}
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _ERRORS_H_
|
||||
#define _ERRORS_H_
|
||||
|
||||
#include <exception>
|
||||
|
||||
#include "lib/types.h"
|
||||
|
||||
typedef u32 PSRETURN;
|
||||
|
||||
class PSERROR : public std::exception
|
||||
{
|
||||
public:
|
||||
virtual const char* what() const throw ();
|
||||
virtual PSRETURN getCode() const = 0; // for functions that catch exceptions then return error codes
|
||||
};
|
||||
|
||||
#define ERROR_GROUP(a) class PSERROR_##a : public PSERROR {}; \
|
||||
extern const PSRETURN MASK__PSRETURN_##a; \
|
||||
extern const PSRETURN CODE__PSRETURN_##a
|
||||
|
||||
#define ERROR_SUBGROUP(a,b) class PSERROR_##a##_##b : public PSERROR_##a {}; \
|
||||
extern const PSRETURN MASK__PSRETURN_##a##_##b; \
|
||||
extern const PSRETURN CODE__PSRETURN_##a##_##b
|
||||
|
||||
|
||||
#define ERROR_TYPE(a,b) class PSERROR_##a##_##b : public PSERROR_##a { public: PSRETURN getCode() const; }; \
|
||||
extern const PSRETURN MASK__PSRETURN_##a##_##b; \
|
||||
extern const PSRETURN CODE__PSRETURN_##a##_##b; \
|
||||
extern const PSRETURN PSRETURN_##a##_##b
|
||||
|
||||
#define ERROR_IS(a, b) ( ((a) & MASK__PSRETURN_##b) == CODE__PSRETURN_##b )
|
||||
|
||||
const PSRETURN PSRETURN_OK = 0;
|
||||
const PSRETURN MASK__PSRETURN_OK = 0xffffffff;
|
||||
const PSRETURN CODE__PSRETURN_OK = 0;
|
||||
|
||||
const char* GetErrorString(PSRETURN code);
|
||||
const char* GetErrorString(const PSERROR& err);
|
||||
void ThrowError(PSRETURN code);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define XP_WIN
|
||||
|
||||
#include <jsapi.h>
|
||||
#include <jsatom.h>
|
||||
#ifndef NDEBUG
|
||||
# include <jsdbgapi.h>
|
||||
#endif
|
||||
|
||||
// Make JS debugging a little easier by automatically naming GC roots
|
||||
// Don't simply #define NAME_ALL_GC_ROOTS, because jsapi.h is horridly broken
|
||||
#ifndef NDEBUG
|
||||
# define JS_AddRoot(cx, rp) JS_AddNamedRoot((cx), (rp), __FILE__ )
|
||||
#endif
|
||||
|
|
@ -1,182 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "Interface.h"
|
||||
|
||||
#include "scripting/SpiderMonkey.h"
|
||||
|
||||
I18n::CLocale_interface* g_CurrentLocale;
|
||||
#define translate(x) g_CurrentLocale->Translate(x)
|
||||
|
||||
std::string readfile(const char* fn)
|
||||
{
|
||||
std::string t;
|
||||
FILE* f = fopen(fn, "rb");
|
||||
assert(f);
|
||||
size_t c;
|
||||
char buf[1024];
|
||||
while (0 != (c = fread(buf, 1, sizeof(buf), f)))
|
||||
t += std::string(buf, buf+c);
|
||||
fclose(f);
|
||||
return t;
|
||||
}
|
||||
|
||||
void errrep(JSContext* cx, const char* msg, JSErrorReport* err)
|
||||
{
|
||||
printf("Error: %s\n", msg);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
JSRuntime* rt = JS_NewRuntime(1024*1024);
|
||||
assert(rt);
|
||||
JSContext* cx = JS_NewContext(rt, 8192);
|
||||
assert(cx);
|
||||
|
||||
JSClass clas =
|
||||
{
|
||||
"global", 0,
|
||||
JS_PropertyStub, JS_PropertyStub,
|
||||
JS_PropertyStub, JS_PropertyStub,
|
||||
JS_EnumerateStub, JS_ResolveStub,
|
||||
JS_ConvertStub, JS_FinalizeStub
|
||||
};
|
||||
|
||||
JSObject* glob = JS_NewObject(cx, &clas, NULL, NULL);
|
||||
JSBool builtins = JS_InitStandardClasses(cx, glob);
|
||||
assert(builtins);
|
||||
|
||||
JS_SetErrorReporter(cx, errrep);
|
||||
|
||||
#ifndef NDEBUG
|
||||
// _CrtSetDbgFlag( _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
|
||||
//_CrtSetDbgFlag( _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_DELAY_FREE_MEM_DF);
|
||||
//CrtSetBreakAlloc(1450);
|
||||
#endif
|
||||
|
||||
g_CurrentLocale = I18n::NewLocale(cx, glob);
|
||||
if (!g_CurrentLocale)
|
||||
return 1;
|
||||
|
||||
|
||||
extern void test(JSContext*, JSObject*);
|
||||
test(cx, glob);
|
||||
|
||||
#if 0
|
||||
std::string lang = readfile("e:\\0ad\\cvs\\binaries\\data\\mods\\official\\language\\test\\phrases.lng");
|
||||
std::string funcs = readfile("e:\\0ad\\cvs\\binaries\\data\\mods\\official\\language\\test\\functions.js");
|
||||
std::string words = readfile("e:\\0ad\\cvs\\binaries\\data\\mods\\official\\language\\test\\nouns.wrd");
|
||||
std::string words2 = readfile("e:\\0ad\\cvs\\binaries\\data\\mods\\official\\language\\test\\nouns2.wrd");
|
||||
|
||||
g_CurrentLocale->LoadFunctions(funcs.c_str(), funcs.size(), "functions.txt");
|
||||
g_CurrentLocale->LoadStrings(lang.c_str());
|
||||
g_CurrentLocale->LoadDictionary(words.c_str());
|
||||
g_CurrentLocale->LoadDictionary(words2.c_str());
|
||||
|
||||
I18n::Str s;
|
||||
|
||||
// const char* script = " translate('Hello $name!', i18n.Noun('apple')) ";
|
||||
const char* script = " translate('Testing things $num of $object', 3/1.5, i18n.Noun('banana')) ";
|
||||
|
||||
jsval rval;
|
||||
if (JS_EvaluateScript(cx, glob, script, (int)strlen(script), "test", 1, &rval) != JS_TRUE)
|
||||
assert(! "Eval failed");
|
||||
//assert(JSVAL_IS_STRING(rval));
|
||||
//s = JS_GetStringChars(JSVAL_TO_STRING(rval));
|
||||
s = JS_GetStringChars(JS_ValueToString(cx, rval));
|
||||
printf("%ls\n", s.c_str());
|
||||
|
||||
#if 0
|
||||
s = translate(L"Hello $name!") << I18n::Name("banana");
|
||||
printf("%ls\n", s.c_str());
|
||||
s = translate(L"Hello $name!") << I18n::Name("banana");
|
||||
printf("%ls\n", s.c_str());
|
||||
|
||||
s = translate(L"Testing things $num of $object") << 1 << I18n::Name("banana");
|
||||
printf("%ls\n", s.c_str());
|
||||
s = translate(L"Testing things $num of $object") << 1234 << I18n::Name("banana");
|
||||
printf("%ls\n", s.c_str());
|
||||
s = translate(L"Testing things $num of $object") << 12345 << I18n::Name("apple");
|
||||
printf("%ls\n", s.c_str());
|
||||
s = translate(L"Testing things $num of $object") << 123456 << I18n::Name("orange");
|
||||
printf("%ls\n", s.c_str());
|
||||
s = translate(L"Testing things $num of $object") << 1234567 << I18n::Name("cheese");
|
||||
printf("%ls\n", s.c_str());
|
||||
|
||||
s = translate(L"Hello $name!") << I18n::Name("Philip");
|
||||
printf("%ls\n", s.c_str());
|
||||
|
||||
s = translate(L"Hello $name!") << I18n::Name("Philip2");
|
||||
printf("%ls\n", s.c_str());
|
||||
|
||||
// s = translate(L"Also hi to $you$me etc") << I18n::DateShort(time(NULL)) << -1;
|
||||
// printf("%ls\n", s.c_str());
|
||||
|
||||
// s = translate(L"Hello $name!") << I18n::DateShort(time(NULL));
|
||||
//char* y = "you";
|
||||
//s = translate(L"Hello $name!") << y;
|
||||
// printf("%ls\n", s.c_str());
|
||||
|
||||
s = translate(L"Your $colour cheese-monster eats $num biscuits") << I18n::Name("blue") << 15;
|
||||
printf("%ls\n", s.c_str());
|
||||
#endif
|
||||
|
||||
// Performance test: (it should go at a few hundred thousand per second)
|
||||
#if 0
|
||||
clock_t t = clock();
|
||||
int limit = 1000000;
|
||||
for (int i=0; i<limit; ++i)
|
||||
{
|
||||
/*
|
||||
I18n::Str s1 = translate(L"Hello world 1");
|
||||
I18n::Str s2 = translate(L"Hello world 2");
|
||||
I18n::Str s3 = translate(L"Hello world 3");
|
||||
I18n::Str s4 = translate(L"Hello world 4");
|
||||
// I18n::Str s1 = translate(L"Hello $name!") << L"Philip";
|
||||
// I18n::Str s2 = translate(L"Your $colour cheese-monster eats $num biscuits") << "blue" << 15;
|
||||
//I18n::Str s3 = translate(L"Hello2 $name!") << L"Philip";
|
||||
//I18n::Str s4 = translate(L"Your2 $colour cheese-monster eats $num biscuits") << "blue" << 15;
|
||||
// I18n::Str s3 = translate(L"Hello $name!") << 1234;
|
||||
// I18n::Str s4 = translate(L"Your $colour cheese-monster eats $num biscuits") << 10000 << 15;
|
||||
/*/
|
||||
|
||||
I18n::Str s1 = translate(L"Testing things $num $obj") << 1234.0 << I18n::Name("cheese bananas");
|
||||
//I18n::Str s2 = translate(L"Testing things $num") << 124;
|
||||
//I18n::Str s3 = translate(L"Testing things $num") << 1231234;
|
||||
//I18n::Str s4 = translate(L"Testing things $num") << 1243456;
|
||||
|
||||
//*/
|
||||
}
|
||||
t = clock() - t;
|
||||
printf("\nTook %f secs (%f/sec)\n", (float)t/(float)CLOCKS_PER_SEC, (float)limit/((float)t/(float)CLOCKS_PER_SEC));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
delete g_CurrentLocale;
|
||||
|
||||
JS_DestroyContext(cx);
|
||||
JS_DestroyRuntime(rt);
|
||||
JS_ShutDown();
|
||||
|
||||
getchar();
|
||||
}
|
||||
|
|
@ -1,298 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "Interface.h"
|
||||
#include "scripting/SpiderMonkey.h"
|
||||
|
||||
#define FILE_PATH "..\\data\\mods\\official\\language\\test\\"
|
||||
|
||||
extern I18n::CLocale_interface* g_CurrentLocale;
|
||||
#define translate(x) g_CurrentLocale->Translate(x)
|
||||
|
||||
extern std::string readfile(const char* fn);
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
typedef char CHAR;
|
||||
typedef const CHAR *LPCSTR;
|
||||
|
||||
extern "C" {
|
||||
__declspec(dllimport) void __stdcall
|
||||
OutputDebugStringA(LPCSTR lpOutputString);
|
||||
}
|
||||
/*
|
||||
WINBASEAPI
|
||||
VOID
|
||||
WINAPI
|
||||
OutputDebugStringA(
|
||||
IN LPCSTR lpOutputString
|
||||
);
|
||||
*/
|
||||
|
||||
void test_assert(bool test, const char* file, int line, const char* fmt, ...)
|
||||
{
|
||||
if (! test)
|
||||
{
|
||||
char msg[512];
|
||||
va_list v;
|
||||
va_start(v, fmt);
|
||||
_vsnprintf(msg, sizeof(msg), fmt, v);
|
||||
char err[512];
|
||||
_snprintf(err, sizeof(err), "%s(%d) : TEST FAILED : %s\n", file, line, msg);
|
||||
err[sizeof(err)-1] = 0;
|
||||
OutputDebugStringA(err);
|
||||
printf("%s", err);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef I18NDEBUG
|
||||
#error Please compile with I18NDEBUG debug
|
||||
#endif
|
||||
namespace I18n { extern bool g_UsedCache; }
|
||||
|
||||
#define TEST_EQ_NOCACHE(answer, str, param) \
|
||||
{ \
|
||||
I18n::Str s = translate(L##str) param; \
|
||||
test_assert(s == L##answer, __FILE__, __LINE__, "Unexpected output: %ls", s.c_str()); \
|
||||
test_assert(!I18n::g_UsedCache, __FILE__, __LINE__, "Unexpectedly used cache"); \
|
||||
}
|
||||
|
||||
#define TEST_EQ_CACHED(answer, str, param) \
|
||||
{ \
|
||||
I18n::Str s = translate(L##str) param; \
|
||||
test_assert(s == L##answer, __FILE__, __LINE__, "Unexpected output: %ls", s.c_str()); \
|
||||
test_assert(I18n::g_UsedCache, __FILE__, __LINE__, "Failed to use cache"); \
|
||||
}
|
||||
|
||||
#define TEST_EQ_SCRIPT(answer, str) \
|
||||
{ \
|
||||
jsval rval; \
|
||||
if (JS_EvaluateScript(cx, glob, str, (int)strlen(str), "test", 1, &rval) != JS_TRUE) \
|
||||
test_assert(false, __FILE__, __LINE__, "Script eval failed"); \
|
||||
else { \
|
||||
JSString* r = JS_ValueToString(cx, rval); \
|
||||
I18n::Str s (JS_GetStringChars(r), JS_GetStringLength(r)); \
|
||||
test_assert(s == L##answer, __FILE__, __LINE__, "Unexpected output:\n '%ls'\nExpected:\n '%ls'", s.c_str(), L##answer); \
|
||||
} \
|
||||
}
|
||||
|
||||
void test(JSContext* cx, JSObject* glob)
|
||||
{
|
||||
// Untranslated strings. Simple strings.
|
||||
TEST_EQ_NOCACHE(
|
||||
"Hello world",
|
||||
"Hello world",
|
||||
);
|
||||
|
||||
// Reporting of an invalid number of parameters.
|
||||
TEST_EQ_NOCACHE(
|
||||
"(translation error)",
|
||||
"Hello world", << 1
|
||||
);
|
||||
|
||||
// Untranslated strings with variables. Int variables.
|
||||
TEST_EQ_NOCACHE(
|
||||
"Hello world 1",
|
||||
"Hello world $n", << 1
|
||||
);
|
||||
|
||||
// Parsing of untranslated strings. Int variables.
|
||||
TEST_EQ_NOCACHE(
|
||||
"Hello world 1 23$4!",
|
||||
"Hello world $a $bee$cee$$$bee!", << 1 << 2 << 3 << 4
|
||||
);
|
||||
// PROBLEM: Duplicated variables aren't handled correctly (or at all).
|
||||
// Make sure they're never used in the identifier strings.
|
||||
|
||||
// Caching with ints.
|
||||
TEST_EQ_CACHED(
|
||||
"Hello world 1",
|
||||
"Hello world $n", << 1
|
||||
);
|
||||
|
||||
// Double variables.
|
||||
TEST_EQ_NOCACHE(
|
||||
"Hello world 1.500000",
|
||||
"Hello world $n", << 1.5
|
||||
);
|
||||
|
||||
// Caching with doubles.
|
||||
TEST_EQ_CACHED(
|
||||
"Hello world 1.500000",
|
||||
"Hello world $n", << 1.5
|
||||
);
|
||||
|
||||
/*
|
||||
// More caching with doubles.
|
||||
int num[2] = { -1, 0x3ff00000 }; // slightly endian-dependent
|
||||
TEST_EQ_NOCACHE(
|
||||
"Hello world 1.000001",
|
||||
"Hello world $n", << *(double*)#
|
||||
);
|
||||
|
||||
num[1] = 0xbff00000;
|
||||
TEST_EQ_NOCACHE(
|
||||
"Hello world -1.000001",
|
||||
"Hello world $n", << *(double*)#
|
||||
);
|
||||
|
||||
num[0] = -2;
|
||||
TEST_EQ_NOCACHE(
|
||||
"Hello world -1.000001",
|
||||
"Hello world $n", << *(double*)#
|
||||
);
|
||||
*/
|
||||
|
||||
// Float variables.
|
||||
TEST_EQ_NOCACHE(
|
||||
"Hello world 2.500000",
|
||||
"Hello world $n", << 2.5f
|
||||
);
|
||||
|
||||
// Caching with floats.
|
||||
TEST_EQ_CACHED(
|
||||
"Hello world 2.500000",
|
||||
"Hello world $n", << 2.5f
|
||||
);
|
||||
|
||||
// Handling nouns (no noun table loaded).
|
||||
TEST_EQ_NOCACHE(
|
||||
"Hello world cheese",
|
||||
"Hello world $n", << I18n::Noun("cheese")
|
||||
);
|
||||
|
||||
g_CurrentLocale->LoadDictionary(readfile(FILE_PATH "nouns2.wrd").c_str());
|
||||
|
||||
// Handling nouns (not in noun table).
|
||||
TEST_EQ_NOCACHE(
|
||||
"Hello world pumpkin",
|
||||
"Hello world $n", << I18n::Noun("pumpkin")
|
||||
);
|
||||
|
||||
// Handling nouns (from noun table but missing singular).
|
||||
TEST_EQ_NOCACHE(
|
||||
"Hello world apple",
|
||||
"Hello world $n", << I18n::Noun("apple")
|
||||
);
|
||||
|
||||
g_CurrentLocale->UnloadDictionaries();
|
||||
|
||||
g_CurrentLocale->LoadDictionary(readfile(FILE_PATH "nouns.wrd").c_str());
|
||||
|
||||
// Name variables.
|
||||
TEST_EQ_NOCACHE(
|
||||
"Hello world banana",
|
||||
"Hello world $n", << I18n::Name("banana")
|
||||
);
|
||||
|
||||
// Raw string variables. Caching names / raw strings.
|
||||
TEST_EQ_CACHED(
|
||||
"Hello world banana",
|
||||
"Hello world $n", << I18n::Raw("banana")
|
||||
);
|
||||
|
||||
// Handling nouns (from noun table).
|
||||
TEST_EQ_NOCACHE(
|
||||
"Hello world BANANA",
|
||||
"Hello world $n", << I18n::Noun("banana")
|
||||
);
|
||||
|
||||
// Caching nouns.
|
||||
TEST_EQ_CACHED(
|
||||
"Hello world BANANA",
|
||||
"Hello world $n", << I18n::Noun("banana")
|
||||
);
|
||||
|
||||
std::string funcs = readfile(FILE_PATH "functions.js");
|
||||
g_CurrentLocale->LoadFunctions(funcs.c_str(), funcs.size(), "functions.txt");
|
||||
|
||||
g_CurrentLocale->LoadStrings(readfile(FILE_PATH "phrases.lng").c_str());
|
||||
|
||||
// Functions with strings, doubles, ints, variable ints, and variable strings.
|
||||
TEST_EQ_NOCACHE(
|
||||
"1.2345+67890=67891.2345. An armadillo buys a platypus for 14.99 (platypus! 14.990000!)",
|
||||
"Test $obj ($$$amnt)", << I18n::Noun("platypus") << 14.99
|
||||
);
|
||||
|
||||
// Noun lookups in JS functions.
|
||||
TEST_EQ_NOCACHE(
|
||||
"There are (1 BANANA) here",
|
||||
"Testing things $num of $object", << 1 << I18n::Noun("banana")
|
||||
);
|
||||
|
||||
// More noun lookups in JS functions.
|
||||
TEST_EQ_NOCACHE(
|
||||
"There are (2 bananas) here",
|
||||
"Testing things $num of $object", << 2 << I18n::Noun("banana")
|
||||
);
|
||||
|
||||
// Noun lookups in JS functions, despite being Raw. (JS only sees strings).
|
||||
TEST_EQ_NOCACHE(
|
||||
"There are (2.5 bananas) here",
|
||||
"Testing things $num of $object", << 2.5 << I18n::Raw("banana")
|
||||
);
|
||||
|
||||
// Noun lookup failures in JS functions.
|
||||
TEST_EQ_NOCACHE(
|
||||
"There are (-3.5 orangutan) here",
|
||||
"Testing things $num of $object", << -3.5 << I18n::Raw("orangutan")
|
||||
);
|
||||
|
||||
// Repeated tests, using JS interface.
|
||||
|
||||
TEST_EQ_SCRIPT(
|
||||
"Hello world banana",
|
||||
"translate('Hello world $n', i18n.Name('banana'))"
|
||||
);
|
||||
|
||||
TEST_EQ_SCRIPT(
|
||||
"Hello world banana",
|
||||
"translate('Hello world $n', i18n.Raw('banana'))"
|
||||
);
|
||||
|
||||
TEST_EQ_SCRIPT(
|
||||
"Hello world BANANA",
|
||||
"translate('Hello world $n', i18n.Noun('banana'))"
|
||||
);
|
||||
|
||||
TEST_EQ_SCRIPT(
|
||||
"1.2345+67890=67891.2345. An armadillo buys a platypus for 14.99 (platypus! 14.990000!)",
|
||||
"translate('Test $obj ($$$amnt)', i18n.Noun('platypus'), 14.99)"
|
||||
);
|
||||
|
||||
TEST_EQ_SCRIPT(
|
||||
"There are (1 BANANA) here",
|
||||
"translate('Testing things $num of $object', 1, i18n.Noun('banana'))"
|
||||
);
|
||||
|
||||
TEST_EQ_SCRIPT(
|
||||
"There are (2 bananas) here",
|
||||
"translate('Testing things $num of $object', 2, i18n.Noun('banana'))"
|
||||
);
|
||||
|
||||
TEST_EQ_SCRIPT(
|
||||
"There are (2.5 bananas) here",
|
||||
"translate('Testing things $num of $object', 2.5, i18n.Raw('banana'))"
|
||||
);
|
||||
|
||||
TEST_EQ_SCRIPT(
|
||||
"There are (-3.5 orangutan) here",
|
||||
"translate('Testing things $num of $object', -3.5, i18n.Raw('orangutan'))"
|
||||
);
|
||||
}
|
||||
|
|
@ -1,262 +0,0 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Intel C++ Project"
|
||||
Version="9.0"
|
||||
Name="tests"
|
||||
ProjectGUID="{B48BE4CA-40AF-4D48-86CC-7FCA6BDD02BF}"
|
||||
VCNestedProjectGUID="{1D6A376C-DA9E-4E03-83A7-16784F356633}"
|
||||
VCNestedProjectFileName="tests.vcproj"
|
||||
Keyword="Win32Proj">
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="GeneralTool"
|
||||
OutputDirectory="Debug"
|
||||
IntermediateDirectory="Debug"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2"
|
||||
CompilerName="1"/>
|
||||
<Tool
|
||||
Name="DebugTool"
|
||||
WorkingDirectory="e:\0ad\svnc\trunk\binaries\system"/>
|
||||
<Tool
|
||||
Name="CppCmplrTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories=".;..;..\..\..\libraries\spidermonkey\include"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;I18NDEBUG"
|
||||
MinimalRebuild="1"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="5"
|
||||
UsePrecompiledHeader="3"
|
||||
PrecompiledHeaderThrough="precompiled.h"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="1"
|
||||
DebugInformationFormat="4"/>
|
||||
<Tool
|
||||
Name="LinkerTool"
|
||||
DelayImpLib=""
|
||||
AdditionalDependencies="kernel32.lib js32d.lib"
|
||||
OutputFile="$(OutDir)/tests.exe"
|
||||
LinkIncremental="2"
|
||||
AdditionalLibraryDirectories="E:\0ad\libs\lib"
|
||||
GenerateDebugInformation="1"
|
||||
ProgramDatabaseFile="$(OutDir)/tests.pdb"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="LibrarianTool"/>
|
||||
<Tool
|
||||
Name="ResCmplrTool"/>
|
||||
<Tool
|
||||
Name="MidlCmplrTool"/>
|
||||
<Tool
|
||||
Name="BscMakeTool"/>
|
||||
<Tool
|
||||
Name="PreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="PreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="PostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="CustomTool"/>
|
||||
<Tool
|
||||
Name="CustomNodeTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="GeneralTool"
|
||||
OutputDirectory="Release"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2"
|
||||
CompilerName="1"/>
|
||||
<Tool
|
||||
Name="DebugTool"
|
||||
WorkingDirectory="e:\0ad\svnc\trunk\binaries\system"/>
|
||||
<Tool
|
||||
Name="CppCmplrTool"
|
||||
AdditionalIncludeDirectories=".;..;..\..\..\libraries\spidermonkey\include"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="4"
|
||||
UsePrecompiledHeader="3"
|
||||
PrecompiledHeaderThrough="precompiled.h"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="1"
|
||||
DebugInformationFormat="3"/>
|
||||
<Tool
|
||||
Name="LinkerTool"
|
||||
DelayImpLib=""
|
||||
AdditionalDependencies="kernel32.lib js32.lib"
|
||||
OutputFile="$(OutDir)/tests.exe"
|
||||
LinkIncremental="1"
|
||||
AdditionalLibraryDirectories="E:\0ad\libs\lib"
|
||||
GenerateDebugInformation="1"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="LibrarianTool"/>
|
||||
<Tool
|
||||
Name="ResCmplrTool"/>
|
||||
<Tool
|
||||
Name="MidlCmplrTool"/>
|
||||
<Tool
|
||||
Name="BscMakeTool"/>
|
||||
<Tool
|
||||
Name="PreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="PreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="PostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="CustomTool"/>
|
||||
<Tool
|
||||
Name="CustomNodeTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Coverage|Win32">
|
||||
<Tool
|
||||
Name="GeneralTool"
|
||||
OutputDirectory="Coverage"
|
||||
IntermediateDirectory="Coverage"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2"
|
||||
PGOPhase="2"/>
|
||||
<Tool
|
||||
Name="DebugTool"
|
||||
WorkingDirectory="e:\0ad\svnc\trunk\binaries\system"/>
|
||||
<Tool
|
||||
Name="CppCmplrTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories=".;..;..\..\..\libraries\spidermonkey\include"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;I18NDEBUG"
|
||||
MinimalRebuild="1"
|
||||
BasicRuntimeChecks="0"
|
||||
RuntimeLibrary="5"
|
||||
UsePrecompiledHeader="3"
|
||||
PrecompiledHeaderThrough="precompiled.h"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="1"
|
||||
DebugInformationFormat="3"/>
|
||||
<Tool
|
||||
Name="LinkerTool"
|
||||
DelayImpLib=""
|
||||
AdditionalDependencies="kernel32.lib js32d.lib"
|
||||
OutputFile="$(OutDir)/tests.exe"
|
||||
LinkIncremental="2"
|
||||
SuppressStartupBanner="1"
|
||||
AdditionalLibraryDirectories="E:\0ad\libs\lib"
|
||||
GenerateDebugInformation="1"
|
||||
ProgramDatabaseFile="$(OutDir)/tests.pdb"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="LibrarianTool"/>
|
||||
<Tool
|
||||
Name="ResCmplrTool"/>
|
||||
<Tool
|
||||
Name="MidlCmplrTool"/>
|
||||
<Tool
|
||||
Name="BscMakeTool"/>
|
||||
<Tool
|
||||
Name="PreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="PreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="PostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="CustomTool"/>
|
||||
<Tool
|
||||
Name="CustomNodeTool"/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath=".\CStr.h"/>
|
||||
<File
|
||||
RelativePath=".\precompiled.cpp">
|
||||
<FileConfiguration
|
||||
Name="Coverage|Win32">
|
||||
<Tool
|
||||
Name="CppCmplrTool"
|
||||
UsePrecompiledHeader="1"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="CppCmplrTool"
|
||||
UsePrecompiledHeader="1"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="CppCmplrTool"
|
||||
UsePrecompiledHeader="1"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\precompiled.h"/>
|
||||
<File
|
||||
RelativePath=".\StringConvert.cpp"/>
|
||||
<File
|
||||
RelativePath=".\StringConvert.h"/>
|
||||
<File
|
||||
RelativePath=".\test.cpp"/>
|
||||
<File
|
||||
RelativePath=".\tests.cpp"/>
|
||||
<File
|
||||
RelativePath=".\UniDoubler.h"/>
|
||||
<File
|
||||
RelativePath=".\utf16string.h"/>
|
||||
<File
|
||||
RelativePath="..\BufferVariable.cpp"/>
|
||||
<File
|
||||
RelativePath="..\BufferVariable.h"/>
|
||||
<File
|
||||
RelativePath="..\CLocale.cpp"/>
|
||||
<File
|
||||
RelativePath="..\CLocale.h"/>
|
||||
<File
|
||||
RelativePath="..\Common.h"/>
|
||||
<File
|
||||
RelativePath="..\DataTypes.h"/>
|
||||
<File
|
||||
RelativePath="..\Interface.cpp"/>
|
||||
<File
|
||||
RelativePath="..\Interface.h"/>
|
||||
<File
|
||||
RelativePath="..\ScriptInterface.cpp"/>
|
||||
<File
|
||||
RelativePath="..\ScriptInterface.h"/>
|
||||
<File
|
||||
RelativePath="..\StrImmutable.h"/>
|
||||
<File
|
||||
RelativePath="..\StringBuffer.cpp"/>
|
||||
<File
|
||||
RelativePath="..\StringBuffer.h"/>
|
||||
<File
|
||||
RelativePath="..\TranslatedString.cpp"/>
|
||||
<File
|
||||
RelativePath="..\TranslatedString.h"/>
|
||||
<File
|
||||
RelativePath="..\TSComponent.cpp"/>
|
||||
<File
|
||||
RelativePath="..\TSComponent.h"/>
|
||||
<File
|
||||
RelativePath=".\lib\types.h"/>
|
||||
<File
|
||||
RelativePath=".\lib\sysdep\sysdep.h"/>
|
||||
<File
|
||||
RelativePath=".\ps\CLogger.h"/>
|
||||
<File
|
||||
RelativePath=".\ps\Errors.cpp"/>
|
||||
<File
|
||||
RelativePath=".\ps\Errors.h"/>
|
||||
<File
|
||||
RelativePath=".\scripting\SpiderMonkey.h"/>
|
||||
</Files>
|
||||
</VisualStudioProject>
|
||||
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
Microsoft Visual Studio Solution File, Format Version 8.00
|
||||
Project("{EAF909A5-FA59-4C3D-9431-0FCC20D5BCF9}") = "tests", "tests.icproj", "{9B3CF673-0EF8-4385-8AFE-456CD309D91A}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfiguration) = preSolution
|
||||
Coverage = Coverage
|
||||
Debug = Debug
|
||||
Release = Release
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfiguration) = postSolution
|
||||
{9B3CF673-0EF8-4385-8AFE-456CD309D91A}.Coverage.ActiveCfg = Coverage|Win32
|
||||
{9B3CF673-0EF8-4385-8AFE-456CD309D91A}.Coverage.Build.0 = Coverage|Win32
|
||||
{9B3CF673-0EF8-4385-8AFE-456CD309D91A}.Debug.ActiveCfg = Debug|Win32
|
||||
{9B3CF673-0EF8-4385-8AFE-456CD309D91A}.Debug.Build.0 = Debug|Win32
|
||||
{9B3CF673-0EF8-4385-8AFE-456CD309D91A}.Release.ActiveCfg = Release|Win32
|
||||
{9B3CF673-0EF8-4385-8AFE-456CD309D91A}.Release.Build.0 = Release|Win32
|
||||
{1D6A376C-DA9E-4E03-83A7-16784F356633}.Coverage.ActiveCfg = Coverage|Win32
|
||||
{1D6A376C-DA9E-4E03-83A7-16784F356633}.Debug.ActiveCfg = Debug|Win32
|
||||
{1D6A376C-DA9E-4E03-83A7-16784F356633}.Debug.Build.0 = Debug|Win32
|
||||
{1D6A376C-DA9E-4E03-83A7-16784F356633}.Release.ActiveCfg = Release|Win32
|
||||
{1D6A376C-DA9E-4E03-83A7-16784F356633}.Release.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityAddIns) = postSolution
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
@ -1,343 +0,0 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="7.10"
|
||||
Name="tests"
|
||||
ProjectGUID="{1D6A376C-DA9E-4E03-83A7-16784F356633}"
|
||||
RootNamespace="tests"
|
||||
Keyword="Win32Proj">
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"/>
|
||||
</Platforms>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="Debug"
|
||||
IntermediateDirectory="Debug"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories=".;..;..\..\..\libraries\spidermonkey\include"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;I18NDEBUG"
|
||||
MinimalRebuild="TRUE"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="5"
|
||||
UsePrecompiledHeader="3"
|
||||
PrecompiledHeaderThrough="precompiled.h"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="4"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="kernel32.lib js32d.lib"
|
||||
OutputFile="$(OutDir)/tests.exe"
|
||||
LinkIncremental="2"
|
||||
AdditionalLibraryDirectories="E:\0ad\libs\lib"
|
||||
GenerateDebugInformation="TRUE"
|
||||
ProgramDatabaseFile="$(OutDir)/tests.pdb"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="Release"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories=".;..;..\..\..\libraries\spidermonkey\include"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="4"
|
||||
UsePrecompiledHeader="3"
|
||||
PrecompiledHeaderThrough="precompiled.h"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="3"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="kernel32.lib js32.lib"
|
||||
OutputFile="$(OutDir)/tests.exe"
|
||||
LinkIncremental="1"
|
||||
AdditionalLibraryDirectories="E:\0ad\libs\lib"
|
||||
GenerateDebugInformation="TRUE"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Coverage|Win32"
|
||||
OutputDirectory="Coverage"
|
||||
IntermediateDirectory="Coverage"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories=".;..;..\..\..\libraries\spidermonkey\include"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;I18NDEBUG"
|
||||
MinimalRebuild="TRUE"
|
||||
BasicRuntimeChecks="0"
|
||||
RuntimeLibrary="5"
|
||||
UsePrecompiledHeader="3"
|
||||
PrecompiledHeaderThrough="precompiled.h"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="3"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="kernel32.lib js32d.lib"
|
||||
OutputFile="$(OutDir)/tests.exe"
|
||||
LinkIncremental="2"
|
||||
SuppressStartupBanner="TRUE"
|
||||
AdditionalLibraryDirectories="E:\0ad\libs\lib"
|
||||
GenerateDebugInformation="TRUE"
|
||||
ProgramDatabaseFile="$(OutDir)/tests.pdb"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
|
||||
<File
|
||||
RelativePath=".\CStr.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\precompiled.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Coverage|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\precompiled.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\StringConvert.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\StringConvert.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\test.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\tests.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\UniDoubler.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\utf16string.h">
|
||||
</File>
|
||||
<Filter
|
||||
Name="i18n"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath="..\BufferVariable.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\BufferVariable.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\CLocale.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\CLocale.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\Common.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\DataTypes.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\Interface.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\Interface.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\ScriptInterface.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\ScriptInterface.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\StrImmutable.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\StringBuffer.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\StringBuffer.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\TranslatedString.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\TranslatedString.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\TSComponent.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\TSComponent.h">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="lib"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath=".\lib\types.h">
|
||||
</File>
|
||||
<Filter
|
||||
Name="sysdep"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath=".\lib\sysdep\sysdep.h">
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="ps"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath=".\ps\CLogger.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\ps\Errors.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Coverage|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\ps\Errors.h">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="scripting"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath=".\scripting\SpiderMonkey.h">
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
|
|
@ -1,122 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
A basic_string derivative that works with uint16_t as its underlying char
|
||||
type.
|
||||
*/
|
||||
#ifndef INCLUDED_UTF16STRING
|
||||
#define INCLUDED_UTF16STRING
|
||||
|
||||
// On Windows, wchar_t is typedef'ed to unsigned short, which conflicts
|
||||
// with uint16_t (which is also an unsigned short), so just use std::wstring
|
||||
#ifdef _MSC_VER
|
||||
|
||||
typedef wchar_t utf16_t;
|
||||
typedef std::wstring utf16string;
|
||||
typedef std::wstringstream utf16stringstream;
|
||||
|
||||
// On Linux, wchar_t is 32-bit, so define a new version of it
|
||||
#else
|
||||
|
||||
#include <string>
|
||||
#include "types.h"
|
||||
|
||||
typedef uint16_t utf16_t;
|
||||
typedef std::basic_string<utf16_t> utf16string;
|
||||
typedef std::basic_stringstream<utf16_t> utf16stringstream;
|
||||
|
||||
namespace std {
|
||||
template<>
|
||||
struct char_traits<utf16_t>
|
||||
{
|
||||
typedef utf16_t char_type;
|
||||
typedef int int_type;
|
||||
typedef streampos pos_type;
|
||||
typedef streamoff off_type;
|
||||
typedef mbstate_t state_type;
|
||||
|
||||
static void assign(char_type& c1, const char_type& c2)
|
||||
{ c1 = c2; }
|
||||
|
||||
static bool eq(const char_type& c1, const char_type& c2)
|
||||
{ return c1 == c2; }
|
||||
|
||||
static bool lt(const char_type& c1, const char_type& c2)
|
||||
{ return c1 < c2; }
|
||||
|
||||
static int compare(const char_type* s1, const char_type* s2, size_t n)
|
||||
{
|
||||
return memcmp(s1, s2, n*sizeof(char_type));
|
||||
}
|
||||
|
||||
static size_t length(const char_type* s)
|
||||
{
|
||||
const char_type* end=s;
|
||||
while (*end) end++;
|
||||
return end-s;
|
||||
}
|
||||
|
||||
static const char_type* find(const char_type* s, size_t n, const char_type& a)
|
||||
{
|
||||
size_t i;
|
||||
for (i=0;i<n;i++)
|
||||
{
|
||||
if (s[i] == a) return s+i;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char_type* move(char_type* s1, const char_type* s2, size_t n)
|
||||
{
|
||||
return (char_type *)memmove(s1, s2, n*sizeof(char_type));
|
||||
}
|
||||
|
||||
static char_type* copy(char_type* s1, const char_type* s2, size_t n)
|
||||
{
|
||||
return (char_type *)memcpy(s1, s2, n*sizeof(char_type));
|
||||
}
|
||||
|
||||
static char_type* assign(char_type* s, size_t n, char_type a)
|
||||
{
|
||||
while (n--)
|
||||
{
|
||||
s[n]=a;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
static char_type to_char_type(const int_type& c)
|
||||
{ return (char_type)c; }
|
||||
|
||||
static int_type to_int_type(const char_type& c)
|
||||
{ return (int_type)c; }
|
||||
|
||||
static bool eq_int_type(const int_type& c1, const int_type& c2)
|
||||
{ return c1 == c2; }
|
||||
|
||||
static int_type eof()
|
||||
{ return -1; }
|
||||
|
||||
static int_type not_eof(const int_type& c)
|
||||
{ return (c == -1) ? 0 : c; }
|
||||
};
|
||||
}
|
||||
|
||||
#endif // #ifdef _MSC_VER / #else
|
||||
|
||||
#endif
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define MINIMAL_PCH 1
|
||||
#include "lib/precompiled.h" // common precompiled header
|
||||
|
||||
// Minimal is a bit *too* minimal to let things compile, so include a few more headers
|
||||
#include "lib/debug.h"
|
||||
#include "lib/secure_crt.h"
|
||||
|
|
@ -52,7 +52,6 @@
|
|||
#include "ps/Util.h"
|
||||
#include "ps/VideoMode.h"
|
||||
#include "ps/World.h"
|
||||
#include "ps/i18n.h"
|
||||
|
||||
#include "graphics/CinemaTrack.h"
|
||||
#include "graphics/GameView.h"
|
||||
|
|
@ -185,8 +184,7 @@ retry:
|
|||
// display progress / description in loading screen
|
||||
void GUI_DisplayLoadProgress(int percent, const wchar_t* pending_task)
|
||||
{
|
||||
CStrW i18n_description = I18n::translate(pending_task);
|
||||
JSString* js_desc = StringConvert::wstring_to_jsstring(g_ScriptingHost.getContext(), i18n_description);
|
||||
JSString* js_desc = StringConvert::wstring_to_jsstring(g_ScriptingHost.getContext(), pending_task);
|
||||
g_ScriptingHost.SetGlobal("g_Progress", INT_TO_JSVAL(percent));
|
||||
g_ScriptingHost.SetGlobal("g_LoadDescription", STRING_TO_JSVAL(js_desc));
|
||||
g_GUI->SendEventToAll("progress");
|
||||
|
|
@ -475,14 +473,9 @@ static void InitPs(bool setup_gui, const CStrW& gui_page, CScriptVal initData)
|
|||
g_Console->m_iFontOffset = 7;
|
||||
}
|
||||
|
||||
// language and hotkeys
|
||||
// hotkeys
|
||||
{
|
||||
TIMER(L"ps_lang_hotkeys");
|
||||
|
||||
std::string lang = "english";
|
||||
CFG_GET_SYS_VAL("language", String, lang);
|
||||
I18n::LoadLanguage(lang.c_str());
|
||||
|
||||
LoadHotkeys();
|
||||
}
|
||||
|
||||
|
|
@ -547,10 +540,6 @@ static void ShutdownPs()
|
|||
|
||||
// disable the special Windows cursor, or free textures for OGL cursors
|
||||
cursor_draw(g_VFS, 0, g_mouse_x, g_yres-g_mouse_y);
|
||||
|
||||
// Unload the real language (since it depends on the scripting engine,
|
||||
// which is going to be killed later) and use the English fallback messages
|
||||
I18n::LoadLanguage(NULL);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -669,12 +658,6 @@ void Shutdown(int UNUSED(flags))
|
|||
delete &g_ConfigDB;
|
||||
TIMER_END(L"shutdown ConfigDB");
|
||||
|
||||
// Really shut down the i18n system. Any future calls
|
||||
// to translate() will crash.
|
||||
TIMER_BEGIN(L"shutdown I18N");
|
||||
I18n::Shutdown();
|
||||
TIMER_END(L"shutdown I18N");
|
||||
|
||||
// resource
|
||||
// first shut down all resource owners, and then the handle manager.
|
||||
TIMER_BEGIN(L"resource modules");
|
||||
|
|
@ -768,17 +751,6 @@ void Init(const CmdLineArgs& args, int flags)
|
|||
exit(0);
|
||||
}
|
||||
|
||||
// Call LoadLanguage(NULL) to initialize the I18n system, but
|
||||
// without loading an actual language file - translate() will
|
||||
// just show the English key text, which is better than crashing
|
||||
// from a null pointer when attempting to translate e.g. error messages.
|
||||
// Real languages can only be loaded when the scripting system has
|
||||
// been initialised.
|
||||
//
|
||||
// this uses LOG and must therefore come after CLogger init.
|
||||
MICROLOG(L"init i18n");
|
||||
I18n::LoadLanguage(NULL);
|
||||
|
||||
// override ah_translate with our i18n code.
|
||||
AppHooks hooks = {0};
|
||||
hooks.translate = psTranslate;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
#include <cstdio>
|
||||
|
||||
#include "Pyrogenesis.h"
|
||||
#include "ps/i18n.h"
|
||||
|
||||
#include "lib/sysdep/sysdep.h"
|
||||
#include "lib/path_util.h"
|
||||
|
|
@ -31,21 +30,7 @@ static const wchar_t* translate_no_mem = L"(no mem)";
|
|||
// overrides ah_translate. registered in GameSetup.cpp
|
||||
const wchar_t* psTranslate(const wchar_t* text)
|
||||
{
|
||||
// make sure i18n system is (already|still) initialized.
|
||||
if(g_CurrentLocale)
|
||||
{
|
||||
// be prepared for this to fail, because translation potentially
|
||||
// involves script code and the JS context might be corrupted.
|
||||
try
|
||||
{
|
||||
CStrW ret = I18n::translate(text);
|
||||
const wchar_t* ret_dup = wcsdup(ret.c_str());
|
||||
return ret_dup? ret_dup : translate_no_mem;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
}
|
||||
}
|
||||
// TODO: implement this somehow
|
||||
|
||||
// i18n not available: at least try and return the text (unchanged)
|
||||
const wchar_t* ret_dup = wcsdup(text);
|
||||
|
|
|
|||
|
|
@ -1,133 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "ps/i18n.h"
|
||||
|
||||
#include "lib/utf8.h"
|
||||
#include "ps/Filesystem.h"
|
||||
#include "scripting/ScriptingHost.h"
|
||||
|
||||
#include "ps/CLogger.h"
|
||||
#define LOG_CATEGORY L"i18n"
|
||||
|
||||
// Yay, global variables. (The user only ever wants to be using one language
|
||||
// at a time, so this is sufficient)
|
||||
I18n::CLocale_interface* g_CurrentLocale = NULL;
|
||||
std::string g_CurrentLocaleName;
|
||||
|
||||
bool I18n::LoadLanguage(const char* name)
|
||||
{
|
||||
// Special case: If name==NULL, use an 'empty' locale which should have
|
||||
// no external dependencies other than CLogger, so it can be called
|
||||
// before SpiderMonkey/etc has been initialised (useful for localised
|
||||
// error messages that should fall back to English if the language hasn't
|
||||
// been loaded yet)
|
||||
if (name == NULL)
|
||||
{
|
||||
CLocale_interface* locale_ptr = I18n::NewLocale(NULL, NULL);
|
||||
debug_assert(locale_ptr);
|
||||
delete g_CurrentLocale;
|
||||
g_CurrentLocale = locale_ptr;
|
||||
g_CurrentLocaleName = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
CLocale_interface* locale_ptr = I18n::NewLocale(g_ScriptingHost.getContext(), JS_GetGlobalObject(g_ScriptingHost.getContext()));
|
||||
|
||||
if (! locale_ptr)
|
||||
{
|
||||
debug_warn(L"Failed to create locale");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Automatically delete the pointer when returning early
|
||||
std::auto_ptr<CLocale_interface> locale (locale_ptr);
|
||||
|
||||
VfsPath dirname = AddSlash(VfsPath(L"language")/wstring_from_utf8(name));
|
||||
|
||||
// Open *.lng with LoadStrings
|
||||
VfsPaths pathnames;
|
||||
if(fs_util::GetPathnames(g_VFS, dirname, L"*.lng", pathnames) < 0)
|
||||
return false;
|
||||
for (size_t i = 0; i < pathnames.size(); i++)
|
||||
{
|
||||
CVFSFile strings;
|
||||
if (! (strings.Load(g_VFS, pathnames[i]) == PSRETURN_OK && locale->LoadStrings((const char*)strings.GetBuffer())))
|
||||
{
|
||||
LOG(CLogger::Error, LOG_CATEGORY, L"Error opening language string file '%ls'", pathnames[i].string().c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Open *.wrd with LoadDictionary
|
||||
if(fs_util::GetPathnames(g_VFS, dirname, L"*.wrd", pathnames) < 0)
|
||||
return false;
|
||||
for (size_t i = 0; i < pathnames.size(); i++)
|
||||
{
|
||||
CVFSFile strings;
|
||||
if (! (strings.Load(g_VFS, pathnames[i]) == PSRETURN_OK && locale->LoadDictionary((const char*)strings.GetBuffer())))
|
||||
{
|
||||
LOG(CLogger::Error, LOG_CATEGORY, L"Error opening language string file '%ls'", pathnames[i].string().c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Open *.js with LoadFunctions
|
||||
if(fs_util::GetPathnames(g_VFS, dirname, L"*.js", pathnames) < 0)
|
||||
return false;
|
||||
for (size_t i = 0; i < pathnames.size(); i++)
|
||||
{
|
||||
const wchar_t* pathname = pathnames[i].string().c_str();
|
||||
CStr8 pathname8(pathname);
|
||||
CVFSFile strings;
|
||||
if (! (strings.Load(g_VFS, pathname) == PSRETURN_OK
|
||||
&&
|
||||
locale->LoadFunctions(
|
||||
(const char*)strings.GetBuffer(),
|
||||
strings.GetBufferSize(),
|
||||
pathname8.c_str()
|
||||
)))
|
||||
{
|
||||
LOG(CLogger::Error, LOG_CATEGORY, L"Error opening language function file '%ls'", pathname);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Free any previously loaded data
|
||||
delete g_CurrentLocale;
|
||||
|
||||
// Store the new CLocale*, and stop the auto_ptr from deleting it
|
||||
g_CurrentLocale = locale.release();
|
||||
|
||||
// Remember the name
|
||||
g_CurrentLocaleName = name;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* I18n::CurrentLanguageName()
|
||||
{
|
||||
return g_CurrentLocaleName.c_str();
|
||||
}
|
||||
|
||||
void I18n::Shutdown()
|
||||
{
|
||||
delete g_CurrentLocale;
|
||||
g_CurrentLocale = NULL;
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_I18N
|
||||
#define INCLUDED_I18N
|
||||
|
||||
#include "i18n/Interface.h"
|
||||
|
||||
extern I18n::CLocale_interface* g_CurrentLocale;
|
||||
|
||||
namespace I18n
|
||||
{
|
||||
inline StringBuffer translate(const wchar_t* s) { return g_CurrentLocale->Translate(s); }
|
||||
|
||||
bool LoadLanguage(const char* name);
|
||||
const char* CurrentLanguageName();
|
||||
void Shutdown();
|
||||
}
|
||||
|
||||
#endif // INCLUDED_I18N
|
||||
|
|
@ -50,7 +50,6 @@
|
|||
#include "ps/Hotkey.h"
|
||||
#include "ps/ProfileViewer.h"
|
||||
#include "ps/World.h"
|
||||
#include "ps/i18n.h"
|
||||
#include "ps/scripting/JSInterface_Console.h"
|
||||
#include "ps/scripting/JSInterface_VFS.h"
|
||||
#include "renderer/Renderer.h"
|
||||
|
|
|
|||
|
|
@ -1,72 +0,0 @@
|
|||
use strict;
|
||||
use warnings;
|
||||
|
||||
package DataFiles;
|
||||
|
||||
# Field numbers, so the arrays which (read|write)_file use can be accessed more pleasantly
|
||||
use constant STR_ID => 0;
|
||||
use constant STR_CONTEXT => 1;
|
||||
use constant STR_DESCRIPTION => 2;
|
||||
use constant STR_FLAGS => 3;
|
||||
|
||||
# Export the field numbers
|
||||
require Exporter;
|
||||
our @ISA = qw(Exporter);
|
||||
our @EXPORT = qw(STR_ID STR_CONTEXT STR_DESCRIPTION STR_FLAGS);
|
||||
|
||||
|
||||
# Read a file containing \n-separated fields and \n\n-separated records
|
||||
sub read_file {
|
||||
my ($filename, %params) = @_;
|
||||
|
||||
# If 'ignoremissing' has been passed, handle non-existent files as if they were empty
|
||||
if ($params{ignoremissing} and not -e $filename) {
|
||||
return [];
|
||||
}
|
||||
|
||||
open my $f, '<', $filename or die "Error opening $filename for input: $!";
|
||||
|
||||
my (@records, @fields);
|
||||
while (<$f>) {
|
||||
chomp;
|
||||
if (length) {
|
||||
# Each line stores a separate field
|
||||
push @fields, unescape($_);
|
||||
} else {
|
||||
# Split records by empty lines
|
||||
push @records, [@fields];
|
||||
@fields = ();
|
||||
}
|
||||
}
|
||||
push @records, [@fields] if @fields;
|
||||
|
||||
return \@records;
|
||||
}
|
||||
|
||||
# Inverse of read_file
|
||||
sub write_file {
|
||||
my ($filename, $data) = @_;
|
||||
open my $f, '>', $filename or die "Error opening $filename for output: $!";
|
||||
for (@$data) {
|
||||
print $f escape($_), "\n" for @$_;
|
||||
print $f "\n";
|
||||
}
|
||||
}
|
||||
|
||||
# Convert \ to \\, newlines to \n, blank lines to \
|
||||
sub unescape {
|
||||
my $t = $_[0];
|
||||
return "" if $t eq "\\";
|
||||
$t =~ s/\\n/\n/g;
|
||||
$t =~ s/\\\\/\\/g;
|
||||
$t;
|
||||
}
|
||||
sub escape {
|
||||
my $t = $_[0];
|
||||
return "\\" unless defined $t and length $t;
|
||||
$t =~ s/\\/\\\\/g;
|
||||
$t =~ s/\n/\\n/g;
|
||||
$t;
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
use strict;
|
||||
use warnings;
|
||||
|
||||
package StringExtract::CCode;
|
||||
|
||||
use StringExtract::Utils;
|
||||
|
||||
use Regexp::Common qw(delimited);
|
||||
|
||||
our $data = {
|
||||
|
||||
file_roots => [
|
||||
'source',
|
||||
],
|
||||
|
||||
file_roots_ignore => [
|
||||
'source/i18n/tests',
|
||||
'source/tools',
|
||||
],
|
||||
|
||||
file_types => qr/\.(?:cpp|h)$/i,
|
||||
|
||||
readfile_func => sub { extract(StringExtract::Utils::read_text(@_)); },
|
||||
};
|
||||
|
||||
sub extract {
|
||||
my ($data, $text) = @_;
|
||||
|
||||
$text = StringExtract::Utils::strip_comments($text, 'C++');
|
||||
|
||||
my @strings;
|
||||
|
||||
while ($text =~ /translate\s*\(\s*L\s*($RE{delimited}{-delim=>'"'})\s*\)/g) {
|
||||
my $str = $1;
|
||||
|
||||
# Remove surrounding quotes
|
||||
$str =~ s/^"(.*)"$/$1/;
|
||||
# Translate \" sequences
|
||||
$str =~ s/\\"/"/g;
|
||||
# and \n
|
||||
$str =~ s/\\n/\n/g;
|
||||
# and \\
|
||||
$str =~ s/\\\\/\\/g;
|
||||
|
||||
(my $filename = $data->{filename}) =~ s~.*?source/~~; # make the filenames a bit neater
|
||||
|
||||
push @strings, [ "phrase:".$str, "C++ $filename:".(1+StringExtract::Utils::count_newlines(substr $text, 0, pos $text)) ];
|
||||
}
|
||||
|
||||
return @strings;
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
use strict;
|
||||
use warnings;
|
||||
|
||||
package StringExtract::JSCode;
|
||||
|
||||
use StringExtract::Utils;
|
||||
|
||||
use Regexp::Common qw(delimited);
|
||||
|
||||
our $data = {
|
||||
|
||||
file_roots => [
|
||||
'binaries/data/mods/official/gui',
|
||||
],
|
||||
|
||||
file_types => qr/\.js$/i,
|
||||
|
||||
readfile_func => sub { extract(StringExtract::Utils::read_text(@_)); },
|
||||
};
|
||||
|
||||
sub extract {
|
||||
my ($data, $text) = @_;
|
||||
|
||||
return unless defined $text;
|
||||
|
||||
$text = StringExtract::Utils::strip_comments($text, 'Java');
|
||||
|
||||
my @strings;
|
||||
|
||||
while ($text =~ /translate\s*\(\s*($RE{delimited}{-delim=>'"'})/g) {
|
||||
my $str = $1;
|
||||
# Remove surrounding quotes
|
||||
$str =~ s/^"(.*)"$/$1/;
|
||||
# Translate \" sequences
|
||||
$str =~ s/\\"/"/g;
|
||||
# and \n
|
||||
$str =~ s/\\n/\n/g;
|
||||
# and \\
|
||||
$str =~ s/\\\\/\\/g;
|
||||
|
||||
push @strings, [ "phrase:".$1, "GUI script" ];
|
||||
}
|
||||
|
||||
return @strings;
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
use strict;
|
||||
use warnings;
|
||||
|
||||
package StringExtract::Utils;
|
||||
|
||||
use XML::Simple();
|
||||
use Carp;
|
||||
|
||||
use Regexp::Common qw(comment);
|
||||
|
||||
sub read_xml {
|
||||
my ($filename) = $_;
|
||||
|
||||
my $xml = new XML::Simple(
|
||||
ForceArray => 1,
|
||||
KeepRoot => 1,
|
||||
KeyAttr => [],
|
||||
ForceContent => 1,
|
||||
);
|
||||
|
||||
my $filedata = do { open my $f, '<', $filename or die $!; local $/; <$f> };
|
||||
|
||||
# Fix DTD paths
|
||||
my ($dir) = ($filename =~ m~(.*)[\\/]~);
|
||||
$filedata =~ s {SYSTEM "(?!/)} {SYSTEM "$dir/};
|
||||
$filedata =~ s {SYSTEM "/} {SYSTEM "../../../binaries/data/mods/official/};
|
||||
|
||||
my $data = eval { $xml->XMLin($filedata) };
|
||||
|
||||
if ($@) {
|
||||
warn "Error reading $filename: $@";
|
||||
return;
|
||||
}
|
||||
recursive_process($data);
|
||||
|
||||
my ($filename_short) = ($filename =~ m~([^\\/]+)$~);
|
||||
|
||||
my $root = (keys %$data)[0];
|
||||
return [ $root, $filename_short, @{$data->{$root}} ];
|
||||
}
|
||||
|
||||
sub recursive_process {
|
||||
if (ref($_[0]) eq 'HASH') {
|
||||
|
||||
# Force keys to lowercase
|
||||
my %temp;
|
||||
@temp{map lc, keys %{$_[0]}} = values %{$_[0]};
|
||||
%{$_[0]} = %temp;
|
||||
|
||||
# Trim whitespace in content
|
||||
$_[0]{content} =~ s/^\s*(.*?)\s*$/$1/s if exists $_[0]{content};
|
||||
|
||||
# Recurse through sub-elements
|
||||
recursive_process($_) for values %{$_[0]};
|
||||
|
||||
} elsif (ref($_[0]) eq 'ARRAY') {
|
||||
|
||||
# Recurse through sub-elements
|
||||
recursive_process($_) for @{$_[0]};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub read_text {
|
||||
my ($filename) = $_;
|
||||
|
||||
open my $file, '<', $filename or carp "Error opening $filename: $!";
|
||||
my $data = do { local $/; <$file> };
|
||||
|
||||
return ({ filename => $filename }, $data);
|
||||
}
|
||||
|
||||
|
||||
sub strip_comments {
|
||||
my ($data, $lang) = @_;
|
||||
|
||||
#$data =~ s/($RE{comment}{$lang})/ "\n" x count_newlines($1) /eg;
|
||||
|
||||
# TODO: Make it work. (The above code fails on lines like 'translate(L"Go to http://oops, this shouldn't be a comment)"')
|
||||
|
||||
$data;
|
||||
}
|
||||
|
||||
|
||||
sub count_newlines {
|
||||
return $_[0] =~ tr/\n//;
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
use strict;
|
||||
use warnings;
|
||||
|
||||
package StringExtract::XML;
|
||||
|
||||
use StringExtract::Utils;
|
||||
use StringExtract::JSCode;
|
||||
|
||||
our $data = {
|
||||
|
||||
file_roots => [
|
||||
'binaries/data/mods/official/art',
|
||||
'binaries/data/mods/official/entities',
|
||||
'binaries/data/mods/official/gui',
|
||||
],
|
||||
|
||||
file_types => qr/\.xml$/i,
|
||||
|
||||
readfile_func => sub { extract(StringExtract::Utils::read_xml(@_)); },
|
||||
};
|
||||
|
||||
sub extract {
|
||||
my ($xmldata) = @_;
|
||||
return unless $xmldata;
|
||||
|
||||
my ($root, $filename, %elements) = (@{$xmldata}[0, 1], %{$xmldata->[2]});
|
||||
|
||||
my @strings;
|
||||
|
||||
# Entities
|
||||
if ($root eq 'entity') {
|
||||
|
||||
push @strings, map [ "noun:".$_->{content}, "Entity name ($filename)" ], @{$elements{name}};
|
||||
|
||||
# Actors
|
||||
} elsif ($root eq 'object') {
|
||||
|
||||
push @strings, map [ "noun:".$_->{content}, "Actor name ($filename)" ], @{$elements{name}};
|
||||
|
||||
# Materials
|
||||
} elsif ($root eq 'material') {
|
||||
|
||||
# GUI objects
|
||||
} elsif ($root eq 'objects') {
|
||||
|
||||
recursive_extract_guiobject($filename, \@strings, [\%elements]);
|
||||
|
||||
# GUI setup
|
||||
} elsif ($root eq 'setup') {
|
||||
# Do nothing
|
||||
|
||||
# GUI sprites
|
||||
} elsif ($root eq 'sprites') {
|
||||
# Do nothing
|
||||
|
||||
# GUI styles
|
||||
} elsif ($root eq 'styles') {
|
||||
# Do nothing
|
||||
|
||||
} else {
|
||||
warn "Unrecognised XML file type '$root' - ignoring";
|
||||
}
|
||||
return @strings;
|
||||
|
||||
}
|
||||
|
||||
sub recursive_extract_guiobject {
|
||||
my ($filename, $strings, $elements) = @_;
|
||||
for my $element (@$elements) {
|
||||
push @$strings, [ "phrase:".$element->{tooltip}, "GUI tooltip ($filename)" ] if defined $element->{tooltip};
|
||||
push @$strings, [ "phrase:".$element->{content}, "GUI text ($filename)" ] if defined $element->{content};
|
||||
|
||||
if ($element->{script}) {
|
||||
push @$strings, StringExtract::JSCode::extract($_->{content}) for @{$element->{script}};
|
||||
}
|
||||
if ($element->{action}) {
|
||||
push @$strings, StringExtract::JSCode::extract($_->{content}) for @{$element->{action}};
|
||||
}
|
||||
|
||||
recursive_extract_guiobject($filename, $strings, $element->{object}) if $element->{object};
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
use strict;
|
||||
use warnings;
|
||||
|
||||
package Strings;
|
||||
|
||||
use DataFiles;
|
||||
|
||||
sub merge {
|
||||
my ($filename, %new_strings) = @_;
|
||||
|
||||
# Read the earlier string data
|
||||
my $strings = DataFiles::read_file($filename, ignoremissing=>1);
|
||||
|
||||
for my $old (@$strings) {
|
||||
my $stringid = $old->[STR_ID];
|
||||
|
||||
if (exists $new_strings{$stringid}) {
|
||||
# String already exists; just update the content
|
||||
if ($new_strings{$stringid}{context}) {
|
||||
$old->[STR_CONTEXT] = $new_strings{$stringid}{context};
|
||||
}
|
||||
if ($new_strings{$stringid}{description}) {
|
||||
$old->[STR_DESCRIPTION] = $new_strings{$stringid}{description};
|
||||
}
|
||||
|
||||
# Make sure it's not obsolete now
|
||||
flag_set(\$old->[STR_FLAGS], 'obsolete', 0);
|
||||
|
||||
# Remove it from this list, so the unprocessed ones can be found later
|
||||
delete $new_strings{$stringid};
|
||||
|
||||
} else {
|
||||
# String has been removed; set obsolete flag
|
||||
flag_set(\$old->[STR_FLAGS], 'obsolete', 1);
|
||||
}
|
||||
}
|
||||
|
||||
for (keys %new_strings) {
|
||||
# Newly added strings
|
||||
push @$strings, [ $_, len_or($new_strings{$_}{context}, "?"), len_or($new_strings{$_}{description}, "?"), "" ];
|
||||
}
|
||||
|
||||
DataFiles::write_file($filename, $strings);
|
||||
}
|
||||
|
||||
sub len_or { (defined $_[0] and length $_[0]) ? $_[0] : $_[1] }
|
||||
|
||||
|
||||
sub flag_set {
|
||||
my ($str, $flagname, $value) = @_;
|
||||
my @flags = split / /, $$str;
|
||||
if ($value) {
|
||||
push @flags, $flagname unless grep $_ eq $flagname, @flags;
|
||||
} else {
|
||||
@flags = grep $_ ne $flagname, @flags;
|
||||
}
|
||||
$$str = join ' ', @flags;
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
use strict;
|
||||
use warnings;
|
||||
|
||||
package Translations;
|
||||
|
||||
use DataFiles;
|
||||
|
||||
sub merge {
|
||||
my ($filename, %new_translations) = @_;
|
||||
|
||||
# Read the earlier translation data
|
||||
my $translations = DataFiles::read_file($filename, ignoremissing=>1);
|
||||
|
||||
for my $old (@$translations) {
|
||||
my $stringid = $old->[0];
|
||||
|
||||
if (exists $new_translations{$stringid}) {
|
||||
# Translation already exists; just update the content
|
||||
$old->[1] = $new_translations{$stringid};
|
||||
|
||||
# Remove it from this list, so the unprocessed ones can be found later
|
||||
delete $new_translations{$stringid};
|
||||
|
||||
} else {
|
||||
# String has been removed; leave it for now
|
||||
}
|
||||
}
|
||||
|
||||
for (keys %new_translations) {
|
||||
# Newly added translations
|
||||
push @$translations, [ $_, len_or($new_translations{$_}, "") ];
|
||||
}
|
||||
|
||||
DataFiles::write_file($filename, $translations);
|
||||
}
|
||||
|
||||
sub len_or { (defined $_[0] and length $_[0]) ? $_[0] : $_[1] }
|
||||
|
||||
|
||||
1;
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
use strict;
|
||||
use warnings;
|
||||
|
||||
our %config;
|
||||
|
||||
$config{data_path} = "../../../binaries/data/tools/i18n";
|
||||
|
||||
$config{strings_filename} = "$config{data_path}/strings.txt";
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
use strict;
|
||||
use warnings;
|
||||
|
||||
my $language = "english";
|
||||
|
||||
our %config;
|
||||
do "config.pl";
|
||||
|
||||
use DataFiles;
|
||||
use Strings;
|
||||
use Translations;
|
||||
|
||||
use Spreadsheet::ParseExcel;
|
||||
|
||||
fromspreadsheet($config{strings_filename}, $config{data_path}."/$language/translations.txt", $config{data_path}."/$language/work.xls");
|
||||
|
||||
sub fromspreadsheet {
|
||||
my ($strings_filename, $translations_filename, $spreadsheet_filename) = @_;
|
||||
|
||||
# Read data from spreadsheet:
|
||||
|
||||
my $strings = DataFiles::read_file($strings_filename);
|
||||
my $translations = DataFiles::read_file($translations_filename, ignoremissing=>1);
|
||||
|
||||
my $workbook = Spreadsheet::ParseExcel::Workbook->Parse($spreadsheet_filename);
|
||||
|
||||
my %strings; # Data associated with each string. (type:id => { description => '...' }, ...)
|
||||
my %translations; # Data associated with each translation. (type:id => translation, ...)
|
||||
|
||||
for my $worksheet (@{$workbook->{Worksheet}}) {
|
||||
my $type = $worksheet->{Name};
|
||||
|
||||
my @rows;
|
||||
for my $row ($worksheet->{MinRow} .. $worksheet->{MaxRow}) {
|
||||
next if $row == 0;
|
||||
push @rows, [];
|
||||
for my $col ($worksheet->{MinCol} .. $worksheet->{MaxCol}) {
|
||||
push @{$rows[-1]}, $worksheet->{Cells}[$row][$col]->{Val};
|
||||
}
|
||||
}
|
||||
|
||||
for (@rows) {
|
||||
my $id = $type.':'.$_->[0];
|
||||
|
||||
if ($strings{$id}) {
|
||||
warn "Duplicated string $id!";
|
||||
}
|
||||
$strings{$id} = { description => $_->[2] };
|
||||
$translations{$id} = $_->[1];
|
||||
}
|
||||
}
|
||||
|
||||
Strings::merge($strings_filename, %strings);
|
||||
|
||||
Translations::merge($translations_filename, %translations);
|
||||
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
=pod
|
||||
|
||||
String extraction utility.
|
||||
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our %config;
|
||||
do "config.pl";
|
||||
|
||||
use File::Find;
|
||||
|
||||
# Include appropriate pieces of code
|
||||
use StringExtract::XML;
|
||||
use StringExtract::JSCode;
|
||||
use StringExtract::CCode;
|
||||
|
||||
use DataFiles;
|
||||
use Strings;
|
||||
|
||||
my %all_strings;
|
||||
|
||||
# Repeat for each data type that needs to be parsed
|
||||
for my $type (
|
||||
$StringExtract::XML::data,
|
||||
# $StringExtract::JSCode::data,
|
||||
# $StringExtract::CCode::data,
|
||||
) {
|
||||
|
||||
# Get the list of files that the module wants to handle
|
||||
|
||||
my @files;
|
||||
|
||||
# Search each file_roots, relative to ../../../
|
||||
my $prefix = "../../../";
|
||||
my @dirs = map $prefix.$_, @{$type->{file_roots}};
|
||||
find({
|
||||
preprocess => sub {
|
||||
# Trim the ../../../ prefix
|
||||
my $path = substr($File::Find::dir, length $prefix);
|
||||
# Ignore all directories that are called '.svn', or whose paths are any of file_roots_ignore
|
||||
grep not ($_ eq '.svn' or contains($type->{file_roots_ignore}, $path.'/'.$_)), @_;
|
||||
},
|
||||
wanted => sub {
|
||||
# Include files that match the file_types regexp
|
||||
push @files, $File::Find::name if /$type->{file_types}/;
|
||||
},
|
||||
no_chdir => 1,
|
||||
}, @dirs);
|
||||
|
||||
|
||||
# Call the appropriate read function on every matching file
|
||||
my @strings = map $type->{readfile_func}->($_), @files;
|
||||
|
||||
# Now @strings = ( [stringid, context], ... )
|
||||
# where context eq 'Entity (whatever.xml:123)'
|
||||
|
||||
# Build %all_strings = (stringid => [context, context, ...], ...)
|
||||
for (@strings) {
|
||||
# Make sure the value is an array ref
|
||||
$all_strings{$_->[0]} ||= [];
|
||||
# Push the string's context data onto the array ref
|
||||
push @{$all_strings{$_->[0]}}, $_->[1];
|
||||
}
|
||||
}
|
||||
|
||||
# Transform into %all_strings = (stringid => { context => '...' })
|
||||
for (keys %all_strings) {
|
||||
$all_strings{$_} = { context => join "\n", uniq(sort @{$all_strings{$_}}) };
|
||||
}
|
||||
|
||||
# Merge the string data with any existing information
|
||||
Strings::merge($config{strings_filename}, %all_strings);
|
||||
|
||||
sub contains { $_[1] eq $_ && return 1 for @{$_[0]}; 0 }
|
||||
|
||||
sub uniq { # Uniquify sorted lists
|
||||
my @r;
|
||||
for (@_) { push @r, $_ unless @r and $r[-1] eq $_ };
|
||||
@r;
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
use strict;
|
||||
use warnings;
|
||||
|
||||
my $language = "english";
|
||||
|
||||
our %config;
|
||||
do "config.pl";
|
||||
|
||||
use DataFiles;
|
||||
|
||||
use Spreadsheet::WriteExcel;
|
||||
|
||||
tospreadsheet($config{strings_filename}, $config{data_path}."/$language/translations.txt", $config{data_path}."/$language/work.xls");
|
||||
|
||||
sub tospreadsheet {
|
||||
my ($strings_filename, $translations_filename, $spreadsheet_filename) = @_;
|
||||
|
||||
my $strings = DataFiles::read_file($strings_filename);
|
||||
my %translations = map @$_, DataFiles::read_file($translations_filename, ignoremissing=>1);
|
||||
|
||||
my %data; # = ("phrase" => [ [id, translation, description, context, flags ], ... ], "noun" => ...)
|
||||
|
||||
for my $string (@$strings) {
|
||||
my ($type, $id) = split /:/, $string->[STR_ID], 2;
|
||||
|
||||
my $translation = $translations{$string->[STR_ID]};
|
||||
|
||||
push @{$data{$type}}, [ $id, $translation, @$string[STR_DESCRIPTION, STR_CONTEXT, STR_FLAGS] ];
|
||||
}
|
||||
|
||||
|
||||
my $workbook = new Spreadsheet::WriteExcel ($spreadsheet_filename);
|
||||
for my $type (reverse sort keys %data) {
|
||||
|
||||
my $worksheet = $workbook->add_worksheet($type);
|
||||
|
||||
my $headerformat = $workbook->add_format();
|
||||
$headerformat->set_bold(1);
|
||||
|
||||
$worksheet->write(0,0, "String", $headerformat);
|
||||
$worksheet->write(0,1, "Translation", $headerformat);
|
||||
$worksheet->write(0,2, "Description", $headerformat);
|
||||
$worksheet->write(0,3, "Used by", $headerformat);
|
||||
|
||||
$worksheet->freeze_panes(1, 0);
|
||||
|
||||
my $mainformat = $workbook->add_format();
|
||||
$mainformat->set_align('top');
|
||||
$mainformat->set_text_wrap();
|
||||
|
||||
$worksheet->set_column(0,0, 27, $mainformat);
|
||||
$worksheet->set_column(1,1, 45, $mainformat);
|
||||
$worksheet->set_column(2,2, 33, $mainformat);
|
||||
$worksheet->set_column(3,3, 33, $mainformat);
|
||||
|
||||
my $row = 1;
|
||||
|
||||
for my $string (@{ $data{$type} }) {
|
||||
|
||||
my $col = 0;
|
||||
$worksheet->write($row, $col++, $_) for @$string;
|
||||
|
||||
++$row;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
sub find_translation {
|
||||
$_->[0] eq $_[1] && return $_->[1] for @{$_[0]};
|
||||
"";
|
||||
}
|
||||
Loading…
Reference in a new issue