diff --git a/legacyworlds-server-beans-i18n/src/main/java/com/deepclone/lw/beans/i18n/I18NData.java b/legacyworlds-server-beans-i18n/src/main/java/com/deepclone/lw/beans/i18n/I18NData.java index 77bca8a..3ebac74 100644 --- a/legacyworlds-server-beans-i18n/src/main/java/com/deepclone/lw/beans/i18n/I18NData.java +++ b/legacyworlds-server-beans-i18n/src/main/java/com/deepclone/lw/beans/i18n/I18NData.java @@ -239,6 +239,20 @@ class I18NData } + /** + * Access the store for some language + * + * @param language + * the language to access + * + * @return the language store, or null if the language is not defined. + */ + LanguageStore getStore( String language ) + { + return this.languages.get( language ); + } + + /** * Sets or creates the translation for a given language/string identifier pair. * @@ -257,7 +271,8 @@ class I18NData * @throws IllegalArgumentException * if the string does not exist */ - String setTranslation( final int administrator , final String language , final String string , final String translation ) + String setTranslation( final int administrator , final String language , final String string , + final String translation ) { // Get existing translation LanguageStore store = this.languages.get( language ); diff --git a/legacyworlds-server-beans-i18n/src/main/java/com/deepclone/lw/beans/i18n/TranslatorBean.java b/legacyworlds-server-beans-i18n/src/main/java/com/deepclone/lw/beans/i18n/TranslatorBean.java index 7ce8046..4e97fbf 100644 --- a/legacyworlds-server-beans-i18n/src/main/java/com/deepclone/lw/beans/i18n/TranslatorBean.java +++ b/legacyworlds-server-beans-i18n/src/main/java/com/deepclone/lw/beans/i18n/TranslatorBean.java @@ -1,7 +1,10 @@ package com.deepclone.lw.beans.i18n; +import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; import org.springframework.beans.factory.annotation.Autowired; @@ -13,10 +16,13 @@ import com.deepclone.lw.interfaces.i18n.UnknownStringException; /** + * Translation component + * + *

* The translator bean's implementation uses the contents of the {@link I18NData} instance, which it * only accesses in read-only mode. * - * @author tseeker + * @author E. Benoît */ public class TranslatorBean implements Translator @@ -83,6 +89,23 @@ public class TranslatorBean } + /* Documentation in Translator interface */ + @Override + public String getLanguageName( String language ) + throws UnknownLanguageException + { + this.data.readLock( ).lock( ); + try { + if ( !this.data.isLanguageComplete( language ) ) { + throw new UnknownLanguageException( language ); + } + return this.data.getLanguageName( language ); + } finally { + this.data.readLock( ).unlock( ); + } + } + + /* Documentation in Translator interface */ @Override public String translate( String language , String string ) @@ -103,17 +126,30 @@ public class TranslatorBean } - /* Documentation in Translator interface */ + /** + * Access the store for the specified language then extract translations + */ @Override - public String getLanguageName( String language ) - throws UnknownLanguageException + public Map< String , String > translate( String language , Collection< String > strings ) + throws UnknownStringException , UnknownLanguageException { this.data.readLock( ).lock( ); try { if ( !this.data.isLanguageComplete( language ) ) { throw new UnknownLanguageException( language ); } - return this.data.getLanguageName( language ); + + LanguageStore store = this.data.getStore( language ); + HashMap< String , String > result = new HashMap< String , String >( ); + for ( String identifier : strings ) { + String value = store.getTranslation( identifier ); + if ( value == null ) { + throw new UnknownStringException( identifier ); + } + result.put( identifier , value ); + } + + return result; } finally { this.data.readLock( ).unlock( ); } diff --git a/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/EmpireDAOBean.java b/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/EmpireDAOBean.java index 43524db..e515d04 100644 --- a/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/EmpireDAOBean.java +++ b/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/EmpireDAOBean.java @@ -79,19 +79,8 @@ public class EmpireDAOBean public GeneralInformation getInformation( int empireId ) { String sql = "SELECT * FROM emp.general_information WHERE id = ?"; - RowMapper< GeneralInformation > mapper = new RowMapper< GeneralInformation >( ) { - @Override - public GeneralInformation mapRow( ResultSet rs , int rowNum ) - throws SQLException - { - String st = rs.getString( "status" ); - Character status = ( st == null ) ? null : st.charAt( 0 ); - return new GeneralInformation( status , rs.getString( "name" ) , rs.getString( "alliance" ) , rs - .getLong( "cash" ) , rs.getLong( "game_time" ) , rs.getInt( "account_id" ) ); - } - }; try { - return this.dTemplate.queryForObject( sql , mapper , empireId ); + return this.dTemplate.queryForObject( sql , new GeneralInformationRowMapper( ) , empireId ); } catch ( EmptyResultDataAccessException e ) { return null; } diff --git a/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/EmpireManagementBean.java b/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/EmpireManagementBean.java index 7a4c6fe..a940ef7 100644 --- a/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/EmpireManagementBean.java +++ b/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/EmpireManagementBean.java @@ -117,7 +117,7 @@ public class EmpireManagementBean return new GamePageData( generalInformation.getName( ) , generalInformation.getStatus( ) , generalInformation.getTag( ) , generalInformation.getCash( ) , generalInformation.getNextTick( ) , - planets , rlTime ); + planets , rlTime, generalInformation.getLanguage( ) ); } diff --git a/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/GeneralInformationRowMapper.java b/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/GeneralInformationRowMapper.java new file mode 100644 index 0000000..fd8be8a --- /dev/null +++ b/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/GeneralInformationRowMapper.java @@ -0,0 +1,36 @@ +package com.deepclone.lw.beans.empire; + + +import java.sql.ResultSet; +import java.sql.SQLException; + +import org.springframework.jdbc.core.RowMapper; + +import com.deepclone.lw.sqld.game.GeneralInformation; + + + +class GeneralInformationRowMapper + implements RowMapper< GeneralInformation > +{ + + @Override + public GeneralInformation mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + GeneralInformation info = new GeneralInformation( ); + + info.setName( rs.getString( "name" ) ); + info.setTag( rs.getString( "alliance" ) ); + info.setCash( rs.getLong( "cash" ) ); + info.setLanguage( rs.getString( "language" ) ); + info.setNextTick( rs.getLong( "game_time" ) ); + info.setAccountId( rs.getInt( "account_id" ) ); + + String statusString = rs.getString( "status" ); + info.setStatus( rs.wasNull( ) ? null : statusString.charAt( 0 ) ); + + return info; + } + +} diff --git a/legacyworlds-server-data/db-structure/parts/040-functions/040-empire.sql b/legacyworlds-server-data/db-structure/parts/040-functions/040-empire.sql index 563c356..16443aa 100644 --- a/legacyworlds-server-data/db-structure/parts/040-functions/040-empire.sql +++ b/legacyworlds-server-data/db-structure/parts/040-functions/040-empire.sql @@ -506,6 +506,7 @@ CREATE VIEW emp.enemies -- General information view -- +DROP VIEW IF EXISTS emp.general_information CASCADE; CREATE VIEW emp.general_information AS SELECT e.name_id AS id , en.name AS name , ( CASE @@ -516,13 +517,17 @@ CREATE VIEW emp.general_information END ) AS status , e.cash AS cash , a.tag AS alliance , st.next_tick AS game_time , - av.id AS account_id + av.id AS account_id , + av.language AS language FROM emp.empires e - INNER JOIN naming.empire_names en ON en.id = e.name_id - INNER JOIN users.accounts_view av ON av.id = en.owner_id + INNER JOIN naming.empire_names en + ON en.id = e.name_id + INNER JOIN users.accounts_view av + ON av.id = en.owner_id LEFT OUTER JOIN emp.alliance_members am ON am.empire_id = e.name_id AND NOT am.is_pending - LEFT OUTER JOIN emp.alliances a ON a.id = am.alliance_id + LEFT OUTER JOIN emp.alliances a + ON a.id = am.alliance_id CROSS JOIN sys.status st; GRANT SELECT ON emp.general_information TO :dbuser; diff --git a/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/GeneralInformation.java b/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/GeneralInformation.java index 82b7270..afd37d3 100644 --- a/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/GeneralInformation.java +++ b/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/GeneralInformation.java @@ -3,11 +3,12 @@ package com.deepclone.lw.sqld.game; public class GeneralInformation { + private String name; + + private String language; private Character status; - private String name; - private String tag; private long cash; @@ -17,50 +18,87 @@ public class GeneralInformation private int accountId; - public GeneralInformation( Character status , String name , String tag , long cash , long nextTick , int accountId ) + public String getName( ) + { + return this.name; + } + + + public void setName( String name ) { - this.status = status; this.name = name; - this.tag = tag; - this.cash = cash; - this.nextTick = nextTick; - this.accountId = accountId; + } + + + public String getLanguage( ) + { + return this.language; + } + + + public void setLanguage( String language ) + { + this.language = language; } public Character getStatus( ) { - return status; + return this.status; } - public String getName( ) + public void setStatus( Character status ) { - return name; + this.status = status; } public String getTag( ) { - return tag; + return this.tag; + } + + + public void setTag( String tag ) + { + this.tag = tag; } public long getCash( ) { - return cash; + return this.cash; + } + + + public void setCash( long cash ) + { + this.cash = cash; } public long getNextTick( ) { - return nextTick; + return this.nextTick; + } + + + public void setNextTick( long nextTick ) + { + this.nextTick = nextTick; } public int getAccountId( ) { - return accountId; + return this.accountId; + } + + + public void setAccountId( int accountId ) + { + this.accountId = accountId; } } diff --git a/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/Translator.java b/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/Translator.java index 9c5eb39..92ada50 100644 --- a/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/Translator.java +++ b/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/Translator.java @@ -1,6 +1,8 @@ package com.deepclone.lw.interfaces.i18n; +import java.util.Collection; +import java.util.Map; import java.util.Set; @@ -8,12 +10,12 @@ import java.util.Set; /** * Translator service interface * + *

* This interface defines the methods available on the Translator service. One such service should * be present on all nodes. All Translator service instances are managed by the I18NManager service, * which is shared between nodes and notifies Translator instances of database updates. * - * @author tseeker - * + * @author E. Benoît */ public interface Translator { @@ -62,4 +64,28 @@ public interface Translator */ public String translate( String language , String string ) throws UnknownStringException , UnknownLanguageException; + + + /** + * Translate multiple strings based on their identifiers + * + *

+ * This method must be implemented to allow "en masse" string translations. It will fetch the + * translations in a given language for an arbitrary quantity of string identifiers, returning + * the results as a map of identifiers to translations. + * + * @param language + * the identifier of the language to translate to + * @param strings + * a collection of string identifiers + * + * @return a map associating string identifiers to translations + * + * @throws UnknownStringException + * if one of the string identifiers does not match a string + * @throws UnknownLanguageException + * if the language does not exist or is not supported + */ + public Map< String , String > translate( String language , Collection< String > strings ) + throws UnknownStringException , UnknownLanguageException; } diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/GamePageData.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/GamePageData.java index 82e1767..59cef53 100644 --- a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/GamePageData.java +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/GamePageData.java @@ -8,23 +8,91 @@ import java.util.List; +/** + * General information included in a game response + * + *

+ * This class stores common information which is included in most in-game responses. This + * information includes some essential preferences, the general state of the empire, and some + * information about the server's state. + * + * @author E. Benoît + */ public class GamePageData implements Serializable { - + /** + * The serialisation version identifier + * + *

+ */ private static final long serialVersionUID = 1L; + + /** The name of the current empire */ private final String empire; + + /** + * State of the account + * + *

+ * This field indicates the "special" state of the account: q is for accounts that + * are quitting, v for accounts in vacation mode and s for accounts + * that are about to enter vacation mode. null indicates "none of the above". + */ private final Character special; + + /** Alliance tag, or null if not a full member of any alliance */ private final String alliance; + + /** + * Current cash of the empire + * + *

+ * FIXME: will be replaced with actual resources + */ private final long cash; + + /** Timestamp from the server's system */ private final Date serverTime; + + /** Current game time (from last update identifier) */ private final GameTime gameTime; + + /** Planets owned by the empire */ private final List< NameIdPair > planets; + + /** Whether the player wants to see "real" times or in-game times */ private final boolean useRLTime; + /** Code of selected language */ + private final String language; + + /** + * Initialise the general game information record + * + * @param empire + * the empire's name + * @param special + * the special account state character (see {@link #special}) + * @param alliance + * current alliance tag + * @param cash + * current cash + * @param gameTime + * last update identifier + * @param planets + * list of planets owned by the empire + * @param useRLTime + * whether the player wants to see "real" times or in-game times + * @param language + * selected language code + */ public GamePageData( String empire , Character special , String alliance , long cash , long gameTime , - List< NameIdPair > planets , boolean useRLTime ) + List< NameIdPair > planets , boolean useRLTime , String language ) { this.empire = empire; this.special = special; @@ -34,54 +102,107 @@ public class GamePageData this.gameTime = new GameTime( gameTime ); this.planets = Collections.unmodifiableList( planets ); this.useRLTime = useRLTime; + this.language = language; } + /** + * Gets the name of the current empire. + * + * @return the name of the current empire + */ public String getEmpire( ) { - return empire; + return this.empire; } + /** + * Gets the state of the account + * + * @return the state of the account + */ public Character getSpecial( ) { - return special; + return this.special; } + /** + * Gets the alliance tag + * + * @return the alliance tag, or null if not a full member of any alliance + */ public String getAlliance( ) { - return alliance; + return this.alliance; } + /** + * Gets the current cash of the empire + * + * @return the current cash of the empire + */ public long getCash( ) { - return cash; + return this.cash; } + /** + * Gets the timestamp from the server's system. + * + * @return the timestamp from the server's system + */ public Date getServerTime( ) { - return serverTime; + return this.serverTime; } + /** + * Gets the current game time + * + * @return the current game time + */ public GameTime getGameTime( ) { - return gameTime; + return this.gameTime; } + /** + * Gets the planets owned by the empire. + * + * @return the list of planets owned by the empire + */ public List< NameIdPair > getPlanets( ) { - return planets; + return this.planets; } + /** + * Checks if the player wants to see "real" times or in-game times. + * + * @return true if the player wants to see "real" times, false for + * in-game times + */ public boolean isUseRLTime( ) { - return useRLTime; + return this.useRLTime; + } + + + /** + * Gets the code of selected language. + * + * @return the code of selected language + */ + public String getLanguage( ) + { + return this.language; } }