Domanda

Vorrei utilizzare un database per archiviare le coppie chiave/valore i18n in modo da poter modificare/ricaricare i dati i18n in fase di esecuzione.Qualcuno l'ha fatto?Oppure qualcuno ha un'idea di come implementarlo?Ho letto diversi thread a riguardo, ma non ho visto una soluzione praticabile.

Mi riferisco specificamente a qualcosa che funzionerebbe con i tag jstl come

<fmt:setlocale>
<fmt:bundle>
<fmt:setBundle>
<fmt:message>

Penso che ciò comporterà l'estensione di ResourceBundle, ma quando l'ho provato ho riscontrato problemi che avevano a che fare con il modo in cui i tag jstl ottengono il pacchetto di risorse.

È stato utile?

Soluzione

Stai solo chiedendo come memorizzare i caratteri UTF-8/16 in un DB?in mysql è solo questione di assicurarsi di creare con il supporto UTF8 e impostarlo come predefinito o specificarlo a livello di colonna o tabella.L'ho già fatto in Oracle e MySQL.Crea una tabella e taglia e incolla alcuni dati i18n al suo interno e guarda cosa succede...potresti essere già impostato..

oppure mi sto sbagliando completamente?

modificare:

per essere più esplicito...Di solito implemento una tabella a tre colonne...lingua, chiave, valore...dove "valore" contiene parole o frasi in lingua potenzialmente straniera..."lingua" contiene alcune chiavi della lingua e "chiave" è una chiave inglese (ad es.login.errore.password.dup)...la lingua e la chiave sono indicizzate...

Ho quindi creato interfacce su una struttura come questa che mostra ogni chiave con tutte le sue traduzioni (valori)...può essere fantasioso e includere tracce di controllo, marcatori "sporchi" e tutte le altre cose necessarie per consentire ai traduttori e agli addetti all'immissione dati di farne uso.

Modifica 2:

Ora che hai aggiunto le informazioni sui tag JSTL, capisco qualcosa in più...Non l'ho mai fatto personalmente..ma ho trovato queste vecchie informazioni su theserverside...

HttpSession session = .. [get hold of the session] 
ResourceBundle bundle = new PropertyResourceBundle(toInputStream(myOwnProperties)) [toInputStream just stores the properties into an inputstream] 
Locale locale = .. [get hold of the locale]
javax.servlet.jsp.jstl.core.Config.set(session, Config.FMT_LOCALIZATION_CONTEXT, new LocalizationContext(bundle ,locale));

Altri suggerimenti

Finalmente sono riuscito a farlo funzionare con l'aiuto di danb sopra.

Questa è la mia classe del bundle di risorse e la classe di controllo del bundle di risorse.

Ho usato questo codice di @[danb].

ResourceBundle bundle = ResourceBundle.getBundle("AwesomeBundle", locale, DbResourceBundle.getMyControl());
javax.servlet.jsp.jstl.core.Config.set(actionBeanContext.getRequest(), Config.FMT_LOCALIZATION_CONTEXT, new LocalizationContext(bundle, locale));

e ho scritto questo corso.

public class DbResourceBundle extends ResourceBundle
{
    private Properties properties;

    public DbResourceBundle(Properties inProperties)
    {
        properties = inProperties;
    }

    @Override
    @SuppressWarnings(value = { "unchecked" })
    public Enumeration<String> getKeys()
    {
        return properties != null ? ((Enumeration<String>) properties.propertyNames()) : null;
    }

    @Override
    protected Object handleGetObject(String key)
    {
        return properties.getProperty(key);
    }

    public static ResourceBundle.Control getMyControl()
    {
        return new ResourceBundle.Control()
        {

            @Override
            public List<String> getFormats(String baseName)
            {
                if (baseName == null)
                {
                    throw new NullPointerException();
                }
                return Arrays.asList("db");
            }

            @Override
            public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IllegalAccessException,
                  InstantiationException, IOException
            {
                if ((baseName == null) || (locale == null) || (format == null) || (loader == null))
                    throw new NullPointerException();
                ResourceBundle bundle = null;
                if (format.equals("db"))
                {
                    Properties p = new Properties();
                    DataSource ds = (DataSource) ContextFactory.getApplicationContext().getBean("clinicalDataSource");
                    Connection con = null;
                    Statement s = null;
                    ResultSet rs = null;
                    try
                    {
                        con = ds.getConnection();
                        StringBuilder query = new StringBuilder();
                        query.append("select label, value from i18n where bundle='" + StringEscapeUtils.escapeSql(baseName) + "' ");

                        if (locale != null)
                        {
                            if (StringUtils.isNotBlank(locale.getCountry()))
                            {
                                query.append("and country='" + escapeSql(locale.getCountry()) + "' ");

                            }
                            if (StringUtils.isNotBlank(locale.getLanguage()))
                            {
                                query.append("and language='" + escapeSql(locale.getLanguage()) + "' ");

                            }
                            if (StringUtils.isNotBlank(locale.getVariant()))
                            {
                                query.append("and variant='" + escapeSql(locale.getVariant()) + "' ");

                            }
                        }
                        s = con.createStatement();
                        rs = s.executeQuery(query.toString());
                        while (rs.next())
                        {
                            p.setProperty(rs.getString(1), rs.getString(2));
                        }
                    }
                    catch (Exception e)
                    {
                        e.printStackTrace();
                        throw new RuntimeException("Can not build properties: " + e);
                    }
                    finally
                    {
                        DbUtils.closeQuietly(con, s, rs);
                    }
                    bundle = new DbResourceBundle(p);
                }
                return bundle;
            }

            @Override
            public long getTimeToLive(String baseName, Locale locale)
            {
                return 1000 * 60 * 30;
            }

            @Override
            public boolean needsReload(String baseName, Locale locale, String format, ClassLoader loader, ResourceBundle bundle, long loadTime)
            {
                return true;
            }

        };
    }

Abbiamo una tabella di database con chiave/lingua/termine dove chiave è un numero intero n ed è una chiave primaria combinata insieme alla lingua.

Stiamo usando Struts, quindi abbiamo finito per scriverne uno nostro PropertyMessageResources implementazione che ci permette di fare qualcosa di simile <bean:message key="impressum.text" />.

Funziona molto bene e ci dà la flessibilità di cambiare lingua dinamicamente nel front-end e di aggiornare le traduzioni al volo.

In realtà ciò di cui ScArcher2 aveva bisogno è la risposta di David che non è contrassegnata come corretta o utile.

La soluzione che ScArcher2 ha scelto di utilizzare è un errore terribile :) Caricamento di TUTTE le traduzioni contemporaneamente...in qualsiasi applicazione più grande lo ucciderà.Caricamento di migliaia di traduzioni per ogni richiesta...

il metodo di David è più comunemente utilizzato in ambienti di produzione reali.A volte per limitare le chiamate al db, cioè ad ogni messaggio tradotto, è possibile creare gruppi di traduzioni per argomento, funzionalità ecc.per precaricarli.Ma questo è un po’ più complesso e può essere sostituito con un buon sistema di cache.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top