Question

J'aimerais utiliser une base de données pour stocker les paires clé/valeur i18n afin que nous puissions modifier/recharger les données i18n au moment de l'exécution.Quelqu'un a-t-il fait ça ?Ou est-ce que quelqu'un a une idée sur la façon de mettre en œuvre cela ?J'ai lu plusieurs discussions à ce sujet, mais je n'ai pas vu de solution réalisable.

Je fais spécifiquement référence à quelque chose qui fonctionnerait avec les balises jstl telles que

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

Je pense que cela impliquera d'étendre ResourceBundle, mais lorsque j'ai essayé cela, j'ai rencontré des problèmes liés à la façon dont les balises jstl obtiennent le paquet de ressources.

Était-ce utile?

La solution

Demandez-vous simplement comment stocker les caractères UTF-8/16 dans une base de données ?dans MySQL, il s'agit simplement de vous assurer que vous construisez avec le support UTF8 et de le définir par défaut, ou de le spécifier au niveau de la colonne ou de la table.J'ai déjà fait cela dans Oracle et MySQL.Créez un tableau, coupez et collez des données i18n et voyez ce qui se passe...vous êtes peut-être déjà prêt..

ou est-ce que je manque complètement de comprendre ?

modifier:

pour être plus explicite...J'implémente habituellement un tableau à trois colonnes...langue, clé, valeur...où "valeur" contient des mots ou des expressions potentiellement étrangers..."langue" contient une clé de langue et "clé" est une clé anglaise (c'est-à-direlogin.error.password.dup)...la langue et la clé sont indexées...

J'ai ensuite construit des interfaces sur une structure comme celle-ci qui montre chaque clé avec toutes ses traductions (valeurs)...cela peut devenir sophistiqué et inclure des pistes d'audit et des marqueurs « sales » et tous les autres éléments dont vous avez besoin pour permettre aux traducteurs et aux personnes chargées de la saisie de données de l'utiliser.

Modifier 2 :

Maintenant que vous avez ajouté les informations sur les balises JSTL, je comprends un peu plus...Je n'ai jamais fait ça moi-même..mais j'ai trouvé cette vieille information sur le côté serveur...

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));

Autres conseils

J'ai finalement réussi à faire fonctionner cela avec l'aide de Danb ci-dessus.

Il s'agit de ma classe de regroupement de ressources et de ma classe de contrôle de regroupement de ressources.

J'ai utilisé ce code de @[danb]'s.

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));

et j'ai écrit ce cours.

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;
            }

        };
    }

Nous avons une table de base de données avec clé/langue/terme où clé est un n entier et est une clé primaire combinée avec la langue.

Nous utilisons Struts, nous avons donc fini par écrire le nôtre PropertyMessageResources implémentation qui nous permet de faire quelque chose comme <bean:message key="impressum.text" />.

Cela fonctionne très bien et nous donne la flexibilité de changer dynamiquement de langue dans le front-end ainsi que de mettre à jour les traductions à la volée.

En fait, ce dont ScArcher2 avait besoin, c'est d'une réponse de David qui n'est pas marquée comme correcte ou utile.

La solution que ScArcher2 a choisi d'utiliser est, à mon avis, une terrible erreur :) Charger TOUTES les traductions en même temps...dans n'importe quelle application plus importante, cela va le tuer.Chargement de milliers de traductions à chaque demande...

la méthode de David est plus couramment utilisée dans des environnements de production réels.Parfois, pour limiter les appels à la base de données, c'est-à-dire avec chaque message traduit, vous pouvez créer des groupes de traductions par sujet, fonctionnalité, etc.pour les précharger.Mais c'est un peu plus complexe et peut être remplacé par un bon système de cache.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top